📄 dw_page.c
字号:
/* * File: dw_page.c * * Copyright (C) 1997 Raph Levien <raph@acm.org> * Copyright (C) 1999 Luca Rota <drake@freemail.it> * * 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. *//* * This module contains the Dw_page widget, which is the "back end" to * Web text widgets including html. */#define TRACE_GTK_METHODS#undef NO_WINDOW#define HUGE_WINDOW#define DW_PAGE_MAX_WINDOW_SIZE 32760#include <ctype.h>#include <string.h>#include <stdio.h>#include <gtk/gtk.h>#include "list.h"#include "dw_page.h"static void Dw_page_init(DwPage * page);static void Dw_page_class_init(DwPageClass * klass);static void Dw_page_destroy(GtkObject * object);static void Dw_page_size_request(DwWidget * widget, DwRequisition * requisition);static void Dw_page_size_allocate(DwWidget * widget, DwAllocation * allocation);static void Dw_page_set_width(DwWidget * widget, gint32 width);static void Dw_page_set_ascent(DwWidget * widget, gint32 ascent);static void Dw_page_set_descent(DwWidget * widget, gint32 descent);static void Dw_page_draw(DwWidget * page, DwRectangle * area, GdkEventExpose * event);static void Dw_page_realize(DwWidget * widget);static void Dw_page_unrealize(DwWidget * widget);static gint Dw_page_button_press(DwWidget * widget, gint32 x, gint32 y, GdkEventButton * event);static gint Dw_page_button_release(DwWidget * widget, gint32 x, gint32 y, GdkEventButton * event);static gint Dw_page_motion_notify(DwWidget * widget, gint32 x, gint32 y, GdkEventMotion * event);static void Dw_page_add(DwContainer * container, DwWidget * widget);static void Dw_page_remove(DwContainer * container, DwWidget * widget);static void Dw_page_forall(DwContainer * container, DwCallback callback, gpointer callback_data);static void Dw_page_real_link_entered(DwPage * page, const char *url);static void Dw_page_rewrap(DwPage * page);static gint Dw_page_line_x_offset(DwPage * page, DwPageLine * line);enum { LINK_ENTERED, LINK_PRESSED, LINK_RELEASED, LINK_CLICKED, LAST_SIGNAL};static DwContainerClass *parent_class;static guint page_signals[LAST_SIGNAL] = { 0 };/* * Return the type of DwPage */GtkType a_Dw_page_get_type(void){ static GtkType type = 0; if (!type) { GtkTypeInfo info = { "DwPage", sizeof(DwPage), sizeof(DwPageClass), (GtkClassInitFunc) Dw_page_class_init, (GtkObjectInitFunc) Dw_page_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL, }; type = gtk_type_unique(DW_TYPE_CONTAINER, &info); } return type;}/* * Create a new DwPage */DwWidget *a_Dw_page_new(void){ GtkObject *object; object = gtk_object_new(DW_TYPE_PAGE, NULL); return DW_WIDGET(object);}/* * Initialize a DwPage */static void Dw_page_init(DwPage * page){ page->num_lines_max = 16; page->num_lines = 0; page->lines = g_new(DwPageLine, page->num_lines_max); page->num_words_max = 512; page->num_words = 0; page->current_word = 0; page->words = g_new(DwPageWord, page->num_words_max); page->num_links_max = 16; page->num_links = 0; page->links = g_new(DwPageLink, page->num_links_max); page->last_line_max_width = 0; page->hover_link = -1; /* end stuff from gtk_page_init. */ page->link_color = 0x0000ff; /* blue */ page->visited_color = 0x736f6e; /* gray */ page->bgnd_color = 0xffffff; /* white */ page->x_click = -1; page->current_map = 0; page->num_shapes = 0; page->num_shapes_max = 8; /* not a critical value */ page->shapes = g_new(DwPageShape, page->num_shapes_max); /* random values */ page->avail_width = 100; page->avail_ascent = 100; page->avail_descent = 0; page->wrapped_width = 100; /* todo: ??? */ page->wrapped_ascent = 100; page->wrapped_descent = 0;}/* * Initialize the DwPage's class */static void Dw_page_class_init(DwPageClass * klass){ GtkObjectClass *object_class; DwWidgetClass *widget_class; DwContainerClass *container_class; object_class = (GtkObjectClass *) klass; widget_class = (DwWidgetClass *) klass; container_class = (DwContainerClass *) klass; parent_class = gtk_type_class(DW_TYPE_CONTAINER); /* todo: the link_xxx signals should return boolean values, which are * then returned by the event signal function of DwPage. But I don't * know that much about Gtk+ signals :-( * --SG */ page_signals[LINK_ENTERED] = gtk_signal_new("link_entered", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET(DwPageClass, link_entered), gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); page_signals[LINK_PRESSED] = gtk_signal_new("link_pressed", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET(DwPageClass, link_pressed), gtk_marshal_NONE__POINTER_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_GDK_EVENT); page_signals[LINK_RELEASED] = gtk_signal_new("link_released", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET(DwPageClass, link_released), gtk_marshal_NONE__POINTER_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_GDK_EVENT); page_signals[LINK_CLICKED] = gtk_signal_new("link_clicked", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET(DwPageClass, link_clicked), gtk_marshal_NONE__POINTER_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_GDK_EVENT); gtk_object_class_add_signals(object_class, page_signals, LAST_SIGNAL); object_class->destroy = Dw_page_destroy; widget_class->size_request = Dw_page_size_request; widget_class->size_allocate = Dw_page_size_allocate; widget_class->set_width = Dw_page_set_width; widget_class->set_ascent = Dw_page_set_ascent; widget_class->set_descent = Dw_page_set_descent; widget_class->draw = Dw_page_draw; widget_class->realize = Dw_page_realize; widget_class->unrealize = Dw_page_unrealize; widget_class->button_press_event = Dw_page_button_press; widget_class->button_release_event = Dw_page_button_release; widget_class->motion_notify_event = Dw_page_motion_notify; container_class->add = Dw_page_add; container_class->remove = Dw_page_remove; container_class->forall = Dw_page_forall; klass->link_entered = Dw_page_real_link_entered; klass->link_pressed = NULL; klass->link_released = NULL; klass->link_clicked = NULL;} /* * Destroy the page (standard Gtk+ function) */static void Dw_page_destroy(GtkObject * object){ DwPage *page; DwPageWord *word; gint word_index; gint link_index; page = DW_PAGE(object); for (word_index = 0; word_index < page->num_words; word_index++) { word = &page->words[word_index]; if (word->content_type == DW_PAGE_CONTENT_WIDGET) gtk_object_destroy(GTK_OBJECT(word->content.widget.widget)); else if (word->content_type == DW_PAGE_CONTENT_TEXT) g_free(word->content.text); else if (word->content_type == DW_PAGE_CONTENT_ANCHOR) g_free(word->content.anchor); a_Dw_style_unref(word->style); } g_free(page->lines); page->num_words = 0; /* make sure we don't own widgets anymore */ g_free(page->shapes); for (link_index = 0; link_index < page->num_links; link_index++) { g_free(page->links[link_index].url); g_free(page->links[link_index].alt); } g_free(page->links); (*(GTK_OBJECT_CLASS(parent_class)->destroy)) (object);}/* * Standard Dw function */static void Dw_page_size_request(DwWidget * widget, DwRequisition * requisition){ DwPage *page; DwPageWord *word; gboolean must_rewrap = FALSE; int word_index; page = DW_PAGE(widget); /* Rewrapping is only necessary, when the viewport size has changed, * or a child widget needs resizing. In a third case, when new words have * been added, there is no need to call Dw_page_rewrap. * * The code can be optimized: If in the first case the width did not * change, and there are no child widgets with a relative height, * rewrapping is neither necessary. */ if (page->wrapped_width != page->avail_width || page->wrapped_ascent != page->avail_ascent || page->wrapped_descent != page->avail_descent) { must_rewrap = TRUE; /*g_print(">>> Dw_page_size_request: new size\n"); */ } else { for (word_index = 0; !must_rewrap && word_index < page->num_words; word_index++) { word = &page->words[word_index]; if (word->content_type == DW_PAGE_CONTENT_WIDGET && DW_WIDGET_NEEDS_RESIZE(word->content.widget.widget)) must_rewrap = TRUE; } /*if (must_rewrap) g_print(">>> Dw_page_size_request: children\n"); */ } if (must_rewrap) { Dw_page_rewrap(page); page->wrapped_width = page->avail_width; page->wrapped_ascent = page->avail_ascent; page->wrapped_descent = page->avail_descent; } requisition->width = page->real_width; if (page->num_lines > 0) requisition->ascent = page->lines[page->num_lines - 1].y_top + page->lines[page->num_lines - 1].y_ascent + page->lines[page->num_lines - 1].y_descent; else requisition->ascent = 0; /* todo: requisition->descent could get a useful value (as in TeX), but I don't have any idea where this will really be needed ;-) */ requisition->descent = 0;}/* * Standard Dw function */static void Dw_page_size_allocate(DwWidget * widget, DwAllocation * allocation){ DwPage *page; int line_index, word_index; DwPageLine *line; DwPageWord *word; int x_cursor; DwAllocation child_allocation; page = DW_PAGE(widget); //g_print ("Dw_page_size_allocate\n"); for (line_index = 0; line_index < page->num_lines; line_index++) { line = &(page->lines[line_index]); x_cursor = Dw_page_line_x_offset(page, line); for (word_index = line->first_word; word_index < line->last_word; word_index++) { word = &(page->words[word_index]); if (word->content_type == DW_PAGE_CONTENT_WIDGET) { /*g_print (" %20s: (%d, %d)\n", gtk_type_name (GTK_OBJECT_TYPE (word->content.widget.widget)), x_cursor, line->y_top); */ /* todo: justification within the line is done here! */ child_allocation.x = x_cursor + widget->allocation.x; /* align=top: child_allocation.y = line->y_top + widget->allocation.y; */ /* align=bottom (base line) */ child_allocation.y = line->y_top + widget->allocation.y + (line->y_ascent - word->y_ascent); child_allocation.width = word->x_size; child_allocation.ascent = word->y_ascent; child_allocation.descent = word->y_descent; a_Dw_widget_size_allocate(word->content.widget.widget, &child_allocation); } x_cursor += (word->x_size + word->x_space); } } widget->allocation = *allocation;}/* * Standard Dw function */static void Dw_page_set_width(DwWidget * widget, gint32 width){ DwPage *page; page = DW_PAGE(widget); //g_print (">>> Dw_page_set_width: %d -> %d\n", page->avail_width, width); if (page->avail_width != width) { page->avail_width = width; Dw_widget_queue_resize(widget); }}/* * Standard Dw function */static void Dw_page_set_ascent(DwWidget * widget, gint32 ascent){ DwPage *page; page = DW_PAGE(widget); //g_print (">>> Dw_page_set_ascent: %d -> %d\n", page->avail_ascent, ascent); if (page->avail_ascent != ascent) { page->avail_ascent = ascent; Dw_widget_queue_resize(widget); }}/* * Standard Dw function */static void Dw_page_set_descent(DwWidget * widget, gint32 descent){ DwPage *page; page = DW_PAGE(widget); //g_print (">>> Dw_page_set_descent: %d -> %d\n", page->avail_descent, //descent); if (page->avail_descent != descent) { page->avail_descent = descent; Dw_widget_queue_resize(widget); }}/* * Standard Dw function */static void Dw_page_realize(DwWidget * widget){ DwPage *page = DW_PAGE(widget); page->hand_cursor = gdk_cursor_new(GDK_HAND2);}/* * Standard Dw function */static void Dw_page_unrealize(DwWidget * widget){ DwPage *page = DW_PAGE(widget); gdk_cursor_destroy(page->hand_cursor);}/* * Standard Dw function */static void Dw_page_add(DwContainer * container, DwWidget * widget){ /* todo */}/* * Standard Dw function */static void Dw_page_remove(DwContainer * container, DwWidget * widget){ /* todo */}/* * Standard Dw function */static void Dw_page_forall(DwContainer * container, DwCallback callback, gpointer callback_data){ DwPage *page; int word_index; DwPageWord *word; page = DW_PAGE(container); for (word_index = 0; word_index < page->num_words; word_index++) { word = &page->words[word_index]; if (word->content_type == DW_PAGE_CONTENT_WIDGET) (*callback) (word->content.widget.widget, callback_data); }}static void Dw_page_real_link_entered(DwPage * page, const char *url){ a_Dw_widget_set_cursor(DW_WIDGET(page), url ? page->hand_cursor : NULL);}/* todo:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -