📄 textwidget.c
字号:
/* textwidget.c - for drawing a scrollable text window widget Copyright (C) 1996-2000 Paul Sheer 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */#include <config.h>#include <stdio.h>#include <my_string.h>#include <stdlib.h>#include <stdarg.h>#include <X11/Intrinsic.h>#include <X11/Xatom.h>#include "lkeysym.h"#include "stringtools.h"#include "app_glob.c"#include "edit.h"#include "editcmddef.h"#include "coolwidget.h"#include "coollocal.h"#include "mousemark.h"#include "mad.h"extern struct look *look;int option_text_fg_normal = 0;int option_text_fg_bold = 1;int option_text_fg_italic = 18;int option_text_bg_normal = 26;int option_text_bg_marked = 25;int option_text_bg_highlighted = 12;void selection_clear (void);static long current;extern int calc_text_pos2 (CWidget * w, long b, long *q, int l);extern void convert_text2 (CWidget * w, long from, cache_type *line, int x, int x_max, int row);void edit_translate_xy (int xs, int ys, int *x, int *y);/* returns the position in the edit buffer of a window click */long text_get_click_pos (CWidget * w, int x, int y){ long click, c, q; int width; width = w->options & TEXTBOX_WRAP ? (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000; if (y > 1) c = strmovelines (w->text, w->current, y - 1, width); else c = w->current; if (y > 0) click = strmovelines (w->text, c, 1, width); else click = w->current; if (w->options & TEXTBOX_MARK_WHOLE_LINES) { if (click == c && y > 0) { calc_text_pos2 (w, click, &q, 32000); /* this is to get the last line */ return q; } return click; } else calc_text_pos2 (w, click, &q, x); return q;}static void xy (int x, int y, int *x_return, int *y_return){ edit_translate_xy (x, y, x_return, y_return);}static long cp (CWidget * w, int x, int y){ return text_get_click_pos (w, --x, --y);}/* return 1 if not marked */static int marks (CWidget * w, long *start, long *end){ if (w->mark1 == w->mark2) return 1; *start = min (w->mark1, w->mark2); *end = max (w->mark1, w->mark2); return 0;}int range (CWidget * w, long start, long end, int click){ return (start <= click && click < end);}static void move_mark (CWidget * w){ w->mark2 = w->mark1 = current;}static void fin_mark (CWidget * w){ w->mark2 = w->mark1 = -1;}static void release_mark (CWidget * w, XEvent * event){ w->mark2 = current; if (w->mark2 != w->mark1 && event) { selection_clear (); XSetSelectionOwner (CDisplay, XA_PRIMARY, w->winid, event->xbutton.time); }}static char *get_block (CWidget * w, long start_mark, long end_mark, int *type, int *l){ char *t, *t2; *l = abs (w->mark2 - w->mark1); t = CMalloc (*l + 1); memcpy (t, w->text + min (w->mark1, w->mark2), *l); t[*l] = 0; t2 = str_strip_nroff ((char *) t, l); free (t); t2[*l] = 0; if (w->options & TEXTBOX_FILE_LIST) {#ifdef HAVE_DND char *p; int i; p = CDndFileList (t2, l, &i); if (!p) { free (t2); return 0; } free (t2); t2 = p; if (i == 1) *type = DndFile; else#endif *type = DndFiles; } else { *type = DndText; } return t2;}static void move (CWidget * w, long click, int row){ int h; current = click; if (w->mark2 == -1) w->mark1 = current; h = (w->height - TEXTBOX_BDR) / FONT_PIX_PER_LINE; if (row > h && w->firstline < w->numlines - h - 2) CSetTextboxPos (w, TEXT_SET_LINE, w->firstline + row - h); if (row < 1) CSetTextboxPos (w, TEXT_SET_LINE, w->firstline + row - 1); w->mark2 = click;}static void motion (CWidget * w, long click){ w->mark2 = click;}struct mouse_funcs textbox_mouse_mark = { 0, (void (*)(int, int, int *, int *)) xy, (long (*)(void *, int, int)) cp, (int (*)(void *, long *, long *)) marks, (int (*)(void *, long, long, long)) range, (void (*)(void *)) fin_mark, (void (*)(void *)) move_mark, (void (*)(void *, XEvent *)) release_mark, (char *(*)(void *, long, long, int *, int *)) get_block, (void (*)(void *, long, int)) move, (void (*)(void *, long)) motion, 0, 0, 0, 0, DndText};/* If options & TEXTBOX_NO_STRDUP then text must be passed as an malloced string which will be free'd automatically when the text box is destroyed. If !options & TEXTBOX_NO_STRDUP then text will be strdup'ed (creating its own internal copy of the text), like other widgets. CRedrawTextbox will do the same as CDrawTextbox: it will not free old text or make its own copy of new text. */CWidget *CDrawTextbox (const char *identifier, Window parent, int x, int y, int width, int height, int line, int column, const char *text, long options){ char *scroll; int numlines; CWidget *wdt; int w, h; CPushFont ("editor", 0); if (width == AUTO_WIDTH || height == AUTO_HEIGHT) CTextSize (&w, &h, text); if (width == AUTO_WIDTH) width = w + 6; if (height == AUTO_HEIGHT) height = h + 6; wdt = CSetupWidget (identifier, parent, x, y, width, height, C_TEXTBOX_WIDGET, INPUT_KEY, color_palette (option_text_bg_normal), 1); wdt->funcs = mouse_funcs_new (wdt, &textbox_mouse_mark); xdnd_set_type_list (CDndClass, wdt->winid, xdnd_typelist_send[DndText]); wdt->options = options | WIDGET_TAKES_SELECTION; if (options & TEXTBOX_NO_STRDUP) wdt->text = (char *) text; else wdt->text = (char *) strdup (text); numlines = strcountlines (text, 0, 1000000000, options & TEXTBOX_WRAP ? (wdt->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000) + 1; wdt->firstline = 0; wdt->firstcolumn = 0; wdt->cursor = 0; wdt->current = 0; wdt->numlines = numlines; wdt->textlength = strlen (wdt->text); CSetTextboxPos (wdt, TEXT_SET_LINE, line); CSetTextboxPos (wdt, TEXT_SET_COLUMN, column); if (height > 80) {/* this will also set the hint position, set_hint_pos() */ wdt->vert_scrollbar = CDrawVerticalScrollbar (scroll = catstrs (identifier, ".vsc", 0), parent, x + width + WIDGET_SPACING, y, height, AUTO_WIDTH, 0, 0); CSetScrollbarCallback (wdt->vert_scrollbar->ident, wdt->ident, link_scrollbar_to_textbox); } else { set_hint_pos (x + width + WIDGET_SPACING, y + height + WIDGET_SPACING); } CPopFont (); return wdt;}int CSetTextboxPos (CWidget * w, int which, long p);/* redraws the text box. If preserve is 0 then view position is reset to 0 */CWidget *CRedrawTextbox (const char *identifier, const char *text, int preserve){ CWidget *w = CIdent (identifier); int numlines, firstline, firstcolumn, cursor; if (!w) return 0; if (w->options & TEXTBOX_NO_STRDUP) w->text = (char *) text; else { if (w->text) free (w->text); w->text = (char *) strdup (text); } CPushFont ("editor", 0); w->textlength = strlen (w->text); numlines = strcountlines (text, 0, 1000000000, w->options & TEXTBOX_WRAP ? (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000) + 1; w->numlines = numlines; firstline = w->firstline; firstcolumn = w->firstcolumn; cursor = w->cursor; w->firstline = 0; w->current = 0; w->firstcolumn = 0; w->cursor = 0; w->mark1 = w->mark2 = -1; if (preserve) { CSetTextboxPos (w, TEXT_SET_LINE, firstline); CSetTextboxPos (w, TEXT_SET_COLUMN, firstcolumn); CSetTextboxPos (w, TEXT_SET_CURSOR_LINE, cursor); } CExpose (identifier); CPopFont (); return w;}/* result must not be free'd, and must be used immediately */char *CGetTextBoxLine (CWidget * w, int i){ int width; char *r; CPushFont ("editor", 0); width = w->options & TEXTBOX_WRAP ? (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000; r = strline (w->text, strmovelines (w->text, w->current, i - w->firstline, width)); CPopFont (); return r;}/* clears the text box */CWidget *CClearTextbox (const char *identifier){ CWidget *w; w = CIdent (identifier); if (w) { if (!(w->options & TEXTBOX_NO_STRDUP)) if (w->text) free (w->text); w->text = (char *) strdup (""); w->textlength = w->numlines = 0; w->firstline = w->firstcolumn = 0; w->mark1 = w->mark2 = 0; CExpose (identifier); } return w;}CWidget *CDrawManPage (const char *identifier, Window parent, int x, int y, int width, int height, int line, int column, const char *text){ CWidget *w; w = CDrawTextbox (identifier, parent, x, y, width, height, line, column, text, TEXTBOX_MAN_PAGE); return w;}/* If which is TEXT_SET_POS the current offset of the top right corner is set to p. returns non-zero if anything actually changed. */int CSetTextboxPos (CWidget * wdt, int which, long p){ long q; int width, i, j; if (p < 0) p = 0; CPushFont ("editor", 0); width = wdt->options & TEXTBOX_WRAP ? (wdt->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000; switch (which) { case TEXT_SET_COLUMN: i = wdt->firstcolumn; wdt->firstcolumn = p; CPopFont (); return (i != wdt->firstcolumn); case TEXT_SET_LINE: i = wdt->firstline; if (p >= wdt->numlines) p = wdt->numlines - 1; if (p < 0) p = 0; if (wdt->kind == C_FIELDED_TEXTBOX_WIDGET) { wdt->firstline = p; } else { q = strmovelines (wdt->text, wdt->current, p - wdt->firstline, width); wdt->firstline += strcountlines (wdt->text, wdt->current, q - wdt->current, width); wdt->current = q; } CPopFont (); return (i != wdt->firstline); case TEXT_SET_POS: i = wdt->firstline; if (wdt->kind == C_FIELDED_TEXTBOX_WIDGET) { break; } else { wdt->firstline += strcountlines (wdt->text, wdt->current, p - wdt->current, width); wdt->current = p; } CPopFont (); return (i != wdt->firstline);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -