📄 dw_page.c
字号:
return shape->link; } } } } } } return -1;}/* * Standard Dw function. */static gint Dw_page_button_press(DwWidget * widget, gint32 x, gint32 y, GdkEventButton * event){ DwPage *page = DW_PAGE(widget);#ifdef VERBOSE g_print("Dw_page_button_press: button (%d, %d) +%d\n", x, y, button->button);#endif page->link_pressed = Dw_page_find_link(page, x, y); if (page->link_pressed >= 0) { gtk_signal_emit(GTK_OBJECT(widget), page_signals[LINK_PRESSED], page->links[page->link_pressed].url, event); return TRUE; } else return FALSE;}/* * Standard Dw function. */static gint Dw_page_button_release(DwWidget * widget, gint32 x, gint32 y, GdkEventButton * event){ DwPage *page = DW_PAGE(widget); char full_url[1024]; gint link_pressed, link_released; /* gint i, j, changed; */ link_pressed = page->link_pressed; link_released = Dw_page_find_link(page, x, y); page->link_pressed = -1; if (link_released >= 0) { gtk_signal_emit(GTK_OBJECT(widget), page_signals[LINK_RELEASED], page->links[link_released].url, event); if (link_pressed == link_released) { /* * todo: How do we pass these datas to the server ? * Url.c functions can't deal with that yet */ if (page->x_click > 0) { sprintf(full_url, "%s?%d,%d", page->links[link_pressed].url, page->x_click, page->y_click); gtk_signal_emit(GTK_OBJECT(widget), page_signals[LINK_CLICKED], full_url, event); } else gtk_signal_emit(GTK_OBJECT(widget), page_signals[LINK_CLICKED], page->links[link_released].url, event); /* * This is only a workaround to visualize links opened in a * new window. It will definitely change. */#if 0 if (link_released >= 0) for (i = 0; i < page->num_lines; i++) { changed = FALSE; for (j = page->lines[i].first_word; j < page->lines[i].last_word; j++) if (page->words[j].style->link == link_released) { DwStyle style_attr = *(page->words[j].style); style_attr.color = a_Dw_style_color_new(page->visited_color, widget->window); a_Dw_style_unref(page->words[j].style); page->words[j].style = a_Dw_style_new(&style_attr, widget->window); changed = TRUE; } if (changed) Dw_widget_queue_draw_area(widget, 0, page->lines[i].y_top, widget->allocation.width, page->lines[i].y_ascent + page->lines[i].y_descent); }#endif /* end workaround */ } page->x_click = -1; return TRUE; } else return FALSE;}/* * Standard Dw function. */static gint Dw_page_motion_notify(DwWidget * widget, gint32 x, gint32 y, GdkEventMotion * event){ DwPage *page = DW_PAGE(widget); gint hover_link; char full_url[1024]; hover_link = Dw_page_find_link(page, x, y); if (hover_link >= 0 && page->x_click >= 0) { sprintf(full_url, "%s?%d,%d", page->links[hover_link].url, page->x_click, page->y_click); gtk_signal_emit(GTK_OBJECT(widget), page_signals[LINK_ENTERED], full_url); } if (page->hover_link != hover_link) { if (hover_link >= 0) { /* If page->x_click >= 0, the signal has already been emitted. */ if (page->x_click < 0) { if (page->links[hover_link].alt) gtk_signal_emit(GTK_OBJECT(widget), page_signals[LINK_ENTERED], page->links[hover_link].alt); else gtk_signal_emit(GTK_OBJECT(widget), page_signals[LINK_ENTERED], page->links[hover_link].url); } } else gtk_signal_emit(GTK_OBJECT(widget), page_signals[LINK_ENTERED], NULL); page->hover_link = hover_link; return TRUE; } else return FALSE;}/* * Create a new link, return the index. */gint a_Dw_page_new_link(DwPage * page, const char *url, const char *alt){ gint nl; nl = page->num_links; a_List_add(page->links, nl, sizeof(*page->links), page->num_links_max); page->links[nl].url = url ? g_strdup(url) : NULL; page->links[nl].alt = alt ? g_strdup(alt) : NULL; return page->num_links++;}/* * Add a word to the page structure. Stashes the argument pointer in * the page data structure so that it will be deallocated on destroy. */void a_Dw_page_add_text(DwPage * page, char *text, DwStyle * style){ DwPageWord *word; gint x_size, y_ascent, y_descent; /* todo: ??? if (attr >= page->num_attrs || page->attrs[attr].font >= page->num_fonts) return; / *BUG: Should use default text! * / */ x_size = gdk_string_width(style->font->font, text); y_ascent = style->font->font->ascent; y_descent = style->font->font->descent; /* In case of a sub or super script we increase the word's height and * potentially the line's height. */ if (style->SubSup == TEXT_SUB) y_descent += (y_ascent / 2); else if (style->SubSup == TEXT_SUP) y_ascent += (y_ascent / 3); word = Dw_page_new_word(page, x_size, y_ascent, y_descent, style); word->content_type = DW_PAGE_CONTENT_TEXT; word->content.text = text; word->style = style; a_Dw_style_ref(style);}/* * Add a widget (word type) to the page. todo: comments. */void a_Dw_page_add_widget(DwPage * page, DwWidget * widget, gfloat rel_width, gfloat rel_height, DwStyle * style){ DwPageWord st_word, *word; gint x_size, y_ascent, y_descent; /* First, find the child widget's width. For now, we always * give the minimum requisition, but that will change with table * support (tables should probably get 100% of the set width - the * margins, or the maximum requisition, whichever is smaller). */ /* todo: a bit kludgy */ st_word.content.widget.rel_width = rel_width; st_word.content.widget.rel_height = rel_height; st_word.content.widget.widget = widget; Dw_page_calc_widget_size(page, &st_word); x_size = st_word.x_size; y_ascent = st_word.y_ascent; y_descent = st_word.y_descent; word = Dw_page_new_word(page, x_size, y_ascent, y_descent, style); word->content_type = DW_PAGE_CONTENT_WIDGET; word->content.widget.widget = widget; word->content.widget.rel_width = rel_width; word->content.widget.rel_height = rel_height; word->style = style; a_Dw_style_ref(style); Dw_widget_set_parent(widget, DW_WIDGET(page)); a_Dw_widget_set_style(widget, style);}/* * Add an anchor to the page. name is copied, so no strdup is neccessary for * the caller. */void a_Dw_page_add_anchor(DwPage * page, char *name, DwStyle * style){ DwPageWord *word; word = Dw_page_new_word(page, 0, 0, 0, style); word->content_type = DW_PAGE_CONTENT_ANCHOR; word->content.anchor = g_strdup(name); word->style = style; a_Dw_style_ref(style); Dw_widget_set_anchor(DW_WIDGET(page), word->content.anchor, page->lines[page->num_lines - 1].y_top);}/* * ? */void a_Dw_page_add_space(DwPage * page, DwStyle * style){ gint nl, nw; gint space; nl = page->num_lines - 1; if (nl >= 0) { nw = page->num_words - 1; if (nw >= 0) { space = style->font->space_width; page->words[nw].x_space = space; } }}/* * Cause a line break */void a_Dw_page_linebreak(DwPage * page){ gint i; i = page->num_lines; if (i == 0) return; page->lines[i - 1].hard = TRUE;}/* * Cause a paragraph break */void a_Dw_page_parbreak(DwPage * page, gint space){ gint i; i = page->num_lines; if (i == 0) return; page->lines[i - 1].hard = TRUE; if (space > page->lines[i - 1].y_space) page->lines[i - 1].y_space = space;}/* * Call this routine before updating the state. By wrapping all state * changes between these two routines, the internal state of the widget * always matches the display, without requiring each state change * operation to calculate updates on a fine-grained basis. */void a_Dw_page_update_begin(DwPage * page){}/* * Call this routine after updating the state. */void a_Dw_page_update_end(DwPage * page){ Dw_widget_queue_resize(DW_WIDGET(page));}typedef struct { gint LineNum; gint Index;} LineData;typedef enum { F_NewKey, F_Read, F_Seek, F_Found, F_End} FindState;typedef struct { gchar *Key; guint KeyLen; DwPage *Page; gint LineNum; gint Matches; GSList *IList; GString *TextBuf; gchar StopSet[3]; gint Eof; FindState State;} FindData;/* * Read lines into local buffer */void Dw_page_read_lines(FindData * F, gint N){ gint i, j, nw; LineData *LNode; for (j = 0; F->LineNum < F->Page->num_lines && j < N; F->LineNum++, j++) { LNode = g_new(LineData, 1); LNode->LineNum = F->LineNum; LNode->Index = F->TextBuf->len; F->IList = g_slist_append(F->IList, LNode); /* This can find strings that span over two or more lines */ for (nw = i = F->Page->lines[F->LineNum].first_word; i < F->Page->lines[F->LineNum].last_word; i++) { if (F->Page->words[i].content_type != DW_PAGE_CONTENT_TEXT) continue; F->TextBuf = g_string_append(F->TextBuf, F->Page->words[i].content.text); F->TextBuf = g_string_append(F->TextBuf, " "); ++nw; } if (nw == 0) /* Empty line ? */ F->IList = g_slist_remove(F->IList, LNode); } F->Eof = (F->LineNum == F->Page->num_lines);}/* * Erase the first N characters from local buffer */void Dw_page_erase_chars(FindData * F, gint N){ gint i; LineData *LNode, *LNext; for (i = 0; (LNode = g_slist_nth_data(F->IList, i)); i++) LNode->Index -= N; while ((LNode = g_slist_nth_data(F->IList, 0)) && LNode->Index <= 0) { LNode->Index = 0; if ((LNext = g_slist_nth_data(F->IList, 1)) && LNext->Index <= 0) F->IList = g_slist_remove(F->IList, LNode); else break; } F->TextBuf = g_string_erase(F->TextBuf, 0, N);}/* * Erase the local buffer */void Dw_page_erase_buf(FindData * F){ LineData *LNode; if (F->IList) while ((LNode = g_slist_nth_data(F->IList, 0))) F->IList = g_slist_remove(F->IList, LNode); if (F->TextBuf) F->TextBuf = g_string_truncate(F->TextBuf, 0);}/* * Find the text in the page. */void a_Dw_page_find_text(DwPage * page, char *NewKey){ gint i; gchar *Ptr = NULL; LineData *LNode; static FindData *F = NULL; DwWidget *widget = DW_WIDGET(page); g_return_if_fail(widget->viewport != NULL); if (!F) F = g_new0(FindData, 1); if (!F->Key || strcmp(F->Key, NewKey) || F->Page != page) F->State = F_NewKey; /* Let the FSM find the search string */ while (1) { switch (F->State) { case F_NewKey: if (!F->TextBuf) F->TextBuf = g_string_sized_new(256); if (F->Key) g_free(F->Key); F->Key = g_strdup(NewKey); if (!(F->KeyLen = strlen(F->Key))) return; sprintf(F->StopSet, "%c%c", tolower(F->Key[0]), toupper(F->Key[0])); Dw_page_erase_buf(F); F->Page = page; F->Matches = F->LineNum = F->Eof = 0; F->State = F_Read; break; case F_Read: if (F->Eof) F->State = F_End; else { Dw_page_read_lines(F, 10); F->State = F_Seek; } // g_print("TextBuf: %s\n", F->TextBuf->str); break; case F_Seek: if (!(Ptr = strpbrk(F->TextBuf->str, F->StopSet))) { Dw_page_erase_buf(F); F->State = F_Read; } else if (strlen(Ptr) < F->KeyLen) { F->State = F_Read; } else if (g_strncasecmp(Ptr, F->Key, F->KeyLen) == 0) { Dw_page_erase_chars(F, Ptr - F->TextBuf->str); F->State = F_Found; } else Dw_page_erase_chars(F, Ptr - F->TextBuf->str + 1); break; case F_Found: F->Matches++; LNode = g_slist_nth_data(F->IList, 0); i = LNode->LineNum; a_Dw_widget_scroll_to(widget, page->lines[i].y_top); Dw_page_erase_chars(F, 1); F->State = F_Seek; return; case F_End: if (F->Matches) F->State = F_NewKey; else return; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -