]> Pileus Git - ~andy/gtk/blob - gtk/gtktoggletoolbutton.c
gtkradiotoolbutton.c gtkradiotoolbutton.h gtktoggletoolbutton.c
[~andy/gtk] / gtk / gtktoggletoolbutton.c
1 /* gtktoggletoolbutton.c
2  *
3  * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se>
4  * Copyright (C) 2002 James Henstridge <james@daa.com.au>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "gtktoggletoolbutton.h"
23 #include "gtkcheckmenuitem.h"
24 #include "gtklabel.h"
25 #include "gtktogglebutton.h"
26 #include "gtkstock.h"
27 #include "gtkintl.h"
28
29 #define MENU_ID "gtk-toggle-tool-button-menu-id"
30
31 enum {
32   TOGGLED,
33   LAST_SIGNAL
34 };
35
36 static void gtk_toggle_tool_button_init       (GtkToggleToolButton      *button);
37 static void gtk_toggle_tool_button_class_init (GtkToggleToolButtonClass *klass);
38
39 static gboolean gtk_toggle_tool_button_create_menu_proxy (GtkToolItem *button);
40
41 static void button_toggled      (GtkWidget           *widget,
42                                  GtkToggleToolButton *button);
43 static void menu_item_activated (GtkWidget           *widget,
44                                  GtkToggleToolButton *button);
45
46 static GObjectClass *parent_class = NULL;
47 static guint         toggle_signals[LAST_SIGNAL] = { 0 };
48
49 GType
50 gtk_toggle_tool_button_get_type (void)
51 {
52   static GType type = 0;
53
54   if (!type)
55     {
56       static const GTypeInfo type_info =
57         {
58           sizeof (GtkToggleToolButtonClass),
59           (GBaseInitFunc) 0,
60           (GBaseFinalizeFunc) 0,
61           (GClassInitFunc) gtk_toggle_tool_button_class_init,
62           (GClassFinalizeFunc) 0,
63           NULL,
64           sizeof (GtkToggleToolButton),
65           0, /* n_preallocs */
66           (GInstanceInitFunc) gtk_toggle_tool_button_init
67         };
68
69       type = g_type_register_static (GTK_TYPE_TOOL_BUTTON,
70                                      "GtkToggleToolButton", &type_info, 0);
71     }
72   return type;
73 }
74
75
76 static void
77 gtk_toggle_tool_button_class_init (GtkToggleToolButtonClass *klass)
78 {
79   GObjectClass *object_class;
80   GtkToolItemClass *toolitem_class;
81   GtkToolButtonClass *toolbutton_class;
82
83   parent_class = g_type_class_peek_parent (klass);
84
85   object_class = (GObjectClass *)klass;
86   toolitem_class = (GtkToolItemClass *)klass;
87   toolbutton_class = (GtkToolButtonClass *)klass;
88
89   toolitem_class->create_menu_proxy = gtk_toggle_tool_button_create_menu_proxy;
90   toolbutton_class->button_type = GTK_TYPE_TOGGLE_BUTTON;
91   
92   toggle_signals[TOGGLED] =
93     g_signal_new ("toggled",
94                   G_OBJECT_CLASS_TYPE (klass),
95                   G_SIGNAL_RUN_FIRST,
96                   G_STRUCT_OFFSET (GtkToggleToolButtonClass, toggled),
97                   NULL, NULL,
98                   g_cclosure_marshal_VOID__VOID,
99                   G_TYPE_NONE, 0);
100 }
101
102 static void
103 gtk_toggle_tool_button_init (GtkToggleToolButton *button)
104 {
105   g_signal_connect_object (GTK_TOOL_BUTTON (button)->button, "toggled",
106                            G_CALLBACK (button_toggled), button, 0);
107 }
108
109 static gboolean
110 gtk_toggle_tool_button_create_menu_proxy (GtkToolItem *item)
111 {
112   GtkToolButton *tool_button = GTK_TOOL_BUTTON (item);
113   GtkToggleToolButton *toggle_tool_button = GTK_TOGGLE_TOOL_BUTTON (item);
114   GtkWidget *menu_item = NULL;
115   GtkStockItem stock_item;
116   gboolean use_mnemonic = TRUE;
117   const char *label = "";
118
119   if (tool_button->label_widget && GTK_IS_LABEL (tool_button->label_widget))
120     label = gtk_label_get_label (GTK_LABEL (tool_button->label_widget));
121   else if (tool_button->label_text)
122     {
123       label = tool_button->label_text;
124       use_mnemonic = tool_button->use_underline;
125     }
126   else if (tool_button->stock_id && gtk_stock_lookup (tool_button->stock_id, &stock_item))
127     label = stock_item.label;
128   
129   if (use_mnemonic)
130     menu_item = gtk_check_menu_item_new_with_mnemonic (label);
131   else
132     menu_item = gtk_check_menu_item_new_with_label (label);
133
134   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
135                                   toggle_tool_button->active);
136
137   g_signal_connect_closure_by_id (menu_item,
138                                   g_signal_lookup ("activate", G_OBJECT_TYPE (menu_item)), 0,
139                                   g_cclosure_new_object (G_CALLBACK (menu_item_activated),
140                                                          G_OBJECT (toggle_tool_button)),
141                                   FALSE);
142
143   gtk_tool_item_set_proxy_menu_item (item, MENU_ID, menu_item);
144   
145   return TRUE;
146 }
147
148 /* There are two activatable widgets, a toggle button and a menu item.
149  *
150  * If a widget is activated and the state of the tool button is the same as
151  * the new state of the activated widget, then the other widget was the one
152  * that was activated by the user and updated the tool button's state.
153  *
154  * If the state of the tool button is not the same as the new state of the
155  * activated widget, then the activation was activated by the user, and the
156  * widget needs to make sure the tool button is updated before the other
157  * widget is activated. This will make sure the other widget a tool button
158  * in a state that matches its own new state.
159  */
160 static void
161 menu_item_activated (GtkWidget           *menu_item,
162                      GtkToggleToolButton *toggle_tool_button)
163 {
164   GtkToolButton *tool_button = GTK_TOOL_BUTTON (toggle_tool_button);
165   gboolean menu_active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_item));
166
167   if (toggle_tool_button->active != menu_active)
168     {
169       toggle_tool_button->active = menu_active;
170
171       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tool_button->button),
172                                     toggle_tool_button->active);
173
174       g_signal_emit (G_OBJECT (toggle_tool_button), toggle_signals[TOGGLED], 0);
175     }
176 }
177
178 static void
179 button_toggled (GtkWidget           *widget,
180                 GtkToggleToolButton *toggle_tool_button)
181 {
182   gboolean toggle_active = GTK_TOGGLE_BUTTON (widget)->active;
183
184   if (toggle_tool_button->active != toggle_active)
185     {
186       GtkWidget *menu_item;
187       
188       toggle_tool_button->active = toggle_active;
189        
190       if ((menu_item =
191            gtk_tool_item_get_proxy_menu_item (GTK_TOOL_ITEM (toggle_tool_button), MENU_ID)))
192         {
193           gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
194                                           toggle_tool_button->active);
195         }
196
197       g_signal_emit (G_OBJECT (toggle_tool_button), toggle_signals[TOGGLED], 0);
198     }
199 }
200
201 GtkToolItem *
202 gtk_toggle_tool_button_new (void)
203 {
204   GtkToolButton *button;
205
206   button = g_object_new (GTK_TYPE_TOGGLE_TOOL_BUTTON,
207                          NULL);
208   
209   return GTK_TOOL_ITEM (button);
210 }
211
212 GtkToolItem *
213 gtk_toggle_tool_button_new_from_stock (const gchar *stock_id)
214 {
215   GtkToolButton *button;
216
217   g_return_val_if_fail (stock_id != NULL, NULL);
218   
219   button = g_object_new (GTK_TYPE_TOGGLE_TOOL_BUTTON,
220                          "stock_id", stock_id,
221                          NULL);
222   
223   return GTK_TOOL_ITEM (button);
224 }
225
226 void
227 gtk_toggle_tool_button_set_active (GtkToggleToolButton *button,
228                                    gboolean is_active)
229 {
230   g_return_if_fail (GTK_IS_TOGGLE_TOOL_BUTTON (button));
231
232   is_active = is_active != FALSE;
233
234   if (button->active != is_active)
235     gtk_button_clicked (GTK_BUTTON (GTK_TOOL_BUTTON (button)->button));
236 }
237
238 gboolean
239 gtk_toggle_tool_button_get_active (GtkToggleToolButton *button)
240 {
241   g_return_val_if_fail (GTK_IS_TOGGLE_TOOL_BUTTON (button), FALSE);
242
243   return button->active;
244 }