update
[midnight-commander.git] / xv / xvhelp.c
blobabb59af2a33cb053df56e5c2d65f14d52bbb4fd1
1 /* XView help viewer routines.
2 Copyright (C) 1995 Jakub Jelinek.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 #include <config.h>
20 #include <X11/Xlib.h>
21 #include <X11/cursorfont.h>
22 #include <xview/xview.h>
23 #include <xview/frame.h>
24 #include <xview/panel.h>
25 #include <xview/svrimage.h>
26 #include <xview/canvas.h>
27 #include <xview/scrollbar.h>
28 #include <xview/cms.h>
29 #include <xview/xv_xrect.h>
30 #include "help.h"
31 #include "../src/mad.h"
32 #include "../src/util.h"
33 #include "xvmain.h"
35 #include "help.icons"
37 #define TOPMARGIN 10
38 #define LEFTMARGIN 10
39 #define RIGHTMARGIN 10
40 #define BOTTOMMARGIN 10
42 extern Frame mcframe;
43 extern Server_image mcimage; /* xvinfo.c */
44 Frame helpframe = XV_NULL;
45 Panel helppanel;
46 Canvas helpcanvas;
47 Cms helpcms;
48 extern Display *dpy;
49 typedef struct {
50 Xv_Font font;
51 GC gc;
52 int height;
53 } fontstruct;
55 extern char *currentpoint, *startpoint;
56 static void repaint (void);
57 static void clear_link_areas (void);
59 static void x_index_cmd (void)
61 help_index_cmd ();
62 repaint ();
65 static void x_back_cmd (void)
69 static void x_previous_cmd (void)
73 static void x_next_cmd (void)
77 static void x_search_cmd (void)
81 static void x_help_on_help (void)
83 help_help_cmd ();
84 repaint ();
87 static void x_quit_cmd (void)
89 xv_destroy_safe (helpframe);
90 clear_link_areas ();
91 helpframe = XV_NULL;
92 interactive_display_finish ();
93 xv_dispatch_a_bit ();
96 fontstruct getfont (char *name, int fg)
98 fontstruct f;
99 XGCValues gcvalues;
101 f.font = (Xv_Font) xv_find (helpcanvas, FONT, FONT_NAME, name, NULL);
102 if (f.font == XV_NULL)
103 f.font = (Xv_Font) xv_get (helpframe, XV_FONT);
104 gcvalues.font = (Font) xv_get (f.font, XV_XID);
105 gcvalues.foreground = (unsigned long) xv_get (helpcms, CMS_PIXEL, fg);
106 gcvalues.background = (unsigned long) xv_get (helpcms, CMS_BACKGROUND_PIXEL);
107 gcvalues.graphics_exposures = FALSE;
108 f.gc = XCreateGC (dpy, RootWindow (dpy, DefaultScreen (dpy)),
109 GCForeground|GCBackground|GCFont|GCGraphicsExposures, &gcvalues);
110 f.height = xv_get (f.font, FONT_DEFAULT_CHAR_HEIGHT);
111 return f;
114 static char buffer [200];
115 int x, h, y;
116 int bufferindex;
117 fontstruct fonormal, fobold, folink, fotitle;
118 #define NORMAL &fonormal
119 #define BOLD &fobold
120 #define LINK &folink
121 #define TITLE &fotitle
122 fontstruct *curfont, *linefont, *wordfont;
123 int startup;
124 int paintwidth;
125 Window xId;
126 char *linebegin, *wordbegin;
127 int tabsize = 30;
128 struct area;
129 typedef struct area *AREA;
130 struct area {
131 int wx; /* West x, Northwest y, Southwest y etc. */
132 int nwy;
133 int swy;
134 int ex;
135 int ney;
136 int sey;
137 char *jump;
138 AREA next;
140 AREA firstarea = NULL, lastarea = NULL;
141 int do_link_areas = 1;
142 static int painting = 1, linepainting = 1;
144 static void clear_link_areas (void)
146 AREA p;
148 while (firstarea != NULL) {
149 p = firstarea;
150 firstarea = firstarea->next;
151 free (p);
153 lastarea = NULL;
156 static void start_link_area (char *link, int test)
158 AREA p;
160 if (test || !do_link_areas)
161 return;
163 p = (AREA) xmalloc (sizeof (struct area), "Help link area");
164 if (firstarea != NULL)
165 lastarea->next = p;
166 else
167 firstarea = p;
168 lastarea = p;
169 p->wx = x;
170 p->nwy = y - h;
171 p->swy = y;
172 p->ex = x;
173 p->ney = y - h;
174 p->sey = y;
175 p->jump = link;
176 p->next = NULL;
179 static void end_link_area (int test)
181 if (test || !do_link_areas || !lastarea)
182 return;
184 lastarea->ex = x;
185 lastarea->ney = y - h;
186 lastarea->sey = y;
189 static AREA is_in_area (int x, int y)
191 AREA p;
193 for (p = firstarea; p != (AREA) NULL; p = p->next) {
194 if (y < p->nwy || y >= p->sey)
195 continue;
196 if (y < p->swy) {
197 if (x < p->wx)
198 continue;
199 if (p->nwy == p->ney && x >= p->ex)
200 continue;
201 } else if (y >= p->ney) {
202 if (x >= p->ex)
203 continue;
205 return p;
207 return NULL;
210 static void hparse (char *paint_start, int test);
212 static void setfont (fontstruct *f)
214 curfont = f;
217 static void newline (void)
219 x = LEFTMARGIN;
220 y += h;
221 curfont = linefont;
222 hparse (linebegin, 0);
223 h = 0;
224 x = LEFTMARGIN;
225 linepainting = painting;
226 linebegin = wordbegin;
227 linefont = curfont;
230 static int flush (char *p, int test)
232 Font_string_dims dims;
234 buffer [bufferindex] = 0;
235 xv_get (curfont->font, FONT_STRING_DIMS, buffer, &dims);
236 if (x + dims.width > paintwidth - RIGHTMARGIN && x) {
237 if (test)
238 newline ();
239 else
240 return 1;
242 if (!test) {
243 XDrawString (dpy, xId, curfont->gc, x, y, buffer, strlen (buffer));
245 x += dims.width;
246 if (dims.height > h)
247 h = dims.height;
248 wordbegin = p + 1;
249 bufferindex = 0;
250 return 0;
253 static void hparse (char *paint_start, int test)
255 char *p;
256 int c;
258 if (test) {
259 painting = 1;
260 linepainting = 1;
261 } else
262 painting = linepainting;
264 if (test)
265 setfont (NORMAL);
266 h = 0;
267 x = LEFTMARGIN;
268 bufferindex = 0;
269 if (test) {
270 wordbegin = paint_start;
271 linebegin = paint_start;
272 linefont = curfont;
275 for (p = paint_start; *p != CHAR_NODE_END; p++){
276 c = *p;
277 switch (c){
278 case CHAR_LINK_START:
279 if (flush (p, test))
280 return;
281 setfont (LINK);
282 start_link_area (p, test);
283 break;
284 case CHAR_LINK_POINTER:
285 if (flush (p, test))
286 return;
287 setfont (NORMAL);
288 painting = 0;
289 end_link_area (test);
290 break;
291 case CHAR_LINK_END:
292 painting = 1;
293 break;
294 case CHAR_ALTERNATE:
295 break;
296 case CHAR_NORMAL:
297 break;
298 case CHAR_VERSION:
299 strcpy (buffer + bufferindex, VERSION);
300 bufferindex += strlen (VERSION);
301 break;
302 case CHAR_BOLD_ON:
303 if (flush (p, test))
304 return;
305 setfont (BOLD);
306 break;
307 case CHAR_BOLD_OFF:
308 if (flush (p, test))
309 return;
310 setfont (NORMAL);
311 break;
312 case CHAR_MCLOGO:
314 int mcimage_width = (int) xv_get (mcimage, XV_WIDTH);
315 int mcimage_height = (int) xv_get (mcimage, XV_HEIGHT);
317 if (flush (p, test))
318 return;
319 if (!test) {
320 XCopyArea (dpy,
321 (Drawable) xv_get (mcimage, SERVER_IMAGE_PIXMAP),
322 xId, curfont->gc, 0,0, mcimage_width, mcimage_height,
323 x, y - mcimage_height);
325 x += mcimage_width;
326 if (h < mcimage_height)
327 h = mcimage_height;
328 break;
330 case CHAR_TEXTONLY_START:
331 while (*p && *p != CHAR_NODE_END && *p != CHAR_TEXTONLY_END)
332 p++;
333 if (*p != CHAR_TEXTONLY_END)
334 p--;
335 break;
336 case CHAR_XONLY_START:
337 case CHAR_XONLY_END:
338 break;
339 case '\n':
340 if (p [1] == '\n') {
341 if (flush (p, test))
342 return;
343 if (x > LEFTMARGIN) {
344 if (!test)
345 return;
346 else
347 newline ();
349 break;
351 case ' ':
352 buffer [bufferindex++] = ' ';
353 if (flush (p, test))
354 return;
355 break;
356 case '\t':
357 if (flush (p, test))
358 return;
359 x = (x + tabsize - LEFTMARGIN) / tabsize * tabsize + LEFTMARGIN;
360 if (x > paintwidth - RIGHTMARGIN) {
361 if (!test)
362 return;
363 else
364 newline ();
365 x = tabsize + LEFTMARGIN;
367 break;
368 default:
369 if (!painting)
370 continue;
371 buffer [bufferindex++] = c;
372 break;
375 if (flush (p, test))
376 return;
377 if (x > LEFTMARGIN) {
378 if (!test)
379 return;
380 else
381 newline ();
385 static void canvas_repaint (Canvas canvas, Xv_Window paint)
387 if (startup)
388 return;
389 xId = (Window) xv_get (paint, XV_XID);
390 y = TOPMARGIN;
391 paintwidth = (int) xv_get (xv_get (paint, CANVAS_PAINT_VIEW_WINDOW), XV_WIDTH);
392 XClearWindow (dpy, xId);
393 hparse (startpoint, 1);
394 XFlush (dpy);
397 static void canvas_resize (Canvas canvas, int width, int height)
399 if (startup)
400 return;
401 if (width != paintwidth)
402 repaint ();
405 static void repaint (void)
407 Xv_Window paint, view;
408 Scrollbar scroll;
410 clear_link_areas ();
411 do_link_areas = 1;
412 OPENWIN_EACH_VIEW (helpcanvas, view)
413 paint = (Xv_Window) xv_get (view, CANVAS_VIEW_PAINT_WINDOW);
414 canvas_repaint (helpcanvas, paint);
415 if (do_link_areas) {
416 do_link_areas = 0;
417 xv_set (helpcanvas,
418 CANVAS_MIN_PAINT_HEIGHT, y + BOTTOMMARGIN,
419 NULL);
421 scroll = (Scrollbar) xv_get (helpcanvas,
422 OPENWIN_VERTICAL_SCROLLBAR, view);
424 if (scroll != XV_NULL) {
425 xv_set (scroll,
426 SCROLLBAR_VIEW_START, 0,
427 NULL);
428 xv_set (scroll,
429 SCROLLBAR_OBJECT_LENGTH, y + BOTTOMMARGIN,
430 NULL);
432 OPENWIN_END_EACH
435 static struct {
436 unsigned short *bits;
437 void (*callback) (void);
438 } buttons [] = {
439 index_bits, x_index_cmd,
440 back_bits, x_back_cmd,
441 previous_bits, x_previous_cmd,
442 next_bits, x_next_cmd,
443 search_bits, x_search_cmd };
444 Cursor cursors [2];
446 static void event_handler (Xv_Window paint, Event *event)
448 int x, y;
449 AREA p;
450 static int current_cursor = 0;
452 switch (event_action (event)) {
453 case ACTION_SELECT:
454 x = event_x (event);
455 y = event_y (event);
456 p = is_in_area (x, y);
457 if (p != NULL && p->jump != NULL) {
458 currentpoint = startpoint = help_follow_link (startpoint, p->jump);
459 repaint ();
461 break;
462 case LOC_MOVE:
463 x = event_x (event);
464 y = event_y (event);
465 p = is_in_area (x, y);
466 if (p != NULL) {
467 if (!current_cursor) {
468 XDefineCursor (dpy, xv_get (paint, XV_XID), cursors [1]);
469 current_cursor = 1;
471 } else {
472 if (current_cursor) {
473 XDefineCursor (dpy, xv_get (paint, XV_XID), cursors [0]);
474 current_cursor = 0;
477 break;
481 static void create_frame (void)
483 Panel_button_item button;
484 int i;
486 helpcms = (Cms) xv_create (XV_NULL, CMS,
487 CMS_CONTROL_CMS, TRUE,
488 CMS_SIZE, CMS_CONTROL_COLORS + 5,
489 CMS_NAMED_COLORS, "black", "black", "green4", "red4", "black", NULL,
490 NULL);
492 helpframe = xv_create (mcframe, FRAME,
493 FRAME_LABEL, "Midnight X Commander Help",
494 WIN_CMS, helpcms,
495 FRAME_INHERIT_COLORS, TRUE,
496 NULL);
498 helppanel = xv_create (helpframe, PANEL,
499 NULL);
501 xv_create (helppanel, PANEL_BUTTON,
502 PANEL_LABEL_STRING, "Help",
503 PANEL_ITEM_MENU, xv_create (XV_NULL, MENU,
504 MENU_ITEM,
505 MENU_STRING, "Help on Help",
506 MENU_NOTIFY_PROC, x_help_on_help,
507 NULL,
508 MENU_ITEM,
509 MENU_STRING, "Index",
510 MENU_NOTIFY_PROC, x_index_cmd,
511 NULL,
512 MENU_ITEM,
513 MENU_STRING, "Back",
514 MENU_NOTIFY_PROC, x_back_cmd,
515 NULL,
516 MENU_ITEM,
517 MENU_STRING, "Previous",
518 MENU_NOTIFY_PROC, x_previous_cmd,
519 NULL,
520 MENU_ITEM,
521 MENU_STRING, "Next",
522 MENU_NOTIFY_PROC, x_next_cmd,
523 NULL,
524 MENU_ITEM,
525 MENU_STRING, "Search",
526 MENU_NOTIFY_PROC, x_search_cmd,
527 NULL,
528 NULL),
529 NULL);
530 button = (Panel_button_item) xv_create (helppanel, PANEL_BUTTON,
531 PANEL_LABEL_STRING, "Quit",
532 PANEL_NOTIFY_PROC, x_quit_cmd,
533 NULL);
534 for (i = 0; i < sizeof (buttons) / sizeof (buttons [0]); i++) {
535 button = (Panel_button_item) xv_create (helppanel, PANEL_BUTTON,
536 PANEL_LABEL_IMAGE, xv_create (XV_NULL, SERVER_IMAGE,
537 SERVER_IMAGE_DEPTH, 1,
538 XV_WIDTH, 48,
539 XV_HEIGHT, 48,
540 SERVER_IMAGE_BITS, buttons [i].bits,
541 NULL),
542 PANEL_NOTIFY_PROC, buttons [i].callback,
543 NULL);
544 if (!i)
545 xv_set (button,
546 PANEL_NEXT_ROW, -1,
547 NULL);
550 window_fit (helppanel);
552 xv_set (helpframe,
553 XV_WIDTH, xv_get (helppanel, XV_WIDTH),
554 NULL);
556 xv_set (helppanel,
557 XV_WIDTH, WIN_EXTEND_TO_EDGE,
558 NULL);
560 startup = 1;
562 helpcanvas = xv_create (helpframe, CANVAS,
563 WIN_BELOW, helppanel,
564 CANVAS_REPAINT_PROC, canvas_repaint,
565 CANVAS_RESIZE_PROC, canvas_resize,
566 CANVAS_X_PAINT_WINDOW, FALSE,
567 CANVAS_PAINTWINDOW_ATTRS,
568 WIN_CONSUME_EVENTS,
569 WIN_MOUSE_BUTTONS, LOC_MOVE, NULL,
570 WIN_EVENT_PROC, event_handler,
571 NULL,
572 NULL);
574 cursors [0] = (Cursor) xv_get (xv_get (helpcanvas, WIN_CURSOR), XV_XID);
575 cursors [1] = XCreateFontCursor (dpy, XC_hand2);
577 xv_create (helpcanvas, SCROLLBAR,
578 SCROLLBAR_DIRECTION, SCROLLBAR_VERTICAL,
579 SCROLLBAR_SPLITTABLE, TRUE,
580 NULL);
582 fonormal = getfont ("lucidasans-12", CMS_CONTROL_COLORS);
583 fobold = getfont ("lucidasans-bold-12", CMS_CONTROL_COLORS + 1);
584 folink = getfont ("lucidasans-12", CMS_CONTROL_COLORS + 2);
585 fotitle = getfont ("lucidasans-bold-18", CMS_CONTROL_COLORS + 3);
587 window_fit (helpframe);
589 xv_set (helpframe,
590 XV_SHOW, TRUE,
591 NULL);
593 startup = 0;
595 repaint ();
598 void x_interactive_display (void)
600 if (helpframe == XV_NULL)
601 create_frame ();