From 53a4634fc4ce2e72278c8d8df65148f89bd4cf0a Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sat, 10 Dec 2011 18:13:42 -0800 Subject: [PATCH 1/2] Change the look of dialogs created with `x-popup-dialog'(Gtk) New code creates dialogs that looks(hopefully) more similar to dialogs created by other Gtk applications such as GEdit. Created dialog no longer has more than two buttons and multiple choices situation is handled with radio-buttons. --- src/gtkutil.c | 255 +++++++++++++++++++++++++++++++++++++++++--------------- src/xmenu.c | 2 - 2 files changed, 186 insertions(+), 71 deletions(-) diff --git a/src/gtkutil.c b/src/gtkutil.c index bc71685..03228a8 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -1398,36 +1398,38 @@ xg_set_frame_icon (FRAME_PTR f, Pixmap icon_pixmap, Pixmap icon_mask) /* Return the dialog title to use for a dialog of type KEY. This is the encoding used by lwlib. We use the same for GTK. */ -static const char * -get_dialog_title (char key) +static GtkWidget * +get_dialog_icon (char key) { - const char *title = ""; + GtkWidget *image = NULL; switch (key) { case 'E': case 'e': - title = "Error"; + image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, + GTK_ICON_SIZE_DIALOG); break; case 'I': case 'i': - title = "Information"; + image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, + GTK_ICON_SIZE_DIALOG); break; case 'L': case 'l': - title = "Prompt"; break; case 'P': case 'p': - title = "Prompt"; break; case 'Q': case 'q': - title = "Question"; + image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION, + GTK_ICON_SIZE_DIALOG); break; } - return title; + return image; } + /* Callback for dialogs that get WM_DELETE_WINDOW. We pop down the dialog, but return TRUE so the event does not propagate further in GTK. This prevents GTK from destroying the dialog widget automatically @@ -1458,99 +1460,214 @@ create_dialog (widget_value *wv, GCallback select_cb, GCallback deactivate_cb) { - const char *title = get_dialog_title (wv->name[0]); int total_buttons = wv->name[1] - '0'; - int right_buttons = wv->name[4] - '0'; - int left_buttons; - int button_nr = 0; - int button_spacing = 10; + + /* + Depending on the `total_buttons' value the dialog created can be + of two types: + + 1. when total_buttons > 2, then resulting dialog has following + structure: + + +------- content_area -------------------------+ + | +-------- hbox ----------------------------+ | + | | +-------+ +-- vbox --------------------+ | | + | | | | | | | | + | | | image | | +------ choices_box -----+ | | | + | | | | | | o first item | | | | + | | | | | | o second item | | | | + | | | | | | o third item | | | | + | | | | | | ... | | | | + | | | | | +------------------------+ | | | + | | | | | +------ bbox ------------+ | | | + | | | | | | +----+ +--------+ | | | | + | | | | | | | OK | | Cancel | | | | | + | | | | | | +----+ +--------+ | | | | + | | | | | +------------------------+ | | | + | | +-------+ +----------------------------+ | | + | +------------------------------------------+ | + +----------------------------------------------+ + + 2. when total_buttons <= 2, its structure is this: + + +------------- content_area ------------------------------+ + | +--------- hbox -------------------------------------+ | + | | +---------+ +------ vbox ------------------------+ | | + | | | | | | | | + | | | image | | +----------- choices_box --------+ | | | + | | | | | | +------------+ +-------------+ | | | | + | | | | | | | first item | | second item | | | | | + | | | | | | +------------+ +-------------+ | | | | + | | | | | +--------------------------------+ | | | + | | +---------+ +------------------------------------+ | | + | +----------------------------------------------------+ | + +---------------------------------------------------------+ + + */ + GtkWidget *wdialog = gtk_dialog_new (); - GtkDialog *wd = GTK_DIALOG (wdialog); - GtkBox *cur_box = GTK_BOX (gtk_dialog_get_action_area (wd)); + GtkWidget *content_area = gtk_dialog_get_action_area (GTK_DIALOG (wdialog)); widget_value *item; - GtkWidget *whbox_down; - /* If the number of buttons is greater than 4, make two rows of buttons - instead. This looks better. */ - int make_two_rows = total_buttons > 4; + GtkWidget *hbox, *vbox, *choices_box = NULL, *w = NULL; + gboolean first_item_p = TRUE; - if (right_buttons == 0) right_buttons = total_buttons/2; - left_buttons = total_buttons - right_buttons; + g_object_set (wdialog, + "destroy-with-parent" , TRUE, + "modal" , TRUE, + "title" , "", + "name" , "emacs-dialog", + "resizable" , FALSE, + "skip-taskbar-hint" , TRUE, + NULL); - gtk_window_set_title (GTK_WINDOW (wdialog), title); - gtk_widget_set_name (wdialog, "emacs-dialog"); + hbox = gtk_hbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + vbox = gtk_vbox_new (FALSE, 12); - if (make_two_rows) - { - GtkWidget *wvbox = gtk_vbox_new (TRUE, button_spacing); - GtkWidget *whbox_up = gtk_hbox_new (FALSE, 0); - whbox_down = gtk_hbox_new (FALSE, 0); + { + GtkWidget *image = get_dialog_icon (wv->name[0]); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); - gtk_box_pack_start (cur_box, wvbox, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (wvbox), whbox_up, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (wvbox), whbox_down, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); + } - cur_box = GTK_BOX (whbox_up); - } + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (content_area), hbox); - g_signal_connect (G_OBJECT (wdialog), "delete-event", - G_CALLBACK (dialog_delete_callback), 0); - - if (deactivate_cb) - { - g_signal_connect (G_OBJECT (wdialog), "close", deactivate_cb, 0); - g_signal_connect (G_OBJECT (wdialog), "response", deactivate_cb, 0); - } for (item = wv->contents; item; item = item->next) { char *utf8_label = get_utf8_string (item->value); - GtkWidget *w; - GtkRequisition req; + /* Question */ if (item->name && strcmp (item->name, "message") == 0) { - GtkBox *wvbox = GTK_BOX (gtk_dialog_get_content_area (wd)); - /* This is the text part of the dialog. */ - w = gtk_label_new (utf8_label); - gtk_box_pack_start (wvbox, gtk_label_new (""), FALSE, FALSE, 0); - gtk_box_pack_start (wvbox, w, TRUE, TRUE, 0); - gtk_misc_set_alignment (GTK_MISC (w), 0.1, 0.5); + GtkRequisition req; + + w = gtk_label_new (NULL); + g_object_set (w, + "wrap" , TRUE, + "use-markup" , TRUE, + "selectable" , TRUE, + "xalign" , 0.0, + "yalign" , 0.5, + NULL); + { + gchar *message = g_strconcat + ("", + utf8_label, "", NULL); + + gtk_label_set_markup (GTK_LABEL (w), message); + g_free (message); + } + + gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0); /* Try to make dialog look better. Must realize first so the widget can calculate the size it needs. */ gtk_widget_realize (w); gtk_widget_get_preferred_size (w, NULL, &req); - gtk_box_set_spacing (wvbox, req.height); - if (item->value && strlen (item->value) > 0) - button_spacing = 2*req.width/strlen (item->value); + gtk_box_set_spacing (GTK_BOX (vbox), req.height); + + w = NULL; } + /* Choices (radiobuttons) */ + else if (total_buttons > 2) + { + if (!choices_box) + choices_box = gtk_vbox_new (TRUE, 5); + + w = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (w), + utf8_label); + if (!item->enabled) + gtk_widget_set_sensitive (w, FALSE); + + if (select_cb) + { + g_signal_connect (G_OBJECT (w), "clicked", + G_CALLBACK (select_cb), item->call_data); + + /* + Since the first item of radiobutton group is selected + by default we have to call select_cb to set + `menu_item_selection' to appropriate value. + */ + if (first_item_p) + { + first_item_p = FALSE; + ((void (*) (GtkWidget *, gpointer)) select_cb) + (w, item->call_data); + } + } + + gtk_box_pack_start (GTK_BOX (choices_box), w, TRUE, TRUE, 0); + } + /* Choices (buttons) */ else { - /* This is one button to add to the dialog. */ + if (!choices_box) + { + choices_box = gtk_hbutton_box_new (); + gtk_button_box_set_layout (GTK_BUTTON_BOX (choices_box), + GTK_BUTTONBOX_END); + gtk_box_set_spacing (GTK_BOX (choices_box), 10); + } + w = gtk_button_new_with_label (utf8_label); - if (! item->enabled) - gtk_widget_set_sensitive (w, FALSE); + if (select_cb) g_signal_connect (G_OBJECT (w), "clicked", select_cb, item->call_data); + if (deactivate_cb) + g_signal_connect (G_OBJECT (w), "clicked", deactivate_cb, NULL); - gtk_box_pack_start (cur_box, w, TRUE, TRUE, button_spacing); - if (++button_nr == left_buttons) - { - if (make_two_rows) - cur_box = GTK_BOX (whbox_down); - else - gtk_box_pack_start (cur_box, - gtk_label_new (""), - TRUE, TRUE, - button_spacing); - } + + gtk_container_add (GTK_CONTAINER (choices_box), w); } + if (utf8_label) + g_free (utf8_label); + } + + if (total_buttons > 2) + { + GtkWidget *bbox = gtk_hbutton_box_new (); + GtkWidget *ok = gtk_button_new_from_stock (GTK_STOCK_OK); + GtkWidget *cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL); + GtkWidget *frame = gtk_frame_new ("Possible actions/answers"); + + gtk_container_add (GTK_CONTAINER (bbox), ok); + gtk_container_add (GTK_CONTAINER (bbox), cancel); + + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); + gtk_box_set_spacing (GTK_BOX (bbox), 10); + + + gtk_container_add (GTK_CONTAINER (frame), choices_box); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (vbox), bbox, TRUE, TRUE, 0); - if (utf8_label) - g_free (utf8_label); + if (deactivate_cb) + { + g_signal_connect (G_OBJECT (ok), "clicked", deactivate_cb, 0); + g_signal_connect (G_OBJECT (cancel), "clicked", select_cb, 0); + g_signal_connect (G_OBJECT (cancel), "clicked", deactivate_cb, 0); + } + } + else + { + gtk_box_pack_start (GTK_BOX (vbox), choices_box, TRUE, TRUE, 0); + } + + g_signal_connect (G_OBJECT (wdialog), "delete-event", + G_CALLBACK (dialog_delete_callback), 0); + + if (deactivate_cb) + { + g_signal_connect (G_OBJECT (wdialog), "close", deactivate_cb, 0); + g_signal_connect (G_OBJECT (wdialog), "response", deactivate_cb, 0); } return wdialog; diff --git a/src/xmenu.c b/src/xmenu.c index 4b7bbfd..547b538 100644 --- a/src/xmenu.c +++ b/src/xmenu.c @@ -1904,8 +1904,6 @@ dialog_selection_callback (GtkWidget *widget, gpointer client_data) as long as pointers have enough bits to hold small integers. */ if ((intptr_t) client_data != -1) menu_item_selection = (Lisp_Object *) client_data; - - popup_activated_flag = 0; } /* Pop up the dialog for frame F defined by FIRST_WV and loop until the -- 1.7.5.4