/* * Copyright (C) 2001, 2002 Damien Tanner * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include #include static gchar *default_colors = "black:white:gray50:red:purple:blue:light blue:green:yellow:orange:lavender:brown:goldenrod4:dodger blue:pink:light green:gray10:gray30:gray75:gray90"; void popup_menu_close (GtkWidget *parent_button) { GtkWidget *parent_arrow; if(g_object_get_data (G_OBJECT (parent_button), "active") == FALSE) return; parent_arrow = g_object_get_data (G_OBJECT (parent_button), "arrow"); gtk_widget_destroy (g_object_get_data (G_OBJECT (parent_button), "window")); g_object_set_data (G_OBJECT (parent_button), "active", FALSE); gtk_arrow_set (GTK_ARROW (parent_arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE); } static void toggle_popup_menu (GtkWidget *parent_button, GtkWidget *(construct_func)()) { GtkWidget *popup_window, *frame, *child_widget, *scrolled_window; GtkWidget *parent_arrow; GtkRequisition frame_requisition, parent_button_requisition, child_requisition; gint x, y; gint screen_width; gint screen_height; parent_arrow = g_object_get_data (G_OBJECT (parent_button), "arrow"); if ((gboolean) g_object_get_data (G_OBJECT (parent_button), "active") == TRUE) { popup_menu_close (parent_button); } else { g_object_set_data (G_OBJECT (parent_button), "active", (gpointer) TRUE); gtk_arrow_set (GTK_ARROW (parent_arrow), GTK_ARROW_UP, GTK_SHADOW_NONE); popup_window = gtk_window_new (GTK_WINDOW_POPUP); frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); child_widget = construct_func (parent_button); gtk_widget_show_all (child_widget); screen_width = gdk_screen_width (); screen_height = gdk_screen_height (); gdk_window_get_position (gtk_widget_get_parent_window (parent_button), &x, &y); gtk_widget_size_request (child_widget, &child_requisition); gtk_widget_size_request (parent_button, &parent_button_requisition); if (child_requisition.height >= screen_height - (y + parent_button->allocation.y + parent_button->allocation.height)) { scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), child_widget); gtk_container_add (GTK_CONTAINER (frame), scrolled_window); gtk_widget_set_size_request (frame, -1, screen_height - (y + parent_button->allocation.y + parent_button->allocation.height)); } else { gtk_container_add (GTK_CONTAINER (frame), child_widget); } gtk_container_add (GTK_CONTAINER (popup_window), frame); gtk_widget_show_all (frame); gtk_widget_size_request (frame, &frame_requisition); x = CLAMP (x + parent_button->allocation.x, 0, MAX (0, screen_width - frame_requisition.width)); y += parent_button->allocation.y; y += parent_button_requisition.height; gtk_widget_set_uposition (popup_window, x, y); g_object_set_data (G_OBJECT (parent_button), "window", popup_window); gtk_widget_show_all (popup_window); } } GtkWidget * popup_menu_button_new (GtkWidget *child, GtkWidget *(construct_func)(), void *(callback_func)()) { GtkWidget *button, *arrow, *hbox; GtkRequisition requisition; gint width = 0, height; button = gtk_button_new (); arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); hbox = gtk_hbox_new (FALSE, 0); gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE); g_object_set_data (G_OBJECT (button), "active", FALSE); g_object_set_data (G_OBJECT (button), "hbox", hbox); g_object_set_data (G_OBJECT (button), "child", child); g_object_set_data (G_OBJECT (button), "arrow", arrow); g_object_set_data (G_OBJECT (button), "callback", callback_func); gtk_box_pack_start (GTK_BOX (hbox), child, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0); gtk_widget_size_request (child, &requisition); width = width + requisition.width; height = requisition.height; gtk_widget_size_request (arrow, &requisition); width = (width + requisition.width) - 5; gtk_signal_connect (GTK_OBJECT (button), "pressed", GTK_SIGNAL_FUNC (toggle_popup_menu), (gpointer) construct_func); gtk_widget_set_size_request (hbox, width, height); gtk_container_add (GTK_CONTAINER (button), hbox); gtk_widget_show_all (button); return button; } GtkWidget * popup_menu_button_new_from_stock (const gchar *stock_id, GtkWidget *(construct_func)(), void *(callback_func)()) { GtkWidget *image; image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_SMALL_TOOLBAR); return popup_menu_button_new (image, construct_func, callback_func); } static int construct_font_popup_cmp_families (const void *a, const void *b) { const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a); const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b); return g_utf8_collate (a_name, b_name); } static GtkWidget * construct_font_popup (GtkWidget *parent_button) { GtkWidget *vbox, *button, *alignment, *button_label; GtkRcStyle *button_label_rc_style; PangoFontFamily **families; gint n_families, i; vbox = gtk_vbox_new (FALSE, 0); pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (parent_button)), &families, &n_families); qsort (families, n_families, sizeof (PangoFontFamily *), construct_font_popup_cmp_families); for (i=0; ifont_desc = pango_font_description_from_string (g_strdup_printf ("%s 9", font_name)); gtk_widget_modify_style (button_label, button_label_rc_style); alignment = gtk_alignment_new (0, 0, 0, 0); button = gtk_button_new (); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (g_object_get_data (G_OBJECT (parent_button), "callback")), families[i]); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); g_object_set_data (G_OBJECT (button), "parent_button", parent_button); gtk_container_add (GTK_CONTAINER (alignment), button_label); gtk_container_add (GTK_CONTAINER (button), alignment); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); } g_free (families); return vbox; } static void construct_color_popup_add_color (GtkWidget *table, GdkColor color, gint i, gint j, GtkWidget *parent_button) { GtkWidget *frame, *drawing_area; frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); drawing_area = gtk_drawing_area_new (); gtk_widget_set_size_request (drawing_area, 12, 12); gtk_widget_modify_bg (drawing_area, GTK_STATE_NORMAL, &color); g_signal_connect (G_OBJECT (drawing_area), "button-release-event", G_CALLBACK (g_object_get_data (G_OBJECT (parent_button), "callback")), &color); gtk_widget_add_events (GTK_WIDGET (drawing_area), GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); gtk_container_add (GTK_CONTAINER (frame), drawing_area); gtk_table_attach_defaults (GTK_TABLE (table), frame, i, i+1, j, j+1); } static GtkWidget * construct_color_popup (GtkWidget *parent_button) { GtkWidget *vbox, *table, *button; GdkColor *colors = NULL; gint i = 0, j = 0, k = 0; gint n_colors = 0; vbox = gtk_vbox_new (FALSE, 0); table = gtk_table_new (4, 5, TRUE); gtk_table_set_row_spacings (GTK_TABLE (table), 1); gtk_table_set_col_spacings (GTK_TABLE (table), 1); gtk_color_selection_palette_from_string (default_colors, &colors, &n_colors); while (k < n_colors) { if (j == 4) { j = 0; i++; } construct_color_popup_add_color (table, colors[k], i, j, parent_button); k++; j++; } button = gtk_button_new_with_label ("Custom..."); gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); return vbox; } GtkWidget * popup_menu_button_new_type_color (void *(callback_func)()) { return popup_menu_button_new_from_stock (GTK_STOCK_SELECT_COLOR, construct_color_popup, callback_func); } GtkWidget * popup_menu_button_new_type_font (void *(callback_func)()) { return popup_menu_button_new_from_stock (GTK_STOCK_SELECT_FONT, construct_font_popup, callback_func); }