From 778feecff66a1331a3795bc820b67423016ac16f Mon Sep 17 00:00:00 2001 From: gambas Date: Mon, 23 Nov 2020 03:55:46 +0100 Subject: [PATCH] Use GTK+ internals to make ComboBox Border, Foreground and Background properties work as expected. [GB.GTK3] * BUG: Use GTK+ internals to make ComboBox Border, Foreground and Background properties work as expected. --- gb.gtk/src/gbutton.cpp | 2 +- gb.gtk/src/gcombobox.cpp | 169 +++++++++++++++++++++++++++++++++++---- gb.gtk/src/gcombobox.h | 13 ++- gb.gtk/src/gcontrol.cpp | 76 ++++++++++++++---- gb.gtk/src/gcontrol.h | 7 +- 5 files changed, 231 insertions(+), 36 deletions(-) diff --git a/gb.gtk/src/gbutton.cpp b/gb.gtk/src/gbutton.cpp index cffc1d371..235a3d72a 100644 --- a/gb.gtk/src/gbutton.cpp +++ b/gb.gtk/src/gbutton.cpp @@ -122,7 +122,7 @@ static gboolean button_expose(GtkWidget *wid, GdkEventExpose *e, gButton *data) if (data->hasText()) { gt_set_cell_renderer_text_from_font((GtkCellRendererText *)data->rendtxt, data->font()); - wt = data->font()->width(data->text(), strlen(data->text())); + wt = data->font()->width(data->text(), strlen(data->text())) + 4; } if (data->rendpix) diff --git a/gb.gtk/src/gcombobox.cpp b/gb.gtk/src/gcombobox.cpp index a69403f50..6818d26ac 100644 --- a/gb.gtk/src/gcombobox.cpp +++ b/gb.gtk/src/gcombobox.cpp @@ -26,6 +26,72 @@ #include "gdesktop.h" #include "gcombobox.h" +#ifdef GTK3 + +struct _GtkComboBoxPrivate +{ + GtkTreeModel *model; + + GtkCellArea *area; + + gint col_column; + gint row_column; + + gint wrap_width; + + gint active; /* Only temporary */ + GtkTreeRowReference *active_row; + + GtkWidget *tree_view; + + GtkWidget *cell_view; + + GtkWidget *box; + GtkWidget *button; + GtkWidget *arrow; + + GtkWidget *popup_widget; + GtkWidget *popup_window; + GtkWidget *scrolled_window; + + //GtkCssGadget *gadget; + void *gadget; + + guint popup_idle_id; + GdkEvent *trigger_event; + guint scroll_timer; + guint resize_idle_id; + + /* For "has-entry" specific behavior we track + * an automated cell renderer and text column + */ + gint text_column; + GtkCellRenderer *text_renderer; + + gint id_column; + + guint popup_in_progress : 1; + guint popup_shown : 1; + guint add_tearoffs : 1; + guint has_frame : 1; + guint is_cell_renderer : 1; + guint editing_canceled : 1; + guint auto_scroll : 1; + guint button_sensitivity : 2; + guint has_entry : 1; + guint popup_fixed_width : 1; + + GtkTreeViewRowSeparatorFunc row_separator_func; + gpointer row_separator_data; + GDestroyNotify row_separator_destroy; + + GdkDevice *grab_pointer; + + gchar *tearoff_title; +}; + +#endif + /************************************************************************** gComboBox @@ -158,13 +224,14 @@ void gComboBox::create(bool readOnly) cell = NULL; gtk_widget_destroy(widget); _button = NULL; + createWidget(); } if (readOnly) { widget = gtk_combo_box_new_with_model(GTK_TREE_MODEL(tree->store)); entry = NULL; - + cell = gtk_cell_renderer_text_new (); g_object_ref_sink(cell); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), cell, true); @@ -237,15 +304,19 @@ void gComboBox::create(bool readOnly) updateFocusHandler(); + //gtk_widget_reset_style(border); + if (!first) { setBackground(bg); setForeground(fg); updateFont(); + + setText(save); + g_free(save); + + updateDesign(); } - - setText(save); - g_free(save); unlock(); } @@ -260,7 +331,8 @@ gComboBox::gComboBox(gContainer *parent) : gTextBox(parent, true) _last_key = 0; _model_dirty = false; _model_dirty_timeout = 0; - sort = false; + _sort = false; + _has_border = true; border = widget = NULL; entry = NULL; _button = NULL; @@ -293,26 +365,80 @@ void gComboBox::popup() } #ifdef GTK3 + GtkWidget *gComboBox::getStyleSheetWidget() { - return entry ? entry : border; + if (entry) + return entry; + + return GTK_COMBO_BOX(widget)->priv->button; +} + +const char *gComboBox::getStyleSheetColorNode() +{ + return ""; +} + +const char *gComboBox::getStyleSheetFontNode() +{ + return ""; +} + +void gComboBox::customStyleSheet(GString *css) +{ + if (!_has_border) + { + setStyleSheetNode(css, ""); + g_string_append_printf(css, "border:none;box-shadow:none;\n"); + if (background() == COLOR_DEFAULT) + g_string_append_printf(css, "background:none;"); + + if (entry) + { + setStyleSheetNode(css, " + *"); + g_string_append_printf(css, "border:none;box-shadow:none;"); + if (background() == COLOR_DEFAULT) + g_string_append_printf(css, "background:none;"); + } + } +} + +void gComboBox::setForeground(gColor color) +{ + GdkRGBA rgba; + + gControl::setForeground(color); + + gt_from_color(realForeground(true), &rgba); + g_object_set(G_OBJECT(cell), "foreground-rgba", &rgba, NULL); } #else + void gComboBox::setRealBackground(gColor color) { gControl::setRealBackground(color); if (entry) set_gdk_base_color(entry, color); } -#endif void gComboBox::setRealForeground(gColor color) { gControl::setRealForeground(color); if (entry) set_gdk_text_color(entry, color); + +#ifdef GTK3 + GdkRGBA rgba; + gt_from_color(color, &rgba); + g_object_set(G_OBJECT(cell), "foreground-rgba", &rgba, NULL); +#else + GdkColor col; + fill_gdk_color(&col, color); + g_object_set(G_OBJECT(cell), "foreground-gdk", &col, NULL); +#endif } +#endif int gComboBox::count() { @@ -629,20 +755,29 @@ void gComboBox::updateFocusHandler() g_signal_connect(G_OBJECT(button), "focus-out-event", G_CALLBACK(button_focus_out), (gpointer)this); } -bool gComboBox::hasBorder() const -{ - gboolean v; - - g_object_get(G_OBJECT(widget), "has-frame", &v, (void *)NULL); - return v; -} - void gComboBox::setBorder(bool v) { - g_object_set(G_OBJECT(widget), "has-frame", v, (void *)NULL); + _has_border = v; + updateBorder(); +} + +void gComboBox::updateBorder() +{ +#ifdef GTK3 + updateStyleSheet(); +#else + g_object_set(G_OBJECT(widget), "has-frame", _has_border, NULL); +#endif } bool gComboBox::canFocus() const { - return true; + return !_design; +} + +void gComboBox::setDesign(bool ignore) +{ + gControl::setDesign(ignore); + if (entry) + gtk_widget_set_can_focus(entry, false); } diff --git a/gb.gtk/src/gcombobox.h b/gb.gtk/src/gcombobox.h index 30dfd469a..2cb5ea0dc 100644 --- a/gb.gtk/src/gcombobox.h +++ b/gb.gtk/src/gcombobox.h @@ -49,7 +49,7 @@ public: void setSorted(bool vl); virtual void setText(const char *vl); - bool hasBorder() const; + bool hasBorder() const { return _has_border; } void setBorder(bool v); //"Methods" @@ -61,18 +61,23 @@ public: #ifdef GTK3 virtual GtkWidget *getStyleSheetWidget(); + virtual const char *getStyleSheetColorNode(); + virtual const char *getStyleSheetFontNode(); + virtual void customStyleSheet(GString *css); + virtual void setForeground(gColor color); #else virtual void setRealBackground(gColor vl); -#endif virtual void setRealForeground(gColor vl); +#endif virtual void setFocus(); virtual bool canFocus() const; + void updateBorder(); + virtual void setDesign(bool ignore = false); //"Signals" void (*onClick)(gComboBox *sender); //"Private" - bool sort; GtkCellRenderer *cell; virtual int minimumHeight(); gTree *tree; @@ -80,6 +85,8 @@ public: int _last_key; GtkWidget *_button; int _model_dirty_timeout; + unsigned _sort : 1; + unsigned _has_border : 1; virtual void updateFont(); void updateModel(); diff --git a/gb.gtk/src/gcontrol.cpp b/gb.gtk/src/gcontrol.cpp index af6bc3dab..a2a719dcc 100644 --- a/gb.gtk/src/gcontrol.cpp +++ b/gb.gtk/src/gcontrol.cpp @@ -1148,6 +1148,15 @@ void gControl::setDesign(bool ignore) _design_ignore = ignore; } +void gControl::updateDesign() +{ + if (!_design) + return; + + _design = false; + setDesign(_design_ignore); +} + gControl *gControl::ignoreDesign() { //fprintf(stderr, "ignoreDesign: %s", name()); @@ -2041,17 +2050,32 @@ void gControl::customStyleSheet(GString *css) { } +void gControl::setStyleSheetNode(GString *css, const char *node) +{ + if (node == _css_node) + return; + + if (node && _css_node && !::strcmp(node, _css_node)) + return; + + if (_css_node) + g_string_append(css, "}\n"); + + _css_node = node; + + if (node) + g_string_append_printf(css, "#%s %s {\ntransition:none;\n", gtk_widget_get_name(getStyleSheetWidget()), node); +} + void gControl::updateStyleSheet() { - static int count = 0; - GtkWidget *wid; GtkStyleContext *context; GString *css; char *css_str; - char buffer[16]; int s; gColor fg; + char buffer[16]; wid = getStyleSheetWidget(); context = gtk_widget_get_style_context(wid); @@ -2067,20 +2091,18 @@ void gControl::updateStyleSheet() { if (!_css) { - count++; - sprintf(buffer, "g%d", count); - gtk_widget_set_name(wid, buffer); - + setWidgetName(); _css = GTK_STYLE_PROVIDER(gtk_css_provider_new()); } else gtk_style_context_remove_provider(context, _css); css = g_string_new(NULL); + _css_node = NULL; if (_bg != COLOR_DEFAULT || fg != COLOR_DEFAULT) { - g_string_append_printf(css, "#%s %s {\ntransition:none;\n", gtk_widget_get_name(wid), getStyleSheetColorNode()); + setStyleSheetNode(css, getStyleSheetColorNode()); if (_bg != COLOR_DEFAULT) { @@ -2097,13 +2119,11 @@ void gControl::updateStyleSheet() g_string_append(css, buffer); g_string_append(css, ";\n"); } - - g_string_append(css, "}\n"); } if (_font) { - g_string_append_printf(css, "#%s %s {\ntransition:none;\n", gtk_widget_get_name(wid), getStyleSheetFontNode()); + setStyleSheetNode(css, getStyleSheetFontNode()); if (_font->_name_set) { @@ -2150,17 +2170,20 @@ void gControl::updateStyleSheet() { g_string_append(css, "letter-spacing:1px;\n"); } - - g_string_append(css, "}\n"); } customStyleSheet(css); - //fprintf(stderr, "---- %s\n%s", _name, css); + setStyleSheetNode(css, NULL); + css_str = g_string_free(css, FALSE); gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(_css), css_str, -1, NULL); g_free(css_str); gtk_style_context_add_provider(context, _css, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + /*css_str = gtk_css_provider_to_string(GTK_CSS_PROVIDER(_css)); + fprintf(stderr, "---- %s\n%s", gtk_widget_get_name(wid), css_str); + g_free(css_str);*/ } } @@ -2826,6 +2849,17 @@ gControl *gControl::previousFocus() return ctrl; } +void gControl::createWidget() +{ +#ifdef GTK3 + if (_css) + { + g_object_unref(_css); + _css = NULL; + } +#endif +} + void gControl::createBorder(GtkWidget *new_border, bool keep_widget) { GtkWidget *old = border; @@ -2840,5 +2874,19 @@ void gControl::createBorder(GtkWidget *new_border, bool keep_widget) _no_delete = true; gtk_widget_destroy(old); _no_delete = false; + createWidget(); } } + +#ifdef GTK3 +void gControl::setWidgetName() +{ + static int count = 0; + + char buffer[16]; + + count++; + sprintf(buffer, "g%d", count); + gtk_widget_set_name(getStyleSheetWidget(), buffer); +} +#endif diff --git a/gb.gtk/src/gcontrol.h b/gb.gtk/src/gcontrol.h index 0f0a22f76..44816d63b 100644 --- a/gb.gtk/src/gcontrol.h +++ b/gb.gtk/src/gcontrol.h @@ -122,6 +122,7 @@ public: virtual void setDesign(bool ignore = false); gControl *ignoreDesign(); + void updateDesign(); char *tooltip() { return _tooltip; } void setTooltip(char *vl); @@ -151,11 +152,13 @@ public: bool hasNativePopup() const { return _has_native_popup; } #ifdef GTK3 + void setWidgetName(); virtual GtkWidget *getStyleSheetWidget(); virtual const char *getStyleSheetColorNode(); virtual const char *getStyleSheetFontNode(); void updateStyleSheet(); virtual void customStyleSheet(GString *css); + void setStyleSheetNode(GString *css, const char *node); virtual void updateColor(); void setColorNames(const char *bg_names[], const char *fg_names[]); void setColorBase(); @@ -213,7 +216,7 @@ public: void lock() { _locked++; } void unlock() { _locked--; } - bool locked() { return _locked; } + bool locked() const { return _locked; } void emit(void *signal); void emit(void *signal, intptr_t arg); @@ -248,6 +251,7 @@ public: char *_tooltip; #ifdef GTK3 GtkStyleProvider *_css; + const char *_css_node; const char *_bg_name; const char **_bg_name_list; GdkRGBA _bg_default; @@ -335,6 +339,7 @@ public: #endif void createBorder(GtkWidget *new_border, bool keep_widget = false); + void createWidget(); virtual int minimumHeight() const; virtual int minimumWidth() const;