]> git.sur5r.net Git - glabels/blob - src/wdgt-chain-button.c
Cleanup some '-Wall' warnings.
[glabels] / src / wdgt-chain-button.c
1 /*
2  *  wdgt-chain-button.c
3  *  Modified version of gimpchainbutton.h for gLabels:
4  *
5  *  LIBGIMP - The GIMP Library
6  *  Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
7  *
8  *  gimpchainbutton.h
9  *  Copyright (C) 1999-2000 Sven Neumann <sven@gimp.org>
10  *
11  *  Modified or gLabels by Jim Evins <evins@snaught.com>
12  *
13  *
14  *  This file is part of gLabels.
15  *
16  *  gLabels is free software: you can redistribute it and/or modify
17  *  it under the terms of the GNU General Public License as published by
18  *  the Free Software Foundation, either version 3 of the License, or
19  *  (at your option) any later version.
20  *
21  *  gLabels is distributed in the hope that it will be useful,
22  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  *  GNU General Public License for more details.
25  *
26  *  You should have received a copy of the GNU General Public License
27  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
28  */
29
30 #include "wdgt-chain-button.h"
31
32 #include <glib/gi18n.h>
33 #include <gtk/gtk.h>
34
35
36 enum
37 {
38   TOGGLED,
39   LAST_SIGNAL
40 };
41
42
43 static void      gl_wdgt_chain_button_clicked_callback (GtkWidget          *widget,
44                                                         glWdgtChainButton  *button);
45 static gboolean  gl_wdgt_chain_button_draw_lines       (GtkWidget          *widget,
46                                                         cairo_t            *cr,
47                                                         glWdgtChainButton  *button);
48
49
50 static const gchar *gl_wdgt_chain_stock_items[] =
51 {
52 #if 0
53   "glabels-hchain",
54   "glabels-hchain-broken",
55   "glabels-vchain",
56   "glabels-vchain-broken"
57 #else
58   "changes-prevent",
59   "changes-allow",
60   "changes-prevent",
61   "changes-allow",
62 #endif
63 };
64
65
66 static guint gl_wdgt_chain_button_signals[LAST_SIGNAL] = { 0 };
67
68
69
70 G_DEFINE_TYPE (glWdgtChainButton, gl_wdgt_chain_button, GTK_TYPE_TABLE);
71
72
73 static void
74 gl_wdgt_chain_button_class_init (glWdgtChainButtonClass *class)
75 {
76         gl_wdgt_chain_button_parent_class = g_type_class_peek_parent (class);
77
78         gl_wdgt_chain_button_signals[TOGGLED] =
79                 g_signal_new ("toggled",
80                               G_TYPE_FROM_CLASS (class),
81                               G_SIGNAL_RUN_FIRST,
82                               G_STRUCT_OFFSET (glWdgtChainButtonClass, toggled),
83                               NULL, NULL,
84                               g_cclosure_marshal_VOID__VOID,
85                               G_TYPE_NONE, 0);
86
87         class->toggled = NULL;
88 }
89
90 static void
91 gl_wdgt_chain_button_init (glWdgtChainButton *button)
92 {
93         button->position = GL_WDGT_CHAIN_TOP;
94         button->active   = FALSE;
95
96         button->line1    = gtk_drawing_area_new ();
97         button->line2    = gtk_drawing_area_new ();
98         button->image    = gtk_image_new ();
99
100         button->button   = gtk_toggle_button_new ();
101
102         gtk_button_set_relief (GTK_BUTTON (button->button), GTK_RELIEF_NONE);
103         gtk_button_set_focus_on_click (GTK_BUTTON (button->button), FALSE);
104         gtk_container_add (GTK_CONTAINER (button->button), button->image);
105         gtk_widget_show (button->image);
106
107         g_signal_connect (button->button, "clicked",
108                           G_CALLBACK (gl_wdgt_chain_button_clicked_callback),
109                           button);
110         g_signal_connect (button->line1, "draw",
111                           G_CALLBACK (gl_wdgt_chain_button_draw_lines),
112                           button);
113         g_signal_connect (button->line2, "draw",
114                           G_CALLBACK (gl_wdgt_chain_button_draw_lines),
115                           button);
116
117 }
118
119
120 /**
121  * gl_wdgt_chain_button_new:
122  * @position: The position you are going to use for the button
123  *            with respect to the widgets you want to chain.
124  *
125  * Creates a new #glWdgtChainButton widget.
126  *
127  * This returns a button showing either a broken or a linked chain and
128  * small clamps attached to both sides that visually group the two widgets
129  * you want to connect. This widget looks best when attached
130  * to a table taking up two columns (or rows respectively) next
131  * to the widgets that it is supposed to connect. It may work
132  * for more than two widgets, but the look is optimized for two.
133  *
134  * Returns: Pointer to the new #glWdgtChainButton, which is inactive
135  *          by default. Use gl_wdgt_chain_button_set_active() to
136  *          change its state.
137  */
138 GtkWidget *
139 gl_wdgt_chain_button_new (glWdgtChainPosition position)
140 {
141   glWdgtChainButton *button;
142
143   button = g_object_new (GL_WDGT_TYPE_CHAIN_BUTTON, NULL);
144
145   button->position = position;
146
147   gtk_image_set_from_icon_name
148     (GTK_IMAGE (button->image),
149      gl_wdgt_chain_stock_items[((position & GL_WDGT_CHAIN_LEFT) << 1) + ! button->active],
150      GTK_ICON_SIZE_BUTTON);
151
152   if (position & GL_WDGT_CHAIN_LEFT) /* are we a vertical chainbutton? */
153     {
154       gtk_table_resize (GTK_TABLE (button), 3, 1);
155       gtk_table_attach (GTK_TABLE (button), button->button, 0, 1, 1, 2,
156                         GTK_SHRINK, GTK_SHRINK, 0, 0);
157       gtk_table_attach (GTK_TABLE (button), button->line1, 0, 1, 0, 1,
158                         GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0 );
159       gtk_table_attach (GTK_TABLE (button), button->line2, 0, 1, 2, 3,
160                         GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0 );
161     }
162   else
163     {
164       gtk_table_resize (GTK_TABLE (button), 1, 3);
165       gtk_table_attach (GTK_TABLE (button), button->button, 1, 2, 0, 1,
166                         GTK_SHRINK, GTK_SHRINK, 0, 0);
167       gtk_table_attach (GTK_TABLE (button), button->line1, 0, 1, 0, 1,
168                         GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
169       gtk_table_attach (GTK_TABLE (button), button->line2, 2, 3, 0, 1,
170                         GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
171     }
172
173   gtk_widget_show (button->button);
174   gtk_widget_show (button->line1);
175   gtk_widget_show (button->line2);
176
177   return GTK_WIDGET (button);
178 }
179
180 /**
181  * gl_wdgt_chain_button_set_active:
182  * @button: Pointer to a #glWdgtChainButton.
183  * @active: The new state.
184  *
185  * Sets the state of the #glWdgtChainButton to be either locked (%TRUE) or
186  * unlocked (%FALSE) and changes the showed pixmap to reflect the new state.
187  */
188 void
189 gl_wdgt_chain_button_set_active (glWdgtChainButton  *button,
190                                  gboolean          active)
191 {
192   g_return_if_fail (GL_WDGT_IS_CHAIN_BUTTON (button));
193
194   if (button->active != active)
195     {
196       guint num;
197
198       button->active = active ? TRUE : FALSE;
199
200       num = ((button->position & GL_WDGT_CHAIN_LEFT) << 1) + (active ? 0 : 1);
201
202       gtk_image_set_from_icon_name (GTK_IMAGE (button->image),
203                                     gl_wdgt_chain_stock_items[num],
204                                     GTK_ICON_SIZE_MENU);
205
206       g_signal_handlers_block_by_func (G_OBJECT (button->button),
207                                        gl_wdgt_chain_button_clicked_callback, button);
208       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button->button), active);
209       g_signal_handlers_unblock_by_func (G_OBJECT (button->button),
210                                          gl_wdgt_chain_button_clicked_callback, button);
211     }
212 }
213
214 /**
215  * gl_wdgt_chain_button_get_active
216  * @button: Pointer to a #glWdgtChainButton.
217  *
218  * Checks the state of the #glWdgtChainButton.
219  *
220  * Returns: %TRUE if the #glWdgtChainButton is active (locked).
221  */
222 gboolean
223 gl_wdgt_chain_button_get_active (glWdgtChainButton *button)
224 {
225   g_return_val_if_fail (GL_WDGT_IS_CHAIN_BUTTON (button), FALSE);
226
227   return button->active;
228 }
229
230 static void
231 gl_wdgt_chain_button_clicked_callback (GtkWidget       *widget,
232                                        glWdgtChainButton *button)
233 {
234   g_return_if_fail (GL_WDGT_IS_CHAIN_BUTTON (button));
235
236   gl_wdgt_chain_button_set_active (button, ! button->active);
237
238   g_signal_emit (button, gl_wdgt_chain_button_signals[TOGGLED], 0);
239 }
240
241 static gboolean
242 gl_wdgt_chain_button_draw_lines (GtkWidget         *widget,
243                                  cairo_t           *cr,
244                                  glWdgtChainButton *button)
245 {
246   GtkAllocation        allocation;
247   gdouble              w, h;
248   glWdgtChainPosition  position;
249   gint                 which_line;
250
251   g_return_val_if_fail (GL_WDGT_IS_CHAIN_BUTTON (button), FALSE);
252
253   gtk_widget_get_allocation (widget, &allocation);
254   w = allocation.width;
255   h = allocation.height;
256
257   which_line = (widget == button->line1) ? 1 : -1;
258
259   position = button->position;
260
261   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
262     switch (position)
263       {
264       case GL_WDGT_CHAIN_LEFT:
265         position = GL_WDGT_CHAIN_RIGHT;
266         break;
267       case GL_WDGT_CHAIN_RIGHT:
268         position = GL_WDGT_CHAIN_LEFT;
269         break;
270       default:
271         break;
272       }
273
274   switch (position)
275     {
276     case GL_WDGT_CHAIN_LEFT:
277       cairo_move_to (cr, w-2, (which_line == 1) ? 0.6*h : 0.4*h);
278       cairo_line_to (cr, w/2, (which_line == 1) ? 0.6*h : 0.4*h);
279       cairo_line_to (cr, w/2, (which_line == 1) ? h-2 : 1);
280       break;
281     case GL_WDGT_CHAIN_RIGHT:
282       cairo_move_to (cr, 1,   (which_line == 1) ? 0.6*h : 0.4*h);
283       cairo_line_to (cr, w/2, (which_line == 1) ? 0.6*h : 0.4*h);
284       cairo_line_to (cr, w/2, (which_line == 1) ? h-2 : 1);
285       break;
286     case GL_WDGT_CHAIN_TOP:
287       cairo_move_to (cr, w/2, h-2);
288       cairo_line_to (cr, w/2, h/2);
289       cairo_line_to (cr, (which_line == 1) ? w-2 : 1, h/2);
290       break;
291     case GL_WDGT_CHAIN_BOTTOM:
292       cairo_move_to (cr, w/2, 1);
293       cairo_line_to (cr, w/2, h/2);
294       cairo_line_to (cr, (which_line == 1) ? w-2 : 1, h/2);
295       break;
296     default:
297       return FALSE;
298     }
299
300   cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
301   cairo_set_line_width (cr, 1.0);
302   cairo_set_source_rgb (cr, 0, 0, 0);
303
304   cairo_stroke (cr);
305
306   return TRUE;
307 }
308
309
310
311 /*
312  * Local Variables:       -- emacs
313  * mode: C                -- emacs
314  * c-basic-offset: 8      -- emacs
315  * tab-width: 8           -- emacs
316  * indent-tabs-mode: nil  -- emacs
317  * End:                   -- emacs
318  */