📄 dw_gtk_viewport.c
字号:
gpointer tmp_anchor; viewport = GTK_DW_VIEWPORT (widget->viewport); _MSG(" name(%p)=[%s]\n", name, name); if (g_hash_table_lookup_extended (viewport->anchors_table, name, NULL, &tmp_anchor)) { anchor = tmp_anchor; } else { anchor = g_new (GtkDwViewportAnchor, 1); g_hash_table_insert (viewport->anchors_table, name, anchor); } anchor->widget = widget; anchor->y = y; Dw_gtk_viewport_update_anchor (viewport);}/* * Used by Dw_gtk_viewport_update_anchor_idle. */static gboolean Dw_gtk_viewport_calc_into (gint32 requested_value, gint32 requested_size, gint32 current_value, gint32 size, gint32 *return_value){ if (requested_size > size) { /* The viewport size is smaller than the size of the region which will * be shown. If the region is already visible, do not change the * position. Otherwise, show the left/upper border, this is most likely * what is needed. */ if (current_value >= requested_value && current_value + size < requested_value + requested_size) return FALSE; else requested_size = size; } if (requested_value < current_value) { *return_value = requested_value; return TRUE; } else if (requested_value + requested_size > current_value + size) { *return_value = requested_value - size + requested_size; return TRUE; } else return FALSE;}/* * See Dw_gtk_viewport_scroll_to. */static gint Dw_gtk_viewport_update_anchor_idle (gpointer data){ gint32 vp_width, vp_height, x = 0, y = 0; GtkScrolledWindow *scrolled; GtkDwViewport *viewport; GtkWidget *vwidget; GtkAdjustment *vadj, *hadj; gboolean change_x, change_y; DBG_MSG (data, "scrolling", 0, "Dw_gtk_viewport_update_anchor_idle"); DBG_MSG_START (data); vwidget = GTK_WIDGET (data); viewport = GTK_DW_VIEWPORT (vwidget); scrolled = GTK_SCROLLED_WINDOW (vwidget->parent->parent); hadj = GTK_LAYOUT(viewport)->hadjustment; vadj = GTK_LAYOUT(viewport)->vadjustment; vp_width = vwidget->allocation.width - GTK_CONTAINER(viewport)->border_width; vp_height = vwidget->allocation.height - GTK_CONTAINER(viewport)->border_width; DBG_MSGF (viewport, "scrolling", 0, "vp_width = %d", vp_width); DBG_MSGF (viewport, "scrolling", 0, "vp_height = %d", vp_height); change_x = TRUE; switch (viewport->anchor_pos.hpos) { case DW_HPOS_LEFT: DBG_MSG (viewport, "scrolling", 0, "DW_HPOS_LEFT"); x = viewport->anchor_pos.x; break; case DW_HPOS_CENTER: DBG_MSG (viewport, "scrolling", 0, "DW_HPOS_CENTER"); x = viewport->anchor_pos.x - (vp_width - viewport->anchor_pos.width) / 2; break; case DW_HPOS_RIGHT: DBG_MSG (viewport, "scrolling", 0, "DW_HPOS_RIGHT"); x = viewport->anchor_pos.x - (vp_width - viewport->anchor_pos.width); break; case DW_HPOS_INTO_VIEW: DBG_MSG (viewport, "scrolling", 0, "DW_HPOS_INTO_VIEW"); change_x = Dw_gtk_viewport_calc_into (viewport->anchor_pos.x, viewport->anchor_pos.width, hadj->value, vp_width, &x); break; case DW_HPOS_NO_CHANGE: DBG_MSG (viewport, "scrolling", 0, "DW_HPOS_NO_CHANGE"); change_x = FALSE; break; } change_y = TRUE; switch (viewport->anchor_pos.vpos) { case DW_VPOS_TOP: DBG_MSG (viewport, "scrolling", 0, "DW_VPOS_TOP"); y = viewport->anchor_pos.y; break; case DW_VPOS_CENTER: DBG_MSG (viewport, "scrolling", 0, "DW_VPOS_CENTER"); y = viewport->anchor_pos.y - (vp_height - viewport->anchor_pos.height) / 2; break; case DW_VPOS_BOTTOM: DBG_MSG (viewport, "scrolling", 0, "DW_VPOS_BOTTOM"); y = viewport->anchor_pos.y - (vp_height - viewport->anchor_pos.height); break; case DW_VPOS_INTO_VIEW: DBG_MSG (viewport, "scrolling", 0, "DW_VPOS_INTO_VIEW"); change_y = Dw_gtk_viewport_calc_into (viewport->anchor_pos.y, viewport->anchor_pos.height, vadj->value, vp_height, &y); case DW_VPOS_NO_CHANGE: DBG_MSG (viewport, "scrolling", 0, "DW_VPOS_NO_CHANGE"); change_y = FALSE; break; } DBG_MSGF (viewport, "scrolling", 0, "scrolling to (%d, %d)\n", x, y); DBG_MSGF (viewport, "scrolling", 0, "hadj->upper = %g, hadj->page_size = %g", hadj->upper, hadj->page_size); DBG_MSGF (viewport, "scrolling", 0, "vadj->upper = %g, vadj->page_size = %g", vadj->upper, vadj->page_size); if (change_x) { if (x > hadj->upper - hadj->page_size) gtk_adjustment_set_value (hadj, hadj->upper - hadj->page_size); else gtk_adjustment_set_value (hadj, x); } if (change_y) { if (y > vadj->upper - vadj->page_size) gtk_adjustment_set_value (vadj, vadj->upper - vadj->page_size); else gtk_adjustment_set_value (vadj, y); } viewport->anchor_idle_id = 0; DBG_MSG_END (viewport); return FALSE;}/* * Called when possibly the scroll position has to be changed because * of anchors. */void Dw_gtk_viewport_update_anchor (GtkDwViewport *viewport){ GtkDwViewportAnchor *anchor; gpointer tmp_anchor; if (viewport->anchor && g_hash_table_lookup_extended (viewport->anchors_table, viewport->anchor, NULL, &tmp_anchor)) { anchor = tmp_anchor; Dw_gtk_viewport_scroll_to (viewport, DW_HPOS_NO_CHANGE, DW_VPOS_TOP, 0, anchor->y + anchor->widget->allocation.y, 0, 0); }}/* * Sets the anchor to scroll to. */void a_Dw_gtk_viewport_set_anchor (GtkDwViewport *viewport, const 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); }}/* * Sets the position to scroll to. The current anchor will be removed. */void a_Dw_gtk_viewport_set_scrolling_position (GtkDwViewport *viewport, gint32 x, gint32 y){ Dw_gtk_viewport_remove_anchor (viewport); Dw_gtk_viewport_scroll_to (viewport, DW_HPOS_LEFT, DW_VPOS_TOP, x, y, 0, 0);}/* * Scrolls the viewport, so that the region [x, y, width, height] (world * coordinates) is seen, according to hpos and vpos. * * The actual scrolling is done in an idle function. */void Dw_gtk_viewport_scroll_to (GtkDwViewport *viewport, DwHPosition hpos, DwVPosition vpos, gint32 x, gint32 y, gint32 width, gint32 height){ viewport->anchor_pos.hpos = hpos; viewport->anchor_pos.vpos = vpos; viewport->anchor_pos.x = x; viewport->anchor_pos.y = y; viewport->anchor_pos.width = width; viewport->anchor_pos.height = height; DBG_OBJ_SET_NUM (viewport, "anchor_pos.hpos", viewport->anchor_pos.hpos); DBG_OBJ_SET_NUM (viewport, "anchor_pos.vpos", viewport->anchor_pos.vpos); DBG_OBJ_SET_NUM (viewport, "anchor_pos.x", viewport->anchor_pos.x); DBG_OBJ_SET_NUM (viewport, "anchor_pos.y", viewport->anchor_pos.y); DBG_OBJ_SET_NUM (viewport, "anchor_pos.width", viewport->anchor_pos.width); DBG_OBJ_SET_NUM (viewport, "anchor_pos.height", viewport->anchor_pos.height); if (viewport->anchor_idle_id == 0) 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 != 0) { gtk_idle_remove (viewport->anchor_idle_id); viewport->anchor_idle_id = 0; }}/* * Drawing and resizing is done in this idle function. */static gint Dw_gtk_viewport_draw_resize_idle (gpointer data){ GtkDwViewport *viewport; GtkLayout *layout; GtkWidget *widget; DwRectangle viewport_area, world_area; GdkRectangle gtk_area; int i; viewport = GTK_DW_VIEWPORT (data); switch (viewport->draw_resize_action) { case DW_GTK_VIEWPORT_DRAW: for (i = 0; i < viewport->num_draw_areas; i++) { widget = GTK_WIDGET (viewport); layout = GTK_LAYOUT (viewport); viewport_area.x = gtk_layout_get_hadjustment(layout)->value; viewport_area.y = gtk_layout_get_vadjustment(layout)->value;; viewport_area.width = widget->allocation.width; viewport_area.height = widget->allocation.height; if (p_Dw_rectangle_intersect (&viewport->draw_areas[i], &viewport_area, &world_area)) { gtk_area.x = world_area.x - viewport_area.x; gtk_area.y = world_area.y - viewport_area.y; gtk_area.width = world_area.width; gtk_area.height = world_area.height; gtk_widget_draw (widget, >k_area); } } /* No more areas to be drawn. */ viewport->num_draw_areas = 0; break; case DW_GTK_VIEWPORT_RESIZE: Dw_gtk_viewport_calc_size (viewport); break; } viewport->draw_resize_idle_id = 0; return FALSE;}/* * Queue an area for drawing. This function is called by * p_Dw_widget_queue_draw_area. x and y are passed in world coordinates. */void Dw_gtk_viewport_queue_draw (GtkDwViewport *viewport, gint32 x, gint32 y, gint32 width, gint32 height){ DwRectangle area; int i; if (viewport->draw_resize_idle_id == 0) { viewport->draw_resize_action = DW_GTK_VIEWPORT_DRAW; viewport->draw_resize_idle_id = gtk_idle_add (Dw_gtk_viewport_draw_resize_idle, (gpointer)viewport); } else if (viewport->draw_resize_action == DW_GTK_VIEWPORT_RESIZE) /* Drawing is always overridden by resizing. */ return; area.x = x; area.y = y; area.width = width; area.height = height; /* First, try to keep the list as clean as possible. Check whether other * rectangles interfer with this one in some way. */ /* An idea for optimization: The list could be sorted, and so the part of * the list we have to consider here, may be reduced, the start may be * found via linear search. However, this probably makes balanced binary * trees necessary, since moving elements within the array may be quite * time-consuming. */ _MSG(" num_draw_areas = %d\n", viewport->num_draw_areas); for (i = 0; i < viewport->num_draw_areas; i++) { if (p_Dw_rectangle_is_subset (&area, &viewport->draw_areas[i])) /* First case: area is a subset of an already queued rectangle * -> nothing to do. */ return; else if (p_Dw_rectangle_is_subset (&viewport->draw_areas[i], &area)) { /* Second case: area is a subset of an already queued rectangle * -> replace the other one with area. */ viewport->draw_areas[i] = area; return; } /* Maybe some more tests: if both areas may exactly be combined to a * rectangle? Very unlikely case ... */ } /* No interference: add the new area to the list. */ viewport->num_draw_areas++; a_List_add (viewport->draw_areas, viewport->num_draw_areas, viewport->num_draw_areas_max); viewport->draw_areas[viewport->num_draw_areas - 1] = area;}/* * Start the resizing idle. This function is called by * p_Dw_widget_queue_resize, after the appropriate attributes have been set in * the widgets, where necessary. */void Dw_gtk_viewport_queue_resize (GtkDwViewport *viewport){ /* Resizing always overrides drawing. */ viewport->draw_resize_action = DW_GTK_VIEWPORT_RESIZE; viewport->num_draw_areas = 0; if (viewport->draw_resize_idle_id == 0) viewport->draw_resize_idle_id = gtk_idle_add (Dw_gtk_viewport_draw_resize_idle, (gpointer)viewport);}/* * Return the DwWidget which is at position (vx, vy) in viewport coordinates. */DwWidget* a_Dw_gtk_viewport_widget_at_viewport_point (GtkDwViewport *viewport, gint32 vx, gint32 vy){ gint32 world_x, world_y; if (viewport->child) { world_x = vx + gtk_layout_get_hadjustment(GTK_LAYOUT(viewport))->value; world_y = vy + gtk_layout_get_vadjustment(GTK_LAYOUT(viewport))->value; return Dw_gtk_viewport_widget_at_point (viewport, world_x, world_y); } else return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -