1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
* arch-tag: Implementation of the "disclosure" widget
5
* Authors: Iain Holmes <iain@ximian.com>
7
* Copyright 2002 Iain Holmes
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
29
#include <gtk/gtktogglebutton.h>
30
#include <libgnome/gnome-i18n.h>
32
#include "disclosure-widget.h"
34
static GtkCheckButtonClass *parent_class = NULL;
36
struct _CDDBDisclosurePrivate {
42
GtkExpanderStyle style;
49
finalize (GObject *object)
51
CDDBDisclosure *disclosure;
53
disclosure = CDDB_DISCLOSURE (object);
54
if (disclosure->priv == NULL) {
58
g_free (disclosure->priv->hidden);
59
g_free (disclosure->priv->shown);
61
if (disclosure->priv->container != NULL) {
62
g_object_unref (G_OBJECT (disclosure->priv->container));
65
g_free (disclosure->priv);
66
disclosure->priv = NULL;
68
G_OBJECT_CLASS (parent_class)->finalize (object);
72
cddb_disclosure_destroy (GtkObject *obj)
74
CDDBDisclosure *disclosure = CDDB_DISCLOSURE (obj);
76
if (disclosure->priv->expand_id) {
77
g_source_remove (disclosure->priv->expand_id);
78
disclosure->priv->expand_id = 0;
83
get_x_y (CDDBDisclosure *disclosure,
86
GtkStateType *state_type)
88
GtkCheckButton *check_button;
89
int indicator_size, indicator_spacing;
92
gboolean interior_focus;
93
GtkWidget *widget = GTK_WIDGET (disclosure);
94
GtkBin *bin = GTK_BIN (disclosure);
97
if (GTK_WIDGET_VISIBLE (disclosure) &&
98
GTK_WIDGET_MAPPED (disclosure)) {
99
check_button = GTK_CHECK_BUTTON (disclosure);
101
gtk_widget_style_get (GTK_WIDGET (check_button),
102
"indicator_size", &indicator_size,
103
"indicator_spacing", &indicator_spacing,
106
gtk_widget_style_get (widget,
107
"interior_focus", &interior_focus,
108
"focus-line-width", &focus_width,
109
"focus-padding", &focus_pad,
112
*state_type = GTK_WIDGET_STATE (widget);
113
if ((*state_type != GTK_STATE_NORMAL) &&
114
(*state_type != GTK_STATE_PRELIGHT)) {
115
*state_type = GTK_STATE_NORMAL;
119
width = indicator_spacing * 3 + indicator_size ;
121
width = widget->allocation.width - 2 * GTK_CONTAINER (widget)->border_width;
124
*x = widget->allocation.x + GTK_CONTAINER (widget)->border_width + (width) / 2;
125
*y = widget->allocation.y + widget->allocation.height / 2;
127
if (interior_focus == FALSE) {
128
*x += focus_width + focus_pad;
131
*state_type = GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE ? GTK_STATE_NORMAL : GTK_WIDGET_STATE (widget);
133
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) {
134
*x = widget->allocation.x + widget->allocation.width - (*x - widget->allocation.x);
139
*state_type = GTK_STATE_NORMAL;
144
expand_collapse_timeout (gpointer data)
146
GtkWidget *widget = data;
147
CDDBDisclosure *disclosure = data;
148
GtkStateType state_type;
152
GDK_THREADS_ENTER ();
154
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
155
g_return_val_if_fail (IS_CDDB_DISCLOSURE (disclosure), FALSE);
157
if (widget->window) {
158
gdk_window_invalidate_rect (widget->window, &widget->allocation, TRUE);
159
get_x_y (disclosure, &x, &y, &state_type);
161
gtk_paint_expander (widget->style,
168
disclosure->priv->style);
171
disclosure->priv->style += disclosure->priv->direction;
172
if ((int) disclosure->priv->style > (int) GTK_EXPANDER_EXPANDED) {
173
disclosure->priv->style = GTK_EXPANDER_EXPANDED;
175
if (disclosure->priv->container != NULL) {
176
gtk_widget_show (disclosure->priv->container);
179
g_object_set (G_OBJECT (disclosure),
180
"label", disclosure->priv->hidden,
184
} else if ((int) disclosure->priv->style < (int) GTK_EXPANDER_COLLAPSED) {
185
disclosure->priv->style = GTK_EXPANDER_COLLAPSED;
187
if (disclosure->priv->container != NULL) {
188
gtk_widget_hide (disclosure->priv->container);
192
g_object_set (G_OBJECT (disclosure),
193
"label", disclosure->priv->shown,
200
disclosure->priv->expand_id = 0;
202
GDK_THREADS_LEAVE ();
207
do_animation (CDDBDisclosure *disclosure,
210
g_return_if_fail (IS_CDDB_DISCLOSURE (disclosure));
212
if (disclosure->priv->expand_id > 0) {
213
g_source_remove (disclosure->priv->expand_id);
214
disclosure->priv->expand_id = 0;
217
disclosure->priv->direction = opening ? 1 : -1;
218
disclosure->priv->expand_id = g_timeout_add (50, expand_collapse_timeout, disclosure);
222
toggled (GtkToggleButton *tb)
224
CDDBDisclosure *disclosure;
226
disclosure = CDDB_DISCLOSURE (tb);
227
do_animation (disclosure, gtk_toggle_button_get_active (tb));
229
if (disclosure->priv->container == NULL) {
235
draw_indicator (GtkCheckButton *check,
238
GtkWidget *widget = GTK_WIDGET (check);
239
CDDBDisclosure *disclosure = CDDB_DISCLOSURE (check);
240
GtkStateType state_type;
243
/* GtkCheckButton-like prelighting, unsurprisingly from gtkcheckbutton.c */
244
if (GTK_WIDGET_STATE (check) == GTK_STATE_PRELIGHT)
246
GdkRectangle restrict_area;
247
GdkRectangle new_area;
249
restrict_area.x = widget->allocation.x + GTK_CONTAINER (widget)->border_width;
250
restrict_area.y = widget->allocation.y + GTK_CONTAINER (widget)->border_width;
251
restrict_area.width = widget->allocation.width - (2 * GTK_CONTAINER (widget)->border_width);
252
restrict_area.height = widget->allocation.height - (2 * GTK_CONTAINER (widget)->border_width);
254
if (gdk_rectangle_intersect (area, &restrict_area, &new_area))
256
gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_PRELIGHT,
257
GTK_SHADOW_ETCHED_OUT,
258
area, widget, "checkbutton",
259
new_area.x, new_area.y,
260
new_area.width, new_area.height);
264
get_x_y (disclosure, &x, &y, &state_type);
265
gtk_paint_expander (widget->style,
272
disclosure->priv->style);
276
class_init (CDDBDisclosureClass *klass)
278
GObjectClass *object_class;
279
GtkObjectClass *gtk_object_class = (GtkObjectClass *) klass;
280
GtkWidgetClass *widget_class;
281
GtkCheckButtonClass *button_class;
282
GtkToggleButtonClass *toggle_class;
284
object_class = G_OBJECT_CLASS (klass);
285
widget_class = GTK_WIDGET_CLASS (klass);
286
button_class = GTK_CHECK_BUTTON_CLASS (klass);
287
toggle_class = GTK_TOGGLE_BUTTON_CLASS (klass);
289
toggle_class->toggled = toggled;
290
button_class->draw_indicator = draw_indicator;
292
object_class->finalize = finalize;
294
gtk_object_class->destroy = cddb_disclosure_destroy;
296
parent_class = g_type_class_peek_parent (klass);
298
gtk_widget_class_install_style_property (widget_class,
299
g_param_spec_int ("expander_size",
301
_("Size of the expander arrow"),
303
10, G_PARAM_READABLE));
307
init (CDDBDisclosure *disclosure)
309
disclosure->priv = g_new0 (CDDBDisclosurePrivate, 1);
310
disclosure->priv->expander_size = 10;
314
cddb_disclosure_get_type (void)
316
static GType type = 0;
320
sizeof (CDDBDisclosureClass),
321
NULL, NULL, (GClassInitFunc) class_init, NULL, NULL,
322
sizeof (CDDBDisclosure), 0, (GInstanceInitFunc) init
325
type = g_type_register_static (GTK_TYPE_CHECK_BUTTON, "CDDBDisclosure", &info, 0);
332
cddb_disclosure_new (const char *shown,
335
CDDBDisclosure *disclosure;
337
disclosure = g_object_new (cddb_disclosure_get_type (), "label", shown, "use_underline", TRUE, NULL);
339
disclosure->priv->shown = g_strdup (shown);
340
disclosure->priv->hidden = g_strdup (hidden);
341
return GTK_WIDGET (disclosure);
345
cddb_disclosure_set_container (CDDBDisclosure *cddb, GtkWidget *widget)
347
if (widget != NULL) {
348
g_object_ref (widget);
350
if (cddb->priv->container != NULL) {
351
g_object_unref (cddb->priv->container);
353
cddb->priv->container = widget;
356
/* Strings for custom glade widgets (see below) can't be translated, so provide
357
* this function for setting translatable labels after the widget has been
361
cddb_disclosure_set_labels (CDDBDisclosure *cddb,
362
const char *label_when_shown,
363
const char *label_when_hidden)
367
g_free (cddb->priv->shown);
368
g_free (cddb->priv->hidden);
369
cddb->priv->shown = g_strdup (label_when_shown);
370
cddb->priv->hidden = g_strdup (label_when_hidden);
372
/* update the correct label text depending on button state */
373
active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(cddb));
374
g_object_set (G_OBJECT(cddb),
375
"label", active ? cddb->priv->shown : cddb->priv->hidden,
379
/* Custom widget creation function for glade */
381
cddb_disclosure_new_from_glade (gchar *widget_name,
382
gchar *string1, gchar *string2,
383
gint int1, gint int2)
385
GtkWidget *w = cddb_disclosure_new ("", "");
386
gtk_widget_set_name (w, widget_name);