mc/src/help.c

973 lines
23 KiB
C
Raw Normal View History

1998-02-27 07:54:42 +03:00
/* Hypertext file browser.
Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007 Free Software Foundation, Inc.
1998-02-27 07:54:42 +03:00
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2005-02-08 12:04:03 +03:00
*/
1998-02-27 07:54:42 +03:00
/** \file help.c
* \brief Source: hypertext file browser
*
* Implements the hypertext file viewer.
* The hypertext file is a file that may have one or more nodes. Each
* node ends with a ^D character and starts with a bracket, then the
* name of the node and then a closing bracket. Right after the closing
* bracket a newline is placed. This newline is not to be displayed by
* the help viewer and must be skipped - its sole purpose is to faciliate
* the work of the people managing the help file template (xnc.hlp) .
*
* Links in the hypertext file are specified like this: the text that
* will be highlighted should have a leading ^A, then it comes the
* text, then a ^B indicating that highlighting is done, then the name
* of the node you want to link to and then a ^C.
*
* The file must contain a ^D at the beginning and at the end of the
* file or the program will not be able to detect the end of file.
*
* Lazyness/widgeting attack: This file does use the dialog manager
* and uses mainly the dialog to achieve the help work. there is only
* one specialized widget and it's only used to forward the mouse messages
* to the appropiate routine.
*/
1998-02-27 07:54:42 +03:00
#include <config.h>
2005-02-08 12:04:03 +03:00
#include <errno.h>
1998-02-27 07:54:42 +03:00
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "lib/global.h"
#include "lib/tty/tty.h"
#include "lib/skin.h"
#include "lib/tty/mouse.h"
#include "lib/tty/key.h"
#include "lib/strutil.h"
#include "dialog.h" /* For Dlg_head */
1998-02-27 07:54:42 +03:00
#include "widget.h" /* For Widget */
#include "wtools.h" /* For common_dialog_repaint() */
#include "cmddef.h"
#include "keybind.h"
#include "help.h"
#include "main.h"
const global_keymap_t *help_map;
1998-02-27 07:54:42 +03:00
#define MAXLINKNAME 80
#define HISTORY_SIZE 20
#define HELP_WINDOW_WIDTH (COLS - 16)
1998-02-27 07:54:42 +03:00
#define STRING_LINK_START "\01"
#define STRING_LINK_POINTER "\02"
#define STRING_LINK_END "\03"
#define STRING_NODE_END "\04"
1998-02-27 07:54:42 +03:00
static char *fdata = NULL; /* Pointer to the loaded data file */
static int help_lines; /* Lines in help viewer */
static int history_ptr; /* For the history queue */
static const char *main_node; /* The main node */
static const char *last_shown = NULL; /* Last byte shown in a screen */
static gboolean end_of_node = FALSE; /* Flag: the last character of the node shown? */
static const char *currentpoint;
static const char *selected_item;
1998-02-27 07:54:42 +03:00
/* The widget variables */
static Dlg_head *whelp;
static struct {
const char *page; /* Pointer to the selected page */
const char *link; /* Pointer to the selected link */
1998-02-27 07:54:42 +03:00
} history [HISTORY_SIZE];
/* Link areas for the mouse */
typedef struct Link_Area {
int x1, y1, x2, y2;
const char *link_name;
1998-02-27 07:54:42 +03:00
} Link_Area;
static GSList *link_area = NULL;
static gboolean inside_link_area = FALSE;
1998-02-27 07:54:42 +03:00
static cb_ret_t help_callback (Dlg_head *h, Widget *sender,
dlg_msg_t msg, int parm, void *data);
1998-02-27 07:54:42 +03:00
/* returns the position where text was found in the start buffer */
/* or 0 if not found */
static const char *
search_string (const char *start, const char *text)
1998-02-27 07:54:42 +03:00
{
const char *result = NULL;
char *local_text = g_strdup (text);
char *d = local_text;
const char *e = start;
1998-02-27 07:54:42 +03:00
/* fmt sometimes replaces a space with a newline in the help file */
/* Replace the newlines in the link name with spaces to correct the situation */
while (*d != '\0') {
1998-02-27 07:54:42 +03:00
if (*d == '\n')
*d = ' ';
str_next_char (&d);
1998-02-27 07:54:42 +03:00
}
1998-02-27 07:54:42 +03:00
/* Do search */
for (d = local_text; *e; e++){
1998-02-27 07:54:42 +03:00
if (*d == *e)
d++;
else
d = local_text;
if (*d == '\0') {
result = e + 1;
break;
}
1998-02-27 07:54:42 +03:00
}
g_free (local_text);
return result;
1998-02-27 07:54:42 +03:00
}
/* Searches text in the buffer pointed by start. Search ends */
/* if the CHAR_NODE_END is found in the text. Returns 0 on failure */
static const char *
search_string_node (const char *start, const char *text)
1998-02-27 07:54:42 +03:00
{
const char *d = text;
const char *e = start;
1998-02-27 07:54:42 +03:00
if (start != NULL)
for (; *e && *e != CHAR_NODE_END; e++) {
if (*d == *e)
d++;
else
d = text;
if (*d == '\0')
return e + 1;
}
return NULL;
1998-02-27 07:54:42 +03:00
}
/* Searches the_char in the buffer pointer by start and searches */
/* it can search forward (direction = 1) or backward (direction = -1) */
static const char *
search_char_node (const char *start, char the_char, int direction)
1998-02-27 07:54:42 +03:00
{
const char *e;
1998-02-27 07:54:42 +03:00
for (e = start; (*e != '\0') && (*e != CHAR_NODE_END); e += direction)
1998-02-27 07:54:42 +03:00
if (*e == the_char)
return e;
return NULL;
1998-02-27 07:54:42 +03:00
}
/* Returns the new current pointer when moved lines lines */
static const char *
move_forward2 (const char *c, int lines)
1998-02-27 07:54:42 +03:00
{
const char *p;
int line;
1998-02-27 07:54:42 +03:00
currentpoint = c;
for (line = 0, p = currentpoint; (*p != '\0') && (*p != CHAR_NODE_END);
str_cnext_char (&p)) {
1998-02-27 07:54:42 +03:00
if (line == lines)
return currentpoint = p;
1998-02-27 07:54:42 +03:00
if (*p == '\n')
line++;
}
return currentpoint = c;
}
static const char *
move_backward2 (const char *c, int lines)
1998-02-27 07:54:42 +03:00
{
const char *p;
1998-02-27 07:54:42 +03:00
int line;
currentpoint = c;
for (line = 0, p = currentpoint; (*p != '\0') && ((int) (p - fdata) >= 0);
str_cprev_char (&p)) {
if (*p == CHAR_NODE_END) {
1998-02-27 07:54:42 +03:00
/* We reached the beginning of the node */
/* Skip the node headers */
while (*p != ']')
str_cnext_char (&p);
return currentpoint = p + 2; /* Skip the newline following the start of the node */
1998-02-27 07:54:42 +03:00
}
1998-02-27 07:54:42 +03:00
if (*(p - 1) == '\n')
line++;
if (line == lines)
return currentpoint = p;
}
return currentpoint = c;
}
static void
move_forward (int i)
1998-02-27 07:54:42 +03:00
{
if (!end_of_node)
currentpoint = move_forward2 (currentpoint, i);
1998-02-27 07:54:42 +03:00
}
static void
move_backward (int i)
1998-02-27 07:54:42 +03:00
{
currentpoint = move_backward2 (currentpoint, ++i);
}
static void
move_to_top (void)
1998-02-27 07:54:42 +03:00
{
while (((int) (currentpoint > fdata) > 0) && (*currentpoint != CHAR_NODE_END))
1998-02-27 07:54:42 +03:00
currentpoint--;
1998-02-27 07:54:42 +03:00
while (*currentpoint != ']')
currentpoint++;
currentpoint = currentpoint + 2; /* Skip the newline following the start of the node */
1998-02-27 07:54:42 +03:00
selected_item = NULL;
}
static void
move_to_bottom (void)
1998-02-27 07:54:42 +03:00
{
while ((*currentpoint != '\0') && (*currentpoint != CHAR_NODE_END))
1998-02-27 07:54:42 +03:00
currentpoint++;
currentpoint--;
move_backward (help_lines - 1);
}
static const char *
help_follow_link (const char *start, const char *lc_selected_item)
1998-02-27 07:54:42 +03:00
{
char link_name [MAXLINKNAME];
const char *p;
int i = 0;
1998-02-27 07:54:42 +03:00
if (lc_selected_item == NULL)
1998-02-27 07:54:42 +03:00
return start;
for (p = lc_selected_item; *p && *p != CHAR_NODE_END && *p != CHAR_LINK_POINTER; p++)
1998-02-27 07:54:42 +03:00
;
if (*p == CHAR_LINK_POINTER){
link_name [0] = '[';
for (i = 1; *p != CHAR_LINK_END && *p && *p != CHAR_NODE_END && i < MAXLINKNAME-3; )
link_name [i++] = *++p;
link_name [i - 1] = ']';
link_name [i] = '\0';
p = search_string (fdata, link_name);
if (p != NULL) {
p += 1; /* Skip the newline following the start of the node */
1998-02-27 07:54:42 +03:00
return p;
}
1998-02-27 07:54:42 +03:00
}
/* Create a replacement page with the error message */
return _(" Help file format error\n");
1998-02-27 07:54:42 +03:00
}
static const char *
select_next_link (const char *current_link)
1998-02-27 07:54:42 +03:00
{
const char *p;
1998-02-27 07:54:42 +03:00
if (current_link == NULL)
return NULL;
1998-02-27 07:54:42 +03:00
p = search_string_node (current_link, STRING_LINK_END);
if (p == NULL)
1998-02-27 07:54:42 +03:00
return NULL;
p = search_string_node (p, STRING_LINK_START);
if (p == NULL)
1998-02-27 07:54:42 +03:00
return NULL;
return p - 1;
}
static const char *
select_prev_link (const char *current_link)
1998-02-27 07:54:42 +03:00
{
return current_link == NULL
? NULL
: search_char_node (current_link - 1, CHAR_LINK_START, -1);
1998-02-27 07:54:42 +03:00
}
static void
start_link_area (int x, int y, const char *link_name)
1998-02-27 07:54:42 +03:00
{
Link_Area *la;
1998-02-27 07:54:42 +03:00
if (inside_link_area)
message (D_NORMAL, _("Warning"), _(" Internal bug: Double start of link area "));
1998-02-27 07:54:42 +03:00
/* Allocate memory for a new link area */
la = g_new (Link_Area, 1);
1998-02-27 07:54:42 +03:00
/* Save the beginning coordinates of the link area */
la->x1 = x;
la->y1 = y;
1998-02-27 07:54:42 +03:00
/* Save the name of the destination anchor */
la->link_name = link_name;
link_area = g_slist_prepend (link_area, la);
1998-02-27 07:54:42 +03:00
inside_link_area = TRUE;
1998-02-27 07:54:42 +03:00
}
static void
end_link_area (int x, int y)
1998-02-27 07:54:42 +03:00
{
if (inside_link_area) {
Link_Area *la = (Link_Area *) link_area->data;
1998-02-27 07:54:42 +03:00
/* Save the end coordinates of the link area */
la->x2 = x;
la->y2 = y;
inside_link_area = FALSE;
1998-02-27 07:54:42 +03:00
}
}
static void
clear_link_areas (void)
1998-02-27 07:54:42 +03:00
{
g_slist_foreach (link_area, (GFunc) g_free, NULL);
g_slist_free (link_area);
link_area = NULL;
inside_link_area = FALSE;
1998-02-27 07:54:42 +03:00
}
static void
help_show (Dlg_head *h, const char *paint_start)
1998-02-27 07:54:42 +03:00
{
const char *p, *n;
int col, line, c, w;
gboolean painting = TRUE;
gboolean acs; /* Flag: Alternate character set active? */
gboolean repeat_paint;
int active_col, active_line; /* Active link position */
static char buff[MB_LEN_MAX + 1];
1998-02-27 07:54:42 +03:00
tty_setcolor (HELP_NORMAL_COLOR);
1998-02-27 07:54:42 +03:00
do {
line = col = active_col = active_line = 0;
repeat_paint = FALSE;
acs = FALSE;
1998-02-27 07:54:42 +03:00
clear_link_areas ();
if ((int) (selected_item - paint_start) < 0)
1998-02-27 07:54:42 +03:00
selected_item = NULL;
p = paint_start;
n = paint_start;
while (n[0] != '\0' && n[0] != CHAR_NODE_END && line < help_lines) {
p = n;
n = str_cget_next_char (p);
memcpy (buff, p, n - p);
buff[n - p] = '\0';
c = (unsigned char) buff[0];
1998-02-27 07:54:42 +03:00
switch (c){
case CHAR_LINK_START:
if (selected_item == NULL)
selected_item = p;
if (p == selected_item){
tty_setcolor (HELP_SLINK_COLOR);
1998-02-27 07:54:42 +03:00
/* Store the coordinates of the link */
active_col = col + 2;
active_line = line + 2;
}
else
tty_setcolor (HELP_LINK_COLOR);
1998-02-27 07:54:42 +03:00
start_link_area (col, line, p);
break;
case CHAR_LINK_POINTER:
painting = FALSE;
1998-02-27 07:54:42 +03:00
end_link_area (col - 1, line);
break;
case CHAR_LINK_END:
painting = TRUE;
tty_setcolor (HELP_NORMAL_COLOR);
1998-02-27 07:54:42 +03:00
break;
case CHAR_ALTERNATE:
acs = TRUE;
1998-02-27 07:54:42 +03:00
break;
case CHAR_NORMAL:
acs = FALSE;
1998-02-27 07:54:42 +03:00
break;
case CHAR_VERSION:
dlg_move (h, line+2, col+2);
tty_print_string (VERSION);
col += str_term_width1 (VERSION);
1998-02-27 07:54:42 +03:00
break;
case CHAR_FONT_BOLD:
tty_setcolor (HELP_BOLD_COLOR);
1998-02-27 07:54:42 +03:00
break;
case CHAR_FONT_ITALIC:
tty_setcolor (HELP_ITALIC_COLOR);
1998-02-27 07:54:42 +03:00
break;
case CHAR_FONT_NORMAL:
tty_setcolor (HELP_NORMAL_COLOR);
1998-02-27 07:54:42 +03:00
break;
case '\n':
line++;
col = 0;
break;
case '\t':
col = (col / 8 + 1) * 8;
1998-02-27 07:54:42 +03:00
break;
default:
if (!painting)
continue;
w = str_term_width1 (buff);
if (col + w > HELP_WINDOW_WIDTH)
1998-02-27 07:54:42 +03:00
continue;
dlg_move (h, line + 2, col + 2);
if (!acs)
tty_print_string (buff);
else if (c == ' ' || c == '.')
tty_print_char (c);
else
#ifndef HAVE_SLANG
tty_print_char (acs_map [c]);
#else
SLsmg_draw_object (h->y + line + 2, h->x + col + 2, c);
#endif
col += w;
1998-02-27 07:54:42 +03:00
break;
}
}
1998-02-27 07:54:42 +03:00
last_shown = p;
end_of_node = line < help_lines;
tty_setcolor (HELP_NORMAL_COLOR);
if ((int) (selected_item - last_shown) >= 0) {
if ((link_area == NULL) || (link_area->data == NULL))
selected_item = NULL;
else {
selected_item = ((Link_Area *) link_area->data)->link_name;
repeat_paint = TRUE;
1998-02-27 07:54:42 +03:00
}
}
} while (repeat_paint);
/* Position the cursor over a nice link */
if (active_col)
dlg_move (h, active_line, active_col);
}
2005-05-23 20:27:33 +04:00
static int
help_event (Gpm_Event *event, void *vp)
1998-02-27 07:54:42 +03:00
{
Widget *w = vp;
GSList *current_area;
1998-02-27 07:54:42 +03:00
if ((event->type & GPM_UP) == 0)
1998-02-27 07:54:42 +03:00
return 0;
/* The event is relative to the dialog window, adjust it: */
event->x -= 2;
1998-02-27 07:54:42 +03:00
event->y -= 2;
1998-02-27 07:54:42 +03:00
if (event->buttons & GPM_B_RIGHT){
currentpoint = history [history_ptr].page;
1998-02-27 07:54:42 +03:00
selected_item = history [history_ptr].link;
history_ptr--;
if (history_ptr < 0)
history_ptr = HISTORY_SIZE-1;
help_callback (w->parent, NULL, DLG_DRAW, 0, NULL);
1998-02-27 07:54:42 +03:00
return 0;
}
/* Test whether the mouse click is inside one of the link areas */
for (current_area = link_area; current_area != NULL; current_area = g_slist_next (current_area))
1998-02-27 07:54:42 +03:00
{
Link_Area *la = (Link_Area *) current_area->data;
1998-02-27 07:54:42 +03:00
/* Test one line link area */
if (event->y == la->y1 && event->x >= la->x1 &&
event->y == la->y2 && event->x <= la->x2)
1998-02-27 07:54:42 +03:00
break;
/* Test two line link area */
if (la->y1 + 1 == la->y2) {
1998-02-27 07:54:42 +03:00
/* The first line */
if (event->y == la->y1 && event->x >= la->x1)
1998-02-27 07:54:42 +03:00
break;
/* The second line */
if (event->y == la->y2 && event->x <= la->x2)
1998-02-27 07:54:42 +03:00
break;
}
/* Mouse will not work with link areas of more than two lines */
}
/* Test whether a link area was found */
if (current_area != NULL) {
Link_Area *la = (Link_Area *) current_area->data;
1998-02-27 07:54:42 +03:00
/* The click was inside a link area -> follow the link */
history_ptr = (history_ptr+1) % HISTORY_SIZE;
history [history_ptr].page = currentpoint;
history [history_ptr].link = la->link_name;
currentpoint = help_follow_link (currentpoint, la->link_name);
1998-02-27 07:54:42 +03:00
selected_item = NULL;
} else if (event->y < 0)
move_backward (help_lines - 1);
else if (event->y >= help_lines)
move_forward (help_lines - 1);
else if (event->y < help_lines/2)
move_backward (1);
else
move_forward (1);
1998-02-27 07:54:42 +03:00
/* Show the new node */
help_callback (w->parent, NULL, DLG_DRAW, 0, NULL);
1998-02-27 07:54:42 +03:00
return 0;
}
/* show help */
1998-12-03 00:27:27 +03:00
static void
help_help (Dlg_head *h)
1998-02-27 07:54:42 +03:00
{
const char *p;
history_ptr = (history_ptr + 1) % HISTORY_SIZE;
1998-02-27 07:54:42 +03:00
history [history_ptr].page = currentpoint;
history [history_ptr].link = selected_item;
p = search_string (fdata, "[How to use help]");
if (p != NULL) {
currentpoint = p + 1; /* Skip the newline following the start of the node */
selected_item = NULL;
help_callback (h, NULL, DLG_DRAW, 0, NULL);
}
1998-02-27 07:54:42 +03:00
}
1998-12-03 00:27:27 +03:00
static void
help_index (Dlg_head *h)
1998-02-27 07:54:42 +03:00
{
const char *new_item;
1998-02-27 07:54:42 +03:00
new_item = search_string (fdata, "[Contents]");
if (new_item == NULL)
message (D_ERROR, MSG_ERROR, _(" Cannot find node %s in help file "),
"[Contents]");
else {
history_ptr = (history_ptr + 1) % HISTORY_SIZE;
history[history_ptr].page = currentpoint;
history[history_ptr].link = selected_item;
1998-02-27 07:54:42 +03:00
currentpoint = new_item + 1; /* Skip the newline following the start of the node */
selected_item = NULL;
help_callback (h, NULL, DLG_DRAW, 0, NULL);
}
1998-02-27 07:54:42 +03:00
}
static void
help_back (Dlg_head *h)
1998-02-27 07:54:42 +03:00
{
currentpoint = history [history_ptr].page;
1998-02-27 07:54:42 +03:00
selected_item = history [history_ptr].link;
history_ptr--;
if (history_ptr < 0)
history_ptr = HISTORY_SIZE - 1;
help_callback (h, NULL, DLG_DRAW, 0, NULL); /* FIXME: unneeded? */
1998-02-27 07:54:42 +03:00
}
static void
help_cmk_move_backward(void *vp, int lines)
1998-02-27 07:54:42 +03:00
{
(void) &vp;
move_backward (lines);
1998-02-27 07:54:42 +03:00
}
static void
help_cmk_move_forward(void *vp, int lines)
1998-02-27 07:54:42 +03:00
{
(void) &vp;
move_forward (lines);
}
static void
help_cmk_moveto_top(void *vp, int lines)
{
(void) &vp;
(void) &lines;
move_to_top ();
}
static void
help_cmk_moveto_bottom(void *vp, int lines)
{
(void) &vp;
(void) &lines;
move_to_bottom ();
}
static void
help_next_link (gboolean move_down)
{
const char *new_item;
1998-02-27 07:54:42 +03:00
new_item = select_next_link (selected_item);
if (new_item != NULL) {
selected_item = new_item;
if ((int) (selected_item - last_shown) >= 0) {
if (move_down)
move_forward (1);
else
selected_item = NULL;
1998-02-27 07:54:42 +03:00
}
} else if (move_down)
move_forward (1);
else
1998-02-27 07:54:42 +03:00
selected_item = NULL;
}
static void
help_prev_link (gboolean move_up)
{
const char *new_item;
new_item = select_prev_link (selected_item);
selected_item = new_item;
if ((selected_item == NULL) || (selected_item < currentpoint)) {
if (move_up)
move_backward (1);
else if ((link_area != NULL) && (link_area->data != NULL))
selected_item = ((Link_Area *) link_area->data)->link_name;
1998-02-27 07:54:42 +03:00
else
selected_item = NULL;
}
}
static void
help_next_node (void)
{
const char *new_item;
new_item = currentpoint;
while ((*new_item != '\0') && (*new_item != CHAR_NODE_END))
new_item++;
if (*++new_item == '[')
while (*++new_item != '\0')
if ((*new_item == ']') && (*++new_item != '\0')
&& (*++new_item != '\0')) {
currentpoint = new_item;
selected_item = NULL;
break;
}
}
static void
help_prev_node (void)
{
const char *new_item;
new_item = currentpoint;
while (((int) (new_item - fdata) > 1) && (*new_item != CHAR_NODE_END))
1998-02-27 07:54:42 +03:00
new_item--;
new_item--;
while (((int) (new_item - fdata) > 0) && (*new_item != CHAR_NODE_END))
new_item--;
while (*new_item != ']')
new_item++;
currentpoint = new_item + 2;
selected_item = NULL;
}
static void
help_select_link (void)
{
/* follow link */
if (selected_item == NULL) {
#ifdef WE_WANT_TO_GO_BACKWARD_ON_KEY_RIGHT
/* Is there any reason why the right key would take us
* backward if there are no links selected?, I agree
* with Torben than doing nothing in this case is better
*/
/* If there are no links, go backward in history */
history_ptr--;
if (history_ptr < 0)
history_ptr = HISTORY_SIZE-1;
currentpoint = history [history_ptr].page;
selected_item = history [history_ptr].link;
#endif
} else {
history_ptr = (history_ptr + 1) % HISTORY_SIZE;
history [history_ptr].page = currentpoint;
history [history_ptr].link = selected_item;
currentpoint = help_follow_link (currentpoint, selected_item);
}
1998-02-27 07:54:42 +03:00
selected_item = NULL;
}
static cb_ret_t
help_execute_cmd (unsigned long command)
{
cb_ret_t ret = MSG_HANDLED;
switch (command) {
case CK_HelpHelp:
help_help (whelp);
break;
case CK_HelpIndex:
help_index (whelp);
break;
case CK_HelpBack:
help_back (whelp);
break;
case CK_HelpMoveUp:
help_prev_link (TRUE);
break;
case CK_HelpMoveDown:
help_next_link (TRUE);
break;
case CK_HelpSelectLink:
help_select_link ();
break;
case CK_HelpNextLink:
help_next_link (FALSE);
break;
case CK_HelpPrevLink:
help_prev_link (FALSE);
break;
case CK_HelpNextNode:
help_next_node ();
break;
case CK_HelpPrevNode:
help_prev_node ();
break;
case CK_HelpQuit:
dlg_stop (whelp);
break;
1998-02-27 07:54:42 +03:00
default:
ret = MSG_NOT_HANDLED;
}
return ret;
}
static cb_ret_t
help_handle_key (Dlg_head *h, int c)
{
if (c != KEY_UP && c != KEY_DOWN &&
check_movement_keys (c, help_lines, NULL,
help_cmk_move_backward,
help_cmk_move_forward,
help_cmk_moveto_top,
help_cmk_moveto_bottom) == MSG_HANDLED) {
/* Nothing */;
} else {
unsigned long command;
command = lookup_keymap_command (help_map, c);
if ((command == CK_Ignore_Key)
|| (help_execute_cmd (command) == MSG_NOT_HANDLED))
return MSG_NOT_HANDLED;
1998-02-27 07:54:42 +03:00
}
help_callback (h, NULL, DLG_DRAW, 0, NULL);
return MSG_HANDLED;
1998-02-27 07:54:42 +03:00
}
static cb_ret_t
help_callback (Dlg_head *h, Widget *sender,
dlg_msg_t msg, int parm, void *data)
1998-02-27 07:54:42 +03:00
{
WButtonBar *bb;
switch (msg) {
case DLG_RESIZE:
help_lines = min (LINES - 4, max (2 * LINES / 3, 18));
dlg_set_size (h, help_lines + 4, HELP_WINDOW_WIDTH + 4);
bb = find_buttonbar (h);
widget_set_size (&bb->widget, LINES - 1, 0, 1, COLS);
return MSG_HANDLED;
1998-02-27 07:54:42 +03:00
case DLG_DRAW:
common_dialog_repaint (h);
help_show (h, currentpoint);
return MSG_HANDLED;
1998-02-27 07:54:42 +03:00
case DLG_KEY:
return help_handle_key (h, parm);
case DLG_ACTION:
/* command from buttonbar */
return help_execute_cmd (parm);
default:
return default_dlg_callback (h, sender, msg, parm, data);
1998-02-27 07:54:42 +03:00
}
}
1998-12-03 00:27:27 +03:00
static void
interactive_display_finish (void)
1998-02-27 07:54:42 +03:00
{
clear_link_areas ();
}
/* translate help file into terminal encoding */
static void
translate_file (char *filedata)
{
GIConv conv;
GString *translated_data;
/* initial allocation for largest whole help file */
translated_data = g_string_sized_new (32 * 1024);
conv = str_crt_conv_from ("UTF-8");
if (conv == INVALID_CONV)
g_string_free (translated_data, TRUE);
else {
g_free (fdata);
if (str_convert (conv, filedata, translated_data) != ESTR_FAILURE)
fdata = g_string_free (translated_data, FALSE);
else {
fdata = NULL;
g_string_free (translated_data, TRUE);
}
str_close_conv (conv);
}
}
static cb_ret_t
md_callback (Widget *w, widget_msg_t msg, int parm)
{
switch (msg) {
case WIDGET_RESIZED:
w->lines = help_lines;
return MSG_HANDLED;
default:
return default_proc (msg, parm);
}
}
static Widget *
mousedispatch_new (int y, int x, int yl, int xl)
{
Widget *w = g_new (Widget, 1);
init_widget (w, y, x, yl, xl, md_callback, help_event);
return w;
1998-02-27 07:54:42 +03:00
}
1998-12-03 00:27:27 +03:00
void
interactive_display (const char *filename, const char *node)
1998-02-27 07:54:42 +03:00
{
const int help_colors[DLG_COLOR_NUM] =
{
HELP_NORMAL_COLOR, /* common text color */
0, /* unused in help */
HELP_BOLD_COLOR, /* title color */
0 /* unused in help */
};
WButtonBar *help_bar;
Widget *md;
char *hlpfile = NULL;
char *filedata;
if (filename != NULL)
filedata = load_file (filename);
else
filedata = load_mc_home_file (mc_home, mc_home_alt, "mc.hlp", &hlpfile);
if (filedata == NULL)
message (D_ERROR, MSG_ERROR, _(" Cannot open file %s \n %s "), filename ? filename : hlpfile,
unix_error_string (errno));
g_free (hlpfile);
if (filedata == NULL)
return;
translate_file (filedata);
g_free (filedata);
if (fdata == NULL)
return;
if ((node == NULL) || (*node == '\0'))
node = "[main]";
main_node = search_string (fdata, node);
if (main_node == NULL) {
message (D_ERROR, MSG_ERROR, _(" Cannot find node %s in help file "),
node);
/* Fallback to [main], return if it also cannot be found */
main_node = search_string (fdata, "[main]");
if (main_node == NULL) {
interactive_display_finish ();
return;
}
1998-02-27 07:54:42 +03:00
}
help_lines = min (LINES - 4, max (2 * LINES / 3, 18));
1998-02-27 07:54:42 +03:00
whelp =
create_dlg (0, 0, help_lines + 4, HELP_WINDOW_WIDTH + 4,
help_colors, help_callback, "[Help]", _("Help"),
DLG_TRYUP | DLG_CENTER | DLG_WANT_TAB);
1998-02-27 07:54:42 +03:00
selected_item = search_string_node (main_node, STRING_LINK_START) - 1;
currentpoint = main_node + 1; /* Skip the newline following the start of the node */
1998-02-27 07:54:42 +03:00
for (history_ptr = HISTORY_SIZE; history_ptr;) {
1998-02-27 07:54:42 +03:00
history_ptr--;
history[history_ptr].page = currentpoint;
history[history_ptr].link = selected_item;
1998-02-27 07:54:42 +03:00
}
help_bar = buttonbar_new (TRUE);
help_bar->widget.y -= whelp->y;
help_bar->widget.x -= whelp->x;
md = mousedispatch_new (1, 1, help_lines, HELP_WINDOW_WIDTH - 2);
1998-02-27 07:54:42 +03:00
add_widget (whelp, md);
add_widget (whelp, help_bar);
1998-02-27 07:54:42 +03:00
buttonbar_set_label (help_bar, 1, Q_("ButtonBar|Help"), help_map, NULL);
buttonbar_set_label (help_bar, 2, Q_("ButtonBar|Index"), help_map, NULL);
buttonbar_set_label (help_bar, 3, Q_("ButtonBar|Prev"), help_map, NULL);
buttonbar_set_label (help_bar, 4, "", help_map, NULL);
buttonbar_set_label (help_bar, 5, "", help_map, NULL);
buttonbar_set_label (help_bar, 6, "", help_map, NULL);
buttonbar_set_label (help_bar, 7, "", help_map, NULL);
buttonbar_set_label (help_bar, 8, "", help_map, NULL);
buttonbar_set_label (help_bar, 9, "", help_map, NULL);
buttonbar_set_label (help_bar, 10, Q_("ButtonBar|Quit"), help_map, NULL);
1998-02-27 07:54:42 +03:00
run_dlg (whelp);
interactive_display_finish ();
destroy_dlg (whelp);
}