/* XView help viewer routines. Copyright (C) 1995 Jakub Jelinek. 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include "help.h" #include "../src/mad.h" #include "../src/util.h" #include "xvmain.h" #include "help.icons" #define TOPMARGIN 10 #define LEFTMARGIN 10 #define RIGHTMARGIN 10 #define BOTTOMMARGIN 10 extern Frame mcframe; extern Server_image mcimage; /* xvinfo.c */ Frame helpframe = XV_NULL; Panel helppanel; Canvas helpcanvas; Cms helpcms; extern Display *dpy; typedef struct { Xv_Font font; GC gc; int height; } fontstruct; extern char *currentpoint, *startpoint; static void repaint (void); static void clear_link_areas (void); static void x_index_cmd (void) { help_index_cmd (); repaint (); } static void x_back_cmd (void) { } static void x_previous_cmd (void) { } static void x_next_cmd (void) { } static void x_search_cmd (void) { } static void x_help_on_help (void) { help_help_cmd (); repaint (); } static void x_quit_cmd (void) { xv_destroy_safe (helpframe); clear_link_areas (); helpframe = XV_NULL; interactive_display_finish (); xv_dispatch_a_bit (); } fontstruct getfont (char *name, int fg) { fontstruct f; XGCValues gcvalues; f.font = (Xv_Font) xv_find (helpcanvas, FONT, FONT_NAME, name, NULL); if (f.font == XV_NULL) f.font = (Xv_Font) xv_get (helpframe, XV_FONT); gcvalues.font = (Font) xv_get (f.font, XV_XID); gcvalues.foreground = (unsigned long) xv_get (helpcms, CMS_PIXEL, fg); gcvalues.background = (unsigned long) xv_get (helpcms, CMS_BACKGROUND_PIXEL); gcvalues.graphics_exposures = FALSE; f.gc = XCreateGC (dpy, RootWindow (dpy, DefaultScreen (dpy)), GCForeground|GCBackground|GCFont|GCGraphicsExposures, &gcvalues); f.height = xv_get (f.font, FONT_DEFAULT_CHAR_HEIGHT); return f; } static char buffer [200]; int x, h, y; int bufferindex; fontstruct fonormal, fobold, folink, fotitle; #define NORMAL &fonormal #define BOLD &fobold #define LINK &folink #define TITLE &fotitle fontstruct *curfont, *linefont, *wordfont; int startup; int paintwidth; Window xId; char *linebegin, *wordbegin; int tabsize = 30; struct area; typedef struct area *AREA; struct area { int wx; /* West x, Northwest y, Southwest y etc. */ int nwy; int swy; int ex; int ney; int sey; char *jump; AREA next; }; AREA firstarea = NULL, lastarea = NULL; int do_link_areas = 1; static int painting = 1, linepainting = 1; static void clear_link_areas (void) { AREA p; while (firstarea != NULL) { p = firstarea; firstarea = firstarea->next; free (p); } lastarea = NULL; } static void start_link_area (char *link, int test) { AREA p; if (test || !do_link_areas) return; p = (AREA) xmalloc (sizeof (struct area), "Help link area"); if (firstarea != NULL) lastarea->next = p; else firstarea = p; lastarea = p; p->wx = x; p->nwy = y - h; p->swy = y; p->ex = x; p->ney = y - h; p->sey = y; p->jump = link; p->next = NULL; } static void end_link_area (int test) { if (test || !do_link_areas || !lastarea) return; lastarea->ex = x; lastarea->ney = y - h; lastarea->sey = y; } static AREA is_in_area (int x, int y) { AREA p; for (p = firstarea; p != (AREA) NULL; p = p->next) { if (y < p->nwy || y >= p->sey) continue; if (y < p->swy) { if (x < p->wx) continue; if (p->nwy == p->ney && x >= p->ex) continue; } else if (y >= p->ney) { if (x >= p->ex) continue; } return p; } return NULL; } static void hparse (char *paint_start, int test); static void setfont (fontstruct *f) { curfont = f; } static void newline (void) { x = LEFTMARGIN; y += h; curfont = linefont; hparse (linebegin, 0); h = 0; x = LEFTMARGIN; linepainting = painting; linebegin = wordbegin; linefont = curfont; } static int flush (char *p, int test) { Font_string_dims dims; buffer [bufferindex] = 0; xv_get (curfont->font, FONT_STRING_DIMS, buffer, &dims); if (x + dims.width > paintwidth - RIGHTMARGIN && x) { if (test) newline (); else return 1; } if (!test) { XDrawString (dpy, xId, curfont->gc, x, y, buffer, strlen (buffer)); } x += dims.width; if (dims.height > h) h = dims.height; wordbegin = p + 1; bufferindex = 0; return 0; } static void hparse (char *paint_start, int test) { char *p; int c; if (test) { painting = 1; linepainting = 1; } else painting = linepainting; if (test) setfont (NORMAL); h = 0; x = LEFTMARGIN; bufferindex = 0; if (test) { wordbegin = paint_start; linebegin = paint_start; linefont = curfont; } for (p = paint_start; *p != CHAR_NODE_END; p++){ c = *p; switch (c){ case CHAR_LINK_START: if (flush (p, test)) return; setfont (LINK); start_link_area (p, test); break; case CHAR_LINK_POINTER: if (flush (p, test)) return; setfont (NORMAL); painting = 0; end_link_area (test); break; case CHAR_LINK_END: painting = 1; break; case CHAR_ALTERNATE: break; case CHAR_NORMAL: break; case CHAR_VERSION: strcpy (buffer + bufferindex, VERSION); bufferindex += strlen (VERSION); break; case CHAR_BOLD_ON: if (flush (p, test)) return; setfont (BOLD); break; case CHAR_BOLD_OFF: if (flush (p, test)) return; setfont (NORMAL); break; case CHAR_MCLOGO: { int mcimage_width = (int) xv_get (mcimage, XV_WIDTH); int mcimage_height = (int) xv_get (mcimage, XV_HEIGHT); if (flush (p, test)) return; if (!test) { XCopyArea (dpy, (Drawable) xv_get (mcimage, SERVER_IMAGE_PIXMAP), xId, curfont->gc, 0,0, mcimage_width, mcimage_height, x, y - mcimage_height); } x += mcimage_width; if (h < mcimage_height) h = mcimage_height; break; } case CHAR_TEXTONLY_START: while (*p && *p != CHAR_NODE_END && *p != CHAR_TEXTONLY_END) p++; if (*p != CHAR_TEXTONLY_END) p--; break; case CHAR_XONLY_START: case CHAR_XONLY_END: break; case '\n': if (p [1] == '\n') { if (flush (p, test)) return; if (x > LEFTMARGIN) { if (!test) return; else newline (); } break; } case ' ': buffer [bufferindex++] = ' '; if (flush (p, test)) return; break; case '\t': if (flush (p, test)) return; x = (x + tabsize - LEFTMARGIN) / tabsize * tabsize + LEFTMARGIN; if (x > paintwidth - RIGHTMARGIN) { if (!test) return; else newline (); x = tabsize + LEFTMARGIN; } break; default: if (!painting) continue; buffer [bufferindex++] = c; break; } } if (flush (p, test)) return; if (x > LEFTMARGIN) { if (!test) return; else newline (); } } static void canvas_repaint (Canvas canvas, Xv_Window paint) { if (startup) return; xId = (Window) xv_get (paint, XV_XID); y = TOPMARGIN; paintwidth = (int) xv_get (xv_get (paint, CANVAS_PAINT_VIEW_WINDOW), XV_WIDTH); XClearWindow (dpy, xId); hparse (startpoint, 1); XFlush (dpy); } static void canvas_resize (Canvas canvas, int width, int height) { if (startup) return; if (width != paintwidth) repaint (); } static void repaint (void) { Xv_Window paint, view; Scrollbar scroll; clear_link_areas (); do_link_areas = 1; OPENWIN_EACH_VIEW (helpcanvas, view) paint = (Xv_Window) xv_get (view, CANVAS_VIEW_PAINT_WINDOW); canvas_repaint (helpcanvas, paint); if (do_link_areas) { do_link_areas = 0; xv_set (helpcanvas, CANVAS_MIN_PAINT_HEIGHT, y + BOTTOMMARGIN, NULL); } scroll = (Scrollbar) xv_get (helpcanvas, OPENWIN_VERTICAL_SCROLLBAR, view); if (scroll != XV_NULL) { xv_set (scroll, SCROLLBAR_VIEW_START, 0, NULL); xv_set (scroll, SCROLLBAR_OBJECT_LENGTH, y + BOTTOMMARGIN, NULL); } OPENWIN_END_EACH } static struct { unsigned short *bits; void (*callback) (void); } buttons [] = { index_bits, x_index_cmd, back_bits, x_back_cmd, previous_bits, x_previous_cmd, next_bits, x_next_cmd, search_bits, x_search_cmd }; Cursor cursors [2]; static void event_handler (Xv_Window paint, Event *event) { int x, y; AREA p; static int current_cursor = 0; switch (event_action (event)) { case ACTION_SELECT: x = event_x (event); y = event_y (event); p = is_in_area (x, y); if (p != NULL && p->jump != NULL) { currentpoint = startpoint = help_follow_link (startpoint, p->jump); repaint (); } break; case LOC_MOVE: x = event_x (event); y = event_y (event); p = is_in_area (x, y); if (p != NULL) { if (!current_cursor) { XDefineCursor (dpy, xv_get (paint, XV_XID), cursors [1]); current_cursor = 1; } } else { if (current_cursor) { XDefineCursor (dpy, xv_get (paint, XV_XID), cursors [0]); current_cursor = 0; } } break; } } static void create_frame (void) { Panel_button_item button; int i; helpcms = (Cms) xv_create (XV_NULL, CMS, CMS_CONTROL_CMS, TRUE, CMS_SIZE, CMS_CONTROL_COLORS + 5, CMS_NAMED_COLORS, "black", "black", "green4", "red4", "black", NULL, NULL); helpframe = xv_create (mcframe, FRAME, FRAME_LABEL, "Midnight X Commander Help", WIN_CMS, helpcms, FRAME_INHERIT_COLORS, TRUE, NULL); helppanel = xv_create (helpframe, PANEL, NULL); xv_create (helppanel, PANEL_BUTTON, PANEL_LABEL_STRING, "Help", PANEL_ITEM_MENU, xv_create (XV_NULL, MENU, MENU_ITEM, MENU_STRING, "Help on Help", MENU_NOTIFY_PROC, x_help_on_help, NULL, MENU_ITEM, MENU_STRING, "Index", MENU_NOTIFY_PROC, x_index_cmd, NULL, MENU_ITEM, MENU_STRING, "Back", MENU_NOTIFY_PROC, x_back_cmd, NULL, MENU_ITEM, MENU_STRING, "Previous", MENU_NOTIFY_PROC, x_previous_cmd, NULL, MENU_ITEM, MENU_STRING, "Next", MENU_NOTIFY_PROC, x_next_cmd, NULL, MENU_ITEM, MENU_STRING, "Search", MENU_NOTIFY_PROC, x_search_cmd, NULL, NULL), NULL); button = (Panel_button_item) xv_create (helppanel, PANEL_BUTTON, PANEL_LABEL_STRING, "Quit", PANEL_NOTIFY_PROC, x_quit_cmd, NULL); for (i = 0; i < sizeof (buttons) / sizeof (buttons [0]); i++) { button = (Panel_button_item) xv_create (helppanel, PANEL_BUTTON, PANEL_LABEL_IMAGE, xv_create (XV_NULL, SERVER_IMAGE, SERVER_IMAGE_DEPTH, 1, XV_WIDTH, 48, XV_HEIGHT, 48, SERVER_IMAGE_BITS, buttons [i].bits, NULL), PANEL_NOTIFY_PROC, buttons [i].callback, NULL); if (!i) xv_set (button, PANEL_NEXT_ROW, -1, NULL); } window_fit (helppanel); xv_set (helpframe, XV_WIDTH, xv_get (helppanel, XV_WIDTH), NULL); xv_set (helppanel, XV_WIDTH, WIN_EXTEND_TO_EDGE, NULL); startup = 1; helpcanvas = xv_create (helpframe, CANVAS, WIN_BELOW, helppanel, CANVAS_REPAINT_PROC, canvas_repaint, CANVAS_RESIZE_PROC, canvas_resize, CANVAS_X_PAINT_WINDOW, FALSE, CANVAS_PAINTWINDOW_ATTRS, WIN_CONSUME_EVENTS, WIN_MOUSE_BUTTONS, LOC_MOVE, NULL, WIN_EVENT_PROC, event_handler, NULL, NULL); cursors [0] = (Cursor) xv_get (xv_get (helpcanvas, WIN_CURSOR), XV_XID); cursors [1] = XCreateFontCursor (dpy, XC_hand2); xv_create (helpcanvas, SCROLLBAR, SCROLLBAR_DIRECTION, SCROLLBAR_VERTICAL, SCROLLBAR_SPLITTABLE, TRUE, NULL); fonormal = getfont ("lucidasans-12", CMS_CONTROL_COLORS); fobold = getfont ("lucidasans-bold-12", CMS_CONTROL_COLORS + 1); folink = getfont ("lucidasans-12", CMS_CONTROL_COLORS + 2); fotitle = getfont ("lucidasans-bold-18", CMS_CONTROL_COLORS + 3); window_fit (helpframe); xv_set (helpframe, XV_SHOW, TRUE, NULL); startup = 0; repaint (); } void x_interactive_display (void) { if (helpframe == XV_NULL) create_frame (); }