1 /*
2 * A subclass of GtkAction that wraps a GtkComboBoxEntry.
3 * Features:
4 * Setting GtkEntryBox width in characters.
5 * Passing a function for formatting cells.
6 * Displaying a warning if text isn't in list.
7 * Setting names for GtkComboBoxEntry and GtkEntry (actionName_combobox, actionName_entry)
8 * to allow setting resources.
9 *
10 * Author(s):
11 * Tavmjong Bah
12 * Jon A. Cruz <jon@joncruz.org>
13 *
14 * Copyright (C) 2010 Authors
15 *
16 * Released under GNU GPL, read the file 'COPYING' for more information
17 */
19 /*
20 * We must provide for both a toolbar item and a menu item.
21 * As we don't know which widgets are used (or even constructed),
22 * we must keep track of things like active entry ourselves.
23 */
25 #include <iostream>
26 #include <string.h>
28 #include <gtk/gtk.h>
29 #include <gtk/gtktoolitem.h>
30 #include <gtk/gtkcomboboxentry.h>
31 #include <gtk/gtkentrycompletion.h>
33 #include "ink-comboboxentry-action.h"
35 // Must handle both tool and menu items!
36 static GtkWidget* create_tool_item( GtkAction* action );
37 static GtkWidget* create_menu_item( GtkAction* action );
39 // Internal
40 static gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text );
42 // Callbacks
43 static void combo_box_changed_cb( GtkComboBoxEntry* widget, gpointer data );
44 static void entry_activate_cb( GtkEntry* widget, gpointer data );
45 static gboolean match_selected_cb( GtkEntryCompletion* widget, GtkTreeModel* model, GtkTreeIter* iter, gpointer data );
47 enum {
48 PROP_MODEL = 1,
49 PROP_COMBOBOX,
50 PROP_ENTRY,
51 PROP_ENTRY_WIDTH,
52 PROP_EXTRA_WIDTH,
53 PROP_CELL_DATA_FUNC,
54 PROP_POPUP
55 };
57 enum {
58 CHANGED = 0,
59 ACTIVATED,
60 N_SIGNALS
61 };
62 static guint signals[N_SIGNALS] = {0};
64 static GtkActionClass *ink_comboboxentry_action_parent_class = NULL;
65 static GQuark gDataName = 0;
67 static void ink_comboboxentry_action_finalize (GObject *object)
68 {
69 // Free any allocated resources.
71 G_OBJECT_CLASS (ink_comboboxentry_action_parent_class)->finalize (object);
72 }
75 static void ink_comboboxentry_action_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
76 {
77 Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION (object);
79 switch(property_id) {
81 case PROP_MODEL:
82 action->model = GTK_TREE_MODEL( g_value_get_object( value ));
83 break;
85 case PROP_COMBOBOX:
86 action->combobox = GTK_COMBO_BOX_ENTRY( g_value_get_object( value ));
87 break;
89 case PROP_ENTRY:
90 action->entry = GTK_ENTRY( g_value_get_object( value ));
91 break;
93 case PROP_ENTRY_WIDTH:
94 action->entry_width = g_value_get_int( value );
95 break;
97 case PROP_EXTRA_WIDTH:
98 action->extra_width = g_value_get_int( value );
99 break;
101 case PROP_CELL_DATA_FUNC:
102 action->cell_data_func = g_value_get_pointer( value );
103 break;
105 case PROP_POPUP:
106 action->popup = g_value_get_boolean( value );
107 break;
109 default:
110 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
111 }
112 }
115 static void ink_comboboxentry_action_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
116 {
117 Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION (object);
119 switch(property_id) {
121 case PROP_MODEL:
122 g_value_set_object (value, action->model);
123 break;
125 case PROP_COMBOBOX:
126 g_value_set_object (value, action->combobox);
127 break;
129 case PROP_ENTRY:
130 g_value_set_object (value, action->entry);
131 break;
133 case PROP_ENTRY_WIDTH:
134 g_value_set_int (value, action->entry_width);
135 break;
137 case PROP_EXTRA_WIDTH:
138 g_value_set_int (value, action->extra_width);
139 break;
141 case PROP_CELL_DATA_FUNC:
142 g_value_set_pointer (value, action->cell_data_func);
143 break;
145 case PROP_POPUP:
146 g_value_set_boolean (value, action->popup);
147 break;
149 default:
150 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
151 }
152 }
154 static void
155 ink_comboboxentry_action_connect_proxy (GtkAction *action,
156 GtkWidget *proxy)
157 {
158 /* Override any proxy properties. */
159 // if (GTK_IS_MENU_ITEM (proxy)) {
160 // }
162 GTK_ACTION_CLASS (ink_comboboxentry_action_parent_class)->connect_proxy (action, proxy);
163 }
166 static void ink_comboboxentry_action_class_init (Ink_ComboBoxEntry_ActionClass *klass)
167 {
169 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
170 GtkActionClass *gtkaction_class = GTK_ACTION_CLASS (klass);
172 gtkaction_class->connect_proxy = ink_comboboxentry_action_connect_proxy;
174 gobject_class->finalize = ink_comboboxentry_action_finalize;
175 gobject_class->set_property = ink_comboboxentry_action_set_property;
176 gobject_class->get_property = ink_comboboxentry_action_get_property;
178 gDataName = g_quark_from_string("ink_comboboxentry-action");
180 klass->parent_class.create_tool_item = create_tool_item;
181 klass->parent_class.create_menu_item = create_menu_item;
183 ink_comboboxentry_action_parent_class = GTK_ACTION_CLASS(g_type_class_peek_parent (klass) );
185 g_object_class_install_property (
186 gobject_class,
187 PROP_MODEL,
188 g_param_spec_object ("model",
189 "Tree Model",
190 "Tree Model",
191 GTK_TYPE_TREE_MODEL,
192 (GParamFlags)G_PARAM_READWRITE));
193 g_object_class_install_property (
194 gobject_class,
195 PROP_COMBOBOX,
196 g_param_spec_object ("combobox",
197 "GtkComboBoxEntry",
198 "GtkComboBoxEntry",
199 GTK_TYPE_WIDGET,
200 (GParamFlags)G_PARAM_READABLE));
201 g_object_class_install_property (
202 gobject_class,
203 PROP_ENTRY,
204 g_param_spec_object ("entry",
205 "GtkEntry",
206 "GtkEntry",
207 GTK_TYPE_WIDGET,
208 (GParamFlags)G_PARAM_READABLE));
209 g_object_class_install_property (
210 gobject_class,
211 PROP_ENTRY_WIDTH,
212 g_param_spec_int ("entry_width",
213 "EntryBox width",
214 "EntryBox width (characters)",
215 -1.0, 100, -1.0,
216 (GParamFlags)G_PARAM_READWRITE));
218 g_object_class_install_property (
219 gobject_class,
220 PROP_EXTRA_WIDTH,
221 g_param_spec_int ("extra_width",
222 "Extra width",
223 "Extra width (px)",
224 -1.0, 500, -1.0,
225 (GParamFlags)G_PARAM_READWRITE));
227 g_object_class_install_property (
228 gobject_class,
229 PROP_CELL_DATA_FUNC,
230 g_param_spec_pointer ("cell_data_func",
231 "Cell Data Func",
232 "Cell Deta Function",
233 (GParamFlags)G_PARAM_READWRITE));
235 g_object_class_install_property (
236 gobject_class,
237 PROP_POPUP,
238 g_param_spec_boolean ("popup",
239 "Entry Popup",
240 "Entry Popup",
241 false,
242 (GParamFlags)G_PARAM_READWRITE));
244 // We need to know when GtkComboBoxEvent or Menu ready for reading
245 signals[CHANGED] = g_signal_new( "changed",
246 G_TYPE_FROM_CLASS(klass),
247 G_SIGNAL_RUN_FIRST,
248 G_STRUCT_OFFSET(Ink_ComboBoxEntry_ActionClass, changed),
249 NULL, NULL,
250 g_cclosure_marshal_VOID__VOID,
251 G_TYPE_NONE, 0);
253 // Probably not needed... originally to keep track of key-presses.
254 signals[ACTIVATED] = g_signal_new( "activated",
255 G_TYPE_FROM_CLASS(klass),
256 G_SIGNAL_RUN_FIRST,
257 G_STRUCT_OFFSET(Ink_ComboBoxEntry_ActionClass, activated),
258 NULL, NULL,
259 g_cclosure_marshal_VOID__VOID,
260 G_TYPE_NONE, 0);
262 }
264 static void ink_comboboxentry_action_init (Ink_ComboBoxEntry_Action *action)
265 {
266 action->active = -1;
267 action->text = NULL;
268 action->entry_completion = NULL;
269 #if !GTK_CHECK_VERSION(2,16,0)
270 action->indicator = NULL;
271 #endif
272 action->popup = false;
273 action->warning = NULL;
274 action->altx_name = NULL;
275 }
277 GType ink_comboboxentry_action_get_type ()
278 {
279 static GType ink_comboboxentry_action_type = 0;
281 if (!ink_comboboxentry_action_type) {
282 static const GTypeInfo ink_comboboxentry_action_info = {
283 sizeof(Ink_ComboBoxEntry_ActionClass),
284 NULL, /* base_init */
285 NULL, /* base_finalize */
286 (GClassInitFunc) ink_comboboxentry_action_class_init,
287 NULL, /* class_finalize */
288 NULL, /* class_data */
289 sizeof(Ink_ComboBoxEntry_Action),
290 0, /* n_preallocs */
291 (GInstanceInitFunc)ink_comboboxentry_action_init, /* instance_init */
292 NULL /* value_table */
293 };
295 ink_comboboxentry_action_type = g_type_register_static (GTK_TYPE_ACTION,
296 "Ink_ComboBoxEntry_Action",
297 &ink_comboboxentry_action_info,
298 (GTypeFlags)0 );
299 }
301 return ink_comboboxentry_action_type;
302 }
305 Ink_ComboBoxEntry_Action *ink_comboboxentry_action_new (const gchar *name,
306 const gchar *label,
307 const gchar *tooltip,
308 const gchar *stock_id,
309 GtkTreeModel *model,
310 gint entry_width,
311 gint extra_width,
312 void *cell_data_func )
313 {
314 g_return_val_if_fail (name != NULL, NULL);
316 return (Ink_ComboBoxEntry_Action*)g_object_new (INK_COMBOBOXENTRY_TYPE_ACTION,
317 "name", name,
318 "label", label,
319 "tooltip", tooltip,
320 "stock-id", stock_id,
321 "model", model,
322 "entry_width", entry_width,
323 "extra_width", extra_width,
324 "cell_data_func", cell_data_func,
325 NULL);
326 }
328 // Create a widget for a toolbar.
329 GtkWidget* create_tool_item( GtkAction* action )
330 {
331 GtkWidget* item = 0;
333 if ( INK_COMBOBOXENTRY_IS_ACTION( action ) && INK_COMBOBOXENTRY_ACTION(action)->model ) {
335 Ink_ComboBoxEntry_Action* ink_comboboxentry_action = INK_COMBOBOXENTRY_ACTION( action );
337 gchar *action_name = g_strdup( gtk_action_get_name( action ) );
338 gchar *combobox_name = g_strjoin( NULL, action_name, "_combobox", NULL );
339 gchar *entry_name = g_strjoin( NULL, action_name, "_entry", NULL );
340 g_free( action_name );
342 item = GTK_WIDGET( gtk_tool_item_new() );
344 GtkWidget* comboBoxEntry = gtk_combo_box_entry_new_with_model( ink_comboboxentry_action->model, 0 );
345 // Name it so we can muck with it using an RC file
346 gtk_widget_set_name( comboBoxEntry, combobox_name );
347 g_free( combobox_name );
349 {
350 GtkWidget *align = gtk_alignment_new(0, 0.5, 0, 0);
351 #if GTK_CHECK_VERSION(2,16,0)
352 gtk_container_add( GTK_CONTAINER(align), comboBoxEntry );
353 #else // GTK_CHECK_VERSION(2,16,0)
354 GtkWidget *hbox = gtk_hbox_new( FALSE, 0 );
355 ink_comboboxentry_action->indicator = gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
356 gtk_box_pack_start( GTK_BOX(hbox), comboBoxEntry, TRUE, TRUE, 0 );
357 gtk_box_pack_start( GTK_BOX(hbox), ink_comboboxentry_action->indicator, FALSE, FALSE, 0 );
358 gtk_container_add( GTK_CONTAINER(align), hbox );
359 #endif // GTK_CHECK_VERSION(2,16,0)
360 gtk_container_add( GTK_CONTAINER(item), align );
361 }
363 ink_comboboxentry_action->combobox = GTK_COMBO_BOX_ENTRY(comboBoxEntry);
365 gtk_combo_box_set_active( GTK_COMBO_BOX( comboBoxEntry ), ink_comboboxentry_action->active );
367 g_signal_connect( G_OBJECT(comboBoxEntry), "changed", G_CALLBACK(combo_box_changed_cb), action );
369 // Optionally add formatting...
370 if( ink_comboboxentry_action->cell_data_func != NULL ) {
371 GtkCellRenderer *cell = gtk_cell_renderer_text_new();
372 gtk_cell_layout_clear( GTK_CELL_LAYOUT( comboBoxEntry ) );
373 gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( comboBoxEntry ), cell, true );
374 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT( comboBoxEntry ), cell,
375 GtkCellLayoutDataFunc (ink_comboboxentry_action->cell_data_func),
376 NULL, NULL );
377 }
379 // Optionally widen the combobox width... which widens the drop-down list in list mode.
380 if( ink_comboboxentry_action->extra_width > 0 ) {
381 GtkRequisition req;
382 gtk_widget_size_request( GTK_WIDGET( ink_comboboxentry_action->combobox ), &req );
383 gtk_widget_set_size_request( GTK_WIDGET( ink_comboboxentry_action->combobox ),
384 req.width + ink_comboboxentry_action->extra_width, -1 );
385 }
387 // Get reference to GtkEntry and fiddle a bit with it.
388 GtkWidget *child = gtk_bin_get_child( GTK_BIN(comboBoxEntry) );
390 // Name it so we can muck with it using an RC file
391 gtk_widget_set_name( child, entry_name );
392 g_free( entry_name );
394 if( child && GTK_IS_ENTRY( child ) ) {
396 ink_comboboxentry_action->entry = GTK_ENTRY(child);
398 // Change width
399 if( ink_comboboxentry_action->entry_width > 0 ) {
400 gtk_entry_set_width_chars (GTK_ENTRY (child), ink_comboboxentry_action->entry_width );
401 }
403 // Add pop-up entry completion if required
404 if( ink_comboboxentry_action->popup ) {
405 ink_comboboxentry_action_popup_enable( ink_comboboxentry_action );
406 }
408 // Add altx_name if required
409 if( ink_comboboxentry_action->altx_name ) {
410 g_object_set_data( G_OBJECT( child ), ink_comboboxentry_action->altx_name, ink_comboboxentry_action->entry );
411 }
413 // Add signal for GtkEntry to check if finished typing.
414 g_signal_connect( G_OBJECT(child), "activate", G_CALLBACK(entry_activate_cb), action );
416 }
418 #if GTK_CHECK_VERSION(2,16,0)
419 gtk_action_connect_proxy( GTK_ACTION( action ), item );
420 #endif
422 gtk_widget_show_all( item );
424 } else {
426 item = ink_comboboxentry_action_parent_class->create_tool_item( action );
428 }
430 return item;
431 }
433 // Create a drop-down menu.
434 GtkWidget* create_menu_item( GtkAction* action )
435 {
436 GtkWidget* item = 0;
438 item = ink_comboboxentry_action_parent_class->create_menu_item( action );
439 g_warning( "ink_comboboxentry_action: create_menu_item not implemented" );
440 // One can easily modify ege-select-one-action routine to implement this.
441 return item;
442 }
444 // Setters/Getters ---------------------------------------------------
446 GtkTreeModel *ink_comboboxentry_action_get_model( Ink_ComboBoxEntry_Action* action ) {
448 return action->model;
449 }
451 GtkComboBoxEntry *ink_comboboxentry_action_get_comboboxentry( Ink_ComboBoxEntry_Action* action ) {
453 return action->combobox;
454 }
456 gchar* ink_comboboxentry_action_get_active_text( Ink_ComboBoxEntry_Action* action ) {
458 gchar* text = g_strdup( action->text );
459 return text;
460 }
462 gboolean ink_comboboxentry_action_set_active_text( Ink_ComboBoxEntry_Action* ink_comboboxentry_action, const gchar* text ) {
464 g_free( ink_comboboxentry_action->text );
465 ink_comboboxentry_action->text = g_strdup( text );
467 // Get active row or -1 if none
468 ink_comboboxentry_action->active = get_active_row_from_text( ink_comboboxentry_action, ink_comboboxentry_action->text );
470 // Set active row, check that combobox has been created.
471 if( ink_comboboxentry_action->combobox ) {
472 gtk_combo_box_set_active( GTK_COMBO_BOX( ink_comboboxentry_action->combobox ), ink_comboboxentry_action->active );
473 }
475 // Fiddle with entry
476 if( ink_comboboxentry_action->entry ) {
478 // Explicitly set text in GtkEntry box (won't be set if text not in list).
479 gtk_entry_set_text( ink_comboboxentry_action->entry, text );
481 // Show or hide warning
482 if( ink_comboboxentry_action->active == -1 && ink_comboboxentry_action->warning != NULL ) {
483 #if GTK_CHECK_VERSION(2,16,0)
484 {
485 GtkStockItem item;
486 gboolean isStock = gtk_stock_lookup( GTK_STOCK_DIALOG_WARNING, &item );
487 if (isStock) {
488 gtk_entry_set_icon_from_stock( ink_comboboxentry_action->entry,
489 GTK_ENTRY_ICON_SECONDARY,
490 GTK_STOCK_DIALOG_WARNING );
491 } else {
492 gtk_entry_set_icon_from_icon_name( ink_comboboxentry_action->entry,
493 GTK_ENTRY_ICON_SECONDARY,
494 GTK_STOCK_DIALOG_WARNING );
495 }
496 }
497 // Can't add tooltip until icon set
498 gtk_entry_set_icon_tooltip_text( ink_comboboxentry_action->entry,
499 GTK_ENTRY_ICON_SECONDARY,
500 ink_comboboxentry_action->warning );
501 #else // GTK_CHECK_VERSION(2,16,0)
502 gtk_image_set_from_stock( GTK_IMAGE(ink_comboboxentry_action->indicator), GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
503 gtk_widget_set_tooltip_text( ink_comboboxentry_action->indicator, ink_comboboxentry_action->warning );
504 #endif // GTK_CHECK_VERSION(2,16,0)
505 } else {
506 #if GTK_CHECK_VERSION(2,16,0)
507 gtk_entry_set_icon_from_icon_name( GTK_ENTRY(ink_comboboxentry_action->entry),
508 GTK_ENTRY_ICON_SECONDARY,
509 NULL );
510 gtk_entry_set_icon_from_stock( GTK_ENTRY(ink_comboboxentry_action->entry),
511 GTK_ENTRY_ICON_SECONDARY,
512 NULL );
513 #else // GTK_CHECK_VERSION(2,16,0)
514 gtk_image_set_from_stock( GTK_IMAGE(ink_comboboxentry_action->indicator), NULL, GTK_ICON_SIZE_SMALL_TOOLBAR);
515 gtk_widget_set_tooltip_text( ink_comboboxentry_action->indicator, NULL );
516 #endif // GTK_CHECK_VERSION(2,16,0)
517 }
518 }
520 // Return if active text in list
521 gboolean found = ( ink_comboboxentry_action->active != -1 );
522 return found;
523 }
525 void ink_comboboxentry_action_set_entry_width( Ink_ComboBoxEntry_Action* action, gint entry_width ) {
527 action->entry_width = entry_width;
529 // Widget may not have been created....
530 if( action->entry ) {
531 gtk_entry_set_width_chars( GTK_ENTRY(action->entry), entry_width );
532 }
533 }
535 void ink_comboboxentry_action_set_extra_width( Ink_ComboBoxEntry_Action* action, gint extra_width ) {
537 action->extra_width = extra_width;
539 // Widget may not have been created....
540 if( action->combobox ) {
541 GtkRequisition req;
542 gtk_widget_size_request( GTK_WIDGET( action->combobox ), &req );
543 gtk_widget_set_size_request( GTK_WIDGET( action->combobox ), req.width + action->extra_width, -1 );
544 }
545 }
547 void ink_comboboxentry_action_popup_enable( Ink_ComboBoxEntry_Action* action ) {
549 action->popup = true;
551 // Widget may not have been created....
552 if( action->entry ) {
554 // Check we don't already have a GtkEntryCompletion
555 if( action->entry_completion ) return;
557 action->entry_completion = gtk_entry_completion_new();
559 gtk_entry_set_completion( action->entry, action->entry_completion );
560 gtk_entry_completion_set_model( action->entry_completion, action->model );
561 gtk_entry_completion_set_text_column( action->entry_completion, 0 );
562 gtk_entry_completion_set_popup_completion( action->entry_completion, true );
563 gtk_entry_completion_set_inline_completion( action->entry_completion, false );
564 gtk_entry_completion_set_inline_selection( action->entry_completion, true );
566 g_signal_connect (G_OBJECT (action->entry_completion), "match-selected", G_CALLBACK (match_selected_cb), action );
568 }
569 }
571 void ink_comboboxentry_action_popup_disable( Ink_ComboBoxEntry_Action* action ) {
573 action->popup = false;
575 if( action->entry_completion ) {
576 gtk_object_destroy( GTK_OBJECT( action->entry_completion ) );
577 action->entry_completion = 0;
578 }
579 }
581 void ink_comboboxentry_action_set_warning( Ink_ComboBoxEntry_Action* action, const gchar* warning ) {
583 g_free( action->warning );
584 action->warning = g_strdup( warning );
586 // Widget may not have been created....
587 if( action->entry ) {
588 #if GTK_CHECK_VERSION(2,16,0)
589 gtk_entry_set_icon_tooltip_text( GTK_ENTRY(action->entry),
590 GTK_ENTRY_ICON_SECONDARY,
591 action->warning );
592 #else // GTK_CHECK_VERSION(2,16,0)
593 gtk_image_set_from_stock( GTK_IMAGE(action->indicator), action->warning ? GTK_STOCK_DIALOG_WARNING : 0, GTK_ICON_SIZE_SMALL_TOOLBAR );
594 #endif // GTK_CHECK_VERSION(2,16,0)
595 }
596 }
598 void ink_comboboxentry_action_set_altx_name( Ink_ComboBoxEntry_Action* action, const gchar* altx_name ) {
600 g_free( action->altx_name );
601 action->altx_name = g_strdup( altx_name );
603 // Widget may not have been created....
604 if( action->entry ) {
605 g_object_set_data( G_OBJECT(action->entry), action->altx_name, action->entry );
606 }
607 }
609 // Internal ---------------------------------------------------
611 // Return row of active text or -1 if not found.
612 gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text ) {
614 // Check if text in list
615 gint row = 0;
616 gboolean found = false;
617 GtkTreeIter iter;
618 gboolean valid = gtk_tree_model_get_iter_first( action->model, &iter );
619 while ( valid ) {
621 // Get text from list entry
622 gchar* text = 0;
623 gtk_tree_model_get( action->model, &iter, 0, &text, -1 ); // Column 0
625 // Check for match
626 if( strcmp( target_text, text ) == 0 ){
627 found = true;
628 break;
629 }
630 ++row;
631 valid = gtk_tree_model_iter_next( action->model, &iter );
632 }
634 if( !found ) row = -1;
636 return row;
638 }
641 // Callbacks ---------------------------------------------------
643 static void combo_box_changed_cb( GtkComboBoxEntry* widget, gpointer data ) {
645 // Two things can happen to get here:
646 // An item is selected in the drop-down menu.
647 // Text is typed.
648 // We only react here if an item is selected.
650 // Get action
651 Ink_ComboBoxEntry_Action *act = INK_COMBOBOXENTRY_ACTION( data );
653 // Check if item selected:
654 gint newActive = gtk_combo_box_get_active( GTK_COMBO_BOX( widget ));
655 if( newActive >= 0 ) {
657 if( newActive != act->active ) {
658 act->active = newActive;
659 g_free( act->text );
660 act->text = gtk_combo_box_get_active_text( GTK_COMBO_BOX( widget ));
662 // Now let the world know
663 g_signal_emit( G_OBJECT(act), signals[CHANGED], 0 );
665 }
666 }
667 }
669 static void entry_activate_cb( GtkEntry* widget, gpointer data ) {
671 // Get text from entry box.. check if it matches a menu entry.
673 // Get action
674 Ink_ComboBoxEntry_Action *ink_comboboxentry_action = INK_COMBOBOXENTRY_ACTION( data );
676 // Get text
677 g_free( ink_comboboxentry_action->text );
678 ink_comboboxentry_action->text = g_strdup( gtk_entry_get_text( widget ) );
680 // Get row
681 ink_comboboxentry_action->active =
682 get_active_row_from_text( ink_comboboxentry_action, ink_comboboxentry_action->text );
684 // Set active row
685 gtk_combo_box_set_active( GTK_COMBO_BOX( ink_comboboxentry_action->combobox), ink_comboboxentry_action->active );
687 // Now let the world know
688 g_signal_emit( G_OBJECT(ink_comboboxentry_action), signals[CHANGED], 0 );
690 }
692 static gboolean match_selected_cb( GtkEntryCompletion* /*widget*/, GtkTreeModel* model, GtkTreeIter* iter, gpointer data )
693 {
694 // Get action
695 Ink_ComboBoxEntry_Action *ink_comboboxentry_action = INK_COMBOBOXENTRY_ACTION( data );
696 GtkEntry *entry = ink_comboboxentry_action->entry;
698 if( entry) {
699 gchar *family = 0;
700 gtk_tree_model_get(model, iter, 0, &family, -1);
702 // Set text in GtkEntry
703 gtk_entry_set_text (GTK_ENTRY (entry), family );
705 // Set text in GtkAction
706 g_free( ink_comboboxentry_action->text );
707 ink_comboboxentry_action->text = family;
709 // Get row
710 ink_comboboxentry_action->active =
711 get_active_row_from_text( ink_comboboxentry_action, ink_comboboxentry_action->text );
713 // Set active row
714 gtk_combo_box_set_active( GTK_COMBO_BOX( ink_comboboxentry_action->combobox), ink_comboboxentry_action->active );
716 // Now let the world know
717 g_signal_emit( G_OBJECT(ink_comboboxentry_action), signals[CHANGED], 0 );
719 return true;
720 }
721 return false;
722 }