📄 dw_gtk_viewport.c
字号:
* Most is done in a_Dw_widget_mouse_event. */static gint Dw_gtk_viewport_mouse_event(GtkWidget * widget, gint32 x, gint32 y, GdkEvent * event){ GtkDwViewport *viewport; DwWidget *dw_widget; gint32 world_x, world_y; viewport = GTK_DW_VIEWPORT(widget); if (viewport->child) { world_x = x + gtk_layout_get_hadjustment(GTK_LAYOUT(viewport))->value; world_y = y + gtk_layout_get_vadjustment(GTK_LAYOUT(viewport))->value; dw_widget = Dw_gtk_viewport_widget_at_point(viewport, world_x, world_y); return Dw_widget_mouse_event(dw_widget, widget, world_x, world_y, event); } return FALSE;}/* * Standard Gtk+ function */static gint Dw_gtk_viewport_button_press(GtkWidget * widget, GdkEventButton * event){ return Dw_gtk_viewport_mouse_event(widget, event->x, event->y, (GdkEvent *) event);}/* * Standard Gtk+ function */static gint Dw_gtk_viewport_button_release(GtkWidget * widget, GdkEventButton * event){ return Dw_gtk_viewport_mouse_event(widget, event->x, event->y, (GdkEvent *) event);}/* * Standard Gtk+ function */static gint Dw_gtk_viewport_motion_notify(GtkWidget * widget, GdkEventMotion * event){ GtkDwViewport *viewport = GTK_DW_VIEWPORT(widget); viewport->mouse_x = event->x; viewport->mouse_y = event->y; return Dw_gtk_viewport_mouse_event(widget, event->x, event->y, (GdkEvent *) event);}/* * Standard Gtk+ function */static gint Dw_gtk_viewport_enter_notify(GtkWidget * widget, GdkEventCrossing * event){ return Dw_gtk_viewport_mouse_event(widget, event->x, event->y, NULL);}/* * Standard Gtk+ function */static gint Dw_gtk_viewport_leave_notify(GtkWidget * widget, GdkEventCrossing * event){ /* There will anyway be no Dw widget, thus this simple call */ return Dw_widget_mouse_event(NULL, widget, 0, 0, NULL);}/* * This function is called when the viewport changes, and causes * motion_notify events to be simulated. */static void Dw_gtk_viewport_adj_changed(GtkAdjustment * adj, GtkDwViewport * viewport){ Dw_gtk_viewport_mouse_event(GTK_WIDGET(viewport), viewport->mouse_x, viewport->mouse_y, NULL);}/********************** * * * public functions * * * **********************//* * Set the top-level Dw widget. * If there is already one, you must destroy it before, otherwise the * function will fail. */void a_Dw_gtk_viewport_add_dw(GtkDwViewport * viewport, DwWidget * widget){ g_return_if_fail(viewport->child == NULL); viewport->child = widget; widget->parent = NULL; widget->viewport = GTK_WIDGET(viewport); widget->window = GTK_LAYOUT(viewport)->bin_window; if (GTK_WIDGET_REALIZED(viewport)) a_Dw_widget_realize(widget); Dw_gtk_viewport_calc_size(viewport); a_Dw_gtk_viewport_set_anchor(viewport, viewport->queued_anchor); a_Dw_gtk_viewport_queue_anchor(viewport, NULL);}/************************************************** * * * Functions used by GtkDwViewport and DwWidget * * * **************************************************//* * This function only *recognizes* that the top-level Dw widget is to * be removed. It is called by Dw_widget_shutdown. * Don't use this function directly! */void Dw_gtk_viewport_remove_dw(GtkDwViewport * viewport){ viewport->child = NULL; Dw_gtk_viewport_remove_anchor(viewport); Dw_gtk_viewport_calc_size(viewport);}/* * Calculate the size of the scrolled area and allocate the top-level * widget. This function is called when the top-level Dw widget has * changed its size etc. */void Dw_gtk_viewport_calc_size(GtkDwViewport * viewport){ DwRequisition requisition; DwAllocation allocation; gint border_width; if (viewport->child) { border_width = GTK_CONTAINER(viewport)->border_width; a_Dw_widget_size_request(viewport->child, &requisition); allocation.x = border_width; allocation.y = border_width; allocation.width = requisition.width; allocation.ascent = requisition.ascent; allocation.descent = requisition.descent; a_Dw_widget_size_allocate(viewport->child, &allocation); gtk_layout_set_size(GTK_LAYOUT(viewport), requisition.width + 2 * border_width, requisition.ascent + requisition.descent + 2 * border_width); } else gtk_layout_set_size(GTK_LAYOUT(viewport), 1, 1); Dw_gtk_viewport_update_anchor(viewport); gtk_widget_queue_draw(GTK_WIDGET(viewport));}/* used by Dw_gtk_viewport_widget_at_point */typedef struct { gint32 x; gint32 y; DwWidget *widget;} WidgetAtPointData;/* used by Dw_gtk_viewport_widget_at_point */static void Dw_gtk_viewport_widget_at_point_callback(DwWidget * widget, gpointer data){ WidgetAtPointData *callback_data; callback_data = (WidgetAtPointData *) data; if (callback_data->x >= widget->allocation.x && callback_data->y >= widget->allocation.y && callback_data->x < widget->allocation.x + widget->allocation.width && callback_data->y < widget->allocation.y + (widget->allocation.ascent + widget->allocation.descent)) { if (DW_IS_CONTAINER(widget)) a_Dw_container_forall(DW_CONTAINER(widget), Dw_gtk_viewport_widget_at_point_callback, data); if (callback_data->widget == NULL) callback_data->widget = widget; }}/* * Return the widget at point (x, y) (world coordinates). */DwWidget *Dw_gtk_viewport_widget_at_point(GtkDwViewport * viewport, gint32 x, gint32 y){ WidgetAtPointData callback_data; callback_data.x = x; callback_data.y = y; callback_data.widget = NULL; if (viewport->child) Dw_gtk_viewport_widget_at_point_callback(viewport->child, &callback_data); return callback_data.widget;}/************* * * * Anchors * * * *************//* * See Dw_gtk_viewport_scroll_to. */static gint Dw_gtk_viewport_update_anchor_idle(gpointer data){ GtkDwViewport *viewport; GtkAdjustment *adj; viewport = GTK_DW_VIEWPORT(data); adj = GTK_LAYOUT(viewport)->vadjustment; if (viewport->anchor_y > adj->upper - adj->page_size) gtk_adjustment_set_value(adj, adj->upper - adj->page_size); else gtk_adjustment_set_value(adj, viewport->anchor_y); viewport->anchor_idle_id = -1; return FALSE;}/* * Called by Dw_gtk_viewport_update_anchor. */static void Dw_gtk_viewport_update_anchor_rec(DwWidget * widget){ gpointer p; GtkDwViewport *viewport; viewport = GTK_DW_VIEWPORT(widget->viewport); if (widget->anchors_table && (p = g_hash_table_lookup(widget->anchors_table, viewport->anchor))) Dw_gtk_viewport_scroll_to(viewport, *(gint *) p + widget->allocation.y); else { if (DW_IS_CONTAINER(widget)) a_Dw_container_forall(DW_CONTAINER(widget), (DwCallback) Dw_gtk_viewport_update_anchor_rec, NULL); }}/* * Called when possibly the scroll position has to be changed because * of anchors. */void Dw_gtk_viewport_update_anchor(GtkDwViewport * viewport){ if (viewport->anchor && viewport->child) Dw_gtk_viewport_update_anchor_rec(viewport->child);}/* * Sets the anchor to scroll to. */void a_Dw_gtk_viewport_set_anchor(GtkDwViewport * viewport, gchar * anchor){ Dw_gtk_viewport_remove_anchor(viewport); if (anchor) { viewport->anchor = g_strdup(anchor); Dw_gtk_viewport_update_anchor(viewport); } else { viewport->anchor = NULL; gtk_adjustment_set_value(GTK_LAYOUT(viewport)->vadjustment, 0); }}/* * Set anchor for *next* DwWidget. This will be the anchor for the * next added Dw widget. * todo: Should this perhaps better implemented by a modified url * passing scheme? */void a_Dw_gtk_viewport_queue_anchor(GtkDwViewport * viewport, gchar * anchor){ if (viewport->queued_anchor) g_free(viewport->queued_anchor); if (anchor) viewport->queued_anchor = g_strdup(anchor); else viewport->queued_anchor = NULL;}/* * Scrolls the viewport to position y. * This is done in an idle function. */void Dw_gtk_viewport_scroll_to(GtkDwViewport * viewport, gint32 y){ viewport->anchor_y = y; if (viewport->anchor_idle_id == -1) viewport->anchor_idle_id = gtk_idle_add(Dw_gtk_viewport_update_anchor_idle, (gpointer) viewport);}/* * Remove anchor and idle function. */void Dw_gtk_viewport_remove_anchor(GtkDwViewport * viewport){ if (viewport->anchor) { g_free(viewport->anchor); viewport->anchor = NULL; } if (viewport->anchor_idle_id != -1) { gtk_idle_remove(viewport->anchor_idle_id); viewport->anchor_idle_id = -1; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -