6

I`ve got a GtkLabel whose text is to remain centered regardless of whether it is shorter or longer than the label.

For example, a Win32 static control that has the SS_CENTER style flag set behaves like that:

             ┌===========================┐
             │     Lorem ipsum dolor     │
             └===========================┘

— when the text is shorter than the control;

             ┌===========================┐
  Lorem ipsum│dolor sit amet, consectetur│adipiscing
             └===========================┘

— when the text is longer than the control.

N.B.: The only part of the text seen by the user is inside the frame.

I expected GtkLabel-s to do the same thing, but actually they render centered text differently:

             ┌===========================┐
             │     Lorem ipsum dolor     │
             └===========================┘

— when the text is shorter than the control;

             ┌===========================┐
             │Lorem ipsum dolor sit amet,│consectetur adipiscing
             └===========================┘

— when the text is longer than the control.

How do I make centered text in a GtkLabel remain centered even when it is long?

Just in case: the actual text the user sees is updated at ~4 FPS and is unknown prior to runtime.

hidefromkgb
  • 5,834
  • 1
  • 13
  • 44

2 Answers2

2

That may be doable, but showing a semi-random part of a sentence doesn't really make sense from a user experience point of view.

Maybe give a look to gtk_label_set_ellipsize? They use a PangoEllipsizeMode to tell which part of the sentence to hide. You can then hide the beginning, middle, or end part of the label. It's an enum though, not a flag, so you won't be able to hide beginning + end to show only the middle part.

So the possible solutions I see is:

  • subclass GtkLabel and do the drawing yourself, possibly with PangoCairo
  • or add new wrap mode in GTK+ and implement it (inside pango? PangoCairo? Both?)

If this is not a strong requirement, just use a saner comportment and use existing elipsize modes.

liberforce
  • 11,189
  • 37
  • 48
  • This is a requirement that cannot be questioned. I do that for a cross-platform app which uses WinAPI on Win32, GTK+ on Linux, and Cocoa on Mac. Algorithms that work perfectly on Windows and Mac get weird on Linux. – hidefromkgb Aug 10 '18 at 13:06
  • Well. I was afraid of exactly that. GTK+ seems to lack the required functionality. OK, since I\`m forced to subclass, I\`ll post an answer myself when I\`m done. – hidefromkgb Aug 10 '18 at 13:12
  • There may be a simpler solution, it's just that I'm not aware of it. – liberforce Aug 10 '18 at 15:14
  • There isn`t, judging by the lack of answers here and elsewhere on the Internet; I did try hard to find the solution before I turned to SO. – hidefromkgb Aug 10 '18 at 15:21
  • You may find better advice by reaching to GTK+ developpers on IRC: irc://irc.gnome.org/gtk+ – liberforce Aug 10 '18 at 15:27
  • The GTK+ developers have just confirmed my suspicion: there is no easy way of doing that. [subclassing underway…] – hidefromkgb Aug 10 '18 at 16:13
  • Just in case you wanted to know, I\`ve posted a solution, and it isn\`t even that ugly. – hidefromkgb Sep 20 '18 at 23:21
1

At last the solution is ready.

#include <gtk/gtk.h>

struct SCTX {
    GtkWidget *text;
    GdkRectangle rect;
};

void Resize(GtkWidget *view, GdkRectangle *rect, gpointer user) {
    struct SCTX *sctx = user;
    GtkRequisition requ;

    if ((sctx->rect.width  != rect->width )
    ||  (sctx->rect.height != rect->height)) {
        sctx->rect = *rect;
        gtk_widget_size_request(sctx->text, &requ);
        gtk_layout_move(view, sctx->text, (rect->width  - requ.width ) / 2,
                                          (rect->height - requ.height) / 2);
    }
}

int main(int argc, char *argv[]) {
    GtkWidget *hwnd, *view;
    struct SCTX sctx = {0};

    gtk_init(&argc, &argv);
    hwnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(hwnd, "destroy", gtk_main_quit, 0);

    view = gtk_layout_new(0, 0);
    g_signal_connect(view, "size-allocate", G_CALLBACK(Resize), &sctx);
    gtk_widget_set_size_request(view, 320, 200);

    sctx.text = gtk_label_new("Lorem ipsum dolor sit amet, consectetur "
                              "adipiscing elit, sed do eiusmod tempor "
                              "incididunt ut labore et dolore magna aliqua");
    gtk_container_add(view, sctx.text);

    gtk_container_add(hwnd, view);
    gtk_container_set_border_width(GTK_CONTAINER(hwnd), 32);
    gtk_window_set_position(GTK_WINDOW(hwnd), GTK_WIN_POS_CENTER);
    gtk_widget_show_all(hwnd);
    gtk_main();
    return 0;
}

The crucial part here is wrapping a GtkLayout around our GtkLabel so the former could move the latter around inside its bounds.

hidefromkgb
  • 5,834
  • 1
  • 13
  • 44
  • I still think this is UI nonsense. By just truncating the text, you could transform "RETURN RIGHTFULLY" into "TURN RIGHT". Same for displaying numbers: showing mosts significant digits, or least significant digits may provide useful informations, but a random amount of digits in the middle won't. Bad requirements shoud be questionned, even if I acknowledge sometimes you can't (because of management, for example). So it's nice you got it to work. – liberforce Sep 25 '18 at 09:49
  • @liberforce That\`s not exactly a «bad requirement». All this is needed to implement crawling text that is center-aligned if it fits into the space it occupies. The algorithm already exists in the project`s cross-platform core, works perfectly on Windows and MacOS. – hidefromkgb Sep 25 '18 at 15:57
  • …Well, I seem to have jinxed it. When I began refining the MacOS implementation it turned out that MacOS also has its [fair share of oddities](https://stackoverflow.com/questions/53385139/nstextfield-do-not-strip-trailing-spaces-while-center-aligned). – hidefromkgb Nov 20 '18 at 01:56