⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gtkcombo.c

📁 gtk是linux一款强大的夸平台的图形化开发工具
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *//* * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS * file for a list of people on the GTK+ Team.  See the ChangeLog * files for a list of changes.  These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/.  */#include <string.h>#include "gtkarrow.h"#include "gtklabel.h"#include "gtklist.h"#include "gtkentry.h"#include "gtkeventbox.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"#include "gtkframe.h"const gchar *gtk_combo_string_key = "gtk-combo-string-value";#define COMBO_LIST_MAX_HEIGHT	(400)#define	EMPTY_LIST_HEIGHT	(15)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      (GtkCombo      *combo);static void         gtk_combo_activate        (GtkWidget        *widget,					       GtkCombo         *combo);static void         gtk_combo_popup_button_press (GtkWidget        *button,						  GdkEventButton   *event,						  GtkCombo         *combo);static void         gtk_combo_popup_button_leave (GtkWidget        *button,						  GdkEventCrossing *event,						  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_button_release  (GtkWidget     *widget,				               GdkEvent      *event,				               GtkCombo      *combo);static gint         gtk_combo_list_enter      (GtkWidget        *widget,				               GdkEventCrossing *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 void         gtk_combo_size_allocate   (GtkWidget     *widget,					       GtkAllocation *allocation);static GtkHBoxClass *parent_class = NULL;static voidgtk_combo_class_init (GtkComboClass * klass){  GtkObjectClass *oclass;  GtkWidgetClass *widget_class;  parent_class = gtk_type_class (gtk_hbox_get_type ());  oclass = (GtkObjectClass *) klass;  widget_class = (GtkWidgetClass *) klass;  oclass->destroy = gtk_combo_destroy;    widget_class->size_allocate = gtk_combo_size_allocate;}static voidgtk_combo_destroy (GtkObject * combo){  gtk_widget_destroy (GTK_COMBO (combo)->popwin);  gtk_widget_unref (GTK_COMBO (combo)->popwin);  if (GTK_OBJECT_CLASS (parent_class)->destroy)    (*GTK_OBJECT_CLASS (parent_class)->destroy) (combo);}static intgtk_combo_entry_key_press (GtkEntry * entry, GdkEventKey * event, GtkCombo * combo){  GList *li;  /* completion */  if ((event->keyval == GDK_Tab) && (event->state & GDK_MOD1_MASK))     {    GCompletion * cmpl;    gchar* prefix;    gchar* nprefix = NULL;    gint pos;    if ( !GTK_LIST (combo->list)->children )      return FALSE;        gtk_signal_emit_stop_by_name (GTK_OBJECT (entry), "key_press_event");    cmpl = g_completion_new ((GCompletionFunc)gtk_combo_func);    g_completion_add_items (cmpl, GTK_LIST (combo->list)->children);    pos = GTK_EDITABLE (entry)->current_pos;    prefix = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, pos);    g_completion_complete(cmpl, prefix, &nprefix);    if (nprefix && strlen (nprefix) > strlen (prefix))       {    	gtk_editable_insert_text (GTK_EDITABLE (entry), nprefix + pos, 				 strlen (nprefix) - strlen (prefix), &pos);    	GTK_EDITABLE (entry)->current_pos = pos;    }    if (nprefix)      g_free (nprefix);    g_free (prefix);    g_completion_free (cmpl);    return TRUE;  }  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)      || ((event->state & GDK_MOD1_MASK) && ((event->keyval == 'p') || (event->keyval == 'P'))))    {      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)	   || ((event->state & GDK_MOD1_MASK) && ((event->keyval == 'n') || (event->keyval == 'N'))))    {      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 = g_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), &ltext);    }  return ltext;}static gintgtk_combo_focus_idle (GtkCombo * combo){  if (combo)    {      GDK_THREADS_ENTER ();      gtk_widget_grab_focus (combo->entry);      GDK_THREADS_LEAVE ();    }  return FALSE;}static gintgtk_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 voidgtk_combo_get_pos (GtkCombo * combo, gint * x, gint * y, gint * height, gint * width){  GtkBin *popwin;  GtkWidget *widget;  GtkScrolledWindow *popup;    gint real_height;  GtkRequisition list_requisition;  gboolean show_hscroll = FALSE;  gboolean show_vscroll = FALSE;  gint avail_height;  gint min_height;  gint alloc_width;  gint work_height;  gint old_height;  gint old_width;    widget = GTK_WIDGET(combo);  popup  = GTK_SCROLLED_WINDOW (combo->popup);  popwin = GTK_BIN (combo->popwin);    gdk_window_get_origin (combo->entry->window, x, y);  real_height = MIN (combo->entry->requisition.height, 		     combo->entry->allocation.height);  *y += real_height;  avail_height = gdk_screen_height () - *y;    gtk_widget_size_request (combo->list, &list_requisition);  min_height = MIN (list_requisition.height, 		    popup->vscrollbar->requisition.height);  if (!GTK_LIST (combo->list)->children)    list_requisition.height += EMPTY_LIST_HEIGHT;    alloc_width = (widget->allocation.width -		 2 * popwin->child->style->klass->xthickness -		 2 * GTK_CONTAINER (popwin->child)->border_width -		 2 * GTK_CONTAINER (combo->popup)->border_width -		 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width - 		 2 * GTK_BIN (popup)->child->style->klass->xthickness);    work_height = (2 * popwin->child->style->klass->ythickness +		 2 * GTK_CONTAINER (popwin->child)->border_width +		 2 * GTK_CONTAINER (combo->popup)->border_width +		 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width +		 2 * GTK_BIN (popup)->child->style->klass->xthickness);    do     {      old_width = alloc_width;      old_height = work_height;            if (!show_hscroll &&	  alloc_width < list_requisition.width)	{	  work_height += popup->hscrollbar->requisition.height +	    GTK_SCROLLED_WINDOW_CLASS 	    (GTK_OBJECT (combo->popup)->klass)->scrollbar_spacing;	  show_hscroll = TRUE;	}      if (!show_vscroll && 	  work_height + list_requisition.height > avail_height)	{	  if (work_height + min_height > avail_height && 	      *y - real_height > avail_height)	    {	      *y -= (work_height + list_requisition.height + real_height);	      break;	    }	  alloc_width -= 	    popup->vscrollbar->requisition.width +	    GTK_SCROLLED_WINDOW_CLASS 	    (GTK_OBJECT (combo->popup)->klass)->scrollbar_spacing;	  show_vscroll = TRUE;	}    } while (old_width != alloc_width || old_height != work_height);    *width = widget->allocation.width;  if (show_vscroll)    *height = avail_height;  else    *height = work_height + list_requisition.height;    if (*x < 0)    *x = 0;}static voidgtk_combo_popup_list (GtkCombo * combo){  gint height, width, x, y;  gint old_width, old_height;  old_width = combo->popwin->allocation.width;  old_height  = combo->popwin->allocation.height;  gtk_combo_get_pos (combo, &x, &y, &height, &width);  /* workaround for gtk_scrolled_window_size_allocate bug */  if (old_width != width || old_height != height)    {      gtk_widget_hide (GTK_SCROLLED_WINDOW (combo->popup)->hscrollbar);      gtk_widget_hide (GTK_SCROLLED_WINDOW (combo->popup)->vscrollbar);    }  gtk_widget_set_uposition (combo->popwin, x, y);  gtk_widget_set_usize (combo->popwin, width, height);  gtk_widget_realize (combo->popwin);  gdk_window_resize (combo->popwin->window, width, height);  gtk_widget_show (combo->popwin);  gtk_widget_grab_focus (combo->popwin);}static void        gtk_combo_activate (GtkWidget        *widget,		    GtkCombo         *combo){  gtk_combo_popup_list (combo);  if (!GTK_WIDGET_HAS_FOCUS (combo->entry))    gtk_widget_grab_focus (combo->entry);  gtk_grab_add (combo->popwin);  gdk_pointer_grab (combo->popwin->window, TRUE,		    GDK_BUTTON_PRESS_MASK | 		    GDK_BUTTON_RELEASE_MASK |		    GDK_POINTER_MOTION_MASK, 		    NULL, NULL, GDK_CURRENT_TIME);}static void        gtk_combo_popup_button_press (GtkWidget        *button,			      GdkEventButton   *event,			      GtkCombo         *combo){  if (!GTK_WIDGET_HAS_FOCUS (combo->entry))    gtk_widget_grab_focus (combo->entry);  if (!combo->current_button && (event->button == 1))    gtk_combo_popup_list (combo);  combo->current_button = event->button;    GTK_LIST (combo->list)->drag_selection = TRUE;  gdk_pointer_grab (combo->list->window, TRUE,		    GDK_POINTER_MOTION_HINT_MASK |		    GDK_BUTTON1_MOTION_MASK |		    GDK_BUTTON_RELEASE_MASK,		    NULL, NULL, event->time);  gtk_grab_add (combo->list);}static void         gtk_combo_popup_button_leave (GtkWidget        *button,			      GdkEventCrossing *event,			      GtkCombo         *combo){  if (combo->current_button)    gtk_signal_emit_stop_by_name (GTK_OBJECT (button), "leave_notify_event");}static voidgtk_combo_update_entry (GtkList * list, GtkCombo * combo){  char *text;  gtk_grab_remove (GTK_WIDGET (combo));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -