/*************************************************************************** gbutton.cpp (c) 2004-2006 - Daniel Campos Fernández Gtkmae "GTK+ made easy" classes Realizado para la Junta de Extremadura. Consejería de Educación Ciencia y Tecnología. Proyecto gnuLinEx 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #include "widgets.h" #include "widgets_private.h" #include "gapplication.h" #include "gmainwindow.h" #include "gbutton.h" #include static void bt_click(GtkButton *object, gButton *data) { if (data->disable) { data->disable=false; return; } if (!gApplication::userEvents()) return; data->unsetOtherRadioButtons(); if (data->type == gButton::Tool) { if (!data->isToggle()) { data->disable = true; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->widget), false); } } data->emit(SIGNAL(data->onClick)); } static bool button_expose(GtkWidget *wid,GdkEventExpose *e,gButton *data) { GdkGC *gc; GdkPixbuf *img; GdkRectangle rpix={0,0,0,0}; GdkRectangle rect={0,0,0,0}; GtkCellRendererState state; gint py,px; bool rtl,bcenter=false; gint dx, dy; rtl = gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL; rect = wid->allocation; px = rect.width; if (GTK_WIDGET_STATE(data->widget) == GTK_STATE_ACTIVE) { gtk_widget_style_get (wid, "child-displacement-x", &dx, "child-displacement-y", &dy, (void *)NULL); rect.x += dx; rect.y += dy; } //g_debug("button_expose: %d %d %d %d", e->area.x, e->area.y, e->area.width, e->area.height); //g_debug("rect: %d %d %d %d", rect.x, rect.y, rect.width, rect.height); if (data->rendpix) { if (GTK_WIDGET_STATE(data->widget)==GTK_STATE_INSENSITIVE) { if (!data->rendinc) data->rendinc = gt_pixbuf_create_disabled(data->rendpix); img = data->rendinc; } else img = data->rendpix; rpix.width = gdk_pixbuf_get_width(img); rpix.height = gdk_pixbuf_get_height(img); py = (rect.height - rpix.height)/2; gc=gdk_gc_new(wid->window); gdk_gc_set_clip_origin(gc,0,0); gdk_gc_set_clip_rectangle(gc,&e->area); bcenter = !(data->text()) || !(*data->text()); if (bcenter) { gdk_draw_pixbuf(GDK_DRAWABLE(wid->window),gc,img,0,0,rect.x + (px-rpix.width)/2, rect.y + py, -1,-1,GDK_RGB_DITHER_MAX,0,0); g_object_unref(gc); return false; } if (rtl) gdk_draw_pixbuf(GDK_DRAWABLE(wid->window),gc,img,0,0,rect.x + rect.width - 6, rect.y + py, -1,-1,GDK_RGB_DITHER_MAX,0,0); else gdk_draw_pixbuf(GDK_DRAWABLE(wid->window),gc,img,0,0,rect.x + 6, rect.y + py, -1,-1,GDK_RGB_DITHER_MAX,0,0); g_object_unref(G_OBJECT(gc)); rect.width -= rpix.width; rect.x += rpix.width; } gt_set_cell_renderer_text_from_font((GtkCellRendererText *)data->rendtxt, data->font()); g_object_set(G_OBJECT(data->rendtxt),"sensitive",true, (void *)NULL); switch(GTK_WIDGET_STATE(data->widget)) { //case GTK_STATE_NORMAL: //case GTK_STATE_ACTIVE: state=GTK_CELL_RENDERER_PRELIT; break; //case GTK_STATE_PRELIGHT: state=GTK_CELL_RENDERER_PRELIT; break; case GTK_STATE_SELECTED: state=GTK_CELL_RENDERER_SELECTED; break; case GTK_STATE_INSENSITIVE: state=GTK_CELL_RENDERER_INSENSITIVE; g_object_set(G_OBJECT(data->rendtxt),"sensitive",false, (void *)NULL); break; default: state=(GtkCellRendererState)0; break; } /*rect.width-=12; rect.x+=6; if (rtl) { rect.width=px-rect.x-6; rect.x=6; }*/ if (rect.width >= 1 && rect.height >= 1) { gtk_cell_renderer_set_fixed_size(data->rendtxt,rect.width,rect.height); gtk_cell_renderer_render(data->rendtxt,wid->window,wid,&rect,&rect,&rect,state); } return FALSE; } static void rd_click (GtkButton *object,gControl *data) { if (!gApplication::userEvents()) return; if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(object))) if (((gButton*)data)->onClick) ((gButton*)data)->onClick((gControl*)data); return; } gButton::gButton(gContainer *par, Type typ) : gControl(par) { gContainer *ct; g_typ = Type_gButton; _toggle = false; _radio = false; _animated = false; _stretch = true; scaled = false; disable = false; bufText = NULL; rendtxt = NULL; label = NULL; rendpix = NULL; rendinc = NULL; pic = NULL; shortcut = 0; //border=gtk_event_box_new(); switch(typ) { case Toggle: rendtxt=gtk_cell_renderer_text_new(); border=gtk_toggle_button_new(); break; case Check: border=gtk_check_button_new(); break; case Radio: ct = parent(); if (!ct->radiogroup) { ct->radiogroup=gtk_radio_button_new(NULL); g_object_ref(ct->radiogroup); border=gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(ct->radiogroup)); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(border),true); } else { border=gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(ct->radiogroup)); } break; case Tool: rendtxt=gtk_cell_renderer_text_new(); border=gtk_toggle_button_new(); break; default: border=gtk_button_new(); rendtxt=gtk_cell_renderer_text_new(); typ = Button; break; } widget = border; border = gtk_event_box_new(); type = typ; if (rendtxt) { g_object_set(G_OBJECT(rendtxt),"xalign",0.5,(void *)NULL); g_object_set(G_OBJECT(rendtxt),"yalign",0.5,(void *)NULL); g_signal_connect_after(G_OBJECT(widget),"expose-event",G_CALLBACK(button_expose),(gpointer)this); } else { label = gtk_label_new_with_mnemonic(""); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); gtk_container_add (GTK_CONTAINER(widget), GTK_WIDGET(label)); } realize(); gtk_button_set_focus_on_click (GTK_BUTTON(widget),true); //gtk_widget_add_events(widget, GDK_POINTER_MOTION_MASK); onClick=NULL; if (type == Radio) g_signal_connect(G_OBJECT(widget),"clicked",G_CALLBACK(rd_click),(gpointer)this); else g_signal_connect(G_OBJECT(widget),"clicked",G_CALLBACK(bt_click),(gpointer)this); //resize(100,30); if (type == Tool) setBorder(false); } gButton::~gButton() { setDefault(false); setCancel(false); setPicture(0); g_free(bufText); } void gButton::setInconsistent(bool vl) { if (type != Check) return; gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON(widget),vl); } bool gButton::inconsistent() { gboolean vl=false; if (type != Check) return false; g_object_get (G_OBJECT(widget),"inconsistent",&vl,(void *)NULL); return vl; } #if 0 void gButton::setFont(gFont *ft) { PangoFontDescription *desc=pango_context_get_font_description(ft->ct); GtkBox *box; GtkLabel *lbl; GList *chd; gControl::setFont(ft); return; /* TODO */ font_change=true; if (type==4) { gtk_widget_modify_font(widget,desc); return; } if (rendtxt) { } else { box=(GtkBox*)gtk_bin_get_child(GTK_BIN(widget)); chd=gtk_container_get_children(GTK_CONTAINER(box)); chd=chd->next; lbl=GTK_LABEL(chd->data); gtk_widget_modify_font(GTK_WIDGET(lbl),desc); g_list_free(chd); } } #endif void gButton::setFont(gFont *ft) { gControl::setFont(ft); if (label) gtk_widget_modify_font(label, fnt ? fnt->desc() : NULL); } bool gButton::enabled() { return GTK_WIDGET_SENSITIVE(widget); } void gButton::setEnabled(bool vl) { gtk_widget_set_sensitive(widget, vl); } #if 0 void gButton::setBackground(long color) { GtkWidget *wid; wid=(type == Check) ? border : widget; set_gdk_bg_color(wid,color); if (!border->window) gtk_widget_realize(border); gdk_window_process_updates(border->window,true); } long gButton::background() { if (type == Check) get_gdk_bg_color(border); return get_gdk_bg_color(widget); } void gButton::setForeground(long color) { GdkColor col; GtkWidget *lbl; set_gdk_fg_color(widget,color); if (rendtxt) { fill_gdk_color(&col,color); g_object_set(G_OBJECT(rendtxt),"foreground-set",TRUE,NULL); g_object_set(G_OBJECT(rendtxt),"foreground-gdk",&col,NULL); } else { lbl=gtk_bin_get_child(GTK_BIN(widget)); set_gdk_fg_color(lbl,color); } if (!border->window) gtk_widget_realize(border); gdk_window_process_updates(border->window,true); } long gButton::foreground() { return get_gdk_fg_color(widget); } #endif const char* gButton::text() { //if (type == Tool) return this->toolTip(); return bufText; } void gButton::setText(const char *st) { GtkLabel *lbl=NULL; GtkAccelGroup *accel; char *buf; accel = window()->accel; if (bufText) { if (shortcut) gtk_widget_remove_accelerator(widget, accel, (guint)shortcut, GDK_MOD1_MASK); g_free(bufText); } bufText = g_strdup(st); resize(); if (!rendtxt) { lbl=(GtkLabel*)gtk_bin_get_child(GTK_BIN(widget)); if (!st) st=""; if (!strlen(st)) { gtk_label_set_text(lbl,""); g_object_set(G_OBJECT(lbl),"visible",false,(void *)NULL); return; } gMnemonic_correctText((char*)st,&buf); gtk_label_set_text_with_mnemonic(lbl,buf); g_object_set(G_OBJECT(lbl),"visible",true,(void *)NULL); g_free(buf); return; } shortcut = (int)gMnemonic_correctMarkup((char*)st,&buf); if (shortcut) gtk_widget_add_accelerator(widget, "clicked", accel, (guint)shortcut, GDK_MOD1_MASK, (GtkAccelFlags)0); g_object_set(G_OBJECT(rendtxt),"markup",buf,(void *)NULL); g_free(buf); refresh(); } gPicture* gButton::picture() { if ( (type == Check) || (type == Radio) ) return NULL; return pic; } void gButton::setPicture(gPicture *npic) { GdkPixbuf *new_rendpix = NULL; if ((type == Check) || (type == Radio)) return; gPicture::assign(&pic, npic); if (pic) { new_rendpix = pic->getPixbuf(); if (new_rendpix) g_object_ref(new_rendpix); } if (rendpix) { g_object_unref(G_OBJECT(rendpix)); rendpix = NULL; } if (rendinc) { g_object_unref(G_OBJECT(rendinc)); rendinc = NULL; } rendpix = new_rendpix; refresh(); } bool gButton::getBorder() { switch(gtk_button_get_relief(GTK_BUTTON(widget))) { case GTK_RELIEF_NORMAL: case GTK_RELIEF_HALF: return true; default: return false; } } void gButton::setBorder(bool vl) { if (vl) gtk_button_set_relief (GTK_BUTTON(widget),GTK_RELIEF_NORMAL); else gtk_button_set_relief (GTK_BUTTON(widget),GTK_RELIEF_NONE); } bool gButton::isDefault() { gMainWindow *win = window(); return win ? win->_default == this : false; } void gButton::setDefault(bool vl) { gMainWindow *win = window(); if (type != Button || !win) return; if (vl) { win->_default = this; GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT); //gtk_widget_grab_default (widget); } else { GTK_WIDGET_UNSET_FLAGS(widget, GTK_CAN_DEFAULT); if (win->_default == this) win->_default = NULL; } } bool gButton::isCancel() { gMainWindow *win = window(); return win ? win->_cancel == this : false; } void gButton::setCancel(bool vl) { gMainWindow *win = window(); if (type != Button || !win) return; if (vl) win->_cancel = this; else if (win->_cancel == this) win->_cancel = NULL; } bool gButton::value() { if (type == Button) return false; else return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)); } void gButton::setValue(bool vl) { if (type == Button) { if (vl) gtk_button_clicked(GTK_BUTTON(widget)); } else gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget),vl); } void gButton::setToggle(bool vl) { if (type != Tool) return; _toggle = vl; } bool gButton::isToggle() { return type == Toggle || type == Check || type == Radio || _toggle; } void gButton::animateClick(bool on) { if (type != Button) return; if (!on && !_animated) { gtk_widget_set_state(widget, GTK_STATE_ACTIVE); _animated = true; } else if (on && _animated) { _animated = false; gtk_widget_set_state(widget, GTK_STATE_NORMAL); gtk_button_clicked(GTK_BUTTON(widget)); } } int gButton::minimumHeight() { if (bufText && *bufText) { if (type == Button || type == Toggle || type == Tool) return font()->height() + 8; else return font()->height() + 2; } return 0; } void gButton::setRadio(bool vl) { _radio = vl; if (value()) unsetOtherRadioButtons(); } bool gButton::isRadio() { return type == Radio || _radio; } void gButton::unsetOtherRadioButtons() { gContainer *pr = parent(); gControl *child; gButton *button; int i; if (type == Radio || type == Button || !isRadio() || !isToggle()) return; for (i = 0; i < pr->childCount(); i++) { child = pr->child(i); if (child->getClass() != getClass()) continue; button = (gButton *)child; if (button == this) { if (!value()) { button->disable = true; button->setValue(true); } } else if (button->type == type && button->isRadio() && button->isToggle() && button->value()) { button->disable = true; button->setValue(false); } } } bool gButton::hasShortcut() { return isDefault() || isCancel() || shortcut; } void gButton::setStretch(bool vl) { _stretch = vl; } #if 0 void gButton::setBackground(gColor color) { gControl::setBackground(color); if (rendtxt) { if (color == COLOR_DEFAULT) { g_object_set(G_OBJECT(rendtxt), "background-set", FALSE, NULL); } GdkColor col; fill_gdk_color(&col, color); g_object_set(G_OBJECT(rendtxt), "background-set", TRUE, "background-gdk", &col, NULL); } } void gButton::setForeground(gColor color) { gControl::setForeground(color); if (rendtxt) { if (color == COLOR_DEFAULT) { g_object_set(G_OBJECT(rendtxt), "foreground-set", FALSE, NULL); } else { GdkColor col; fill_gdk_color(&col, color); g_object_set(G_OBJECT(rendtxt), "foreground-set", TRUE, "foreground-gdk", &col, NULL); } } } #endif void gButton::setRealForeground(gColor color) { gControl::setRealForeground(color); if (rendtxt) { if (color == COLOR_DEFAULT) { g_object_set(G_OBJECT(rendtxt), "foreground-set", FALSE, (void *)NULL); } else { GdkColor col; fill_gdk_color(&col, color); g_object_set(G_OBJECT(rendtxt), "foreground-set", TRUE, "foreground-gdk", &col, (void *)NULL); } } if (label) set_gdk_fg_color(label, color); }