2011-10-15 14:56:47 +04:00
|
|
|
/*
|
|
|
|
Hypertext file browser.
|
|
|
|
|
2020-01-18 19:54:37 +03:00
|
|
|
Copyright (C) 1994-2020
|
2014-02-12 10:33:10 +04:00
|
|
|
Free Software Foundation, Inc.
|
2011-10-15 14:56:47 +04:00
|
|
|
|
|
|
|
This file is part of the Midnight Commander.
|
2010-04-01 13:14:00 +04:00
|
|
|
|
2011-10-15 14:56:47 +04:00
|
|
|
The Midnight Commander 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 3 of the License,
|
|
|
|
or (at your option) any later version.
|
2010-04-01 13:14:00 +04:00
|
|
|
|
2011-10-15 14:56:47 +04:00
|
|
|
The Midnight Commander is distributed in the hope that it will be useful,
|
1998-02-27 07:54:42 +03:00
|
|
|
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
|
2011-10-15 14:56:47 +04:00
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2010-04-01 13:14:00 +04:00
|
|
|
*/
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
|
2009-02-05 21:28:18 +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
|
2013-07-23 02:16:20 +04:00
|
|
|
* to the appropriate routine.
|
2009-02-05 21:28:18 +03:00
|
|
|
*/
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
2005-02-08 12:04:03 +03:00
|
|
|
|
|
|
|
#include <errno.h>
|
2017-04-16 07:56:22 +03:00
|
|
|
#include <limits.h> /* MB_LEN_MAX */
|
1998-02-27 07:54:42 +03:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2001-09-03 09:07:40 +04:00
|
|
|
|
2010-01-20 18:11:52 +03:00
|
|
|
#include "lib/global.h"
|
2009-05-09 19:17:57 +04:00
|
|
|
|
2010-01-08 17:47:19 +03:00
|
|
|
#include "lib/tty/tty.h"
|
2010-08-16 16:36:47 +04:00
|
|
|
#include "lib/skin.h"
|
2010-01-21 15:17:26 +03:00
|
|
|
#include "lib/strutil.h"
|
2010-09-16 14:15:40 +04:00
|
|
|
#include "lib/fileloc.h"
|
2010-11-11 16:58:29 +03:00
|
|
|
#include "lib/util.h"
|
2010-11-12 11:03:57 +03:00
|
|
|
#include "lib/widget.h"
|
2011-02-17 15:02:31 +03:00
|
|
|
#include "lib/event-types.h"
|
2009-05-09 19:17:57 +04:00
|
|
|
|
2010-11-18 12:39:09 +03:00
|
|
|
#include "keybind-defaults.h"
|
2009-11-07 18:36:44 +03:00
|
|
|
#include "help.h"
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/*** global variables ****************************************************************************/
|
|
|
|
|
|
|
|
/*** file scope macro definitions ****************************************************************/
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
#define MAXLINKNAME 80
|
|
|
|
#define HISTORY_SIZE 20
|
2016-04-07 10:52:04 +03:00
|
|
|
#define HELP_WINDOW_WIDTH MIN(80, COLS - 16)
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-04-01 13:14:00 +04: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
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/*** file scope type declarations ****************************************************************/
|
|
|
|
|
|
|
|
/* Link areas for the mouse */
|
|
|
|
typedef struct Link_Area
|
|
|
|
{
|
|
|
|
int x1, y1, x2, y2;
|
|
|
|
const char *link_name;
|
|
|
|
} Link_Area;
|
|
|
|
|
|
|
|
/*** file scope variables ************************************************************************/
|
2009-11-07 18:36:44 +03:00
|
|
|
|
2010-04-01 13:14:00 +04: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? */
|
2006-12-31 02:03:48 +03:00
|
|
|
static const char *currentpoint;
|
2004-08-30 03:39:38 +04:00
|
|
|
static const char *selected_item;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* The widget variables */
|
2012-09-28 11:18:45 +04:00
|
|
|
static WDialog *whelp;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-04-01 13:14:00 +04:00
|
|
|
static struct
|
|
|
|
{
|
|
|
|
const char *page; /* Pointer to the selected page */
|
|
|
|
const char *link; /* Pointer to the selected link */
|
|
|
|
} history[HISTORY_SIZE];
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-03-03 19:51:14 +03:00
|
|
|
static GSList *link_area = NULL;
|
2009-11-07 18:36:44 +03:00
|
|
|
static gboolean inside_link_area = FALSE;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2012-09-28 15:05:43 +04:00
|
|
|
static cb_ret_t help_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/*** file scope functions ************************************************************************/
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/** returns the position where text was found in the start buffer
|
|
|
|
* or 0 if not found
|
|
|
|
*/
|
2004-08-30 03:39:38 +04:00
|
|
|
static const char *
|
2004-09-18 18:30:58 +04:00
|
|
|
search_string (const char *start, const char *text)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-09-18 18:30:58 +04:00
|
|
|
const char *result = NULL;
|
2009-02-06 01:40:32 +03:00
|
|
|
char *local_text = g_strdup (text);
|
2004-09-18 18:30:58 +04:00
|
|
|
char *d = local_text;
|
2004-08-30 03:39:38 +04:00
|
|
|
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 */
|
2010-04-01 13:14:00 +04:00
|
|
|
while (*d != '\0')
|
|
|
|
{
|
|
|
|
if (*d == '\n')
|
|
|
|
*d = ' ';
|
|
|
|
str_next_char (&d);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2009-11-07 18:36:44 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Do search */
|
2010-04-01 13:14:00 +04:00
|
|
|
for (d = local_text; *e; e++)
|
|
|
|
{
|
|
|
|
if (*d == *e)
|
|
|
|
d++;
|
|
|
|
else
|
|
|
|
d = local_text;
|
|
|
|
if (*d == '\0')
|
|
|
|
{
|
|
|
|
result = e + 1;
|
|
|
|
break;
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2009-11-07 18:36:44 +03:00
|
|
|
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (local_text);
|
2004-09-18 18:30:58 +04:00
|
|
|
return result;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/** Searches text in the buffer pointed by start. Search ends
|
|
|
|
* if the CHAR_NODE_END is found in the text.
|
2012-11-05 17:57:50 +04:00
|
|
|
* @return NULL on failure
|
2010-11-10 14:09:42 +03:00
|
|
|
*/
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static const char *
|
|
|
|
search_string_node (const char *start, const char *text)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-08-30 03:39:38 +04:00
|
|
|
const char *d = text;
|
|
|
|
const char *e = start;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
if (start != NULL)
|
2010-04-01 13:14:00 +04:00
|
|
|
for (; *e && *e != CHAR_NODE_END; e++)
|
|
|
|
{
|
|
|
|
if (*d == *e)
|
|
|
|
d++;
|
|
|
|
else
|
|
|
|
d = text;
|
|
|
|
if (*d == '\0')
|
|
|
|
return e + 1;
|
|
|
|
}
|
2009-11-07 18:36:44 +03:00
|
|
|
|
|
|
|
return NULL;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/** Searches the_char in the buffer pointer by start and searches
|
|
|
|
* it can search forward (direction = 1) or backward (direction = -1)
|
|
|
|
*/
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static const char *
|
|
|
|
search_char_node (const char *start, char the_char, int direction)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-08-30 03:39:38 +04:00
|
|
|
const char *e;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
for (e = start; (*e != '\0') && (*e != CHAR_NODE_END); e += direction)
|
2010-04-01 13:14:00 +04:00
|
|
|
if (*e == the_char)
|
|
|
|
return e;
|
2009-11-07 18:36:44 +03:00
|
|
|
|
|
|
|
return NULL;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/** Returns the new current pointer when moved lines lines */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static const char *
|
|
|
|
move_forward2 (const char *c, int lines)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-08-30 03:39:38 +04:00
|
|
|
const char *p;
|
2009-11-07 18:36:44 +03:00
|
|
|
int line;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
currentpoint = c;
|
2010-04-01 13:14:00 +04:00
|
|
|
for (line = 0, p = currentpoint; (*p != '\0') && (*p != CHAR_NODE_END); str_cnext_char (&p))
|
|
|
|
{
|
|
|
|
if (line == lines)
|
|
|
|
return currentpoint = p;
|
2009-11-07 18:36:44 +03:00
|
|
|
|
2010-04-01 13:14:00 +04:00
|
|
|
if (*p == '\n')
|
|
|
|
line++;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
return currentpoint = c;
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static const char *
|
|
|
|
move_backward2 (const char *c, int lines)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-08-30 03:39:38 +04:00
|
|
|
const char *p;
|
1998-02-27 07:54:42 +03:00
|
|
|
int line;
|
|
|
|
|
|
|
|
currentpoint = c;
|
2010-04-01 13:14:00 +04:00
|
|
|
for (line = 0, p = currentpoint; (*p != '\0') && ((int) (p - fdata) >= 0); str_cprev_char (&p))
|
|
|
|
{
|
|
|
|
if (*p == CHAR_NODE_END)
|
|
|
|
{
|
|
|
|
/* 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 */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*(p - 1) == '\n')
|
|
|
|
line++;
|
|
|
|
if (line == lines)
|
|
|
|
return currentpoint = p;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
return currentpoint = c;
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
move_forward (int i)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2009-11-07 18:36:44 +03:00
|
|
|
if (!end_of_node)
|
2010-04-01 13:14:00 +04:00
|
|
|
currentpoint = move_forward2 (currentpoint, i);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
move_backward (int i)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
currentpoint = move_backward2 (currentpoint, ++i);
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
move_to_top (void)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2009-11-07 18:36:44 +03:00
|
|
|
while (((int) (currentpoint > fdata) > 0) && (*currentpoint != CHAR_NODE_END))
|
2010-04-01 13:14:00 +04:00
|
|
|
currentpoint--;
|
2009-11-07 18:36:44 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
while (*currentpoint != ']')
|
2010-04-01 13:14:00 +04:00
|
|
|
currentpoint++;
|
|
|
|
currentpoint = currentpoint + 2; /* Skip the newline following the start of the node */
|
1998-02-27 07:54:42 +03:00
|
|
|
selected_item = NULL;
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
move_to_bottom (void)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2009-11-07 18:36:44 +03:00
|
|
|
while ((*currentpoint != '\0') && (*currentpoint != CHAR_NODE_END))
|
2010-04-01 13:14:00 +04:00
|
|
|
currentpoint++;
|
1998-02-27 07:54:42 +03:00
|
|
|
currentpoint--;
|
2010-03-09 22:41:33 +03:00
|
|
|
move_backward (1);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static const char *
|
|
|
|
help_follow_link (const char *start, const char *lc_selected_item)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-08-30 03:39:38 +04:00
|
|
|
const char *p;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
if (lc_selected_item == NULL)
|
2010-04-01 13:14:00 +04:00
|
|
|
return start;
|
2009-11-07 18:36:44 +03:00
|
|
|
|
2009-10-30 04:12:04 +03:00
|
|
|
for (p = lc_selected_item; *p && *p != CHAR_NODE_END && *p != CHAR_LINK_POINTER; p++)
|
2010-04-01 13:14:00 +04:00
|
|
|
;
|
|
|
|
if (*p == CHAR_LINK_POINTER)
|
|
|
|
{
|
2013-10-15 10:34:04 +04:00
|
|
|
int i;
|
|
|
|
char link_name[MAXLINKNAME];
|
|
|
|
|
2010-04-01 13:14:00 +04:00
|
|
|
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 */
|
|
|
|
return p;
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2002-11-12 20:46:54 +03:00
|
|
|
|
|
|
|
/* Create a replacement page with the error message */
|
2010-05-15 18:45:13 +04:00
|
|
|
return _("Help file format error\n");
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static const char *
|
|
|
|
select_next_link (const char *current_link)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-08-30 03:39:38 +04:00
|
|
|
const char *p;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
if (current_link == NULL)
|
2010-04-01 13:14:00 +04:00
|
|
|
return NULL;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
p = search_string_node (current_link, STRING_LINK_END);
|
2009-11-07 18:36:44 +03:00
|
|
|
if (p == NULL)
|
2010-04-01 13:14:00 +04:00
|
|
|
return NULL;
|
1998-02-27 07:54:42 +03:00
|
|
|
p = search_string_node (p, STRING_LINK_START);
|
2009-11-07 18:36:44 +03:00
|
|
|
if (p == NULL)
|
2010-04-01 13:14:00 +04:00
|
|
|
return NULL;
|
1998-02-27 07:54:42 +03:00
|
|
|
return p - 1;
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static const char *
|
|
|
|
select_prev_link (const char *current_link)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2010-04-01 13:14:00 +04:00
|
|
|
return current_link == NULL ? NULL : search_char_node (current_link - 1, CHAR_LINK_START, -1);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
start_link_area (int x, int y, const char *link_name)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2010-03-03 19:51:14 +03:00
|
|
|
Link_Area *la;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
if (inside_link_area)
|
2017-05-25 21:32:46 +03:00
|
|
|
message (D_NORMAL, _("Warning"), "%s", _("Internal bug: Double start of link area"));
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* Allocate memory for a new link area */
|
2010-03-03 19:51:14 +03:00
|
|
|
la = g_new (Link_Area, 1);
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Save the beginning coordinates of the link area */
|
2010-03-03 19:51:14 +03:00
|
|
|
la->x1 = x;
|
|
|
|
la->y1 = y;
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Save the name of the destination anchor */
|
2010-03-03 19:51:14 +03:00
|
|
|
la->link_name = link_name;
|
|
|
|
link_area = g_slist_prepend (link_area, la);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
inside_link_area = TRUE;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
end_link_area (int x, int y)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2010-04-01 13:14:00 +04:00
|
|
|
if (inside_link_area)
|
|
|
|
{
|
|
|
|
Link_Area *la = (Link_Area *) link_area->data;
|
|
|
|
/* 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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
clear_link_areas (void)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2019-12-01 14:59:35 +03:00
|
|
|
g_clear_slist (&link_area, g_free);
|
2009-11-07 18:36:44 +03:00
|
|
|
inside_link_area = FALSE;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2010-03-09 22:41:33 +03:00
|
|
|
static void
|
2012-09-28 11:18:45 +04:00
|
|
|
help_print_word (WDialog * h, GString * word, int *col, int *line, gboolean add_space)
|
2010-03-09 22:41:33 +03:00
|
|
|
{
|
|
|
|
if (*line >= help_lines)
|
2010-04-01 13:14:00 +04:00
|
|
|
g_string_set_size (word, 0);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int w;
|
|
|
|
|
|
|
|
w = str_term_width1 (word->str);
|
|
|
|
if (*col + w >= HELP_WINDOW_WIDTH)
|
|
|
|
{
|
|
|
|
*col = 0;
|
|
|
|
(*line)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*line >= help_lines)
|
|
|
|
g_string_set_size (word, 0);
|
|
|
|
else
|
|
|
|
{
|
2019-10-16 13:07:24 +03:00
|
|
|
widget_gotoyx (h, *line + 2, *col + 2);
|
2010-04-01 13:14:00 +04:00
|
|
|
tty_print_string (word->str);
|
|
|
|
g_string_set_size (word, 0);
|
|
|
|
*col += w;
|
|
|
|
}
|
2010-03-09 22:41:33 +03:00
|
|
|
}
|
|
|
|
|
2010-04-01 13:14:00 +04:00
|
|
|
if (add_space)
|
|
|
|
{
|
|
|
|
if (*col < HELP_WINDOW_WIDTH - 1)
|
|
|
|
{
|
|
|
|
tty_print_char (' ');
|
|
|
|
(*col)++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*col = 0;
|
|
|
|
(*line)++;
|
|
|
|
}
|
2010-03-09 22:41:33 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
2012-09-28 11:18:45 +04:00
|
|
|
help_show (WDialog * h, const char *paint_start)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2008-12-29 02:12:21 +03:00
|
|
|
const char *p, *n;
|
2010-03-09 22:41:33 +03:00
|
|
|
int col, line, c;
|
2009-11-07 18:36:44 +03:00
|
|
|
gboolean painting = TRUE;
|
2010-04-01 13:14:00 +04:00
|
|
|
gboolean acs; /* Flag: Alternate character set active? */
|
2009-11-07 18:36:44 +03:00
|
|
|
gboolean repeat_paint;
|
2010-04-01 13:14:00 +04:00
|
|
|
int active_col, active_line; /* Active link position */
|
2010-03-09 22:41:33 +03:00
|
|
|
char buff[MB_LEN_MAX + 1];
|
|
|
|
GString *word;
|
|
|
|
|
|
|
|
word = g_string_sized_new (32);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2009-05-11 16:13:58 +04:00
|
|
|
tty_setcolor (HELP_NORMAL_COLOR);
|
2010-04-01 13:14:00 +04:00
|
|
|
do
|
|
|
|
{
|
|
|
|
line = col = active_col = active_line = 0;
|
|
|
|
repeat_paint = FALSE;
|
|
|
|
acs = FALSE;
|
|
|
|
|
|
|
|
clear_link_areas ();
|
|
|
|
if ((int) (selected_item - paint_start) < 0)
|
|
|
|
selected_item = NULL;
|
|
|
|
|
2008-12-29 02:12:21 +03:00
|
|
|
p = paint_start;
|
|
|
|
n = paint_start;
|
2010-04-01 13:14:00 +04:00
|
|
|
while ((n[0] != '\0') && (n[0] != CHAR_NODE_END) && (line < help_lines))
|
|
|
|
{
|
2008-12-29 02:12:21 +03:00
|
|
|
p = n;
|
|
|
|
n = str_cget_next_char (p);
|
|
|
|
memcpy (buff, p, n - p);
|
|
|
|
buff[n - p] = '\0';
|
2009-11-07 18:36:44 +03:00
|
|
|
|
2010-04-01 13:14:00 +04:00
|
|
|
c = (unsigned char) buff[0];
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case CHAR_LINK_START:
|
|
|
|
if (selected_item == NULL)
|
|
|
|
selected_item = p;
|
|
|
|
if (p != selected_item)
|
|
|
|
tty_setcolor (HELP_LINK_COLOR);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tty_setcolor (HELP_SLINK_COLOR);
|
|
|
|
|
|
|
|
/* Store the coordinates of the link */
|
|
|
|
active_col = col + 2;
|
|
|
|
active_line = line + 2;
|
|
|
|
}
|
|
|
|
start_link_area (col, line, p);
|
|
|
|
break;
|
|
|
|
case CHAR_LINK_POINTER:
|
|
|
|
painting = FALSE;
|
|
|
|
break;
|
|
|
|
case CHAR_LINK_END:
|
|
|
|
painting = TRUE;
|
|
|
|
help_print_word (h, word, &col, &line, FALSE);
|
2012-03-27 20:46:34 +04:00
|
|
|
end_link_area (col - 1, line);
|
2010-04-01 13:14:00 +04:00
|
|
|
tty_setcolor (HELP_NORMAL_COLOR);
|
|
|
|
break;
|
|
|
|
case CHAR_ALTERNATE:
|
|
|
|
acs = TRUE;
|
|
|
|
break;
|
|
|
|
case CHAR_NORMAL:
|
|
|
|
acs = FALSE;
|
|
|
|
break;
|
|
|
|
case CHAR_VERSION:
|
2019-10-16 13:07:24 +03:00
|
|
|
widget_gotoyx (h, line + 2, col + 2);
|
2010-04-01 13:14:00 +04:00
|
|
|
tty_print_string (VERSION);
|
|
|
|
col += str_term_width1 (VERSION);
|
|
|
|
break;
|
|
|
|
case CHAR_FONT_BOLD:
|
|
|
|
tty_setcolor (HELP_BOLD_COLOR);
|
|
|
|
break;
|
|
|
|
case CHAR_FONT_ITALIC:
|
|
|
|
tty_setcolor (HELP_ITALIC_COLOR);
|
|
|
|
break;
|
|
|
|
case CHAR_FONT_NORMAL:
|
|
|
|
help_print_word (h, word, &col, &line, FALSE);
|
|
|
|
tty_setcolor (HELP_NORMAL_COLOR);
|
|
|
|
break;
|
|
|
|
case '\n':
|
|
|
|
if (painting)
|
|
|
|
help_print_word (h, word, &col, &line, FALSE);
|
|
|
|
line++;
|
|
|
|
col = 0;
|
|
|
|
break;
|
|
|
|
case ' ':
|
2017-01-10 03:07:03 +03:00
|
|
|
case '\t':
|
2013-07-23 02:16:20 +04:00
|
|
|
/* word delimiter */
|
2010-04-01 13:14:00 +04:00
|
|
|
if (painting)
|
2017-01-10 03:07:03 +03:00
|
|
|
{
|
|
|
|
help_print_word (h, word, &col, &line, c == ' ');
|
|
|
|
if (c == '\t')
|
|
|
|
{
|
|
|
|
col = (col / 8 + 1) * 8;
|
|
|
|
if (col >= HELP_WINDOW_WIDTH)
|
|
|
|
{
|
|
|
|
line++;
|
|
|
|
col = 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-04-01 13:14:00 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (painting && (line < help_lines))
|
|
|
|
{
|
|
|
|
if (!acs)
|
|
|
|
/* accumulate symbols in a word */
|
|
|
|
g_string_append (word, buff);
|
|
|
|
else if (col < HELP_WINDOW_WIDTH)
|
|
|
|
{
|
2019-10-16 13:07:24 +03:00
|
|
|
widget_gotoyx (h, line + 2, col + 2);
|
2010-04-01 13:14:00 +04:00
|
|
|
|
|
|
|
if ((c == ' ') || (c == '.'))
|
|
|
|
tty_print_char (c);
|
|
|
|
else
|
2009-08-09 21:40:55 +04:00
|
|
|
#ifndef HAVE_SLANG
|
2010-04-01 13:14:00 +04:00
|
|
|
tty_print_char (acs_map[c]);
|
1998-03-24 02:06:36 +03:00
|
|
|
#else
|
2012-11-20 13:44:14 +04:00
|
|
|
SLsmg_draw_object (WIDGET (h)->y + line + 2, WIDGET (h)->x + col + 2,
|
|
|
|
c);
|
1998-03-24 02:06:36 +03:00
|
|
|
#endif
|
2010-04-01 13:14:00 +04:00
|
|
|
col++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* print last word */
|
|
|
|
if (n[0] == CHAR_NODE_END)
|
|
|
|
help_print_word (h, word, &col, &line, FALSE);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (repeat_paint);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-03-09 22:41:33 +03:00
|
|
|
g_string_free (word, TRUE);
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Position the cursor over a nice link */
|
|
|
|
if (active_col)
|
2019-10-16 13:07:24 +03:00
|
|
|
widget_gotoyx (h, active_line, active_col);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/** show help */
|
|
|
|
|
1998-12-03 00:27:27 +03:00
|
|
|
static void
|
2012-09-28 11:18:45 +04:00
|
|
|
help_help (WDialog * h)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-07-22 12:41:45 +04:00
|
|
|
const char *p;
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
history_ptr = (history_ptr + 1) % HISTORY_SIZE;
|
2010-04-01 13:14:00 +04:00
|
|
|
history[history_ptr].page = currentpoint;
|
|
|
|
history[history_ptr].link = selected_item;
|
2005-07-22 12:41:45 +04:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
p = search_string (fdata, "[How to use help]");
|
2010-04-01 13:14:00 +04:00
|
|
|
if (p != NULL)
|
|
|
|
{
|
|
|
|
currentpoint = p + 1; /* Skip the newline following the start of the node */
|
|
|
|
selected_item = NULL;
|
2016-10-30 12:40:20 +03:00
|
|
|
widget_draw (WIDGET (h));
|
2009-11-07 18:36:44 +03:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
1998-12-03 00:27:27 +03:00
|
|
|
static void
|
2012-09-28 11:18:45 +04:00
|
|
|
help_index (WDialog * h)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-08-30 03:39:38 +04:00
|
|
|
const char *new_item;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
new_item = search_string (fdata, "[Contents]");
|
|
|
|
|
|
|
|
if (new_item == NULL)
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, MSG_ERROR, _("Cannot find node %s in help file"), "[Contents]");
|
2010-04-01 13:14:00 +04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
history_ptr = (history_ptr + 1) % HISTORY_SIZE;
|
|
|
|
history[history_ptr].page = currentpoint;
|
|
|
|
history[history_ptr].link = selected_item;
|
|
|
|
|
|
|
|
currentpoint = new_item + 1; /* Skip the newline following the start of the node */
|
|
|
|
selected_item = NULL;
|
2016-10-30 12:40:20 +03:00
|
|
|
widget_draw (WIDGET (h));
|
2009-11-07 18:36:44 +03:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
2012-09-28 11:18:45 +04:00
|
|
|
help_back (WDialog * h)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2010-04-01 13:14:00 +04:00
|
|
|
currentpoint = history[history_ptr].page;
|
|
|
|
selected_item = history[history_ptr].link;
|
1998-02-27 07:54:42 +03:00
|
|
|
history_ptr--;
|
|
|
|
if (history_ptr < 0)
|
2010-04-01 13:14:00 +04:00
|
|
|
history_ptr = HISTORY_SIZE - 1;
|
2009-08-22 10:02:42 +04:00
|
|
|
|
2016-10-30 12:40:20 +03:00
|
|
|
widget_draw (WIDGET (h)); /* FIXME: unneeded? */
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
help_next_link (gboolean move_down)
|
2010-04-01 13:14:00 +04:00
|
|
|
{
|
2004-08-30 03:39:38 +04:00
|
|
|
const char *new_item;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
new_item = select_next_link (selected_item);
|
2010-04-01 13:14:00 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (move_down)
|
|
|
|
move_forward (1);
|
2009-11-07 18:36:44 +03:00
|
|
|
else
|
2010-04-01 13:14:00 +04:00
|
|
|
selected_item = NULL;
|
2009-11-07 18:36:44 +03:00
|
|
|
}
|
2009-08-22 10:02:42 +04:00
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
help_prev_link (gboolean move_up)
|
|
|
|
{
|
|
|
|
const char *new_item;
|
|
|
|
|
|
|
|
new_item = select_prev_link (selected_item);
|
|
|
|
selected_item = new_item;
|
2010-04-01 13:14:00 +04:00
|
|
|
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;
|
|
|
|
else
|
|
|
|
selected_item = NULL;
|
2009-11-07 18:36:44 +03:00
|
|
|
}
|
|
|
|
}
|
2009-08-22 10:02:42 +04:00
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
help_next_node (void)
|
|
|
|
{
|
|
|
|
const char *new_item;
|
2009-08-22 10:02:42 +04:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
new_item = currentpoint;
|
|
|
|
while ((*new_item != '\0') && (*new_item != CHAR_NODE_END))
|
2010-04-01 13:14:00 +04:00
|
|
|
new_item++;
|
2009-11-07 18:36:44 +03:00
|
|
|
|
|
|
|
if (*++new_item == '[')
|
2010-04-01 13:14:00 +04:00
|
|
|
while (*++new_item != '\0')
|
|
|
|
if ((*new_item == ']') && (*++new_item != '\0') && (*++new_item != '\0'))
|
|
|
|
{
|
|
|
|
currentpoint = new_item;
|
|
|
|
selected_item = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2009-11-07 18:36:44 +03:00
|
|
|
}
|
2009-08-22 10:02:42 +04:00
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
help_prev_node (void)
|
|
|
|
{
|
|
|
|
const char *new_item;
|
|
|
|
|
|
|
|
new_item = currentpoint;
|
|
|
|
while (((int) (new_item - fdata) > 1) && (*new_item != CHAR_NODE_END))
|
2010-04-01 13:14:00 +04:00
|
|
|
new_item--;
|
2009-11-07 18:36:44 +03:00
|
|
|
new_item--;
|
|
|
|
while (((int) (new_item - fdata) > 0) && (*new_item != CHAR_NODE_END))
|
2010-04-01 13:14:00 +04:00
|
|
|
new_item--;
|
2009-11-07 18:36:44 +03:00
|
|
|
while (*new_item != ']')
|
2010-04-01 13:14:00 +04:00
|
|
|
new_item++;
|
2009-11-07 18:36:44 +03:00
|
|
|
currentpoint = new_item + 2;
|
|
|
|
selected_item = NULL;
|
|
|
|
}
|
2009-08-22 10:02:42 +04:00
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
|
|
|
help_select_link (void)
|
|
|
|
{
|
|
|
|
/* follow link */
|
2010-04-01 13:14:00 +04:00
|
|
|
if (selected_item == NULL)
|
|
|
|
{
|
2009-11-07 18:36:44 +03:00
|
|
|
#ifdef WE_WANT_TO_GO_BACKWARD_ON_KEY_RIGHT
|
2010-04-01 13:14:00 +04:00
|
|
|
/* 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;
|
2009-11-07 18:36:44 +03:00
|
|
|
#endif
|
2010-04-01 13:14:00 +04:00
|
|
|
}
|
|
|
|
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);
|
2009-11-07 18:36:44 +03:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
selected_item = NULL;
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static cb_ret_t
|
2015-11-21 18:15:11 +03:00
|
|
|
help_execute_cmd (long command)
|
2009-11-07 18:36:44 +03:00
|
|
|
{
|
|
|
|
cb_ret_t ret = MSG_HANDLED;
|
|
|
|
|
2010-04-01 13:14:00 +04:00
|
|
|
switch (command)
|
|
|
|
{
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Help:
|
2010-04-01 13:14:00 +04:00
|
|
|
help_help (whelp);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Index:
|
2010-04-01 13:14:00 +04:00
|
|
|
help_index (whelp);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Back:
|
2010-04-01 13:14:00 +04:00
|
|
|
help_back (whelp);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Up:
|
2010-04-01 13:14:00 +04:00
|
|
|
help_prev_link (TRUE);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Down:
|
2010-04-01 13:14:00 +04:00
|
|
|
help_next_link (TRUE);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_PageDown:
|
2010-08-16 16:36:47 +04:00
|
|
|
move_forward (help_lines - 1);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_PageUp:
|
2010-08-16 16:36:47 +04:00
|
|
|
move_backward (help_lines - 1);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_HalfPageDown:
|
2010-08-16 16:36:47 +04:00
|
|
|
move_forward (help_lines / 2);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_HalfPageUp:
|
2010-08-16 16:36:47 +04:00
|
|
|
move_backward (help_lines / 2);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Top:
|
2010-08-16 16:36:47 +04:00
|
|
|
move_to_top ();
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Bottom:
|
2010-08-16 16:36:47 +04:00
|
|
|
move_to_bottom ();
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Enter:
|
2010-04-01 13:14:00 +04:00
|
|
|
help_select_link ();
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_LinkNext:
|
2010-04-01 13:14:00 +04:00
|
|
|
help_next_link (FALSE);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_LinkPrev:
|
2010-04-01 13:14:00 +04:00
|
|
|
help_prev_link (FALSE);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_NodeNext:
|
2010-04-01 13:14:00 +04:00
|
|
|
help_next_node ();
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_NodePrev:
|
2010-04-01 13:14:00 +04:00
|
|
|
help_prev_node ();
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Quit:
|
2010-04-01 13:14:00 +04:00
|
|
|
dlg_stop (whelp);
|
|
|
|
break;
|
1998-02-27 07:54:42 +03:00
|
|
|
default:
|
2010-04-01 13:14:00 +04:00
|
|
|
ret = MSG_NOT_HANDLED;
|
2009-11-07 18:36:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static cb_ret_t
|
2012-09-28 11:18:45 +04:00
|
|
|
help_handle_key (WDialog * h, int c)
|
2009-11-07 18:36:44 +03:00
|
|
|
{
|
2015-11-21 18:15:11 +03:00
|
|
|
long command;
|
2010-04-01 13:14:00 +04:00
|
|
|
|
2010-11-18 11:43:23 +03:00
|
|
|
command = keybind_lookup_keymap_command (help_map, c);
|
2011-02-20 18:23:32 +03:00
|
|
|
if ((command == CK_IgnoreKey) || (help_execute_cmd (command) == MSG_NOT_HANDLED))
|
2010-08-16 16:36:47 +04:00
|
|
|
return MSG_NOT_HANDLED;
|
2009-11-07 18:36:44 +03:00
|
|
|
|
2016-10-30 12:40:20 +03:00
|
|
|
widget_draw (WIDGET (h));
|
|
|
|
|
2003-09-08 01:24:01 +04:00
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2016-10-16 11:01:30 +03:00
|
|
|
static cb_ret_t
|
|
|
|
help_bg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
|
|
|
|
{
|
|
|
|
switch (msg)
|
|
|
|
{
|
|
|
|
case MSG_DRAW:
|
|
|
|
frame_callback (w, NULL, MSG_DRAW, 0, NULL);
|
|
|
|
help_show (DIALOG (w->owner), currentpoint);
|
|
|
|
return MSG_HANDLED;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return frame_callback (w, sender, msg, parm, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2016-10-13 10:15:03 +03:00
|
|
|
static cb_ret_t
|
|
|
|
help_resize (WDialog * h)
|
|
|
|
{
|
|
|
|
Widget *w = WIDGET (h);
|
|
|
|
WButtonBar *bb;
|
|
|
|
WRect r;
|
|
|
|
|
|
|
|
help_lines = MIN (LINES - 4, MAX (2 * LINES / 3, 18));
|
|
|
|
rect_init (&r, w->y, w->x, help_lines + 4, HELP_WINDOW_WIDTH + 4);
|
|
|
|
dlg_default_callback (w, NULL, MSG_RESIZE, 0, &r);
|
|
|
|
bb = find_buttonbar (h);
|
|
|
|
widget_set_size (WIDGET (bb), LINES - 1, 0, 1, COLS);
|
|
|
|
|
|
|
|
return MSG_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-09-08 01:24:01 +04:00
|
|
|
static cb_ret_t
|
2012-09-28 15:05:43 +04:00
|
|
|
help_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2012-09-28 15:05:43 +04:00
|
|
|
WDialog *h = DIALOG (w);
|
2009-08-22 10:02:42 +04:00
|
|
|
|
2010-04-01 13:14:00 +04:00
|
|
|
switch (msg)
|
|
|
|
{
|
2012-09-28 15:05:43 +04:00
|
|
|
case MSG_RESIZE:
|
2016-10-13 10:15:03 +03:00
|
|
|
return help_resize (h);
|
2012-09-28 15:05:43 +04:00
|
|
|
|
|
|
|
case MSG_KEY:
|
2010-04-01 13:14:00 +04:00
|
|
|
return help_handle_key (h, parm);
|
2003-09-08 01:24:01 +04:00
|
|
|
|
2012-09-28 15:05:43 +04:00
|
|
|
case MSG_ACTION:
|
2016-02-14 20:40:22 +03:00
|
|
|
/* Handle shortcuts and buttonbar. */
|
|
|
|
return help_execute_cmd (parm);
|
2009-11-09 17:01:23 +03:00
|
|
|
|
2003-09-08 01:24:01 +04:00
|
|
|
default:
|
2012-09-28 15:05:43 +04:00
|
|
|
return dlg_default_callback (w, sender, msg, parm, data);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:09: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 ();
|
2008-12-29 02:12:21 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/** translate help file into terminal encoding */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static void
|
2008-12-29 02:12:21 +03:00
|
|
|
translate_file (char *filedata)
|
|
|
|
{
|
2009-04-14 14:29:01 +04:00
|
|
|
GIConv conv;
|
|
|
|
GString *translated_data;
|
|
|
|
|
2010-03-04 13:15:21 +03:00
|
|
|
/* initial allocation for largest whole help file */
|
|
|
|
translated_data = g_string_sized_new (32 * 1024);
|
2009-04-14 14:29:01 +04:00
|
|
|
|
2008-12-29 02:12:21 +03:00
|
|
|
conv = str_crt_conv_from ("UTF-8");
|
2009-04-14 14:29:01 +04:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
if (conv == INVALID_CONV)
|
2010-04-01 13:14:00 +04:00
|
|
|
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);
|
2009-11-07 18:36:44 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static cb_ret_t
|
2012-06-26 11:52:21 +04:00
|
|
|
md_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
|
2009-11-07 18:36:44 +03:00
|
|
|
{
|
2010-04-01 13:14:00 +04:00
|
|
|
switch (msg)
|
|
|
|
{
|
2012-09-28 15:05:43 +04:00
|
|
|
case MSG_RESIZE:
|
2016-10-13 10:15:03 +03:00
|
|
|
widget_default_callback (w, NULL, MSG_RESIZE, 0, data);
|
2010-04-01 13:14:00 +04:00
|
|
|
w->lines = help_lines;
|
|
|
|
return MSG_HANDLED;
|
2009-11-07 18:36:44 +03:00
|
|
|
|
|
|
|
default:
|
2012-09-28 15:05:43 +04:00
|
|
|
return widget_default_callback (w, sender, msg, parm, data);
|
2009-11-07 18:36:44 +03:00
|
|
|
}
|
|
|
|
}
|
2009-04-24 20:40:18 +04:00
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2016-02-01 10:53:45 +03:00
|
|
|
static void
|
|
|
|
help_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
|
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
GSList *current_area;
|
|
|
|
|
|
|
|
if (msg != MSG_MOUSE_CLICK)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((event->buttons & GPM_B_RIGHT) != 0)
|
|
|
|
{
|
|
|
|
/* Right button click */
|
|
|
|
help_back (whelp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Left bytton click */
|
|
|
|
|
|
|
|
/* The event is relative to the dialog window, adjust it: */
|
|
|
|
x = event->x - 1;
|
|
|
|
y = event->y - 1;
|
|
|
|
|
|
|
|
/* 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))
|
|
|
|
{
|
|
|
|
Link_Area *la = (Link_Area *) current_area->data;
|
|
|
|
|
|
|
|
/* Test one line link area */
|
|
|
|
if (y == la->y1 && x >= la->x1 && y == la->y2 && x <= la->x2)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Test two line link area */
|
|
|
|
if (la->y1 + 1 == la->y2)
|
|
|
|
{
|
|
|
|
/* The first line || The second line */
|
|
|
|
if ((y == la->y1 && x >= la->x1) || (y == la->y2 && x <= la->x2))
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
selected_item = NULL;
|
|
|
|
}
|
|
|
|
else if (y < 0)
|
|
|
|
move_backward (help_lines - 1);
|
|
|
|
else if (y >= help_lines)
|
|
|
|
move_forward (help_lines - 1);
|
|
|
|
else if (y < help_lines / 2)
|
|
|
|
move_backward (1);
|
|
|
|
else
|
|
|
|
move_forward (1);
|
|
|
|
|
|
|
|
/* Show the new node */
|
2016-10-30 12:40:20 +03:00
|
|
|
widget_draw (WIDGET (w->owner));
|
2016-02-01 10:53:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
static Widget *
|
|
|
|
mousedispatch_new (int y, int x, int yl, int xl)
|
|
|
|
{
|
2012-09-28 15:05:43 +04:00
|
|
|
Widget *w;
|
|
|
|
|
2016-02-01 10:53:45 +03:00
|
|
|
w = g_new0 (Widget, 1);
|
2016-03-06 09:44:16 +03:00
|
|
|
widget_init (w, y, x, yl, xl, md_callback, help_mouse_callback);
|
2016-06-07 15:03:20 +03:00
|
|
|
w->options |= WOP_SELECTABLE | WOP_WANT_CURSOR;
|
2016-02-01 10:53:45 +03:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
return w;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-10 14:09:42 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/*** public functions ****************************************************************************/
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2011-02-17 15:02:31 +03:00
|
|
|
/* event callback */
|
|
|
|
gboolean
|
|
|
|
help_interactive_display (const gchar * event_group_name, const gchar * event_name,
|
|
|
|
gpointer init_data, gpointer data)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2010-10-12 13:33:09 +04:00
|
|
|
const dlg_colors_t help_colors = {
|
2010-04-01 13:14:00 +04:00
|
|
|
HELP_NORMAL_COLOR, /* common text color */
|
|
|
|
0, /* unused in help */
|
2010-10-12 13:33:09 +04:00
|
|
|
HELP_BOLD_COLOR, /* bold text color */
|
|
|
|
0, /* unused in help */
|
|
|
|
HELP_TITLE_COLOR /* title color */
|
2010-02-27 12:53:45 +03:00
|
|
|
};
|
|
|
|
|
2016-09-28 11:01:30 +03:00
|
|
|
WGroup *g;
|
2002-09-03 10:53:11 +04:00
|
|
|
WButtonBar *help_bar;
|
|
|
|
Widget *md;
|
2004-08-30 03:39:38 +04:00
|
|
|
char *hlpfile = NULL;
|
2008-12-29 02:12:21 +03:00
|
|
|
char *filedata;
|
2011-02-17 15:02:31 +03:00
|
|
|
ev_help_t *event_data = (ev_help_t *) data;
|
2001-06-09 11:13:46 +04:00
|
|
|
|
2011-02-17 15:02:31 +03:00
|
|
|
(void) event_group_name;
|
|
|
|
(void) event_name;
|
|
|
|
(void) init_data;
|
|
|
|
|
|
|
|
if (event_data->filename != NULL)
|
|
|
|
g_file_get_contents (event_data->filename, &filedata, NULL, NULL);
|
2001-06-09 11:13:46 +04:00
|
|
|
else
|
2016-01-11 16:17:08 +03:00
|
|
|
filedata = load_mc_home_file (mc_global.share_data_dir, MC_HELP, &hlpfile, NULL);
|
2001-06-09 11:13:46 +04:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
if (filedata == NULL)
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, MSG_ERROR, _("Cannot open file %s\n%s"),
|
2011-02-17 15:02:31 +03:00
|
|
|
event_data->filename ? event_data->filename : hlpfile, unix_error_string (errno));
|
2001-06-09 11:13:46 +04:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
g_free (hlpfile);
|
2001-06-09 11:13:46 +04:00
|
|
|
|
2008-12-29 02:12:21 +03:00
|
|
|
if (filedata == NULL)
|
2011-02-17 15:02:31 +03:00
|
|
|
return TRUE;
|
2008-12-29 02:12:21 +03:00
|
|
|
|
|
|
|
translate_file (filedata);
|
2008-12-29 02:12:21 +03:00
|
|
|
|
2008-12-29 02:12:21 +03:00
|
|
|
g_free (filedata);
|
2009-08-22 10:02:42 +04:00
|
|
|
|
2009-11-07 18:36:44 +03:00
|
|
|
if (fdata == NULL)
|
2011-02-17 15:02:31 +03:00
|
|
|
return TRUE;
|
2001-06-09 11:13:46 +04:00
|
|
|
|
2011-02-17 15:02:31 +03:00
|
|
|
if ((event_data->node == NULL) || (*event_data->node == '\0'))
|
|
|
|
event_data->node = "[main]";
|
2002-09-03 10:53:11 +04:00
|
|
|
|
2011-02-17 15:02:31 +03:00
|
|
|
main_node = search_string (fdata, event_data->node);
|
2009-11-07 18:36:44 +03:00
|
|
|
|
2010-04-01 13:14:00 +04:00
|
|
|
if (main_node == NULL)
|
|
|
|
{
|
2011-02-17 15:02:31 +03:00
|
|
|
message (D_ERROR, MSG_ERROR, _("Cannot find node %s in help file"), event_data->node);
|
2010-04-01 13:14:00 +04:00
|
|
|
|
|
|
|
/* Fallback to [main], return if it also cannot be found */
|
|
|
|
main_node = search_string (fdata, "[main]");
|
|
|
|
if (main_node == NULL)
|
|
|
|
{
|
|
|
|
interactive_display_finish ();
|
2011-02-17 15:02:31 +03:00
|
|
|
return TRUE;
|
2010-04-01 13:14:00 +04:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2016-04-07 10:52:04 +03:00
|
|
|
help_lines = MIN (LINES - 4, MAX (2 * LINES / 3, 18));
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2002-09-03 10:53:11 +04:00
|
|
|
whelp =
|
2016-06-18 10:21:42 +03:00
|
|
|
dlg_create (TRUE, 0, 0, help_lines + 4, HELP_WINDOW_WIDTH + 4, WPOS_CENTER | WPOS_TRYUP,
|
|
|
|
FALSE, help_colors, help_callback, NULL, "[Help]", _("Help"));
|
2016-09-28 11:01:30 +03:00
|
|
|
g = GROUP (whelp);
|
2016-05-08 20:25:29 +03:00
|
|
|
widget_want_tab (WIDGET (whelp), TRUE);
|
2016-10-16 11:01:30 +03:00
|
|
|
/* draw background */
|
2016-10-16 19:45:50 +03:00
|
|
|
whelp->bg->callback = help_bg_callback;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
1998-09-22 17:06:59 +04:00
|
|
|
selected_item = search_string_node (main_node, STRING_LINK_START) - 1;
|
2010-04-01 13:14:00 +04:00
|
|
|
currentpoint = main_node + 1; /* Skip the newline following the start of the node */
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-04-01 13:14:00 +04:00
|
|
|
for (history_ptr = HISTORY_SIZE; history_ptr;)
|
|
|
|
{
|
|
|
|
history_ptr--;
|
|
|
|
history[history_ptr].page = currentpoint;
|
|
|
|
history[history_ptr].link = selected_item;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2009-11-06 14:41:54 +03:00
|
|
|
help_bar = buttonbar_new (TRUE);
|
2012-06-20 15:09:44 +04:00
|
|
|
WIDGET (help_bar)->y -= WIDGET (whelp)->y;
|
|
|
|
WIDGET (help_bar)->x -= WIDGET (whelp)->x;
|
2002-09-03 10:53:11 +04:00
|
|
|
|
|
|
|
md = mousedispatch_new (1, 1, help_lines, HELP_WINDOW_WIDTH - 2);
|
|
|
|
|
2016-09-28 11:01:30 +03:00
|
|
|
group_add_widget (g, md);
|
|
|
|
group_add_widget (g, help_bar);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-04-01 13:14:00 +04: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);
|
2009-11-12 21:44:38 +03:00
|
|
|
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);
|
2010-04-01 13:14:00 +04:00
|
|
|
buttonbar_set_label (help_bar, 10, Q_ ("ButtonBar|Quit"), help_map, NULL);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2013-06-24 11:40:53 +04:00
|
|
|
dlg_run (whelp);
|
1998-02-27 07:54:42 +03:00
|
|
|
interactive_display_finish ();
|
2013-06-24 11:40:53 +04:00
|
|
|
dlg_destroy (whelp);
|
2011-02-17 15:02:31 +03:00
|
|
|
return TRUE;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2010-11-10 14:09:42 +03:00
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|