📄 gtkhandlebox.c
字号:
/* 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., 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 <stdlib.h>#include "gdk/gdkx.h"#include "gtkhandlebox.h"#include "gtkmain.h"#include "gtksignal.h"#include "gtkwindow.h"enum { ARG_0, ARG_SHADOW, ARG_HANDLE_POSITION, ARG_SNAP_EDGE};#define DRAG_HANDLE_SIZE 10#define CHILDLESS_SIZE 25#define GHOST_HEIGHT 3#define TOLERANCE 5enum { SIGNAL_CHILD_ATTACHED, SIGNAL_CHILD_DETACHED, SIGNAL_LAST};/* The algorithm for docking and redocking implemented here * has a couple of nice properties: * * 1) During a single drag, docking always occurs at the * the same cursor position. This means that the users * motions are reversible, and that you won't * undock/dock oscillations. * * 2) Docking generally occurs at user-visible features. * The user, once they figure out to redock, will * have useful information about doing it again in * the future. * * Please try to preserve these properties if you * change the algorithm. (And the current algorithm * is far from ideal). Briefly, the current algorithm * for deciding whether the handlebox is docked or not: * * 1) The decision is done by comparing two rectangles - the * allocation if the widget at the start of the drag, * and the boundary of hb->bin_window at the start of * of the drag offset by the distance that the cursor * has moved. * * 2) These rectangles must have one edge, the "snap_edge" * of the handlebox, aligned within TOLERANCE. * * 3) On the other dimension, the extents of one rectangle * must be contained in the extents of the other, * extended by tolerance. That is, either we can have: * * <-TOLERANCE-|--------bin_window--------------|-TOLERANCE-> * <--------float_window--------------------> * * or we can have: * * <-TOLERANCE-|------float_window--------------|-TOLERANCE-> * <--------bin_window--------------------> */static void gtk_handle_box_class_init (GtkHandleBoxClass *klass);static void gtk_handle_box_init (GtkHandleBox *handle_box);static void gtk_handle_box_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);static void gtk_handle_box_get_arg (GtkObject *object, GtkArg *arg, guint arg_id);static void gtk_handle_box_destroy (GtkObject *object);static void gtk_handle_box_map (GtkWidget *widget);static void gtk_handle_box_unmap (GtkWidget *widget);static void gtk_handle_box_realize (GtkWidget *widget);static void gtk_handle_box_unrealize (GtkWidget *widget);static void gtk_handle_box_style_set (GtkWidget *widget, GtkStyle *previous_style);static void gtk_handle_box_size_request (GtkWidget *widget, GtkRequisition *requisition);static void gtk_handle_box_size_allocate (GtkWidget *widget, GtkAllocation *real_allocation);static void gtk_handle_box_add (GtkContainer *container, GtkWidget *widget);static void gtk_handle_box_remove (GtkContainer *container, GtkWidget *widget);static void gtk_handle_box_draw_ghost (GtkHandleBox *hb);static void gtk_handle_box_paint (GtkWidget *widget, GdkEventExpose *event, GdkRectangle *area);static void gtk_handle_box_draw (GtkWidget *widget, GdkRectangle *area);static gint gtk_handle_box_expose (GtkWidget *widget, GdkEventExpose *event);static gint gtk_handle_box_button_changed (GtkWidget *widget, GdkEventButton *event);static gint gtk_handle_box_motion (GtkWidget *widget, GdkEventMotion *event);static gint gtk_handle_box_delete_event (GtkWidget *widget, GdkEventAny *event);static void gtk_handle_box_reattach (GtkHandleBox *hb);static GtkBinClass *parent_class;static guint handle_box_signals[SIGNAL_LAST] = { 0 };GtkTypegtk_handle_box_get_type (void){ static GtkType handle_box_type = 0; if (!handle_box_type) { static const GtkTypeInfo handle_box_info = { "GtkHandleBox", sizeof (GtkHandleBox), sizeof (GtkHandleBoxClass), (GtkClassInitFunc) gtk_handle_box_class_init, (GtkObjectInitFunc) gtk_handle_box_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; handle_box_type = gtk_type_unique (GTK_TYPE_BIN, &handle_box_info); } return handle_box_type;}static voidgtk_handle_box_class_init (GtkHandleBoxClass *class){ GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; object_class = (GtkObjectClass *) class; widget_class = (GtkWidgetClass *) class; container_class = (GtkContainerClass *) class; parent_class = gtk_type_class (GTK_TYPE_BIN); gtk_object_add_arg_type ("GtkHandleBox::shadow", GTK_TYPE_SHADOW_TYPE, GTK_ARG_READWRITE, ARG_SHADOW); gtk_object_add_arg_type ("GtkHandleBox::handle_position", GTK_TYPE_POSITION_TYPE, GTK_ARG_READWRITE, ARG_HANDLE_POSITION); gtk_object_add_arg_type ("GtkHandleBox::snap_edge", GTK_TYPE_POSITION_TYPE, GTK_ARG_READWRITE, ARG_SNAP_EDGE); object_class->set_arg = gtk_handle_box_set_arg; object_class->get_arg = gtk_handle_box_get_arg; handle_box_signals[SIGNAL_CHILD_ATTACHED] = gtk_signal_new ("child_attached", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (GtkHandleBoxClass, child_attached), gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_WIDGET); handle_box_signals[SIGNAL_CHILD_DETACHED] = gtk_signal_new ("child_detached", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (GtkHandleBoxClass, child_detached), gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_WIDGET); gtk_object_class_add_signals (object_class, handle_box_signals, SIGNAL_LAST); object_class->destroy = gtk_handle_box_destroy; widget_class->map = gtk_handle_box_map; widget_class->unmap = gtk_handle_box_unmap; widget_class->realize = gtk_handle_box_realize; widget_class->unrealize = gtk_handle_box_unrealize; widget_class->style_set = gtk_handle_box_style_set; widget_class->size_request = gtk_handle_box_size_request; widget_class->size_allocate = gtk_handle_box_size_allocate; widget_class->draw = gtk_handle_box_draw; widget_class->expose_event = gtk_handle_box_expose; widget_class->button_press_event = gtk_handle_box_button_changed; widget_class->button_release_event = gtk_handle_box_button_changed; widget_class->motion_notify_event = gtk_handle_box_motion; widget_class->delete_event = gtk_handle_box_delete_event; container_class->add = gtk_handle_box_add; container_class->remove = gtk_handle_box_remove; class->child_attached = NULL; class->child_detached = NULL;}static voidgtk_handle_box_init (GtkHandleBox *handle_box){ GTK_WIDGET_UNSET_FLAGS (handle_box, GTK_NO_WINDOW); handle_box->bin_window = NULL; handle_box->float_window = NULL; handle_box->shadow_type = GTK_SHADOW_OUT; handle_box->handle_position = GTK_POS_LEFT; handle_box->float_window_mapped = FALSE; handle_box->child_detached = FALSE; handle_box->in_drag = FALSE; handle_box->shrink_on_detach = TRUE; handle_box->snap_edge = -1;}static voidgtk_handle_box_set_arg (GtkObject *object, GtkArg *arg, guint arg_id){ GtkHandleBox *handle_box = GTK_HANDLE_BOX (object); switch (arg_id) { case ARG_SHADOW: gtk_handle_box_set_shadow_type (handle_box, GTK_VALUE_ENUM (*arg)); break; case ARG_HANDLE_POSITION: gtk_handle_box_set_handle_position (handle_box, GTK_VALUE_ENUM (*arg)); break; case ARG_SNAP_EDGE: gtk_handle_box_set_snap_edge (handle_box, GTK_VALUE_ENUM (*arg)); break; }}static voidgtk_handle_box_get_arg (GtkObject *object, GtkArg *arg, guint arg_id){ GtkHandleBox *handle_box = GTK_HANDLE_BOX (object); switch (arg_id) { case ARG_SHADOW: GTK_VALUE_ENUM (*arg) = handle_box->shadow_type; break; case ARG_HANDLE_POSITION: GTK_VALUE_ENUM (*arg) = handle_box->handle_position; break; case ARG_SNAP_EDGE: GTK_VALUE_ENUM (*arg) = handle_box->snap_edge; break; default: arg->type = GTK_TYPE_INVALID; break; }} GtkWidget*gtk_handle_box_new (void){ return GTK_WIDGET (gtk_type_new (gtk_handle_box_get_type ()));}static voidgtk_handle_box_destroy (GtkObject *object){ GtkHandleBox *hb; g_return_if_fail (object != NULL); g_return_if_fail (GTK_IS_HANDLE_BOX (object)); hb = GTK_HANDLE_BOX (object); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);}static voidgtk_handle_box_map (GtkWidget *widget){ GtkBin *bin; GtkHandleBox *hb; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_HANDLE_BOX (widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); bin = GTK_BIN (widget); hb = GTK_HANDLE_BOX (widget); if (bin->child && GTK_WIDGET_VISIBLE (bin->child) && !GTK_WIDGET_MAPPED (bin->child)) gtk_widget_map (bin->child); if (hb->child_detached && !hb->float_window_mapped) { gdk_window_show (hb->float_window); hb->float_window_mapped = TRUE; } gdk_window_show (hb->bin_window); gdk_window_show (widget->window);}static voidgtk_handle_box_unmap (GtkWidget *widget){ GtkHandleBox *hb; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_HANDLE_BOX (widget)); GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); hb = GTK_HANDLE_BOX (widget); gdk_window_hide (widget->window); if (hb->float_window_mapped) { gdk_window_hide (hb->float_window); hb->float_window_mapped = FALSE; }}static voidgtk_handle_box_realize (GtkWidget *widget){ GdkWindowAttr attributes; gint attributes_mask; GtkHandleBox *hb; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_HANDLE_BOX (widget)); hb = GTK_HANDLE_BOX (widget); GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.window_type = GDK_WINDOW_CHILD; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (widget->window, widget); attributes.x = 0; attributes.y = 0; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.window_type = GDK_WINDOW_CHILD; attributes.event_mask |= (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_BUTTON1_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; hb->bin_window = gdk_window_new (widget->window, &attributes, attributes_mask); gdk_window_set_user_data (hb->bin_window, widget); if (GTK_BIN (hb)->child) gtk_widget_set_parent_window (GTK_BIN (hb)->child, hb->bin_window); attributes.x = 0; attributes.y = 0; attributes.width = widget->requisition.width; attributes.height = widget->requisition.height; attributes.window_type = GDK_WINDOW_TOPLEVEL; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes.event_mask = (gtk_widget_get_events (widget) | GDK_KEY_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; hb->float_window = gdk_window_new (NULL, &attributes, attributes_mask); gdk_window_set_user_data (hb->float_window, widget); gdk_window_set_decorations (hb->float_window, 0); widget->style = gtk_style_attach (widget->style, widget->window); gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (hb)); gtk_style_set_background (widget->style, hb->bin_window, GTK_WIDGET_STATE (hb)); gtk_style_set_background (widget->style, hb->float_window, GTK_WIDGET_STATE (hb)); gdk_window_set_back_pixmap (widget->window, NULL, TRUE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -