📄 gtk_ext_button.c
字号:
/* * File: selection.c * * Copyright 2005 Sebastian Geerken <s.geerken@ping.de> * * 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. *//* * This Gtk+ widget is a variant of GtkButton, which adds two features: * * 1. the possibility to react on different mouse buttons (not only button * 1), and * 2. a clean way to attach menus. * * To archieve this use one of the following functions: * * a_Gtk_ext_button_set_inactive, * a_Gtk_ext_button_set_command, * a_Gtk_ext_button_attach_menu, or * a_Gtk_ext_button_attach_menu_creator. * * See comments there for more informations. * * About signals: For the command button mode, there are some new signals, * "clicked1", "clicked2", and "clicked3", which are emitted for the respective * mouse button. The signal "clicked" should be connected to as well, since * it is still used for non-mouse event handling, e.g. when then button is * activated by the <Enter> key. */#include "gtk_ext_button.h"#include <gtk/gtklabel.h>#include <gtk/gtkmain.h>#include <gtk/gtksignal.h>static void Gtk_ext_button_class_init (GtkExtButtonClass *klass);static void Gtk_ext_button_init (GtkExtButton *button);static void Gtk_ext_button_destroy (GtkObject *object);static gint Gtk_ext_button_button_press (GtkWidget *widget, GdkEventButton *event);static gint Gtk_ext_button_button_release (GtkWidget *widget, GdkEventButton *event);static gint Gtk_ext_button_enter_notify (GtkWidget *widget, GdkEventCrossing *event);static gint Gtk_ext_button_leave_notify (GtkWidget *widget, GdkEventCrossing *event);static void Gtk_ext_button_menu_hidden (GtkExtButton *ext_button);static gint clicked_signals[3];/* * Create a new GtkExtButton with no child. */GtkWidget *a_Gtk_ext_button_new (){ return gtk_type_new (a_Gtk_ext_button_get_type ());}/* * Create a new GtkExtButton with a label. */GtkWidget *a_Gtk_ext_button_new_with_label (const gchar *label){ GtkWidget *button; GtkWidget *label_widget; button = a_Gtk_ext_button_new (); label_widget = gtk_label_new (label); gtk_misc_set_alignment (GTK_MISC (label_widget), 0.5, 0.5); gtk_container_add (GTK_CONTAINER (button), label_widget); gtk_widget_show (label_widget); return button;}/* * Standard Gtk+ function. */guint a_Gtk_ext_button_get_type (){ static gint type = 0; if (!type) { GtkTypeInfo info = { "GtkExtButton", sizeof (GtkExtButton), sizeof (GtkExtButtonClass), (GtkClassInitFunc) Gtk_ext_button_class_init, (GtkObjectInitFunc) Gtk_ext_button_init, (GtkArgSetFunc)NULL, (GtkArgGetFunc)NULL, (GtkClassInitFunc)NULL }; type = gtk_type_unique (gtk_button_get_type (), &info); } return type;}/* * Standard Gtk+ function. */static void Gtk_ext_button_class_init(GtkExtButtonClass *klass){ GtkObjectClass *object_class; GtkWidgetClass *widget_class; object_class = (GtkObjectClass*) klass; object_class->destroy = Gtk_ext_button_destroy; clicked_signals[0] = gtk_signal_new ("clicked1", GTK_RUN_FIRST | GTK_RUN_ACTION, object_class->type, GTK_SIGNAL_OFFSET (GtkExtButtonClass, clicked1), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); clicked_signals[1] = gtk_signal_new ("clicked2", GTK_RUN_FIRST | GTK_RUN_ACTION, object_class->type, GTK_SIGNAL_OFFSET (GtkExtButtonClass, clicked2), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); clicked_signals[2] = gtk_signal_new ("clicked3", GTK_RUN_FIRST | GTK_RUN_ACTION, object_class->type, GTK_SIGNAL_OFFSET (GtkExtButtonClass, clicked3), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); gtk_object_class_add_signals (object_class, clicked_signals, 3); widget_class = (GtkWidgetClass*)klass; widget_class->button_press_event = Gtk_ext_button_button_press; widget_class->button_release_event = Gtk_ext_button_button_release; widget_class->enter_notify_event = Gtk_ext_button_enter_notify; widget_class->leave_notify_event = Gtk_ext_button_leave_notify;}/* * Standard Gtk+ function. */static void Gtk_ext_button_init(GtkExtButton *button){ int i; GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS); button->pressed_button = 0; button->active_menu = NULL; button->menu_signal_id = -1; for(i = 0; i < 5; i++) button->action[i] = GTK_EXT_BUTTON_INACTIVE;}/* * Standard Gtk+ function. */static void Gtk_ext_button_destroy (GtkObject *object){ GtkExtButton *button; button = GTK_EXT_BUTTON (object); if (button->menu_signal_id != -1) gtk_signal_disconnect (GTK_OBJECT (button->active_menu), button->menu_signal_id);}/* * This is used for gtk_menu_popup, to position the menu. */static void Gtk_ext_button_position_menu (GtkMenu *menu, gint *x, gint *y, gpointer user_data){ GtkWidget *widget; GtkRequisition requisition; widget = GTK_WIDGET (user_data); gdk_window_get_origin (widget->window, x, y); gtk_widget_size_request (GTK_WIDGET (menu), &requisition); if (*y + widget->allocation.height + requisition.height > gdk_screen_height()) /* Show menu above button, since there is not enough space below. */ *y -= requisition.height; else /* Show menu below button. */ *y += widget->allocation.height; /* If the menu does not fit horizontilly, adjust position. */ if (*x + requisition.width > gdk_screen_width ()) *x = gdk_screen_width () - requisition.width;}/* * Standard Gtk+ function. */static gint Gtk_ext_button_button_press (GtkWidget *widget, GdkEventButton *event){ GtkButton *button; GtkExtButton *ext_button; GtkStateType new_state; GtkMenu *menu; button = GTK_BUTTON (widget); ext_button = GTK_EXT_BUTTON (widget); if (ext_button->pressed_button) { /* Already a button pressed. */ return FALSE; } else if (event->button >= 1 && event->button <= 3 && ext_button->action[event->button - 1] != GTK_EXT_BUTTON_INACTIVE) { ext_button->pressed_button = event->button; gtk_grab_add (widget); button->button_down = TRUE; new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL); if (GTK_WIDGET_STATE (button) != new_state) { gtk_widget_set_state (GTK_WIDGET (button), new_state); gtk_widget_queue_draw (GTK_WIDGET (button)); } menu = NULL; switch(ext_button->action[event->button - 1]) { case GTK_EXT_BUTTON_INACTIVE: g_assert_not_reached (); break; case GTK_EXT_BUTTON_COMMAND: /* Nothing to do anymore. */ break; case GTK_EXT_BUTTON_MENU: menu = ext_button->action_data[event->button - 1].menu; break; case GTK_EXT_BUTTON_MENU_CREATOR: menu = ext_button->action_data[event->button - 1].creator.func ( ext_button, ext_button->action_data[event->button - 1].creator.data); break; } if (menu) { ext_button->active_menu = menu; gtk_menu_popup (menu, NULL, widget, Gtk_ext_button_position_menu, widget, event->button, event->time); ext_button->menu_signal_id = gtk_signal_connect_object (GTK_OBJECT (menu), "hide", GTK_SIGNAL_FUNC ( Gtk_ext_button_menu_hidden), (gpointer) button); } return TRUE; } else return FALSE;}/* * Standard Gtk+ function. */static gint Gtk_ext_button_button_release (GtkWidget *widget, GdkEventButton *event){ GtkButton *button; GtkExtButton *ext_button; GtkStateType new_state; ext_button = GTK_EXT_BUTTON (widget); /* Only react on the button initially pressed. */ if (event->button == ext_button->pressed_button) { button = GTK_BUTTON (widget); if (button->in_button) gtk_signal_emit (GTK_OBJECT (widget), clicked_signals[event->button - 1]); gtk_grab_remove (widget); button->button_down = FALSE; ext_button->pressed_button = 0; new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); if (GTK_WIDGET_STATE (button) != new_state) { gtk_widget_set_state (GTK_WIDGET (button), new_state); /* We _draw () instead of queue_draw so that if the operation * blocks, the label doesn't vanish. */ gtk_widget_draw (GTK_WIDGET (button), NULL); } } return TRUE;}/* * Standard Gtk+ function. */static gint Gtk_ext_button_enter_notify (GtkWidget *widget, GdkEventCrossing *event){ GtkButton *button; GtkWidget *event_widget; GtkStateType new_state; button = GTK_BUTTON (widget); event_widget = gtk_get_event_widget ((GdkEvent*) event); if ((event_widget == widget) && (event->detail != GDK_NOTIFY_INFERIOR)) { button->in_button = TRUE; new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT); if (GTK_WIDGET_STATE (button) != new_state) { gtk_widget_set_state (GTK_WIDGET (button), new_state); gtk_widget_queue_draw (GTK_WIDGET (button)); } } return FALSE;}/* * Standard Gtk+ function. */static gint Gtk_ext_button_leave_notify (GtkWidget *widget, GdkEventCrossing *event){ GtkButton *button; GtkExtButton *ext_button; GtkWidget *event_widget; button = GTK_BUTTON (widget); event_widget = gtk_get_event_widget ((GdkEvent*) event); if ((event_widget == widget) && (event->detail != GDK_NOTIFY_INFERIOR)) { button->in_button = FALSE; ext_button = GTK_EXT_BUTTON (widget); /* If a men is attached for this mouse button, we keep the button widget * inset. */ if (ext_button->pressed_button == 0 || ext_button->action[ext_button->pressed_button -1] == GTK_EXT_BUTTON_COMMAND) { /* Otherwise, normal behavior. */ if (GTK_WIDGET_STATE (button) != GTK_STATE_NORMAL) { gtk_widget_set_state (GTK_WIDGET (button), GTK_STATE_NORMAL); gtk_widget_queue_draw (GTK_WIDGET (button)); } } } return FALSE;}/* * This function is called, when a popped up menu is hidden again, to reset * the state of the button. */static void Gtk_ext_button_menu_hidden (GtkExtButton *ext_button){ GtkButton *button; g_return_if_fail (ext_button->menu_signal_id != -1); g_return_if_fail (ext_button->active_menu != NULL); gtk_signal_disconnect (GTK_OBJECT (ext_button->active_menu), ext_button->menu_signal_id); ext_button->menu_signal_id = -1; ext_button->active_menu = NULL; gtk_grab_remove (GTK_WIDGET (ext_button)); button = GTK_BUTTON (ext_button); button->in_button = FALSE; button->button_down = FALSE; ext_button->pressed_button = 0; gtk_widget_set_state (GTK_WIDGET (button), GTK_STATE_NORMAL); gtk_widget_queue_draw (GTK_WIDGET (button));}/* * Set no action for the specific mouse button. This is the default. */void a_Gtk_ext_button_set_inactive (GtkExtButton *button, gint button_no){ g_return_if_fail (button_no >= 1 && button_no <= 3); button->action[button_no - 1] = GTK_EXT_BUTTON_INACTIVE;}/* * Make the button behave like normal command button. */void a_Gtk_ext_button_set_command (GtkExtButton *button, gint button_no){ g_return_if_fail (button_no >= 1 && button_no <= 3); button->action[button_no - 1] = GTK_EXT_BUTTON_COMMAND;}/* * Attach a fixed menu to the button, which is popped up, when the user * presses the respective button. */void a_Gtk_ext_button_attach_menu (GtkExtButton *button, gint button_no, GtkMenu *menu){ g_return_if_fail (button_no >= 1 && button_no <= 3); button->action[button_no - 1] = GTK_EXT_BUTTON_MENU; button->action_data[button_no - 1].menu = menu;}/* * Attach a dynamically created menu to the button, which is popped up, when * the user presses the respective button. * * When the respective button has been pressed, the creator function is called * with the button, and the value of the argument data, the return value must * be the menu, which is then popped up. */void a_Gtk_ext_button_attach_menu_creator (GtkExtButton *button, gint button_no, GtkExtButtonMenuCreator *creator, gpointer data){ g_return_if_fail (button_no >= 1 && button_no <= 3); button->action[button_no - 1] = GTK_EXT_BUTTON_MENU_CREATOR; button->action_data[button_no - 1].creator.func = creator; button->action_data[button_no - 1].creator.data = data;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -