diff --git a/ChangeLog b/ChangeLog index a9845729c1..319eb20842 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Tue Jan 20 16:38:52 1998 Owen Taylor + * gtk/gtkcombobox.{c,h}: removed + gtk/gtkcombo.{c,h}: added [Paolo Molaro's version] + gtk/testgtk.c: changed to use new version + gtk/Makefile.am gtk/gtk.h + Mon Jan 19 16:21:00 1998 Federico Mena * gtk/gtktoolbar.c (gtk_toolbar_class_init): Set diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index a9845729c1..319eb20842 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,9 @@ +Tue Jan 20 16:38:52 1998 Owen Taylor + * gtk/gtkcombobox.{c,h}: removed + gtk/gtkcombo.{c,h}: added [Paolo Molaro's version] + gtk/testgtk.c: changed to use new version + gtk/Makefile.am gtk/gtk.h + Mon Jan 19 16:21:00 1998 Federico Mena * gtk/gtktoolbar.c (gtk_toolbar_class_init): Set diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index a9845729c1..319eb20842 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,9 @@ +Tue Jan 20 16:38:52 1998 Owen Taylor + * gtk/gtkcombobox.{c,h}: removed + gtk/gtkcombo.{c,h}: added [Paolo Molaro's version] + gtk/testgtk.c: changed to use new version + gtk/Makefile.am gtk/gtk.h + Mon Jan 19 16:21:00 1998 Federico Mena * gtk/gtktoolbar.c (gtk_toolbar_class_init): Set diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index a9845729c1..319eb20842 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,9 @@ +Tue Jan 20 16:38:52 1998 Owen Taylor + * gtk/gtkcombobox.{c,h}: removed + gtk/gtkcombo.{c,h}: added [Paolo Molaro's version] + gtk/testgtk.c: changed to use new version + gtk/Makefile.am gtk/gtk.h + Mon Jan 19 16:21:00 1998 Federico Mena * gtk/gtktoolbar.c (gtk_toolbar_class_init): Set diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index a9845729c1..319eb20842 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,9 @@ +Tue Jan 20 16:38:52 1998 Owen Taylor + * gtk/gtkcombobox.{c,h}: removed + gtk/gtkcombo.{c,h}: added [Paolo Molaro's version] + gtk/testgtk.c: changed to use new version + gtk/Makefile.am gtk/gtk.h + Mon Jan 19 16:21:00 1998 Federico Mena * gtk/gtktoolbar.c (gtk_toolbar_class_init): Set diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index a9845729c1..319eb20842 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,9 @@ +Tue Jan 20 16:38:52 1998 Owen Taylor + * gtk/gtkcombobox.{c,h}: removed + gtk/gtkcombo.{c,h}: added [Paolo Molaro's version] + gtk/testgtk.c: changed to use new version + gtk/Makefile.am gtk/gtk.h + Mon Jan 19 16:21:00 1998 Federico Mena * gtk/gtktoolbar.c (gtk_toolbar_class_init): Set diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index a9845729c1..319eb20842 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,9 @@ +Tue Jan 20 16:38:52 1998 Owen Taylor + * gtk/gtkcombobox.{c,h}: removed + gtk/gtkcombo.{c,h}: added [Paolo Molaro's version] + gtk/testgtk.c: changed to use new version + gtk/Makefile.am gtk/gtk.h + Mon Jan 19 16:21:00 1998 Federico Mena * gtk/gtktoolbar.c (gtk_toolbar_class_init): Set diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 98ca2adaf1..c401535460 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -18,7 +18,7 @@ libgtk_la_SOURCES = \ gtkcheckmenuitem.c \ gtkclist.c \ gtkcolorsel.c \ - gtkcombobox.c \ + gtkcombo.c \ gtkcontainer.c \ gtkcurve.c \ gtkdata.c \ @@ -108,7 +108,7 @@ gtkinclude_HEADERS = \ gtkcheckmenuitem.h \ gtkclist.h \ gtkcolorsel.h \ - gtkcombobox.h \ + gtkcombo.h \ gtkcontainer.h \ gtkcurve.h \ gtkdata.h \ diff --git a/gtk/gtk.h b/gtk/gtk.h index aca23cc000..22b81b22ee 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/gtk/gtkcombo.c b/gtk/gtkcombo.c new file mode 100644 index 0000000000..449de5f052 --- /dev/null +++ b/gtk/gtkcombo.c @@ -0,0 +1,536 @@ +/* gtkcombo - combo widget for gtk+ + * Copyright 1997 Paolo Molaro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* $Id$ */ + +#include + +#include "gtkarrow.h" +#include "gtklabel.h" +#include "gtklist.h" +#include "gtkentry.h" +#include "gtkbutton.h" +#include "gtklistitem.h" +#include "gtkscrolledwindow.h" +#include "gtkmain.h" +#include "gtksignal.h" +#include "gtkwindow.h" +#include "gdk/gdkkeysyms.h" +#include "gtkcombo.h" + +const gchar *gtk_combo_string_key = "_combo_string_value"; + +#define COMBO_LIST_MAX_HEIGHT 400 + +static void gtk_combo_class_init (GtkComboClass *klass); +static void gtk_combo_init (GtkCombo *combo); +static void gtk_combo_destroy (GtkObject *combo); +static GtkListItem *gtk_combo_find (GtkCombo *combo); +static gchar * gtk_combo_func (GtkListItem *li); +static gint gtk_combo_focus_idle (GtkCombo *combo); +static gint gtk_combo_entry_focus_out (GtkEntry *entry, + GdkEventFocus *event, + GtkCombo *combo); +static void gtk_combo_get_pos (GtkCombo *combo, + gint *x, + gint *y, + gint *height, + gint *width); +static void gtk_combo_popup_list (GtkButton *button, + GtkCombo *combo); +static void gtk_combo_update_entry (GtkList *list, + GtkCombo *combo); +static void gtk_combo_update_list (GtkEntry *entry, + GtkCombo *combo); +static gint gtk_combo_button_press (GtkWidget *widget, + GdkEvent *event, + GtkCombo *combo); +static gint gtk_combo_list_key_press (GtkWidget *widget, + GdkEventKey *event, + GtkCombo *combo); +static gint gtk_combo_entry_key_press (GtkEntry *widget, + GdkEventKey *event, + GtkCombo *combo); +static void gtk_combo_item_destroy (GtkObject *object); + +static GtkHBoxClass *parent_class = NULL; + +void +gtk_combo_class_init (GtkComboClass * klass) +{ + GtkObjectClass *oclass; + + parent_class = gtk_type_class (gtk_hbox_get_type ()); + oclass = (GtkObjectClass *) klass; + + oclass->destroy = gtk_combo_destroy; +} + +static void +gtk_combo_destroy (GtkObject * combo) +{ + + gtk_object_unref (GTK_OBJECT (GTK_COMBO (combo)->popwin)); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (*GTK_OBJECT_CLASS (parent_class)->destroy) (combo); +} + +static int +gtk_combo_entry_key_press (GtkEntry * entry, GdkEventKey * event, GtkCombo * combo) +{ + GList *li; + /* completion? */ + /*if ( event->keyval == GDK_Tab ) { + gtk_signal_emit_stop_by_name (GTK_OBJECT (entry), "key_press_event"); + return TRUE; + } else */ + if (!combo->use_arrows || !GTK_LIST (combo->list)->children) + return FALSE; + li = g_list_find (GTK_LIST (combo->list)->children, gtk_combo_find (combo)); + + if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up) + { + if (li) + li = li->prev; + if (!li && combo->use_arrows_always) + { + li = g_list_last (GTK_LIST (combo->list)->children); + } + if (li) + { + gtk_list_select_child (GTK_LIST (combo->list), GTK_WIDGET (li->data)); + gtk_signal_emit_stop_by_name (GTK_OBJECT (entry), "key_press_event"); + return TRUE; + } + } + else if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down) + { + if (li) + li = li->next; + if (!li && combo->use_arrows_always) + { + li = GTK_LIST (combo->list)->children; + } + if (li) + { + gtk_list_select_child (GTK_LIST (combo->list), GTK_WIDGET (li->data)); + gtk_signal_emit_stop_by_name (GTK_OBJECT (entry), "key_press_event"); + return TRUE; + } + } + return FALSE; +} + +static GtkListItem * +gtk_combo_find (GtkCombo * combo) +{ + gchar *text; + gchar *ltext; + GList *clist; + int (*string_compare) (const char *, const char *); + + if (combo->case_sensitive) + string_compare = strcmp; + else + string_compare = strcasecmp; + + text = gtk_entry_get_text (GTK_ENTRY (combo->entry)); + clist = GTK_LIST (combo->list)->children; + + while (clist && clist->data) + { + ltext = gtk_combo_func (GTK_LIST_ITEM (clist->data)); + if (!ltext) + continue; + if (!(*string_compare) (ltext, text)) + return (GtkListItem *) clist->data; + clist = clist->next; + } + + return NULL; +} + +static gchar * +gtk_combo_func (GtkListItem * li) +{ + GtkWidget *label; + gchar *ltext = NULL; + + ltext = (gchar *) gtk_object_get_data (GTK_OBJECT (li), gtk_combo_string_key); + if (!ltext) + { + label = GTK_BIN (li)->child; + if (!label || !GTK_IS_LABEL (label)) + return NULL; + gtk_label_get (GTK_LABEL (label), <ext); + } + return ltext; +} + +static gint +gtk_combo_focus_idle (GtkCombo * combo) +{ + if (combo) + gtk_widget_grab_focus (combo->entry); + return FALSE; +} + +static gint +gtk_combo_entry_focus_out (GtkEntry * entry, GdkEventFocus * event, GtkCombo * combo) +{ + + if (combo->value_in_list && !gtk_combo_find (combo)) + { + /* gdk_beep(); *//* this can be annoying */ + if (combo->ok_if_empty && !strcmp (gtk_entry_get_text (entry), "")) + return FALSE; +#ifdef TEST + printf ("INVALID ENTRY: `%s'\n", gtk_entry_get_text (entry)); +#endif + gtk_grab_add (GTK_WIDGET (combo)); + /* this is needed because if we call gtk_widget_grab_focus() + it isn't guaranteed it's the *last* call before the main-loop, + so the focus can be lost anyway... + the signal_emit_stop doesn't seem to work either... + */ + gtk_idle_add ((GtkFunction) gtk_combo_focus_idle, combo); + /*gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "focus_out_event"); */ + return TRUE; + } + return FALSE; +} + +static void +gtk_combo_get_pos (GtkCombo * combo, gint * x, gint * y, gint * height, gint * width) +{ + GtkAllocation *pos = &(GTK_WIDGET (combo->entry)->allocation); + GtkRequisition req1; + GtkRequisition req3; + gint some_more = 10 + GTK_CONTAINER (combo->popup)->border_width * 2; /* FIXME: calc from border_width ... */ + + gtk_widget_size_request (combo->popup, &req1); + gtk_widget_size_request (combo->list, &req3); + + *width = pos->width; + gdk_window_get_origin (GTK_WIDGET (combo->entry)->window, x, y); + *y += pos->height; + *height = MIN (COMBO_LIST_MAX_HEIGHT, gdk_screen_height () - *y); + + if (some_more + req3.width > *width) + some_more += 11 + 2 * 2; /* FIXME: get from the scrollbar and scrollbar_spacing */ + if (some_more + req3.height < *height) + *height = some_more + req3.height; + +} + +static void +gtk_combo_popup_list (GtkButton * button, GtkCombo * combo) +{ + gint height, width, x, y; + + if (!GTK_LIST (combo->list)->children) + return; + gtk_combo_get_pos (combo, &x, &y, &height, &width); + + gtk_widget_set_uposition (combo->popwin, x, y); + gtk_widget_set_usize (combo->popwin, width, height); + gtk_widget_realize (combo->popwin); + gdk_window_set_cursor (combo->popwin->window, + gdk_cursor_new (GDK_TOP_LEFT_ARROW)); + gdk_window_resize (combo->popwin->window, width, height); + gtk_widget_show (combo->popwin); + gtk_widget_grab_focus (combo->popwin); + gtk_grab_add (combo->popwin); + gdk_pointer_grab (combo->popwin->window, TRUE, + GDK_BUTTON_PRESS_MASK, NULL, NULL, GDK_CURRENT_TIME); +} + +#if 0 +static void +prelight_bug (GtkButton * b, GtkCombo * combo) +{ + /* avoid prelight state... */ + gtk_widget_set_state (combo->button, GTK_STATE_NORMAL); + +} +#endif + +static void +gtk_combo_update_entry (GtkList * list, GtkCombo * combo) +{ + char *text; + + gtk_grab_remove (GTK_WIDGET (combo)); + gtk_signal_handler_block (GTK_OBJECT (list), combo->list_change_id); + if (list->selection) + { + text = gtk_combo_func (GTK_LIST_ITEM (list->selection->data)); + if (!text) + text = ""; + gtk_entry_set_text (GTK_ENTRY (combo->entry), text); + } + gtk_widget_hide (combo->popwin); + gtk_grab_remove (combo->popwin); + gdk_pointer_ungrab (GDK_CURRENT_TIME); + gtk_signal_handler_unblock (GTK_OBJECT (list), combo->list_change_id); +} + +static void +gtk_combo_update_list (GtkEntry * entry, GtkCombo * combo) +{ + GtkList *list = GTK_LIST (combo->list); + GList *slist = list->selection; + GtkListItem *li; + + gtk_grab_remove (GTK_WIDGET (combo)); + + gtk_signal_handler_block (GTK_OBJECT (entry), combo->entry_change_id); + if (slist && slist->data) + gtk_list_unselect_child (list, GTK_WIDGET (slist->data)); + li = gtk_combo_find (combo); + if (li) + gtk_list_select_child (list, GTK_WIDGET (li)); + gtk_signal_handler_unblock (GTK_OBJECT (entry), combo->entry_change_id); +} + +static gint +gtk_combo_button_press (GtkWidget * widget, GdkEvent * event, GtkCombo * combo) +{ + GtkWidget *child; + + child = gtk_get_event_widget (event); + + /* We don't ask for button press events on the grab widget, so + * if an event is reported directly to the grab widget, it must + * be on a window outside the application (and thus we remove + * the popup window). Otherwise, we check if the widget is a child + * of the grab widget, and only remove the popup window if it + * is not. + */ + if (child != widget) + { + while (child) + { + if (child == widget) + return FALSE; + child = child->parent; + } + } + + gtk_widget_hide (combo->popwin); + gtk_grab_remove (combo->popwin); + gdk_pointer_ungrab (GDK_CURRENT_TIME); + + return TRUE; +} + +static int +gtk_combo_list_key_press (GtkWidget * widget, GdkEventKey * event, GtkCombo * combo) +{ + if (event->keyval == GDK_Escape) + { + gtk_widget_hide (combo->popwin); + gtk_grab_remove (combo->popwin); + gdk_pointer_ungrab (GDK_CURRENT_TIME); + return TRUE; + } + return FALSE; +} + +void +gtk_combo_init (GtkCombo * combo) +{ + GtkWidget *arrow; + + combo->case_sensitive = 0; + combo->value_in_list = 0; + combo->ok_if_empty = 1; + combo->use_arrows = 1; + combo->use_arrows_always = 0; + combo->entry = gtk_entry_new (); + combo->button = gtk_button_new (); + arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_widget_show (arrow); + gtk_container_add (GTK_CONTAINER (combo->button), arrow); + gtk_box_pack_start (GTK_BOX (combo), combo->entry, TRUE, TRUE, 0); + gtk_box_pack_end (GTK_BOX (combo), combo->button, FALSE, FALSE, 0); + gtk_widget_show (combo->entry); + gtk_widget_show (combo->button); + combo->entry_change_id = gtk_signal_connect (GTK_OBJECT (combo->entry), "changed", + (GtkSignalFunc) gtk_combo_update_list, combo); + gtk_signal_connect (GTK_OBJECT (combo->entry), "key_press_event", + (GtkSignalFunc) gtk_combo_entry_key_press, combo); + gtk_signal_connect_after (GTK_OBJECT (combo->entry), "focus_out_event", + (GtkSignalFunc) gtk_combo_entry_focus_out, combo); + gtk_signal_connect (GTK_OBJECT (combo->entry), "activate", + (GtkSignalFunc) gtk_combo_popup_list, combo); + gtk_signal_connect (GTK_OBJECT (combo->button), "clicked", + (GtkSignalFunc) gtk_combo_popup_list, combo); + /*gtk_signal_connect(GTK_OBJECT(combo->button), "clicked", + (GtkSignalFunc)prelight_bug, combo); */ + + combo->popwin = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_policy (GTK_WINDOW (combo->popwin), 1, 1, 0); + combo->popup = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (combo->popup), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + combo->list = gtk_list_new (); + /*gtk_list_set_selection_mode(GTK_LIST(combo->list), GTK_SELECTION_SINGLE); */ + gtk_container_add (GTK_CONTAINER (combo->popwin), combo->popup); + gtk_container_add (GTK_CONTAINER (combo->popup), combo->list); + gtk_widget_show (combo->list); + gtk_widget_show (combo->popup); + gtk_widget_set_events (combo->popwin, gtk_widget_get_events (combo->popwin) | GDK_KEY_PRESS_MASK); + combo->list_change_id = gtk_signal_connect (GTK_OBJECT (combo->list), "selection_changed", + (GtkSignalFunc) gtk_combo_update_entry, combo); + gtk_signal_connect (GTK_OBJECT (combo->popwin), "key_press_event", + (GtkSignalFunc) gtk_combo_list_key_press, combo); + gtk_signal_connect (GTK_OBJECT (combo->popwin), "button_press_event", + GTK_SIGNAL_FUNC (gtk_combo_button_press), combo); + +} + +guint +gtk_combo_get_type () +{ + static guint combo_type = 0; + + if (!combo_type) + { + GtkTypeInfo combo_info = + { + "GtkCombo", + sizeof (GtkCombo), + sizeof (GtkComboClass), + (GtkClassInitFunc) gtk_combo_class_init, + (GtkObjectInitFunc) gtk_combo_init, + (GtkArgSetFunc) NULL, + (GtkArgGetFunc) NULL, + }; + combo_type = gtk_type_unique (gtk_hbox_get_type (), &combo_info); + } + return combo_type; +} + +GtkWidget * +gtk_combo_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_combo_get_type ())); +} + +void +gtk_combo_set_value_in_list (GtkCombo * combo, gint val, gint ok_if_empty) +{ + g_return_if_fail (combo != NULL); + g_return_if_fail (GTK_IS_COMBO (combo)); + + combo->value_in_list = val; + combo->ok_if_empty = ok_if_empty; +} + +void +gtk_combo_set_case_sensitive (GtkCombo * combo, gint val) +{ + g_return_if_fail (combo != NULL); + g_return_if_fail (GTK_IS_COMBO (combo)); + + combo->case_sensitive = val; +} + +void +gtk_combo_set_use_arrows (GtkCombo * combo, gint val) +{ + g_return_if_fail (combo != NULL); + g_return_if_fail (GTK_IS_COMBO (combo)); + + combo->use_arrows = val; +} + +void +gtk_combo_set_use_arrows_always (GtkCombo * combo, gint val) +{ + g_return_if_fail (combo != NULL); + g_return_if_fail (GTK_IS_COMBO (combo)); + + combo->use_arrows_always = val; + combo->use_arrows = 1; +} + +void +gtk_combo_set_popdown_strings (GtkCombo * combo, GList * strings) +{ + GList *list; + GtkWidget *li; + + g_return_if_fail (combo != NULL); + g_return_if_fail (GTK_IS_COMBO (combo)); + g_return_if_fail (strings != NULL); + + gtk_list_clear_items (GTK_LIST (combo->list), 0, -1); + list = strings; + while (list) + { + li = gtk_list_item_new_with_label ((gchar *) list->data); + gtk_widget_show (li); + gtk_container_add (GTK_CONTAINER (combo->list), li); + list = list->next; + } +} + +static void +gtk_combo_item_destroy (GtkObject * object) +{ + gchar *key; + + key = gtk_object_get_data (object, gtk_combo_string_key); + if (key) + g_free (key); +} + +void +gtk_combo_set_item_string (GtkCombo * combo, GtkItem * item, const gchar * item_value) +{ + gchar *val; + gint connected = 0; + + g_return_if_fail (combo != NULL); + g_return_if_fail (GTK_IS_COMBO (combo)); + g_return_if_fail (item != NULL); + + val = gtk_object_get_data (GTK_OBJECT (item), gtk_combo_string_key); + if (val) + { + g_free (val); + connected = 1; + } + if (item_value) + { + val = g_strdup(item_value); + gtk_object_set_data (GTK_OBJECT (item), gtk_combo_string_key, val); + if (!connected) + gtk_signal_connect (GTK_OBJECT (item), "destroy", + (GtkSignalFunc) gtk_combo_item_destroy, val); + } + else + { + gtk_object_set_data (GTK_OBJECT (item), gtk_combo_string_key, NULL); + if (connected) + gtk_signal_disconnect_by_data(GTK_OBJECT (item), val); + } +} diff --git a/gtk/gtkcombo.h b/gtk/gtkcombo.h new file mode 100644 index 0000000000..81d06f98f4 --- /dev/null +++ b/gtk/gtkcombo.h @@ -0,0 +1,91 @@ +/* gtkcombo - combo widget for gtk+ + * Copyright 1997 Paolo Molaro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef __GTK_SMART_COMBO_H__ +#define __GTK_SMART_COMBO_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GTK_COMBO(obj) GTK_CHECK_CAST (obj, gtk_combo_get_type (), GtkCombo) +#define GTK_COMBO_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_combo_get_type (), GtkComboClass) +#define GTK_IS_COMBO(obj) GTK_CHECK_TYPE (obj, gtk_combo_get_type ()) + +typedef struct _GtkCombo GtkCombo; +typedef struct _GtkComboClass GtkComboClass; + +/* you should access only the entry and list fields directly */ +struct _GtkCombo { + GtkHBox hbox; + GtkWidget *entry; + GtkWidget *button; + GtkWidget *popup; + GtkWidget *popwin; + GtkWidget *list; + + gint entry_change_id; + gint list_change_id; + + guint value_in_list:1; + guint ok_if_empty:1; + guint case_sensitive:1; + guint use_arrows:1; + guint use_arrows_always:1; +}; + +struct _GtkComboClass { + GtkHBoxClass parent_class; +}; + +guint gtk_combo_get_type (void); + +GtkWidget *gtk_combo_new (void); +/* the text in the entry must be or not be in the list */ +void gtk_combo_set_value_in_list (GtkCombo* combo, + gint val, + gint ok_if_empty); +/* set/unset arrows working for changing the value (can be annoying */ +void gtk_combo_set_use_arrows (GtkCombo* combo, + gint val); +/* up/down arrows change value if current value not in list */ +void gtk_combo_set_use_arrows_always (GtkCombo* combo, + gint val); +/* perform case-sensitive compares */ +void gtk_combo_set_case_sensitive (GtkCombo* combo, + gint val); +/* call this function on an item if it isn't a label or you + want it to have a different value to be displayed in the entry */ +void gtk_combo_set_item_string (GtkCombo* combo, + GtkItem* item, + const gchar* item_value); +/* simple interface */ +void gtk_combo_set_popdown_strings (GtkCombo* combo, + GList *strings); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GTK_SMART_COMBO_H__ */ + + diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c deleted file mode 100644 index 35ec14f50b..0000000000 --- a/gtk/gtkcombobox.c +++ /dev/null @@ -1,421 +0,0 @@ -/* GTK - The GIMP Toolkit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * Copyright (C) 1998 Elliot Lee - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* NOTES about this widget: - It would be nice if we kept track of the last menu item that - people selected, so that we could allow choosing text by using - up/down arrows. - -- Elliot -*/ -#include -#include -#include "gdk/gdkx.h" -#include "gdk/gdkkeysyms.h" -#include "gdk/gdki18n.h" -#include "gtkcombobox.h" -#include "gtkmain.h" -#include "gtksignal.h" -#include "gtkmenu.h" -#include "gtkmenuitem.h" -#include "gtklabel.h" - -#define ARROW_SIZE_X 20 -#define ARROW_SIZE_Y 20 -#define ARROW_PADDING 4 -/* Copied from gtkentry.c for size_allocate */ -#define INNER_BORDER 2 - -static void gtk_combo_box_class_init (GtkComboBoxClass *class); -static void gtk_combo_box_init (GtkComboBox *combobox); -static void gtk_combo_box_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_combo_box_size_allocate(GtkWidget *widget, - GtkAllocation *allocation); -static void gtk_combo_box_draw (GtkWidget *widget, - GdkRectangle *area); -static void gtk_combo_box_draw_arrow (GtkWidget *widget, gboolean detent); -static gint gtk_combo_box_expose (GtkWidget *object, - GdkEventExpose *event); -static void gtk_combo_box_destroy (GtkObject *object); -static gint gtk_combo_box_key_press (GtkWidget *widget, - GdkEventKey *event); -static gint gtk_combo_box_button_press (GtkWidget *widget, - GdkEventButton *event); -static gint gtk_combo_box_motion_notify(GtkWidget *widget, - GdkEventMotion *event); -static void gtk_combo_box_realize (GtkWidget *widget); -static void gtk_combo_box_item_activate(GtkWidget *widget, - GtkComboBox *cb); -static void gtk_combo_box_set_down (GtkWidget *widget, - GtkComboBox *cb); -static void gtk_combo_box_set_up (GtkWidget *widget, - GtkComboBox *cb); - -static GtkEntryClass *parent_class = NULL; - -guint -gtk_combo_box_get_type () -{ - static guint combo_box_type = 0; - - if (!combo_box_type) - { - GtkTypeInfo combo_box_info = - { - "GtkComboBox", - sizeof (GtkComboBox), - sizeof (GtkComboBoxClass), - (GtkClassInitFunc) gtk_combo_box_class_init, - (GtkObjectInitFunc) gtk_combo_box_init, - (GtkArgSetFunc) NULL, - (GtkArgGetFunc) NULL, - }; - - combo_box_type = gtk_type_unique (gtk_entry_get_type (), &combo_box_info); - } - - return combo_box_type; -} - -static void -gtk_combo_box_class_init (GtkComboBoxClass *class) -{ - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = (GtkObjectClass *) class; - widget_class = (GtkWidgetClass *) class; - - parent_class = gtk_type_class (gtk_entry_get_type ()); - - object_class->destroy = gtk_combo_box_destroy; - - widget_class->button_press_event = gtk_combo_box_button_press; - widget_class->key_press_event = gtk_combo_box_key_press; - widget_class->motion_notify_event = gtk_combo_box_motion_notify; - widget_class->size_request = gtk_combo_box_size_request; - widget_class->size_allocate = gtk_combo_box_size_allocate; - widget_class->draw = gtk_combo_box_draw; - widget_class->expose_event = gtk_combo_box_expose; - widget_class->realize = gtk_combo_box_realize; - -} - -static void -gtk_combo_box_init (GtkComboBox *combobox) -{ - GTK_WIDGET_SET_FLAGS (combobox, GTK_CAN_FOCUS); - - combobox->popdown = NULL; - combobox->menu_is_down = FALSE; - - gtk_widget_set_events(GTK_WIDGET(combobox), - gtk_widget_get_events(GTK_WIDGET(combobox)) | GDK_POINTER_MOTION_MASK); -} - -GtkWidget* -gtk_combo_box_new (GList *popdown_strings) -{ - GtkWidget *retval = GTK_WIDGET (gtk_type_new (gtk_combo_box_get_type ())); - if(popdown_strings) - gtk_combo_box_set_popdown_strings(GTK_COMBO_BOX(retval), popdown_strings); - return retval; -} - -GtkWidget* -gtk_combo_box_new_with_max_length (GList *popdown_strings, - guint16 max) -{ - GtkWidget *retval; - retval = GTK_WIDGET(gtk_type_new (gtk_combo_box_get_type ())); - GTK_ENTRY(retval)->text_max_length = max; - if(popdown_strings) - gtk_combo_box_set_popdown_strings(GTK_COMBO_BOX(retval), popdown_strings); - return retval; -} - -void -gtk_combo_box_set_popdown_strings(GtkComboBox *combobox, - GList *popdown_strings) -{ - GList *t; - - g_return_if_fail(combobox != NULL); - g_return_if_fail(popdown_strings != NULL); - if(combobox->popdown) - gtk_widget_destroy(combobox->popdown); - - combobox->popdown = gtk_menu_new(); - gtk_signal_connect(GTK_OBJECT(combobox->popdown), - "show", - GTK_SIGNAL_FUNC(gtk_combo_box_set_down), - combobox); - gtk_signal_connect(GTK_OBJECT(combobox->popdown), - "hide", - GTK_SIGNAL_FUNC(gtk_combo_box_set_up), - combobox); - - for(t = popdown_strings; t; t = t->next) - { - GtkWidget *mitem; - mitem = gtk_menu_item_new_with_label(t->data); - gtk_widget_show(mitem); - gtk_menu_append(GTK_MENU(combobox->popdown), mitem); - gtk_signal_connect(GTK_OBJECT(mitem), "activate", - GTK_SIGNAL_FUNC(gtk_combo_box_item_activate), - combobox); - } - - gtk_widget_set_usize(combobox->popdown, - GTK_WIDGET(combobox)->allocation.width, - -1); -} - -static void -gtk_combo_box_realize(GtkWidget *widget) -{ - GtkComboBox *cb; - - g_return_if_fail(widget != NULL); - g_return_if_fail(GTK_IS_COMBO_BOX(widget)); - - cb = GTK_COMBO_BOX(widget); - GTK_WIDGET_CLASS(parent_class)->realize(widget); - gdk_window_set_background (GTK_WIDGET(widget)->window, - &widget->style->bg[GTK_WIDGET_STATE(widget)]); - -} - -static void -gtk_combo_box_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_COMBO_BOX (widget)); - g_return_if_fail (requisition != NULL); - - GTK_WIDGET_CLASS(parent_class)->size_request(widget, requisition); - - requisition->width += ARROW_SIZE_X; - if(requisition->height < ARROW_SIZE_Y) - requisition->height = ARROW_SIZE_Y; -} - -static void -gtk_combo_box_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - GtkComboBox *cb; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_COMBO_BOX (widget)); - g_return_if_fail (allocation != NULL); - - cb = GTK_COMBO_BOX(widget); - - widget->allocation = *allocation; - - GTK_WIDGET_CLASS(parent_class)->size_allocate(widget, allocation); - - gdk_window_resize(GTK_ENTRY(widget)->text_area, - allocation->width - (widget->style->klass->xthickness + INNER_BORDER) * 2 - ARROW_SIZE_X, - widget->requisition.height - (widget->style->klass->ythickness + INNER_BORDER) * 2); - if(cb->popdown) - { - gtk_widget_set_usize(cb->popdown, - widget->allocation.width, - -1); - } -} - -static void -gtk_combo_box_draw_arrow (GtkWidget *widget, gboolean detent) -{ - gint sx, sy; - - sx = widget->allocation.width - ARROW_SIZE_X; - sy = ARROW_PADDING; - widget->style->klass->draw_arrow(widget->style, - widget->window, - GTK_WIDGET_STATE(widget), - detent?GTK_SHADOW_IN:GTK_SHADOW_OUT, - GTK_ARROW_DOWN, TRUE, - sx, sy, - ARROW_SIZE_X - ARROW_PADDING, - ARROW_SIZE_Y - ARROW_PADDING - 2); -} - -static void -gtk_combo_box_draw (GtkWidget *widget, - GdkRectangle *area) -{ - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_COMBO_BOX (widget)); - g_return_if_fail (area != NULL); - - if (GTK_WIDGET_DRAWABLE (widget)) - { - gtk_combo_box_draw_arrow(widget, FALSE); - GTK_WIDGET_CLASS(parent_class)->draw(widget, area); - } -} - -static gint -gtk_combo_box_expose (GtkWidget *widget, - GdkEventExpose *event) -{ - gint retval; - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - gtk_combo_box_draw_arrow(widget, FALSE); - retval = GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event); - return retval; -} - -static void -gtk_combo_box_position_menu(GtkMenu *menu, - gint *x, - gint *y, - gpointer user_data) -{ - GtkComboBox *cb; - GtkWidget *widget; - gint rootw, rooth, wy; - - g_return_if_fail(user_data != NULL); - g_return_if_fail(GTK_IS_COMBO_BOX(user_data)); - - cb = GTK_COMBO_BOX(user_data); - widget = GTK_WIDGET(user_data); - - gdk_window_get_origin(widget->window, x, &wy); - *y = wy + widget->requisition.height; - - gdk_window_get_size(GDK_ROOT_PARENT(), &rootw, &rooth); - - /* This check isn't perfect - what if the menu is too big to fit on - the screen going either up or down? *sigh* not a perfect - world, I guess */ - if((*y + GTK_WIDGET(menu)->requisition.height) > rooth) - *y = wy - GTK_WIDGET(menu)->requisition.height; -} - -static void -gtk_combo_box_set_down (GtkWidget *widget, - GtkComboBox *cb) -{ - g_return_if_fail(GTK_IS_COMBO_BOX(cb)); - - cb->menu_is_down = TRUE; -} - -static void -gtk_combo_box_set_up (GtkWidget *widget, - GtkComboBox *cb) -{ - g_return_if_fail(GTK_IS_COMBO_BOX(cb)); - - cb->menu_is_down = FALSE; -} - -static gint -gtk_combo_box_button_press (GtkWidget *widget, - GdkEventButton *event) -{ - GtkComboBox *cb; - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - cb = GTK_COMBO_BOX(widget); - - if(event->window == widget->window - && event->x > (widget->allocation.width - ARROW_SIZE_X) - && event->x < widget->allocation.width - && event->button == 1) - { - gtk_menu_popup(GTK_MENU(cb->popdown), - NULL, NULL, - gtk_combo_box_position_menu, - cb, event->button, - event->time); - return TRUE; - } - else - return FALSE; -/* - return GTK_WIDGET_CLASS(parent_class)->button_press_event(widget, event); -*/ -} - -static gint -gtk_combo_box_key_press (GtkWidget *widget, - GdkEventKey *event) -{ - GtkComboBox *cb; - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_COMBO_BOX (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - cb = GTK_COMBO_BOX(widget); - if(cb->menu_is_down) - return GTK_WIDGET_CLASS(cb->popdown)->key_press_event(cb->popdown, event); - else - return FALSE; -/* - return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event); -*/ -} - -static void -gtk_combo_box_destroy(GtkObject *object) -{ - GtkComboBox *cb; - g_return_if_fail(GTK_IS_COMBO_BOX(object)); - - cb = GTK_COMBO_BOX(object); - if(cb->popdown) - gtk_widget_destroy(cb->popdown); - - GTK_OBJECT_CLASS(parent_class)->destroy(object); -} - -static void gtk_combo_box_item_activate(GtkWidget *widget, - GtkComboBox *cb) -{ - char *newtext = GTK_LABEL(GTK_BIN(widget)->child)->label; - - gtk_entry_set_text(GTK_ENTRY(cb), newtext); -} - -static gint gtk_combo_box_motion_notify(GtkWidget *widget, - GdkEventMotion *event) -{ - if(event->window == widget->window - && event->x > (widget->allocation.width - ARROW_SIZE_X) - && event->x < widget->allocation.width) - { - gtk_combo_box_draw_arrow(widget, TRUE); - } - else - { - gtk_combo_box_draw_arrow(widget, FALSE); - } - return FALSE; -} diff --git a/gtk/gtkcombobox.h b/gtk/gtkcombobox.h deleted file mode 100644 index 6433c77352..0000000000 --- a/gtk/gtkcombobox.h +++ /dev/null @@ -1,67 +0,0 @@ -/* GTK - The GIMP Toolkit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * Copyright (C) 1998 Elliot Lee - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef __GTK_COMBO_BOX_H__ -#define __GTK_COMBO_H__ - - -#include -#include - - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -#define GTK_COMBO_BOX(obj) GTK_CHECK_CAST (obj, gtk_combo_box_get_type (), GtkComboBox) -#define GTK_COMBO_BOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_combo_box_get_type (), GtkComboBoxClass) -#define GTK_IS_COMBO_BOX(obj) GTK_CHECK_TYPE (obj, gtk_combo_box_get_type ()) - - -typedef struct _GtkComboBox GtkComboBox; -typedef struct _GtkComboBoxClass GtkComboBoxClass; - -struct _GtkComboBox -{ - GtkEntry parent_widget; - GtkWidget *popdown; - gboolean menu_is_down; -}; - -struct _GtkComboBoxClass -{ - GtkEntryClass parent_class; -}; - - -guint gtk_combo_box_get_type (void); -/* These GList's should be lists of strings that should be placed - in the popdown menu */ -GtkWidget* gtk_combo_box_new (GList *popdown_strings); -GtkWidget* gtk_combo_box_new_with_max_length (GList *popdown_strings, - guint16 max); -void gtk_combo_box_set_popdown_strings(GtkComboBox *combobox, - GList *popdown_strings); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#endif /* __GTK_COMBO_BOX_H__ */ diff --git a/gtk/testgtk.c b/gtk/testgtk.c index ede3cde21b..835e360c73 100644 --- a/gtk/testgtk.c +++ b/gtk/testgtk.c @@ -1360,9 +1360,10 @@ create_entry () gtk_box_pack_start (GTK_BOX (box2), entry, TRUE, TRUE, 0); gtk_widget_show (entry); - cb = gtk_combo_box_new (cbitems); - gtk_entry_set_text (GTK_ENTRY (cb), "hello world"); - gtk_entry_select_region (GTK_ENTRY (cb), + cb = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (cb), cbitems); + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO(cb)->entry), "hello world"); + gtk_entry_select_region (GTK_ENTRY (GTK_COMBO(cb)->entry), 0, GTK_ENTRY(entry)->text_length); gtk_box_pack_start (GTK_BOX (box2), cb, TRUE, TRUE, 0); gtk_widget_show (cb); @@ -2277,7 +2278,7 @@ create_text () gtk_widget_show (table); text = gtk_text_new (NULL, NULL); - gtk_text_set_editable (text, TRUE); + gtk_text_set_editable (GTK_TEXT (text), TRUE); gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1); gtk_widget_show (text); diff --git a/tests/testgtk.c b/tests/testgtk.c index ede3cde21b..835e360c73 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -1360,9 +1360,10 @@ create_entry () gtk_box_pack_start (GTK_BOX (box2), entry, TRUE, TRUE, 0); gtk_widget_show (entry); - cb = gtk_combo_box_new (cbitems); - gtk_entry_set_text (GTK_ENTRY (cb), "hello world"); - gtk_entry_select_region (GTK_ENTRY (cb), + cb = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (cb), cbitems); + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO(cb)->entry), "hello world"); + gtk_entry_select_region (GTK_ENTRY (GTK_COMBO(cb)->entry), 0, GTK_ENTRY(entry)->text_length); gtk_box_pack_start (GTK_BOX (box2), cb, TRUE, TRUE, 0); gtk_widget_show (cb); @@ -2277,7 +2278,7 @@ create_text () gtk_widget_show (table); text = gtk_text_new (NULL, NULL); - gtk_text_set_editable (text, TRUE); + gtk_text_set_editable (GTK_TEXT (text), TRUE); gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1); gtk_widget_show (text);