da4002dede
[GB.GTK3] * BUG: ComboBox now correctly takes language direction into account.
822 lines
16 KiB
C++
822 lines
16 KiB
C++
/***************************************************************************
|
|
|
|
gcombobox.cpp
|
|
|
|
(c) 2004-2006 - Daniel Campos Fernández <dcamposf@gmail.com>
|
|
|
|
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, 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., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "widgets.h"
|
|
#include "gmainwindow.h"
|
|
#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
|
|
|
|
**************************************************************************/
|
|
|
|
static void cb_click(GtkComboBox *widget,gComboBox *data)
|
|
{
|
|
if (data->locked())
|
|
return;
|
|
|
|
if (!data->isReadOnly() && data->count())
|
|
{
|
|
int index = data->index();
|
|
if (index >= 0)
|
|
{
|
|
const char *text = index >= 0 ? data->itemText(index) : NULL;
|
|
if (!text) text = "";
|
|
data->lock();
|
|
gtk_entry_set_text(GTK_ENTRY(data->entry), text);
|
|
data->setIndex(index);
|
|
data->unlock();
|
|
CB_textbox_change(data);
|
|
}
|
|
}
|
|
|
|
if (data->index() >= 0)
|
|
CB_combobox_click(data);
|
|
}
|
|
|
|
/*static int pathToIndex(GtkTreePath *path)
|
|
{
|
|
gint *indices;
|
|
|
|
if (!path)
|
|
return -1;
|
|
|
|
indices = gtk_tree_path_get_indices(path);
|
|
return indices[0];
|
|
}*/
|
|
|
|
static GtkTreePath *indexToPath(int index)
|
|
{
|
|
char buffer[16];
|
|
sprintf(buffer, "%d", index);
|
|
return gtk_tree_path_new_from_string(buffer);
|
|
}
|
|
|
|
static void combo_cell_text(GtkComboBox *combo, GtkCellRenderer *cell, GtkTreeModel *md, GtkTreeIter *iter, gTree *tr)
|
|
{
|
|
gTreeRow *row = NULL;
|
|
gTreeCell *data;
|
|
const char *buf = "";
|
|
char *key;
|
|
|
|
key = tr->iterToKey(iter);
|
|
if (key)
|
|
row = (gTreeRow*)g_hash_table_lookup(tr->datakey, (gpointer)key);
|
|
|
|
if (row)
|
|
{
|
|
data = row->get(0);
|
|
if (data)
|
|
{
|
|
if (data->text())
|
|
buf = data->text();
|
|
}
|
|
}
|
|
|
|
g_object_set(G_OBJECT(cell),
|
|
"text", buf,
|
|
(void *)NULL);
|
|
}
|
|
|
|
static GtkWidget *_find_button;
|
|
|
|
static void cb_find_button(GtkWidget *widget, gpointer data)
|
|
{
|
|
if (GTK_IS_TOGGLE_BUTTON(widget))
|
|
_find_button = widget;
|
|
else if (GTK_IS_CONTAINER(widget))
|
|
gtk_container_forall(GTK_CONTAINER(widget), cb_find_button, NULL);
|
|
}
|
|
|
|
static GtkWidget *find_button(GtkWidget *combo)
|
|
{
|
|
_find_button = NULL;
|
|
gtk_container_forall(GTK_CONTAINER(combo), cb_find_button, NULL);
|
|
return _find_button;
|
|
}
|
|
|
|
char *gComboBox::indexToKey(int index)
|
|
{
|
|
char *key;
|
|
GtkTreePath *path = indexToPath(index);
|
|
key = find(path);
|
|
gtk_tree_path_free(path);
|
|
return key;
|
|
}
|
|
|
|
void gComboBox::create(bool readOnly)
|
|
{
|
|
bool first = !border;
|
|
char *save = NULL;
|
|
GB_COLOR bg, fg;
|
|
GList *cells;
|
|
|
|
//fprintf(stderr, "create: %d hasFocus = %d\n", readOnly, focus );
|
|
|
|
lock();
|
|
|
|
if (first)
|
|
{
|
|
#if GTK3
|
|
border = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); //gtk_event_box_new();
|
|
#else
|
|
border = gtk_alignment_new(0, 0, 1, 1); //gtk_event_box_new();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
save = g_strdup(text());
|
|
bg = background();
|
|
fg = foreground();
|
|
}
|
|
|
|
if (widget)
|
|
{
|
|
if (cell) g_object_unref(cell);
|
|
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);
|
|
|
|
//gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(widget), cell, "text", 0, (void *)NULL);
|
|
g_object_set(cell, "ypad", 0, (void *)NULL);
|
|
|
|
gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(widget), cell, (GtkCellLayoutDataFunc)combo_cell_text, (gpointer)tree, NULL);
|
|
|
|
#ifdef GTK3
|
|
gtk_widget_set_hexpand(widget, TRUE);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
|
|
#if GTK_CHECK_VERSION(2, 24, 0)
|
|
widget = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(tree->store));
|
|
#else
|
|
widget = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(tree->store), 0);
|
|
#endif
|
|
entry = gtk_bin_get_child(GTK_BIN(widget));
|
|
|
|
#ifdef GTK3
|
|
//gtk_widget_set_hexpand(widget, TRUE);
|
|
gtk_widget_set_hexpand(entry, TRUE);
|
|
#endif
|
|
|
|
g_signal_handler_disconnect(widget, g_signal_handler_find(widget, G_SIGNAL_MATCH_ID, g_signal_lookup("changed", G_OBJECT_TYPE(widget)), 0, 0, 0, 0));
|
|
|
|
cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(widget));
|
|
cell = (GtkCellRenderer *)cells->data;
|
|
g_list_free(cells);
|
|
g_object_ref(cell);
|
|
//gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(widget), cell, "text", 0, (void *)NULL);
|
|
//g_object_set(cell, "ypad", 0, (void *)NULL);
|
|
gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(widget), cell, (GtkCellLayoutDataFunc)combo_cell_text, (gpointer)tree, NULL);
|
|
}
|
|
|
|
#ifdef GTK3
|
|
gtk_combo_box_set_popup_fixed_width(GTK_COMBO_BOX(widget), TRUE);
|
|
#endif
|
|
|
|
if (first)
|
|
{
|
|
realize();
|
|
}
|
|
else
|
|
{
|
|
gtk_container_add(GTK_CONTAINER(border), widget);
|
|
gtk_widget_show(widget);
|
|
widgetSignals();
|
|
#ifdef GTK3
|
|
gt_patch_control(border);
|
|
gt_patch_control(widget);
|
|
#endif
|
|
}
|
|
|
|
#ifdef GTK3
|
|
if (entry)
|
|
gt_patch_control(entry);
|
|
#endif
|
|
|
|
g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(cb_click), (gpointer)this);
|
|
|
|
if (entry)
|
|
{
|
|
initEntry();
|
|
setColorBase();
|
|
//g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(gcb_keypress), (gpointer)this);
|
|
//g_signal_connect(G_OBJECT(entry), "key-release-event", G_CALLBACK(gcb_keyrelease), (gpointer)this);
|
|
g_signal_connect(G_OBJECT(entry), "focus-in-event", G_CALLBACK(gcb_focus_in), (gpointer)this);
|
|
g_signal_connect(G_OBJECT(entry), "focus-out-event", G_CALLBACK(gcb_focus_out), (gpointer)this);
|
|
}
|
|
else
|
|
{
|
|
_has_input_method = FALSE;
|
|
setColorButton();
|
|
}
|
|
|
|
updateFocusHandler();
|
|
|
|
//gtk_widget_reset_style(border);
|
|
|
|
if (!first)
|
|
{
|
|
setBackground(bg);
|
|
setForeground(fg);
|
|
updateFont();
|
|
|
|
setText(save);
|
|
g_free(save);
|
|
|
|
updateDesign();
|
|
updateDirection();
|
|
}
|
|
|
|
unlock();
|
|
}
|
|
|
|
gComboBox::gComboBox(gContainer *parent) : gTextBox(parent, true)
|
|
{
|
|
_no_background = TRUE;
|
|
_last_key = 0;
|
|
_model_dirty = false;
|
|
_model_dirty_timeout = 0;
|
|
_sort = false;
|
|
_has_border = true;
|
|
border = widget = NULL;
|
|
entry = NULL;
|
|
_button = NULL;
|
|
cell = NULL;
|
|
_use_wheel = true;
|
|
|
|
tree = new gTree();
|
|
tree->addColumn();
|
|
//tree->addColumn();
|
|
//tree->setHeaders(false);
|
|
|
|
create(false);
|
|
}
|
|
|
|
gComboBox::~gComboBox()
|
|
{
|
|
if (_model_dirty_timeout)
|
|
g_source_remove(_model_dirty_timeout);
|
|
|
|
gtk_combo_box_popdown(GTK_COMBO_BOX(widget));
|
|
|
|
if (cell) g_object_unref(cell);
|
|
|
|
delete tree;
|
|
}
|
|
|
|
void gComboBox::popup()
|
|
{
|
|
gtk_combo_box_popup(GTK_COMBO_BOX(widget));
|
|
}
|
|
|
|
void gComboBox::popdown()
|
|
{
|
|
gtk_combo_box_popdown(GTK_COMBO_BOX(widget));
|
|
}
|
|
|
|
#ifdef GTK3
|
|
|
|
GtkWidget *gComboBox::getStyleSheetWidget()
|
|
{
|
|
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;padding-top:0;padding-bottom:0;\n");
|
|
/*if (background() == COLOR_DEFAULT)
|
|
g_string_append_printf(css, "background:none;");*/
|
|
|
|
if (entry)
|
|
{
|
|
setStyleSheetNode(css, " + button");
|
|
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);
|
|
}
|
|
|
|
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() const
|
|
{
|
|
return tree->rowCount();
|
|
}
|
|
|
|
int gComboBox::index()
|
|
{
|
|
updateModel();
|
|
return gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
|
|
}
|
|
|
|
char* gComboBox::itemText(int ind)
|
|
{
|
|
gTreeRow *row;
|
|
gTreeCell *cell;
|
|
|
|
if (ind < 0)
|
|
return NULL;
|
|
|
|
updateModel();
|
|
|
|
char *key = indexToKey(ind);
|
|
|
|
if (!key) return NULL;
|
|
row = tree->getRow(key);
|
|
if (!row) return NULL;
|
|
cell = row->get(0);
|
|
if (!cell) return NULL;
|
|
return cell->text();
|
|
}
|
|
|
|
int gComboBox::length()
|
|
{
|
|
gchar *buf;
|
|
|
|
if (!entry)
|
|
{
|
|
buf = itemText(index());
|
|
if (!buf)
|
|
return 0;
|
|
else
|
|
return g_utf8_strlen(buf, -1);
|
|
}
|
|
else
|
|
return gTextBox::length();
|
|
}
|
|
|
|
bool gComboBox::isSorted() const
|
|
{
|
|
return tree->isSorted();
|
|
}
|
|
|
|
char* gComboBox::text()
|
|
{
|
|
if (entry)
|
|
return gTextBox::text();
|
|
else
|
|
return itemText(index());
|
|
}
|
|
|
|
void gComboBox::setIndex(int vl)
|
|
{
|
|
//fprintf(stderr, "setIndex: %d\n", vl);
|
|
|
|
if (vl < 0)
|
|
vl = -1;
|
|
else if (vl >= count())
|
|
return;
|
|
|
|
if (vl == index() && vl >= 0)
|
|
{
|
|
CB_combobox_click(this);
|
|
return;
|
|
}
|
|
|
|
updateModel();
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), vl);
|
|
|
|
if (entry)
|
|
gTextBox::setText(itemText(vl));
|
|
}
|
|
|
|
void gComboBox::checkIndex()
|
|
{
|
|
if (index() < 0)
|
|
{
|
|
lock();
|
|
setIndex(0);
|
|
unlock();
|
|
}
|
|
}
|
|
|
|
void gComboBox::setItemText(int ind, const char *text)
|
|
{
|
|
gTreeRow *row;
|
|
gTreeCell *cell;
|
|
|
|
char *key = indexToKey(ind);
|
|
|
|
if (!key) return;
|
|
row = tree->getRow(key);
|
|
if (!row) return;
|
|
cell = row->get(0);
|
|
if (!cell) return;
|
|
|
|
cell->setText(text);
|
|
|
|
updateSort();
|
|
}
|
|
|
|
void gComboBox::setReadOnly(bool vl)
|
|
{
|
|
if (isReadOnly() == vl)
|
|
return;
|
|
create(!isReadOnly());
|
|
}
|
|
|
|
void gComboBox::setSorted(bool vl)
|
|
{
|
|
tree->setSorted(vl);
|
|
}
|
|
|
|
void gComboBox::setText(const char *vl)
|
|
{
|
|
int index = find(vl);
|
|
|
|
if (!entry || index >= 0)
|
|
setIndex(index);
|
|
else if (entry)
|
|
gTextBox::setText(vl);
|
|
}
|
|
|
|
static gboolean combo_set_model_and_sort(gComboBox *combo)
|
|
{
|
|
//fprintf(stderr, "combo_set_model_and_sort\n");
|
|
gtk_combo_box_set_model(GTK_COMBO_BOX(combo->widget), GTK_TREE_MODEL(combo->tree->store));
|
|
|
|
if (combo->isSorted())
|
|
combo->tree->sort();
|
|
|
|
combo->_model_dirty = false;
|
|
combo->_model_dirty_timeout = 0;
|
|
|
|
if (combo->isReadOnly())
|
|
combo->checkIndex();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void gComboBox::updateModel()
|
|
{
|
|
if (_model_dirty)
|
|
{
|
|
g_source_remove(_model_dirty_timeout);
|
|
combo_set_model_and_sort(this);
|
|
}
|
|
}
|
|
|
|
void gComboBox::updateSort()
|
|
{
|
|
if (_model_dirty)
|
|
return;
|
|
|
|
_model_dirty = true;
|
|
_model_dirty_timeout = g_timeout_add(0, (GSourceFunc)combo_set_model_and_sort, this);
|
|
|
|
gtk_combo_box_set_model(GTK_COMBO_BOX(widget), NULL);
|
|
}
|
|
|
|
void gComboBox::add(const char *text, int pos)
|
|
{
|
|
//GtkTreeModel *model;
|
|
gTreeRow *row;
|
|
gTreeCell *cell;
|
|
|
|
char key[16];
|
|
char *after;
|
|
|
|
_last_key++;
|
|
sprintf(key, "%d", _last_key);
|
|
|
|
if (pos < 0 || pos > count())
|
|
after = NULL;
|
|
else
|
|
after = indexToKey(pos);
|
|
|
|
//g_signal_lookup("rowGTK_TYPE_COMBO_BOX);
|
|
|
|
row = tree->addRow(key, after, true);
|
|
if (row)
|
|
{
|
|
cell = row->get(0);
|
|
if (cell)
|
|
{
|
|
cell->setText(text);
|
|
updateSort();
|
|
}
|
|
}
|
|
|
|
//gtk_combo_box_set_model(GTK_COMBO_BOX(widget), model);
|
|
}
|
|
|
|
void gComboBox::clear()
|
|
{
|
|
lock();
|
|
tree->clear();
|
|
unlock();
|
|
}
|
|
|
|
int gComboBox::find(const char *text)
|
|
{
|
|
int i;
|
|
const char *it;
|
|
|
|
if (!text)
|
|
text = "";
|
|
|
|
for (i = 0; i < count(); i++)
|
|
{
|
|
it = itemText(i);
|
|
if (!it)
|
|
it = "";
|
|
if (!strcmp(it, text))
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void gComboBox::remove(int pos)
|
|
{
|
|
updateModel();
|
|
tree->removeRow(indexToKey(pos));
|
|
updateSort();
|
|
}
|
|
|
|
/*void gComboBox::resize(int w, int h)
|
|
{
|
|
gControl::resize(w,h);
|
|
}*/
|
|
|
|
void gComboBox::updateFont()
|
|
{
|
|
gControl::updateFont();
|
|
if (cell)
|
|
g_object_set(G_OBJECT(cell), "font-desc", font()->desc(), (void *)NULL);
|
|
#ifndef GTK3
|
|
else
|
|
gtk_widget_modify_font(entry, font()->desc());
|
|
#endif
|
|
}
|
|
|
|
void gComboBox::setFocus()
|
|
{
|
|
if (entry && !proxy() && window()->isVisible())
|
|
{
|
|
gtk_editable_set_editable(GTK_EDITABLE(entry), false);
|
|
gtk_widget_grab_focus(entry);
|
|
gtk_editable_set_editable(GTK_EDITABLE(entry), true);
|
|
}
|
|
else
|
|
gControl::setFocus();
|
|
}
|
|
|
|
int gComboBox::minimumHeight()
|
|
{
|
|
int h;
|
|
#ifdef GTK3
|
|
gtk_widget_get_preferred_height(widget, &h, NULL);
|
|
#else
|
|
GtkRequisition req;
|
|
|
|
gtk_widget_size_request(widget, &req);
|
|
h = req.height;
|
|
#endif
|
|
|
|
if (entry)
|
|
return h - 4;
|
|
else
|
|
return h;
|
|
}
|
|
|
|
|
|
bool gComboBox::isReadOnly() const
|
|
{
|
|
return entry == NULL;
|
|
}
|
|
|
|
|
|
static gboolean button_focus_in(GtkWidget *widget, GdkEventFocus *event, gComboBox *control)
|
|
{
|
|
if (control->isReadOnly())
|
|
return gcb_focus_in(widget, event, control);
|
|
|
|
control->setFocus();
|
|
return false;
|
|
}
|
|
|
|
static gboolean button_focus_out(GtkWidget *widget, GdkEventFocus *event, gComboBox *control)
|
|
{
|
|
if (control->isReadOnly())
|
|
return gcb_focus_out(widget, event, control);
|
|
|
|
return false;
|
|
}
|
|
|
|
void gComboBox::updateFocusHandler()
|
|
{
|
|
GtkWidget *button = find_button(widget);
|
|
|
|
if (button == _button)
|
|
return;
|
|
|
|
_button = button;
|
|
//g_signal_connect(G_OBJECT(button), "key-press-event", G_CALLBACK(gcb_keypress), (gpointer)this);
|
|
//g_signal_connect(G_OBJECT(button), "key-release-event", G_CALLBACK(gcb_keyrelease), (gpointer)this);
|
|
g_signal_connect(G_OBJECT(button), "focus-in-event", G_CALLBACK(button_focus_in), (gpointer)this);
|
|
g_signal_connect(G_OBJECT(button), "focus-out-event", G_CALLBACK(button_focus_out), (gpointer)this);
|
|
}
|
|
|
|
void gComboBox::setBorder(bool v)
|
|
{
|
|
if (_has_border == v)
|
|
return;
|
|
|
|
_has_border = v;
|
|
updateBorder();
|
|
}
|
|
|
|
void gComboBox::updateBorder()
|
|
{
|
|
#ifdef GTK3
|
|
updateStyleSheet(true);
|
|
#else
|
|
g_object_set(G_OBJECT(widget), "has-frame", _has_border, NULL);
|
|
#endif
|
|
}
|
|
|
|
bool gComboBox::canFocus() const
|
|
{
|
|
return !_design;
|
|
}
|
|
|
|
void gComboBox::setDesign(bool ignore)
|
|
{
|
|
gControl::setDesign(ignore);
|
|
if (entry)
|
|
gtk_widget_set_can_focus(entry, false);
|
|
}
|
|
|
|
static void cb_update_direction(GtkWidget *widget, gpointer data)
|
|
{
|
|
gtk_widget_set_direction(widget, (GtkTextDirection)(uintptr_t)data);
|
|
|
|
if (GTK_IS_CONTAINER(widget))
|
|
gtk_container_forall(GTK_CONTAINER(widget), cb_update_direction, data);
|
|
}
|
|
|
|
void gComboBox::updateDirection()
|
|
{
|
|
GtkTextDirection dir;
|
|
|
|
gControl::updateDirection();
|
|
|
|
dir = gtk_widget_get_direction(widget);
|
|
cb_update_direction(widget, (gpointer)(uintptr_t)dir);
|
|
}
|
|
|