/* Ukázka nových funkcí pro práci s dialogy v GTK+ 2 */ #include #include /* Struktura pro data zadaná v dialogu */ struct dialog_data { gdouble scale; char radio; } dialog_data = { -1.0, '?' }; GtkWidget *window; /* GtkWindow, hlavní okno programu */ GtkWidget *view; /* Label v hlavním okně, který zobrazuje obsah dialog_data */ GtkWidget *toggle; /* Toggle button pro zobrazování dialogu */ GtkWidget *dialog; /* GtkDialog */ GtkWidget *scale; /* GtkScale v dialogu */ GSList *radios; /* Radio buttons v dialogu */ gboolean modal; /* TRUE pro modální dialog */ gint delete_event_handler; /* Handler dialogu pro "delete-event" */ /* Funkce na čtení hodnot nastavených v dialogu */ typedef void (*get_data_fun)(GtkWidget *widget, void *data, glong offset); static void get_scale_val(GtkWidget *widget, void *data, glong offset) { gdouble d = gtk_range_get_value(GTK_RANGE(widget)); G_STRUCT_MEMBER(gdouble, data, offset) = d; g_printerr("Returning %f from get_scale_val()\n", d); } static void get_radio_val(GtkWidget *widget, void *data, glong offset) { char c = gtk_button_get_label(GTK_BUTTON(widget))[1]; const char *s; if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) { G_STRUCT_MEMBER(char, data, offset) = c; s = "Returning"; } else s = "Not returning"; g_printerr("%s %c from get_radio_val()\n", s, c); } static void get_data(GtkWidget *widget, gpointer data) { get_data_fun f = (get_data_fun)g_object_get_data(G_OBJECT(widget), "get-data-fun"); gpointer o = g_object_get_data(G_OBJECT(widget), "data-offset"); if(f) f(widget, data, GPOINTER_TO_INT(o)); if(GTK_IS_CONTAINER(widget)) gtk_container_foreach(GTK_CONTAINER(widget), get_data, data); } static void get_dialog_data(GtkWidget *widget, struct dialog_data *data) { gtk_container_foreach(GTK_CONTAINER(widget), get_data, data); } /* V hlavním okně aktualizuje zobrazení dat nastavených v dialogu */ static void update_label(GtkLabel *label) { char buf[30]; g_snprintf(buf, sizeof(buf), "scale = %f\nradio = %c", dialog_data.scale, dialog_data.radio); gtk_label_set_text(label, buf); } /* Vyžaduje potvrzení před zavřením hlavního okna */ static gboolean main_delete(GtkWidget *widget, GdkEvent *event, gpointer data) { GtkWidget *dialog; gint resp; /* Hlavní okno je nastaveno jako transient parent dialogu. Window manager * pak zobrazí dialog uprostřed okna. */ dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "Are you sure to quit?"); /* Spuštění modálního dialogu a čekání na reakci uživatele */ resp = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); switch(resp) { case GTK_RESPONSE_NONE: g_printerr("No response from message dialog\n"); return TRUE; case GTK_RESPONSE_YES: g_printerr("Response YES from message dialog\n"); return FALSE; case GTK_RESPONSE_NO: g_printerr("Response NO from message dialog\n"); return TRUE; case GTK_RESPONSE_DELETE_EVENT: g_printerr("Message dialog deleted\n"); return TRUE; default: g_printerr("Response %d from message dialog\n", resp); return TRUE; } } /* Událost "delete-event" nezruší dialog. Standardní obsluha "delete-event" * vygeneruje signál "response" s hodnotou GTK_RESPONSE_DELETE_EVENT. Tato * standardní obsluha se volá jako první, takže proběhne, i když * dialog_delete() vratí TRUE. Funkce gtk_dialog_run() si přidá ještě svůj * handler, který ukončuje rekurzivně volanou smyčku událostí. Tento handler * se nezavolá díky návratové hodnotě TRUE z dialog_delete(). To ale nevadí, * protože standardní obsluha "response" také ukončí vnořenou smyčku událostí. */ static gboolean dialog_delete(GtkWidget *widget, GdkEvent *event, gpointer data) { g_printerr("dialog_delete() called\n"); return TRUE; } /* Nastavení modality dialogu */ static void change_modality(GtkWidget *widget, gpointer data) { modal = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); } /* Zobrazení/schování dialogu (modální nebo nemodální) */ static void show_dialog(GtkWidget *widget, gpointer data) { if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) { /* Zobrazit */ if(modal) { gtk_dialog_run(GTK_DIALOG(data)); } else gtk_widget_show(GTK_WIDGET(data)); } else gtk_widget_hide(GTK_WIDGET(data)); } /* Handler signálu "response", volá se při zavření dialogu */ static void response_handler(GtkDialog *dialog, gint resp, gpointer data) { switch(resp) { case GTK_RESPONSE_NONE: g_printerr("No response from dialog\n"); break; case GTK_RESPONSE_OK: g_printerr("Response OK from dialog\n"); get_dialog_data(GTK_WIDGET(dialog), &dialog_data); update_label(GTK_LABEL(view)); break; case GTK_RESPONSE_CANCEL: g_printerr("Response Cancel from dialog\n"); break; case GTK_RESPONSE_DELETE_EVENT: g_printerr("Dialog deleted\n"); break; default: g_printerr("Response %d from dialog\n", resp); break; } /* Vygeneruje "toggled", zavolá se show_dialog() a schová dialog. */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data), FALSE); } int main(int argc, char *argv[]) { GtkWidget *widget, *box, *frame; gtk_init(&argc, &argv); /* Hlavní okno */ window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "New dialog features"); gtk_container_set_border_width(GTK_CONTAINER(window), 10); g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(main_delete), NULL); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); box = gtk_vbox_new(FALSE, 5); gtk_container_add(GTK_CONTAINER(window), box); view = gtk_label_new(""); gtk_box_pack_start(GTK_BOX(box), view, FALSE, FALSE, 0); update_label(GTK_LABEL(view)); toggle = gtk_toggle_button_new_with_mnemonic("_Show dialog"); GTK_WIDGET_SET_FLAGS(toggle, GTK_CAN_DEFAULT); gtk_box_pack_end(GTK_BOX(box), toggle, FALSE, FALSE, 0); gtk_widget_grab_default(toggle); widget = gtk_check_button_new_with_mnemonic("_Modal"); g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(change_modality), NULL); gtk_box_pack_end(GTK_BOX(box), widget, FALSE, FALSE, 0); /* Připravit dialog, ale nezobrazovat */ dialog = gtk_dialog_new(); delete_event_handler = g_signal_connect(G_OBJECT(dialog), "delete-event", G_CALLBACK(dialog_delete), NULL); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(response_handler), toggle); gtk_window_set_title(GTK_WINDOW(dialog), "A dialog"); gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window)); gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), 5); box = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), box, FALSE, FALSE, 0); widget = gtk_label_new_with_mnemonic("_Scale:"); gtk_box_pack_start(GTK_BOX(box), widget, FALSE, FALSE, 0); scale = gtk_hscale_new(GTK_ADJUSTMENT(gtk_adjustment_new(0, -10, 10, 0.1, 1, 0))); g_object_set_data(G_OBJECT(scale), "get-data-fun", get_scale_val); g_object_set_data(G_OBJECT(scale), "data-offset", GINT_TO_POINTER(G_STRUCT_OFFSET(struct dialog_data, scale))); gtk_label_set_mnemonic_widget(GTK_LABEL(widget), scale); gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT); gtk_box_pack_start(GTK_BOX(box), scale, TRUE, TRUE, 0); frame = gtk_frame_new("Radio buttons in frame"); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 0); box = gtk_vbox_new(FALSE, 5); gtk_container_add(GTK_CONTAINER(frame), box); widget = gtk_radio_button_new_with_mnemonic(NULL, "_A"); g_object_set_data(G_OBJECT(widget), "get-data-fun", get_radio_val); g_object_set_data(G_OBJECT(widget), "data-offset", GINT_TO_POINTER(G_STRUCT_OFFSET(struct dialog_data, radio))); gtk_box_pack_start(GTK_BOX(box), widget, FALSE, FALSE, 0); widget = gtk_radio_button_new_with_mnemonic_from_widget( GTK_RADIO_BUTTON(widget), "_B"); g_object_set_data(G_OBJECT(widget), "get-data-fun", get_radio_val); g_object_set_data(G_OBJECT(widget), "data-offset", GINT_TO_POINTER(G_STRUCT_OFFSET(struct dialog_data, radio))); gtk_box_pack_start(GTK_BOX(box), widget, FALSE, FALSE, 0); widget = gtk_radio_button_new_with_mnemonic_from_widget( GTK_RADIO_BUTTON(widget), "_C"); g_object_set_data(G_OBJECT(widget), "get-data-fun", get_radio_val); g_object_set_data(G_OBJECT(widget), "data-offset", GINT_TO_POINTER(G_STRUCT_OFFSET(struct dialog_data, radio))); gtk_box_pack_start(GTK_BOX(box), widget, FALSE, FALSE, 0); widget = gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK); GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_DEFAULT); gtk_widget_grab_default(widget); gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); g_signal_connect(G_OBJECT(toggle), "toggled", G_CALLBACK(show_dialog), dialog); gtk_container_foreach(GTK_CONTAINER(dialog), (GtkCallback)gtk_widget_show_all, NULL); gtk_widget_show_all(window); gtk_main(); return 0; }