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.
This commit is contained in:
gambas 2020-11-23 03:55:46 +01:00
parent 215cd6f54a
commit 778feecff6
5 changed files with 231 additions and 36 deletions

View File

@ -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)

View File

@ -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);
}

View File

@ -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();

View File

@ -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

View File

@ -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;