diff options
Diffstat (limited to 'app/wlib/gtklib/button.c')
-rw-r--r-- | app/wlib/gtklib/button.c | 630 |
1 files changed, 630 insertions, 0 deletions
diff --git a/app/wlib/gtklib/button.c b/app/wlib/gtklib/button.c new file mode 100644 index 0000000..d9f4880 --- /dev/null +++ b/app/wlib/gtklib/button.c @@ -0,0 +1,630 @@ +/** \file button.c + * Toolbar button creation and handling + */ + +/* XTrkCad - Model Railroad CAD + * Copyright (C) 2005 Dave Bullis + * + * 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 program 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <stdlib.h> + +#define GTK_DISABLE_SINGLE_INCLUDES +#define GDK_DISABLE_DEPRECATED +#define GTK_DISABLE_DEPRECATED +#define GSEAL_ENABLE + +#include <gtk/gtk.h> +#include <gdk/gdk.h> + +#include "gtkint.h" +#include "i18n.h" + +#define MIN_BUTTON_WIDTH (80) + +/* + ***************************************************************************** + * + * Simple Buttons + * + ***************************************************************************** + */ + +/** + * Set the state of the button + * + * \param bb IN the button + * \param value IN TRUE for active, FALSE for inactive + */ + +void wButtonSetBusy(wButton_p bb, int value) +{ + bb->recursion++; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bb->widget), value); + bb->recursion--; + bb->busy = value; +} + +/** + * Set the label of a button, does also allow to set an icon + * + * \param widget IN + * \param option IN + * \param labelStr IN + * \param labelG IN + * \param imageG IN + */ + +void wlibSetLabel( + GtkWidget *widget, + long option, + const char * labelStr, + GtkLabel * * labelG, + GtkWidget * * imageG) +{ + wIcon_p bm; + GdkBitmap * mask; + + if (widget == 0) { + abort(); + } + + if (labelStr) { + if (option&BO_ICON) { + GdkPixbuf *pixbuf; + + bm = (wIcon_p)labelStr; + + if (bm->gtkIconType == gtkIcon_pixmap) { + pixbuf = gdk_pixbuf_new_from_xpm_data((const char**)bm->bits); + } else { + pixbuf = wlibPixbufFromXBM( bm ); + } + if (*imageG==NULL) { + *imageG = gtk_image_new_from_pixbuf(pixbuf); + gtk_container_add(GTK_CONTAINER(widget), *imageG); + gtk_widget_show(*imageG); + } else { + gtk_image_set_from_pixbuf(GTK_IMAGE(*imageG), pixbuf); + } + + g_object_unref(pixbuf); + } else { + if (*labelG==NULL) { + *labelG = (GtkLabel*)gtk_label_new(wlibConvertInput(labelStr)); + gtk_container_add(GTK_CONTAINER(widget), (GtkWidget*)*labelG); + gtk_widget_show((GtkWidget*)*labelG); + } else { + gtk_label_set_text(*labelG, wlibConvertInput(labelStr)); + } + } + } +} + +/** + * Change only the text label of a button + * \param bb IN button handle + * \param labelStr IN new label string + */ + +void wButtonSetLabel(wButton_p bb, const char * labelStr) +{ + wlibSetLabel(bb->widget, bb->option, labelStr, &bb->labelG, &bb->imageG); +} + +/** + * Perform the user callback function + * + * \param bb IN button handle + */ + +void wlibButtonDoAction( + wButton_p bb) +{ + if (bb->action) { + bb->action(bb->data); + } +} + +/** + * Signal handler for button push + * \param widget IN the widget + * \param value IN the button handle (same as widget???) + */ + +static void pushButt( + GtkWidget *widget, + gpointer value) +{ + wButton_p b = (wButton_p)value; + + if (debugWindow >= 2) { + printf("%s button pushed\n", b->labelStr?b->labelStr:"No label"); + } + + if (b->recursion) { + return; + } + + if (b->action) { + b->action(b->data); + } + + if (!b->busy) { + b->recursion++; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->widget), FALSE); + b->recursion--; + } +} + +/** + * Create a button + * + * \param parent IN parent window + * \param x IN X-position + * \param y IN Y-position + * \param helpStr IN Help string + * \param labelStr IN Label + * \param option IN Options + * \param width IN Width of button + * \param action IN Callback + * \param data IN User data as context + * \returns button widget + */ + +wButton_p wButtonCreate( + wWin_p parent, + wPos_t x, + wPos_t y, + const char * helpStr, + const char * labelStr, + long option, + wPos_t width, + wButtonCallBack_p action, + void * data) +{ + wButton_p b; + b = wlibAlloc(parent, B_BUTTON, x, y, labelStr, sizeof *b, data); + b->option = option; + b->action = action; + wlibComputePos((wControl_p)b); + + b->widget = gtk_toggle_button_new(); + g_signal_connect(GTK_OBJECT(b->widget), "clicked", + G_CALLBACK(pushButt), b); + if (width > 0) { + gtk_widget_set_size_request(b->widget, width, -1); + } + if( labelStr ){ + wButtonSetLabel(b, labelStr); + } + + gtk_fixed_put(GTK_FIXED(parent->widget), b->widget, b->realX, b->realY); + + if (option & BB_DEFAULT) { + gtk_widget_set_can_default(b->widget, GTK_CAN_DEFAULT); + gtk_widget_grab_default(b->widget); + gtk_window_set_default(GTK_WINDOW(parent->gtkwin), b->widget); + } + + wlibControlGetSize((wControl_p)b); + + if (width == 0 && b->w < MIN_BUTTON_WIDTH && (b->option&BO_ICON)==0) { + b->w = MIN_BUTTON_WIDTH; + gtk_widget_set_size_request(b->widget, b->w, b->h); + } + + gtk_widget_show(b->widget); + wlibAddButton((wControl_p)b); + wlibAddHelpString(b->widget, helpStr); + return b; +} + + +/* + ***************************************************************************** + * + * Choice Boxes + * + ***************************************************************************** + */ + +struct wChoice_t { + WOBJ_COMMON + long *valueP; + wChoiceCallBack_p action; + int recursion; +}; + + +/** + * Get the state of a group of buttons. If the group consists of + * radio buttons, the return value is the index of the selected button + * or -1 for none. If toggle buttons are checked, a bit is set for each + * button that is active. + * + * \param bc IN + * \returns state of group + */ + +static long choiceGetValue( + wChoice_p bc) +{ + GList * child, * children; + long value, inx; + + if (bc->type == B_TOGGLE) { + value = 0; + } else { + value = -1; + } + + for (children=child=gtk_container_get_children(GTK_CONTAINER(bc->widget)),inx=0; + child; child=child->next,inx++) { + if (gtk_toggle_button_get_active(child->data)) { + if (bc->type == B_TOGGLE) { + value |= (1<<inx); + } else { + value = inx; + } + } + } + + if (children) { + g_list_free(children); + } + + return value; +} + +/** + * Set the active radio button in a group + * + * \param bc IN button group + * \param value IN index of active button + */ + +void wRadioSetValue( + wChoice_p bc, /* Radio box */ + long value) /* Value */ +{ + GList * child, * children; + long inx; + + for (children=child=gtk_container_get_children(GTK_CONTAINER(bc->widget)),inx=0; + child; child=child->next,inx++) { + if (inx == value) { + bc->recursion++; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(child->data), TRUE); + bc->recursion--; + } + } + + if (children) { + g_list_free(children); + } +} + +/** + * Get the active button from a group of radio buttons + * + * \param bc IN + * \returns + */ + +long wRadioGetValue( + wChoice_p bc) /* Radio box */ +{ + return choiceGetValue(bc); +} + +/** + * Set a group of toggle buttons from a bitfield + * + * \param bc IN button group + * \param value IN bitfield + */ + +void wToggleSetValue( + wChoice_p bc, /* Toggle box */ + long value) /* Values */ +{ + GList * child, * children; + long inx; + bc->recursion++; + + for (children=child=gtk_container_get_children(GTK_CONTAINER(bc->widget)),inx=0; + child; child=child->next,inx++) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(child->data), + (value&(1<<inx))!=0); + } + + if (children) { + g_list_free(children); + } + + bc->recursion--; +} + + +/** + * Get the active buttons from a group of toggle buttons + * + * \param b IN + * \returns + */ + +long wToggleGetValue( + wChoice_p b) /* Toggle box */ +{ + return choiceGetValue(b); +} + +/** + * Signal handler for button selection in radio buttons and toggle + * button group + * + * \param widget IN the button group + * \param b IN user data (button group????) + * \returns always 1 + */ + +static int pushChoice( + GtkWidget *widget, + gpointer b) +{ + wChoice_p bc = (wChoice_p)b; + long value = choiceGetValue(bc); + + if (debugWindow >= 2) { + printf("%s choice pushed = %ld\n", bc->labelStr?bc->labelStr:"No label", + value); + } + + if (bc->type == B_RADIO && + !(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))) { + return 1; + } + + if (bc->recursion) { + return 1; + } + + if (bc->valueP) { + *bc->valueP = value; + } + + if (bc->action) { + bc->action(value, bc->data); + } + + return 1; +} + +/** + * Signal handler used to draw a frame around a widget, used to visually + * group several buttons together + * + * \param b IN widget + */ + +static void choiceRepaint( + wControl_p b) +{ + wChoice_p bc = (wChoice_p)b; + + if (gtk_widget_get_visible(b->widget)) { + wlibDrawBox(bc->parent, wBoxBelow, bc->realX-1, bc->realY-1, bc->w+1, bc->h+1); + } +} + +/** + * Create a group of radio buttons. + * + * \param parent IN parent window + * \param x IN X-position + * \param y IN Y-position + * \param helpStr IN Help string + * \param labelStr IN Label + * \param option IN Options + * \param labels IN Labels + * \param valueP IN Selected value + * \param action IN Callback + * \param data IN User data as context + * \returns radio button widget + */ + +wChoice_p wRadioCreate( + wWin_p parent, + wPos_t x, + wPos_t y, + const char * helpStr, + const char * labelStr, + long option, + const char **labels, + long *valueP, + wChoiceCallBack_p action, + void *data) +{ + wChoice_p b; + const char ** label; + GtkWidget *butt0=NULL, *butt; + + if ((option & BC_NOBORDER)==0) { + if (x>=0) { + x++; + } else { + x--; + } + + if (y>=0) { + y++; + } else { + y--; + } + } + + b = wlibAlloc(parent, B_RADIO, x, y, labelStr, sizeof *b, data); + b->option = option; + b->action = action; + b->valueP = valueP; + wlibComputePos((wControl_p)b); + + if (option&BC_HORZ) { + b->widget = gtk_hbox_new(FALSE, 0); + } else { + b->widget = gtk_vbox_new(FALSE, 0); + } + + if (b->widget == 0) { + abort(); + } + + for (label=labels; *label; label++) { + butt = gtk_radio_button_new_with_label( + butt0?gtk_radio_button_get_group(GTK_RADIO_BUTTON(butt0)):NULL, _(*label)); + + if (butt0==NULL) { + butt0 = butt; + } + + gtk_box_pack_start(GTK_BOX(b->widget), butt, TRUE, TRUE, 0); + gtk_widget_show(butt); + g_signal_connect(GTK_OBJECT(butt), "toggled", + G_CALLBACK(pushChoice), b); + wlibAddHelpString(butt, helpStr); + } + + if (option & BB_DEFAULT) { + gtk_widget_set_can_default(b->widget, TRUE); + gtk_widget_grab_default(b->widget); + } + + if (valueP) { + wRadioSetValue(b, *valueP); + } + + if ((option & BC_NOBORDER)==0) { + b->repaintProc = choiceRepaint; + b->w += 2; + b->h += 2; + } + + gtk_fixed_put(GTK_FIXED(parent->widget), b->widget, b->realX, b->realY); + wlibControlGetSize((wControl_p)b); + + if (labelStr) { + b->labelW = wlibAddLabel((wControl_p)b, labelStr); + } + + gtk_widget_show(b->widget); + wlibAddButton((wControl_p)b); + return b; +} + +/** + * Create a group of toggle buttons. + * + * \param parent IN parent window + * \param x IN X-position + * \param y IN Y-position + * \param helpStr IN Help string + * \param labelStr IN Label + * \param option IN Options + * \param labels IN Labels + * \param valueP IN Selected value + * \param action IN Callback + * \param data IN User data as context + * \returns toggle button widget + */ + +wChoice_p wToggleCreate( + wWin_p parent, + wPos_t x, + wPos_t y, + const char * helpStr, + const char * labelStr, + long option, + const char **labels, + long *valueP, + wChoiceCallBack_p action, + void *data) +{ + wChoice_p b; + const char ** label; + + if ((option & BC_NOBORDER)==0) { + if (x>=0) { + x++; + } else { + x--; + } + + if (y>=0) { + y++; + } else { + y--; + } + } + + b = wlibAlloc(parent, B_TOGGLE, x, y, labelStr, sizeof *b, data); + b->option = option; + b->action = action; + wlibComputePos((wControl_p)b); + + if (option&BC_HORZ) { + b->widget = gtk_hbox_new(FALSE, 0); + } else { + b->widget = gtk_vbox_new(FALSE, 0); + } + + if (b->widget == 0) { + abort(); + } + + for (label=labels; *label; label++) { + GtkWidget *butt; + + butt = gtk_check_button_new_with_label(_(*label)); + gtk_box_pack_start(GTK_BOX(b->widget), butt, TRUE, TRUE, 0); + gtk_widget_show(butt); + g_signal_connect(GTK_OBJECT(butt), "toggled", + G_CALLBACK(pushChoice), b); + wlibAddHelpString(butt, helpStr); + } + + if (valueP) { + wToggleSetValue(b, *valueP); + } + + if ((option & BC_NOBORDER)==0) { + b->repaintProc = choiceRepaint; + b->w += 2; + b->h += 2; + } + + gtk_fixed_put(GTK_FIXED(parent->widget), b->widget, b->realX, b->realY); + wlibControlGetSize((wControl_p)b); + + if (labelStr) { + b->labelW = wlibAddLabel((wControl_p)b, labelStr); + } + + gtk_widget_show(b->widget); + wlibAddButton((wControl_p)b); + return b; +} |