1
#include "gtk_helpers.h"
2
#include "image_cache.h"
6
#include <gtkmm/image.h>
7
#include <gtkmm/filechooserdialog.h>
8
#include <gtkmm/stock.h>
9
#include <gtkmm/combobox.h>
10
#include <gtkmm/comboboxtext.h>
11
#include <gtkmm/comboboxentrytext.h>
12
#include <gtkmm/menu.h>
13
#include <gtkmm/eventbox.h>
14
#include <gtkmm/paned.h>
15
#include "text_list_columns_model.h"
17
#include "treemodel_wrapper.h"
19
// This list_model is used for all functions which operate on GTKListStore
20
static TextListColumnsModel _wb_list_model;
22
Glib::RefPtr<Gtk::ListStore> get_empty_model()
24
static Glib::RefPtr<Gtk::ListStore> empty_list_store;
25
if (!empty_list_store)
26
empty_list_store = Gtk::ListStore::create(_wb_list_model);
28
return empty_list_store;
31
//------------------------------------------------------------------------------
32
Gtk::HBox &create_icon_label(const std::string &icon, const std::string &text)
34
Gtk::HBox *hbox= Gtk::manage(new Gtk::HBox(false, 0));
36
Gtk::Image *image= Gtk::manage(new Gtk::Image(ImageCache::get_instance()->image_from_filename(icon)));
37
Gtk::Label *label= Gtk::manage(new Gtk::Label(text));
39
label->set_use_markup(true);
41
hbox->pack_start(*image);
42
hbox->pack_start(*label, true, true);
50
//------------------------------------------------------------------------------
51
Glib::RefPtr<Gtk::ListStore> model_from_string_list(const std::vector<std::string>& list, TextListColumnsModel* columns)
53
Glib::RefPtr<Gtk::ListStore> model = Gtk::ListStore::create(*columns);
55
std::vector<std::string>::const_iterator last = list.end();
57
for (std::vector<std::string>::const_iterator iter = list.begin(); iter != last; ++iter)
58
(*model->append())[columns->item] = *iter;
64
//------------------------------------------------------------------------------
65
Glib::RefPtr<Gtk::ListStore> model_from_string_list(const std::vector<std::string>& list, TextListColumnsModel** columns)
68
*columns = &_wb_list_model;
70
return model_from_string_list(list, &_wb_list_model);
74
//------------------------------------------------------------------------------
75
Glib::RefPtr<Gtk::ListStore> model_from_string_list(const std::list<std::string>& list, TextListColumnsModel** columns)
78
*columns = &_wb_list_model;
80
Glib::RefPtr<Gtk::ListStore> model = Gtk::ListStore::create(_wb_list_model);
82
std::list<std::string>::const_iterator last = list.end();
84
for (std::list<std::string>::const_iterator iter = list.begin(); iter != last; ++iter)
85
(*model->append())[_wb_list_model.item] = *iter;
91
//------------------------------------------------------------------------------
92
void recreate_model_from_string_list(Glib::RefPtr<Gtk::ListStore> model, const std::vector<std::string>& list)
96
std::vector<std::string>::const_iterator last = list.end();
98
for (std::vector<std::string>::const_iterator iter = list.begin(); iter != last; ++iter)
99
(*model->append())[_wb_list_model.item] = *iter;
103
//------------------------------------------------------------------------------
104
void setup_combo_for_string_list(Gtk::ComboBox *combo)
106
Gtk::CellRendererText *cell= Gtk::manage(new Gtk::CellRendererText());
107
combo->pack_end(*cell, true);
108
combo->add_attribute(*cell, "text", 0);
111
//------------------------------------------------------------------------------
112
std::string get_selected_combo_item(Gtk::ComboBox *combo)
114
Gtk::TreeIter iter= combo->get_active();
117
Gtk::TreeRow row= *iter;
118
std::string item= row[_wb_list_model.item];
125
//------------------------------------------------------------------------------
127
bool set_selected_combo_item(Gtk::ComboBox *combo, const std::string &value)
129
Glib::RefPtr<Gtk::TreeModel> store(combo->get_model());
131
for (Gtk::TreeIter end = store->children().end(), iter = store->children().begin();
134
Gtk::TreeRow row= *iter;
135
std::string item = row[_wb_list_model.item];
138
combo->set_active(iter);
145
//------------------------------------------------------------------------------
146
void set_glib_string(Glib::ValueBase& value, const std::string& str, bool escape_nuls)
148
GValue *gval = value.gobj();
150
g_value_init(gval, G_TYPE_STRING);
154
std::string::size_type p = 0, e;
155
std::string::size_type length = str.length();
156
// skip the \0 bytes so that data is displayed as in OSX
159
e = str.find('\0', p);
160
if (e == std::string::npos)
162
tmp.append(str.data()+p, e-p);
166
tmp.append(str.data()+p);
167
g_value_set_string(gval, tmp.c_str());
170
g_value_set_string(gval, str.c_str());
173
//------------------------------------------------------------------------------
174
void set_glib_int(Glib::ValueBase& value, const int i)
176
GValue *gval = value.gobj();
178
g_value_init(gval, G_TYPE_INT);
179
g_value_set_int(gval, i);
182
//------------------------------------------------------------------------------
183
void set_glib_bool(Glib::ValueBase& value, const bool b)
185
GValue *gval = value.gobj();
187
g_value_init(gval, G_TYPE_BOOLEAN);
188
g_value_set_boolean(gval, b);
191
//------------------------------------------------------------------------------
192
void set_glib_double(Glib::ValueBase& value, const double d)
194
GValue *gval = value.gobj();
196
g_value_init(gval, G_TYPE_DOUBLE);
197
g_value_set_double(gval, d);
200
//------------------------------------------------------------------------------
201
void fill_combo_from_string_list(Gtk::ComboBox* combo, const std::vector<std::string>& list)
203
std::vector<std::string>::const_iterator it = list.begin();
204
std::vector<std::string>::const_iterator last = list.end();
206
Glib::RefPtr<Gtk::ListStore> store(Glib::RefPtr<Gtk::ListStore>::cast_dynamic(combo->get_model()));
209
store = get_empty_model();
210
combo->set_model(store);
215
for (; last != it; ++it )
217
Gtk::TreeIter iter = store->append();
218
Gtk::TreeRow row= *iter;
219
row.set_value(0, *it);
223
//------------------------------------------------------------------------------
224
void fill_combo_from_string_list(Gtk::ComboBoxEntryText* combo, const std::vector<std::string>& list)
226
std::vector<std::string>::const_iterator it = list.begin();
227
std::vector<std::string>::const_iterator last = list.end();
229
for (; last != it; ++it )
230
combo->append_text(*it);
233
//------------------------------------------------------------------------------
234
static std::string file_chooser_impl(const bool is_for_save, const std::string &filter)
236
std::string filename;
237
Gtk::FileChooserDialog dialog("Please choose a file",
238
is_for_save ? Gtk::FILE_CHOOSER_ACTION_SAVE : Gtk::FILE_CHOOSER_ACTION_OPEN);
239
dialog.set_transient_for(*get_mainwindow());
241
//Add response buttons the the dialog:
242
dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
243
dialog.add_button(is_for_save ? Gtk::Stock::SAVE : Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
247
Gtk::FileFilter filter_any;
248
//filter_any.set_name("Any files");
249
filter_any.add_pattern(filter);
250
dialog.add_filter(filter_any);
252
const int result = dialog.run();
256
case(Gtk::RESPONSE_OK):
258
filename = dialog.get_filename();
268
//------------------------------------------------------------------------------
269
std::string open_file_chooser(const std::string &filter)
271
return file_chooser_impl(false, filter); // false - is not for save
274
std::string save_file_chooser(const std::string &filter)
276
return file_chooser_impl(true, filter); // true - is for save
279
//------------------------------------------------------------------------------
280
static void expand_node(bec::TreeModel* tm, const bec::NodeId& node, Gtk::TreeView* tv)
282
// Expand the node itself if needed
283
if (tm->is_expandable(node))
285
if (tm->is_expanded(node))
287
const int node_depth = node.depth();
288
Gtk::TreeModel::Path path;
290
for (int i = 0; i < node_depth; ++i)
291
path.push_back(node[i]);
293
tv->expand_row(path, true);
296
// Apply the same thing for all node's children
297
const int children_count = tm->count_children(node);
298
if ( children_count > 0 )
300
for (int i = 0; i < children_count; ++i)
302
bec::NodeId child = tm->get_child(node, i);
303
expand_node(tm, child, tv);
309
//------------------------------------------------------------------------------
310
void expand_tree_nodes_as_in_be(const Glib::RefPtr<TreeModelWrapper> &model, Gtk::TreeView *tv)
312
model->block_expand_collapse_signals();
313
//TODO: This vv will work once grt_value_tree.h will have correct support for storing expanded/collapsed states
314
//bec::TreeModel *tm = static_cast<bec::TreeModel*>(model->get_be_model());
315
//expand_node(tm, tm->get_root(), tv);
317
// The code below is a workaround while we do not have working support for store/retrive expanded state of the node
318
ExpandedRowsStorage* rows = model->expanded_rows_storage();
319
// As: The insert members shall not affect the validity of iterators and references
320
// to the container, and the erase members shall invalidate only iterators and
321
// references to the erased elements. We need to have temp vector of values of invalid rows
322
std::vector<ExpandedRowsStorage::key_type> invalid_rows;
325
ExpandedRowsStorage::const_iterator row = rows->begin();
326
const ExpandedRowsStorage::const_iterator last = rows->end();
328
for (; last != row; ++row)
330
if (!tv->expand_row(Gtk::TreeModel::Path(*row), false))
331
invalid_rows.push_back(*row);
334
std::vector<ExpandedRowsStorage::key_type>::const_iterator i_row = invalid_rows.begin();
335
std::vector<ExpandedRowsStorage::key_type>::const_iterator i_last = invalid_rows.end();
336
for(; i_last != i_row; ++i_row)
339
model->unblock_expand_collapse_signals();
342
//------------------------------------------------------------------------------
343
//std::string run_string_dialog(const std::string& title, const std::string& init_value)
347
// entry.set_text(init_value);
349
// dlg.add_action_widget(entry, 0xff);
350
// dlg.set_title(title);
351
// dlg.set_position(Gtk::WIN_POS_MOUSE);
352
// dlg.set_transient_for(*get_mainwindow());
353
// const int result = dlg.run();
355
// std::string ret = init_value;
358
// case 0xff: // for the magic number 0xff see above add_action_widget
359
// ret = entry.get_text();
368
static void populate_popup_menu(const bec::MenuItemList &items, const int time,
369
const sigc::slot<void, std::string> &activate_slot, Gtk::Menu *popup)
371
popup->foreach(sigc::mem_fun(popup, &Gtk::Container::remove));
373
bec::MenuItemList::const_iterator cur_item = items.begin();
374
const bec::MenuItemList::const_iterator last_item = items.end();
376
for ( ; last_item != cur_item; cur_item++ )
378
Gtk::MenuItem *item = Gtk::manage(new Gtk::MenuItem(bec::replace_string(cur_item->caption, "_", "__"), true));
379
item->set_name(cur_item->name);
380
item->set_sensitive(cur_item->enabled);
381
// not support in Gtk from Ubuntu 8.04
382
//item->set_use_underline(false);
384
//g_message("run_popup: %s", cur_item->caption.c_str());
386
switch ( cur_item->type )
388
case bec::MenuAction:
389
case bec::MenuUnavailable:
392
item->signal_activate().connect(sigc::bind(activate_slot, cur_item->name));
395
case bec::MenuCascade:
397
Gtk::Menu *submenu= Gtk::manage(new Gtk::Menu());
398
item->set_submenu(*submenu);
399
populate_popup_menu(cur_item->subitems, time, activate_slot, submenu);
404
//g_message("%s: fake impl of menuradioitem", __FUNCTION__);
408
Gtk::CheckMenuItem* citem = Gtk::manage(new Gtk::CheckMenuItem(cur_item->caption, true));
410
citem->set_active(cur_item->checked);
411
citem->signal_activate().connect(sigc::bind(activate_slot, cur_item->name));
414
case bec::MenuSeparator:
417
item = Gtk::manage(new Gtk::SeparatorMenuItem());
422
g_message("%s: WARNING! unhandled menuitem type %i, '%s'", __FUNCTION__, cur_item->type, cur_item->name.c_str());
427
popup->append(*item);
435
void run_popup_menu(const bec::MenuItemList &items, const int time,
436
const sigc::slot<void, std::string> &activate_slot, Gtk::Menu *popup)
438
populate_popup_menu(items, time, activate_slot, popup);
440
popup->popup(3, time);
443
//--------------------------------------------------------------------------------
445
Gtk::Widget *create_closeable_tab(const Glib::ustring &title,
446
const sigc::slot<void> &close_callback,
447
Gtk::Label **title_label)
449
Gtk::HBox *hbox= Gtk::manage(new Gtk::HBox(false, 1));
450
Gtk::Label *label= Gtk::manage(new Gtk::Label("\342\234\225"));
451
Gtk::EventBox *evbox= Gtk::manage(new Gtk::EventBox());
452
Gtk::Label *text_label= Gtk::manage(new Gtk::Label(title));
456
hbox->pack_start(*text_label);
457
hbox->pack_start(*evbox);
462
*title_label = text_label;
468
//--------------------------------------------------------------------------------
470
void swap_panned_children(Gtk::Paned *paned, bool fixed_size_1)
472
Gtk::Widget *w1 = paned->get_child1();
473
Gtk::Widget *w2 = paned->get_child2();
481
paned->pack1(*w2, true, fixed_size_1);
482
paned->pack2(*w1, true, !fixed_size_1);
488
//--------------------------------------------------------------------------------
491
static bool disallow_select(const Glib::RefPtr<Gtk::TreeModel> &model, const Gtk::TreeModel::Path &path, bool selected)
496
static bool allow_select(const Glib::RefPtr<Gtk::TreeModel> &model, const Gtk::TreeModel::Path &path, bool selected)
501
static void handle_button_press(GdkEventButton *event, Gtk::TreeView *tree)
503
Gtk::TreeModel::Path path;
504
Gtk::TreeViewColumn *column;
507
if (tree->get_path_at_pos(event->x, event->y, path, column, cx, cy))
509
if (tree->get_selection()->is_selected(path) && (event->state & 0xff) == 0)
511
tree->get_selection()->set_select_function(sigc::ptr_fun(disallow_select));
517
static void handle_button_release(GdkEventButton *event, Gtk::TreeView *tree)
519
tree->get_selection()->set_select_function(sigc::ptr_fun(allow_select));
523
void fix_broken_gtk_selection_handling(Gtk::TreeView *tree)
525
tree->signal_button_press_event().connect_notify(sigc::bind(sigc::ptr_fun(handle_button_press), tree));
526
tree->signal_button_release_event().connect_notify(sigc::bind(sigc::ptr_fun(handle_button_release), tree));
529
//------------------------------------------------------------------------------
530
void gtk_paned_set_pos_ratio(Gtk::Paned* paned, const float ratio)
532
const int min_pos = paned->property_min_position();
533
const int max_pos = paned->property_max_position();
534
const int diff = (max_pos - min_pos) * ratio;
536
paned->set_position(max_pos);
538
paned->set_position(min_pos + diff);
541
//------------------------------------------------------------------------------
542
float gtk_paned_get_pos_ratio(Gtk::Paned* paned)
544
const float min_pos = paned->property_min_position();
545
const float max_pos = paned->property_max_position();
547
return (paned->get_position() - min_pos) / (max_pos - min_pos);