📄 dw_viewport.c
字号:
/* * File: dw_viewport.c * * Copyright (C) 2001-2003 Sebastian Geerken <S.Geerken@ping.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */#include "dillo.h"#include "edillo.h"#include "msg.h"#include "dw_viewport.h"#include "dw_container.h"#include "list.h"#define DEBUG_LEVEL 10#include "debug.h"#include "msg.h"typedef struct{ gchar* name; DwWidget *widget; gint32 y;} DwViewportAnchor;/********************** * * * public functions * * * **********************/DwViewport* a_Dw_viewport_new (HWND hwnd){ RECT rc; DwViewport* viewport = g_new0 (DwViewport, 1); viewport->hwnd = hwnd; GetClientRect (hwnd, &rc); viewport->allocation.x = rc.left; viewport->allocation.y = rc.top; viewport->allocation.width = rc.right; viewport->allocation.height = rc.bottom; viewport->anchors_table = g_hash_table_new (g_str_hash, g_str_equal); viewport->draw_areas = NULL; viewport->num_draw_areas = 0; viewport->num_draw_areas_max = 4; return viewport;}static gboolean Dw_viewport_destroy_anchor (gpointer key, gpointer value, gpointer user_data){ g_free (value); return TRUE;}void a_Dw_viewport_destroy (DwViewport* viewport){ g_hash_table_foreach_remove (viewport->anchors_table, Dw_viewport_destroy_anchor, NULL); g_hash_table_destroy (viewport->anchors_table); Dw_viewport_remove_anchor (viewport); viewport->num_draw_areas = 0; g_free (viewport->draw_areas); g_free (viewport);}/* * Used by Dw_viewport_calc_size. */static void Dw_viewport_calc_child_size (DwViewport *viewport, gint32 child_width, gint32 child_height, DwRequisition *child_requisition){ if (child_width < 0) child_width = 0; if (child_height < 0) child_height = 0; DEBUG_MSG (2, " width = %d, height = %d ...\n", child_width, child_height); a_Dw_widget_set_width (viewport->child, child_width); a_Dw_widget_set_ascent (viewport->child, child_height); a_Dw_widget_set_descent (viewport->child, 0); a_Dw_widget_size_request (viewport->child, child_requisition);}static void Dw_viewport_set_scrollbars (DwViewport* viewport, gint32 width, gint32 height){ SCROLLINFO si; if (width <= viewport->allocation.width) { SetScrollPos (viewport->hwnd, SB_HORZ, 0); EnableScrollBar (viewport->hwnd, SB_HORZ, FALSE); } else { si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMax = width; si.nMin = 0; si.nPage = viewport->allocation.width; si.nPos = viewport->world_x; EnableScrollBar (viewport->hwnd, SB_HORZ, TRUE); SetScrollInfo (viewport->hwnd, SB_HORZ, &si, TRUE); } if (height <= viewport->allocation.height) { SetScrollPos (viewport->hwnd, SB_VERT, 0); EnableScrollBar (viewport->hwnd, SB_VERT, FALSE); } else { si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMax = height; si.nMin = 0; si.nPage = viewport->allocation.height; si.nPos = viewport->world_y; EnableScrollBar (viewport->hwnd, SB_VERT, TRUE); SetScrollInfo (viewport->hwnd, SB_VERT, &si, TRUE); }}/* * 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_viewport_calc_size (DwViewport *viewport){ RECT rc_viewport; DwRequisition child_requisition; DwAllocation child_allocation; gint max_width, max_height; if (viewport->calc_size_blocked) return; viewport->calc_size_blocked = TRUE; if (viewport->child) { /* * Determine the size hints for the Dw widget. This is a bit * tricky, because you must know if scrollbars are visible or * not, which depends on the size of the Dw widget, which then * depends on the hints. The idea is to test several * configurations, there are four of them, from combining the * cases horizontal/vertical scrollbar visible/invisible. * * For optimization, the horizontal scrollbar is currently not * regarded, the height hint is always the same, as if the * scrollbar was allways visible. In future, this may be * implemented correctly, by using the minimal width to optimize * most cases. (Minimal widths will also be used by tables.) * * Furthermore, the last result (vertical scrollbar visible or * not) is stored in the viewport, and tested first. This will * make a second test only necessary when the visibility * switches, which normally happens only once when filling the * page with text. (Actually, this assumes that the page size is * always *growing*, but this is nevertheless true in dillo.) */ max_width = viewport->allocation.width; max_height = viewport->allocation.height; DEBUG_MSG (2, "------------------------------------------------->\n"); DEBUG_MSG (2, "Dw_viewport_calc_size: %d x %d -> %d x %d\n", viewport->allocation.width, viewport->allocation.height, max_width, max_height); Dw_viewport_calc_child_size (viewport, max_width, max_height, &child_requisition); child_allocation.x = 0; child_allocation.y = 0; child_allocation.width = child_requisition.width; child_allocation.ascent = child_requisition.ascent; child_allocation.descent = child_requisition.descent; a_Dw_widget_size_allocate (viewport->child, &child_allocation); DEBUG_MSG (1, "Setting size to %d x %d\n", child_requisition.width, child_requisition.ascent + child_requisition.descent); DEBUG_MSG (2, "<-------------------------------------------------\n"); Dw_viewport_set_scrollbars (viewport, child_allocation.width, child_requisition.ascent + child_requisition.descent); GetClientRect (viewport->hwnd, &rc_viewport); rc_viewport.left = child_allocation.width; rc_viewport.top = child_requisition.ascent + child_requisition.descent; if (rc_viewport.left < rc_viewport.right && rc_viewport.top < rc_viewport.bottom) InvalidateRect (viewport->hwnd, &rc_viewport, TRUE); } else { viewport->hscrollbar_used = FALSE; viewport->vscrollbar_used = FALSE; InvalidateRect (viewport->hwnd, NULL, TRUE); } Dw_viewport_update_anchor (viewport); viewport->calc_size_blocked = FALSE;}/* * Set the top-level Dw widget. * If there is already one, you must destroy it before, otherwise the * function will fail. */void a_Dw_viewport_add_dw (DwViewport *viewport, DwWidget *widget){ if (viewport->child != NULL) g_signal_emit_by_name (G_OBJECT(viewport->child), "destroy", 0); viewport->world_x = viewport->world_y = 0; viewport->child = widget; DBG_OBJ_ASSOC(widget, viewport); widget->parent = NULL; widget->viewport = viewport;#if 0 widget->window = viewport->back_pixmap;#endif a_Dw_widget_realize (widget); Dw_viewport_calc_size (viewport); Dw_viewport_remove_anchor (viewport);}/************************************************** * * * Functions used by DwViewport and DwWidget * * * **************************************************//* * This function only *recognizes* that the top-level Dw widget is to * be removed. It is called by Dw_widget_destroy. * Don't use this function directly! */void Dw_viewport_remove_dw (DwViewport *viewport){ /* Test, that all anchors have been removed properly. */ gint num_anchors_left = g_hash_table_size (viewport->anchors_table); /* g_assert (num_anchors_left == 0); */ if (num_anchors_left != 0) g_warning ("%d anchors left", num_anchors_left); Dw_viewport_remove_anchor (viewport); viewport->child = NULL; Dw_viewport_calc_size (viewport);}/* used by Dw_viewport_widget_at_point */typedef struct{ gint32 x; gint32 y; DwWidget *widget;} WidgetAtPointData;/* used by Dw_viewport_widget_at_point */static void Dw_viewport_widget_at_point_callback (DwWidget *widget, gpointer data){ WidgetAtPointData *callback_data; callback_data = (WidgetAtPointData*) data; DEBUG_MSG (1, " Checking %p ...\n", widget); if (/* As a special exception, for the top-level widget, not the * allocation is regarded, but the whole viewport. This makes * selections more useful, since so the user can start the * selection outside of the allocation. */ widget->parent == NULL || /* Otherwise, check whether pointer is in the allocation. */ (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 + DW_WIDGET_HEIGHT(widget))) { DEBUG_MSG (1, " yes\n"); if (DW_IS_CONTAINER (widget)) a_Dw_container_forall (DW_CONTAINER (widget), Dw_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_viewport_widget_at_point (DwViewport *viewport, gint32 x, gint32 y){ WidgetAtPointData callback_data; callback_data.x = x; callback_data.y = y; callback_data.widget = NULL; if (viewport->child) Dw_viewport_widget_at_point_callback (viewport->child, &callback_data); return callback_data.widget;}/************* * * * Anchors * * * *************//* * todo: Currently, no horizontal scrolling is done. This is generally * possible, DW_HPOS_INTO_VIEW should be used for this, but it is * rather complicated to determine the width of an anchor. This would * be the lenght of the region between <a> and </a>, the page widget * would have to have two kinds of content types (opening and closing * anchor), and some changes in the HTML parser are necessary. *//* * Add an anchor, and assign a position for it. For all widgets * directly or indirectly assigned to a viewports, anchors must be * unique, this is tested. "name" is copied, so no strdup is * neccessary for the caller. * * Return the copy on success, or NULL, when this anchor had already * been added to the widget tree. * * The viewport gets the responsibility to free "name". */gchar* p_Dw_viewport_add_anchor (DwWidget *widget, const gchar *name, gint32 y){ DwViewport *viewport; DwViewportAnchor *anchor; _MSG("new anchor %p/'%s' -> %d\n", widget, name, y); g_return_val_if_fail (widget->viewport != NULL, NULL); viewport = DW_VIEWPORT (widget->viewport); if (g_hash_table_lookup_extended (viewport->anchors_table, name,NULL,NULL)) /* Anchor does already exist. */ return NULL; else { anchor = g_new (DwViewportAnchor, 1); anchor->name = g_strdup (name); anchor->widget = widget; anchor->y = y; g_hash_table_insert (viewport->anchors_table, anchor->name, anchor); Dw_viewport_update_anchor (viewport);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -