James Willcox <jwillcox@cs.indiana.edu>
+Glabels includes a modified version of the gimpchainbutton widget from the
+gimp, as well as several stock icons from the gimp's default theme.
+These are copyright:
+
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ * Copyright (C) 1999-2000 Sven Neumann <sven@gimp.org>
+
Glabels includes contributions from:
Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
Wayne Schuller <k_wayne@linuxpower.org>
- Akkana <akkana@shallowsky.com>
nestor di <nestordi@usuarios.retecal.es> -- excellent splash screen
that first appeared in
0.4.3:
Alessandro Zummo <azummo@towertech.it>
+ Akkana <akkana@shallowsky.com>
Dag Wieers <dag@wieers.com>
Translations:
+2004-02-07 Jim Evins <evins@snaught.com>
+
+ * src/stock-pixmaps/Makefile.am:
+ * src/stock-pixmaps/stock_hchain_24.png:
+ * src/stock-pixmaps/stock_hchain_broken_24.png:
+ * src/stock-pixmaps/stock_vchain_24.png:
+ * src/stock-pixmaps/stock_vchain_broken_24.png:
+ Added chain pixmaps borrowed from the gimp's default theme.
+
+ * src/stock.h:
+ * src/stock.c: (gl_stock_init), (add_button_icon):
+ Added above pixmaps to stock icon sets. Created add_button_icon() to
+ add these pixmaps sized as GTK_ICON_SIZE_BUTTON.
+
+ * src/wdgt-chain-button.h
+ * src/wdgt-chain-button.c
+ * src/Makefile.am:
+ * po/POTFILES.in:
+ Added this Modified version of gimpchainbutton widget, borrowed from
+ the gimp.
+
+ * AUTHORS:
+ Added acknowledgements of the above borrowing from the gimp.
+
+ * src/object-editor-size-page.c: (aspect_toggle_cb), (w_spin_cb),
+ (h_spin_cb):
+ * src/object-editor.c: (gl_object_editor_construct_chain_button):
+ * src/object-editor.glade:
+ Replaced the keep aspect ratio check box with the above chain-button
+ widget.
+
+ * src/text-node.c: (gl_text_node_equal):
+ * src/text-node.h:
+ Added function gl_text_node_equal() to compare text_nodes.
+
+ * src/label-image.c: (gl_label_image_set_filename):
+ Replaced incomplete text_node comparison code with invocation of
+ gl_text_node_equal. This fixed the problem of not being able to
+ resize an image using the object_editor if the aspect ratio is not
+ locked.
+
2004-02-04 Jim Evins <evins@snaught.com>
* src/object-editor-image-page.c:
src/wdgt-mini-preview.h
src/wdgt-rotate-label.c
src/wdgt-rotate-label.h
+src/wdgt-chain-button.c
+src/wdgt-chain-button.h
src/util.c
src/util.h
src/color.c
wdgt-mini-preview.h \
wdgt-rotate-label.c \
wdgt-rotate-label.h \
+ wdgt-chain-button.c \
+ wdgt-chain-button.h \
util.c \
util.h \
color.c \
old_filename = limage->private->filename;
/* If Unchanged don't do anything */
- if ( (filename->field_flag == old_filename->field_flag) &&
- old_filename->data != NULL && filename->data != NULL &&
- !strcmp(filename->data, old_filename->data) )
- {
+ if ( gl_text_node_equal (filename, old_filename ) ) {
return;
}
#include "object-editor.h"
#include "prefs.h"
+#include "wdgt-chain-button.h"
#include "object-editor-private.h"
static void
aspect_toggle_cb (glObjectEditor *editor)
{
- GtkToggleButton *toggle;
- gdouble w, h;
+ glWdgtChainButton *toggle;
+ gdouble w, h;
- toggle = GTK_TOGGLE_BUTTON (editor->priv->size_aspect_checkbutton);
+ toggle = GL_WDGT_CHAIN_BUTTON (editor->priv->size_aspect_checkbutton);
- if (gtk_toggle_button_get_active (toggle)) {
+ if (gl_wdgt_chain_button_get_active (toggle)) {
w = gtk_spin_button_get_value (GTK_SPIN_BUTTON(editor->priv->size_w_spin));
h = gtk_spin_button_get_value (GTK_SPIN_BUTTON(editor->priv->size_h_spin));
static void
w_spin_cb (glObjectEditor *editor)
{
- gdouble w, h;
- GtkToggleButton *toggle;
+ gdouble w, h;
+ glWdgtChainButton *toggle;
- toggle = GTK_TOGGLE_BUTTON (editor->priv->size_aspect_checkbutton);
+ toggle = GL_WDGT_CHAIN_BUTTON (editor->priv->size_aspect_checkbutton);
- if (gtk_toggle_button_get_active (toggle)) {
+ if (gl_wdgt_chain_button_get_active (toggle)) {
w = gtk_spin_button_get_value (GTK_SPIN_BUTTON (editor->priv->size_w_spin));
{
gdouble w, h;
- GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (editor->priv->size_aspect_checkbutton);
+ glWdgtChainButton *toggle = GL_WDGT_CHAIN_BUTTON (editor->priv->size_aspect_checkbutton);
- if (gtk_toggle_button_get_active (toggle)) {
+ if (gl_wdgt_chain_button_get_active (toggle)) {
h = gtk_spin_button_get_value (GTK_SPIN_BUTTON (editor->priv->size_h_spin));
#include "prefs.h"
#include "mygal/widget-color-combo.h"
#include "color.h"
+#include "wdgt-chain-button.h"
#include "marshal.h"
#include "object-editor-private.h"
return color_combo;
}
+/*****************************************************************************/
+/* Construct chain button "Custom widget". */
+/*****************************************************************************/
+GtkWidget *
+gl_object_editor_construct_chain_button (gchar *name,
+ gchar *string1,
+ gchar *string2,
+ gint int1,
+ gint int2)
+{
+ GtkWidget *chain_button;
+
+ chain_button = gl_wdgt_chain_button_new (GL_WDGT_CHAIN_RIGHT);
+ gl_wdgt_chain_button_set_active (GL_WDGT_CHAIN_BUTTON(chain_button), TRUE);
+
+ return chain_button;
+}
+
/*--------------------------------------------------------------------------*/
/* PRIVATE. Prefs changed callback. Update units related items. */
/*--------------------------------------------------------------------------*/
<child>
<widget class="GtkTable" id="table6">
<property name="visible">True</property>
- <property name="n_rows">4</property>
- <property name="n_columns">2</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">3</property>
<property name="homogeneous">False</property>
<property name="row_spacing">12</property>
<property name="column_spacing">12</property>
</child>
<child>
- <widget class="GtkHBox" id="hbox10">
+ <widget class="GtkHBox" id="hbox11">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">12</property>
<child>
- <widget class="GtkSpinButton" id="size_w_spin">
+ <widget class="GtkSpinButton" id="size_h_spin">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="climb_rate">0.01</property>
</child>
<child>
- <widget class="GtkLabel" id="size_w_units_label">
+ <widget class="GtkLabel" id="size_h_units_label">
<property name="visible">True</property>
<property name="label" translatable="yes">inches</property>
<property name="use_underline">False</property>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
<property name="y_options">fill</property>
</packing>
</child>
<child>
- <widget class="GtkHBox" id="hbox11">
+ <widget class="GtkHBox" id="hbox13">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">12</property>
<child>
- <widget class="GtkSpinButton" id="size_h_spin">
+ <widget class="GtkButton" id="size_reset_image_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Reset image size</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox10">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkSpinButton" id="size_w_spin">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="climb_rate">0.01</property>
</child>
<child>
- <widget class="GtkLabel" id="size_h_units_label">
+ <widget class="GtkLabel" id="size_w_units_label">
<property name="visible">True</property>
<property name="label" translatable="yes">inches</property>
<property name="use_underline">False</property>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
<property name="x_options">fill</property>
<property name="y_options">fill</property>
</packing>
</child>
<child>
- <widget class="GtkCheckButton" id="size_aspect_checkbutton">
+ <widget class="Custom" id="size_aspect_checkbutton">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Maintain current aspect ratio</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="active">True</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
+ <property name="creation_function">gl_object_editor_construct_chain_button</property>
+ <property name="int1">0</property>
+ <property name="int2">0</property>
+ <property name="last_modification_time">Sat, 07 Feb 2004 02:56:47 GMT</property>
</widget>
<packing>
- <property name="left_attach">0</property>
- <property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox13">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">12</property>
-
- <child>
- <widget class="GtkButton" id="size_reset_image_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Reset image size</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">2</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options">fill</property>
</packing>
</child>
</widget>
stock_bucket_fill_16.png \
stock_bucket_fill_24.png \
stock_pencil_16.png \
- stock_pencil_24.png
+ stock_pencil_24.png \
+ stock_hchain_24.png \
+ stock_hchain_broken_24.png \
+ stock_vchain_24.png \
+ stock_vchain_broken_24.png
VARIABLES1 = \
stock_arrow_24 $(srcdir)/stock_arrow_24.png \
stock_bucket_fill_16 $(srcdir)/stock_bucket_fill_16.png \
stock_bucket_fill_24 $(srcdir)/stock_bucket_fill_24.png \
stock_pencil_16 $(srcdir)/stock_pencil_16.png \
- stock_pencil_24 $(srcdir)/stock_pencil_24.png
+ stock_pencil_24 $(srcdir)/stock_pencil_24.png \
+ stock_hchain_24 $(srcdir)/stock_hchain_24.png \
+ stock_hchain_broken_24 $(srcdir)/stock_hchain_broken_24.png \
+ stock_vchain_24 $(srcdir)/stock_vchain_24.png \
+ stock_vchain_broken_24 $(srcdir)/stock_vchain_broken_24.png
noinst_DATA = stockpixbufs.h
const guchar *inline_24,
const guchar *inline_16);
+static add_button_icon (GtkIconFactory *factory,
+ const gchar *stock_id,
+ const guchar *inline_24);
+
\f
/****************************************************************************/
/* Initialize our stock icons. */
{ GL_STOCK_CENTER_VERT, N_("Label Ce_nter"), 0, 0, NULL },
{ GL_STOCK_BUCKET_FILL, N_("Fill color"), 0, 0, NULL },
{ GL_STOCK_PENCIL, N_("Line color"), 0, 0, NULL },
+ { GL_STOCK_HCHAIN, N_("Linked"), 0, 0, NULL },
+ { GL_STOCK_HCHAIN_BROKEN, N_("Not Linked"), 0, 0, NULL },
+ { GL_STOCK_VCHAIN, N_("Linked"), 0, 0, NULL },
+ { GL_STOCK_VCHAIN_BROKEN, N_("Not Linked"), 0, 0, NULL },
};
gtk_stock_add (items, G_N_ELEMENTS (items));
add_icons (factory, GL_STOCK_BUCKET_FILL, stock_bucket_fill_24, stock_bucket_fill_16);
add_icons (factory, GL_STOCK_PENCIL, stock_pencil_24, stock_pencil_16);
+ add_button_icon (factory, GL_STOCK_HCHAIN, stock_hchain_24);
+ add_button_icon (factory, GL_STOCK_HCHAIN_BROKEN, stock_hchain_broken_24);
+ add_button_icon (factory, GL_STOCK_VCHAIN, stock_vchain_24);
+ add_button_icon (factory, GL_STOCK_VCHAIN_BROKEN, stock_vchain_broken_24);
+
g_object_unref (G_OBJECT(factory));
}
gtk_icon_set_unref (icon_set);
}
+/*--------------------------------------------------------------------------*/
+/* PRIVATE. Unpack and associate given button icon with stock_id. */
+/*--------------------------------------------------------------------------*/
+static add_button_icon (GtkIconFactory *factory,
+ const gchar *stock_id,
+ const guchar *inline_24)
+{
+ GtkIconSet *icon_set;
+ GdkPixbuf *pixbuf;
+ GtkIconSource *icon_source;
+
+ icon_set = gtk_icon_set_new ();
+
+ icon_source = gtk_icon_source_new ();
+ pixbuf = gdk_pixbuf_new_from_inline (-1, inline_24, FALSE, NULL);
+ gtk_icon_source_set_pixbuf (icon_source, pixbuf);
+ g_object_unref (G_OBJECT(pixbuf));
+ gtk_icon_source_set_size_wildcarded (icon_source, FALSE);
+ gtk_icon_source_set_size (icon_source, GTK_ICON_SIZE_BUTTON);
+ gtk_icon_set_add_source (icon_set, icon_source);
+ g_free (icon_source);
+
+ /* Now associate icon set with stock id */
+ gtk_icon_factory_add (factory, stock_id, icon_set);
+ gtk_icon_set_unref (icon_set);
+}
+
#define GL_STOCK_CENTER_VERT "gl_stock_center_vert"
#define GL_STOCK_BUCKET_FILL "gl_stock_bucket_fill"
#define GL_STOCK_PENCIL "gl_stock_pencil"
+#define GL_STOCK_HCHAIN "gl_stock_hchain"
+#define GL_STOCK_HCHAIN_BROKEN "gl_stock_hchain_broken"
+#define GL_STOCK_VCHAIN "gl_stock_vchain"
+#define GL_STOCK_VCHAIN_BROKEN "gl_stock_vchain_broken"
void gl_stock_init (void);
*text_node = NULL;
}
+/****************************************************************************/
+/* Compare 2 text nodes for equality. */
+/****************************************************************************/
+gboolean
+gl_text_node_equal (glTextNode *text_node1,
+ glTextNode *text_node2)
+{
+ /* First take care of the case of either or both being NULL. */
+ if ( text_node1 == NULL ) {
+ return ( text_node2 == NULL );
+ } else {
+ if ( text_node2 == NULL ) {
+ return FALSE;
+ }
+ }
+
+ /* Bail if field flags differ. */
+ if ( text_node1->field_flag != text_node2->field_flag ) {
+ return FALSE;
+ }
+
+ /* Now take care of the case of either or both data fields being NULL. */
+ if ( text_node1->data == NULL ) {
+ return ( text_node2->data == NULL );
+ } else {
+ if ( text_node2->data == NULL ) {
+ return FALSE;
+ }
+ }
+
+ /* Field flags are identical, so now compare the data. */
+ return (strcmp (text_node1->data, text_node2->data) == 0);
+}
+
/****************************************************************************/
/* Expand text lines into single string. */
/****************************************************************************/
glTextNode *gl_text_node_dup (glTextNode *text_node);
void gl_text_node_free (glTextNode **text_node);
+gboolean gl_text_node_equal (glTextNode *text_node1,
+ glTextNode *text_node2);
+
gchar *gl_text_node_lines_expand (GList *lines,
glMergeRecord *record);
GList *gl_text_node_lines_new_from_text (gchar *text);
--- /dev/null
+/* wdgt-chain-button.c
+ * Modified version of gimpchainbutton.c for gLabels:
+ *
+ * LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpchainbutton.c
+ * Copyright (C) 1999-2000 Sven Neumann <sven@gimp.org>
+ *
+ * Modified or gLabels by Jim Evins <evins@snaught.com>
+ *
+ * This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+#include "wdgt-chain-button.h"
+#include "stock.h"
+
+
+enum
+{
+ TOGGLED,
+ LAST_SIGNAL
+};
+
+
+static void gl_wdgt_chain_button_class_init (glWdgtChainButtonClass *klass);
+static void gl_wdgt_chain_button_init (glWdgtChainButton *button);
+
+static void gl_wdgt_chain_button_clicked_callback (GtkWidget *widget,
+ glWdgtChainButton *button);
+static gboolean gl_wdgt_chain_button_draw_lines (GtkWidget *widget,
+ GdkEventExpose *eevent,
+ glWdgtChainButton *button);
+
+
+static const gchar *gl_wdgt_chain_stock_items[] =
+{
+ GL_STOCK_HCHAIN,
+ GL_STOCK_HCHAIN_BROKEN,
+ GL_STOCK_VCHAIN,
+ GL_STOCK_VCHAIN_BROKEN
+};
+
+
+static guint gl_wdgt_chain_button_signals[LAST_SIGNAL] = { 0 };
+
+static GtkTableClass *parent_class = NULL;
+
+
+GType
+gl_wdgt_chain_button_get_type (void)
+{
+ static GType button_type = 0;
+
+ if (! button_type)
+ {
+ static const GTypeInfo button_info =
+ {
+ sizeof (glWdgtChainButtonClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gl_wdgt_chain_button_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (glWdgtChainButton),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gl_wdgt_chain_button_init,
+ };
+
+ button_type = g_type_register_static (GTK_TYPE_TABLE, "glWdgtChainButton",
+ &button_info, 0);
+ }
+
+ return button_type;
+}
+
+static void
+gl_wdgt_chain_button_class_init (glWdgtChainButtonClass *klass)
+{
+ parent_class = g_type_class_peek_parent (klass);
+
+ gl_wdgt_chain_button_signals[TOGGLED] =
+ g_signal_new ("toggled",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (glWdgtChainButtonClass, toggled),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ klass->toggled = NULL;
+}
+
+static void
+gl_wdgt_chain_button_init (glWdgtChainButton *button)
+{
+ button->position = GL_WDGT_CHAIN_TOP;
+ button->active = FALSE;
+
+ button->line1 = gtk_drawing_area_new ();
+ button->line2 = gtk_drawing_area_new ();
+ button->image = gtk_image_new ();
+
+ button->button = gtk_button_new ();
+
+ gtk_button_set_relief (GTK_BUTTON (button->button), GTK_RELIEF_NONE);
+ gtk_container_add (GTK_CONTAINER (button->button), button->image);
+ gtk_widget_show (button->image);
+
+ g_signal_connect (button->button, "clicked",
+ G_CALLBACK (gl_wdgt_chain_button_clicked_callback),
+ button);
+ g_signal_connect (button->line1, "expose_event",
+ G_CALLBACK (gl_wdgt_chain_button_draw_lines),
+ button);
+ g_signal_connect (button->line2, "expose_event",
+ G_CALLBACK (gl_wdgt_chain_button_draw_lines),
+ button);
+}
+
+
+/**
+ * gl_wdgt_chain_button_new:
+ * @position: The position you are going to use for the button
+ * with respect to the widgets you want to chain.
+ *
+ * Creates a new #glWdgtChainButton widget.
+ *
+ * This returns a button showing either a broken or a linked chain and
+ * small clamps attached to both sides that visually group the two widgets
+ * you want to connect. This widget looks best when attached
+ * to a table taking up two columns (or rows respectively) next
+ * to the widgets that it is supposed to connect. It may work
+ * for more than two widgets, but the look is optimized for two.
+ *
+ * Returns: Pointer to the new #glWdgtChainButton, which is inactive
+ * by default. Use gl_wdgt_chain_button_set_active() to
+ * change its state.
+ */
+GtkWidget *
+gl_wdgt_chain_button_new (glWdgtChainPosition position)
+{
+ glWdgtChainButton *button;
+
+ button = g_object_new (GL_WDGT_TYPE_CHAIN_BUTTON, NULL);
+
+ button->position = position;
+
+ gtk_image_set_from_stock
+ (GTK_IMAGE (button->image),
+ gl_wdgt_chain_stock_items[((position & GL_WDGT_CHAIN_LEFT) << 1) + ! button->active],
+ GTK_ICON_SIZE_BUTTON);
+
+ if (position & GL_WDGT_CHAIN_LEFT) /* are we a vertical chainbutton? */
+ {
+ gtk_table_resize (GTK_TABLE (button), 3, 1);
+ gtk_table_attach (GTK_TABLE (button), button->button, 0, 1, 1, 2,
+ GTK_SHRINK, GTK_SHRINK, 0, 0);
+ gtk_table_attach_defaults (GTK_TABLE (button),
+ button->line1, 0, 1, 0, 1);
+ gtk_table_attach_defaults (GTK_TABLE (button),
+ button->line2, 0, 1, 2, 3);
+ }
+ else
+ {
+ gtk_table_resize (GTK_TABLE (button), 1, 3);
+ gtk_table_attach (GTK_TABLE (button), button->button, 1, 2, 0, 1,
+ GTK_SHRINK, GTK_SHRINK, 0, 0);
+ gtk_table_attach_defaults (GTK_TABLE (button),
+ button->line1, 0, 1, 0, 1);
+ gtk_table_attach_defaults (GTK_TABLE (button),
+ button->line2, 2, 3, 0, 1);
+ }
+
+ gtk_widget_show (button->button);
+ gtk_widget_show (button->line1);
+ gtk_widget_show (button->line2);
+
+ return GTK_WIDGET (button);
+}
+
+/**
+ * gl_wdgt_chain_button_set_active:
+ * @button: Pointer to a #glWdgtChainButton.
+ * @active: The new state.
+ *
+ * Sets the state of the #glWdgtChainButton to be either locked (%TRUE) or
+ * unlocked (%FALSE) and changes the showed pixmap to reflect the new state.
+ */
+void
+gl_wdgt_chain_button_set_active (glWdgtChainButton *button,
+ gboolean active)
+{
+ g_return_if_fail (GL_WDGT_IS_CHAIN_BUTTON (button));
+
+ if (button->active != active)
+ {
+ guint num;
+
+ button->active = active ? TRUE : FALSE;
+
+ num = ((button->position & GL_WDGT_CHAIN_LEFT) << 1) + (active ? 0 : 1);
+
+ gtk_image_set_from_stock (GTK_IMAGE (button->image),
+ gl_wdgt_chain_stock_items[num],
+ GTK_ICON_SIZE_BUTTON);
+ }
+}
+
+/**
+ * gl_wdgt_chain_button_get_active
+ * @button: Pointer to a #glWdgtChainButton.
+ *
+ * Checks the state of the #glWdgtChainButton.
+ *
+ * Returns: %TRUE if the #glWdgtChainButton is active (locked).
+ */
+gboolean
+gl_wdgt_chain_button_get_active (glWdgtChainButton *button)
+{
+ g_return_val_if_fail (GL_WDGT_IS_CHAIN_BUTTON (button), FALSE);
+
+ return button->active;
+}
+
+static void
+gl_wdgt_chain_button_clicked_callback (GtkWidget *widget,
+ glWdgtChainButton *button)
+{
+ g_return_if_fail (GL_WDGT_IS_CHAIN_BUTTON (button));
+
+ gl_wdgt_chain_button_set_active (button, ! button->active);
+
+ g_signal_emit (button, gl_wdgt_chain_button_signals[TOGGLED], 0);
+}
+
+static gboolean
+gl_wdgt_chain_button_draw_lines (GtkWidget *widget,
+ GdkEventExpose *eevent,
+ glWdgtChainButton *button)
+{
+ GdkPoint points[3];
+ GdkPoint buf;
+ GtkShadowType shadow;
+ glWdgtChainPosition position;
+ gint which_line;
+
+#define SHORT_LINE 4
+ /* don't set this too high, there's no check against drawing outside
+ the widgets bounds yet (and probably never will be) */
+
+ g_return_val_if_fail (GL_WDGT_IS_CHAIN_BUTTON (button), FALSE);
+
+ points[0].x = widget->allocation.width / 2;
+ points[0].y = widget->allocation.height / 2;
+
+ which_line = (widget == button->line1) ? 1 : -1;
+
+ position = button->position;
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+ switch (position)
+ {
+ case GL_WDGT_CHAIN_LEFT:
+ position = GL_WDGT_CHAIN_RIGHT;
+ break;
+ case GL_WDGT_CHAIN_RIGHT:
+ position = GL_WDGT_CHAIN_LEFT;
+ break;
+ default:
+ break;
+ }
+
+ switch (position)
+ {
+ case GL_WDGT_CHAIN_LEFT:
+ points[0].x += SHORT_LINE;
+ points[1].x = points[0].x - SHORT_LINE;
+ points[1].y = points[0].y;
+ points[2].x = points[1].x;
+ points[2].y = (which_line == 1) ? widget->allocation.height - 1 : 0;
+ shadow = GTK_SHADOW_ETCHED_IN;
+ break;
+ case GL_WDGT_CHAIN_RIGHT:
+ points[0].x -= SHORT_LINE;
+ points[1].x = points[0].x + SHORT_LINE;
+ points[1].y = points[0].y;
+ points[2].x = points[1].x;
+ points[2].y = (which_line == 1) ? widget->allocation.height - 1 : 0;
+ shadow = GTK_SHADOW_ETCHED_OUT;
+ break;
+ case GL_WDGT_CHAIN_TOP:
+ points[0].y += SHORT_LINE;
+ points[1].x = points[0].x;
+ points[1].y = points[0].y - SHORT_LINE;
+ points[2].x = (which_line == 1) ? widget->allocation.width - 1 : 0;
+ points[2].y = points[1].y;
+ shadow = GTK_SHADOW_ETCHED_OUT;
+ break;
+ case GL_WDGT_CHAIN_BOTTOM:
+ points[0].y -= SHORT_LINE;
+ points[1].x = points[0].x;
+ points[1].y = points[0].y + SHORT_LINE;
+ points[2].x = (which_line == 1) ? widget->allocation.width - 1 : 0;
+ points[2].y = points[1].y;
+ shadow = GTK_SHADOW_ETCHED_IN;
+ break;
+ default:
+ return FALSE;
+ }
+
+ if ( ((shadow == GTK_SHADOW_ETCHED_OUT) && (which_line == -1)) ||
+ ((shadow == GTK_SHADOW_ETCHED_IN) && (which_line == 1)) )
+ {
+ buf = points[0];
+ points[0] = points[2];
+ points[2] = buf;
+ }
+
+ gtk_paint_polygon (widget->style,
+ widget->window,
+ GTK_STATE_NORMAL,
+ shadow,
+ &eevent->area,
+ widget,
+ "chainbutton",
+ points,
+ 3,
+ FALSE);
+
+ return TRUE;
+}
--- /dev/null
+/* wdgt-chain-button.h
+ * Modified version of gimpchainbutton.h for gLabels:
+ *
+ * LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpchainbutton.h
+ * Copyright (C) 1999-2000 Sven Neumann <sven@gimp.org>
+ *
+ * Modified or gLabels by Jim Evins <evins@snaught.com>
+ *
+ * This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * This implements a widget derived from GtkTable that visualizes
+ * it's state with two different pixmaps showing a closed and a
+ * broken chain. It's intented to be used with the GimpSizeEntry
+ * widget. The usage is quite similar to the one the GtkToggleButton
+ * provides.
+ */
+
+#ifndef __WDGT_CHAIN_BUTTON_H__
+#define __WDGT_CHAIN_BUTTON_H__
+
+#include <gtk/gtktable.h>
+
+G_BEGIN_DECLS
+
+
+typedef enum
+{
+ GL_WDGT_CHAIN_TOP,
+ GL_WDGT_CHAIN_LEFT,
+ GL_WDGT_CHAIN_BOTTOM,
+ GL_WDGT_CHAIN_RIGHT
+} glWdgtChainPosition;
+
+
+#define GL_WDGT_TYPE_CHAIN_BUTTON (gl_wdgt_chain_button_get_type ())
+#define GL_WDGT_CHAIN_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GL_WDGT_TYPE_CHAIN_BUTTON, glWdgtChainButton))
+#define GL_WDGT_CHAIN_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GL_WDGT_TYPE_CHAIN_BUTTON, glWdgtChainButtonClass))
+#define GL_WDGT_IS_CHAIN_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GL_WDGT_TYPE_CHAIN_BUTTON))
+#define GL_WDGT_IS_CHAIN_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GL_WDGT_TYPE_CHAIN_BUTTON))
+#define GL_WDGT_CHAIN_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GL_WDGT_TYPE_CHAIN_BUTTON, glWdgtChainButtonClass))
+
+
+typedef struct _glWdgtChainButton glWdgtChainButton;
+typedef struct _glWdgtChainButtonClass glWdgtChainButtonClass;
+
+struct _glWdgtChainButton
+{
+ GtkTable parent_instance;
+
+ glWdgtChainPosition position;
+ gboolean active;
+
+ GtkWidget *button;
+ GtkWidget *line1;
+ GtkWidget *line2;
+ GtkWidget *image;
+};
+
+struct _glWdgtChainButtonClass
+{
+ GtkTableClass parent_class;
+
+ void (* toggled) (glWdgtChainButton *button);
+};
+
+
+GType gl_wdgt_chain_button_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gl_wdgt_chain_button_new (glWdgtChainPosition position);
+
+void gl_wdgt_chain_button_set_active (glWdgtChainButton *button,
+ gboolean active);
+gboolean gl_wdgt_chain_button_get_active (glWdgtChainButton *button);
+
+
+G_END_DECLS
+
+#endif /* __WDGT_CHAIN_BUTTON_H__ */