mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-23 21:06:52 +03:00
e54f318cef
Changed all source files relative to remove MHL Some string-related functions moved into src/util.c This stable fix.
872 lines
18 KiB
C
872 lines
18 KiB
C
/* Dialog box features module for the Midnight Commander
|
|
Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
|
2005, 2007 Free Software Foundation, Inc.
|
|
|
|
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.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "global.h"
|
|
#include "tty.h"
|
|
#include "mouse.h"
|
|
#include "help.h" /* interactive_display() */
|
|
#include "key.h" /* mi_getch() */
|
|
#include "dialog.h"
|
|
#include "layout.h" /* winch_flag */
|
|
#include "execute.h" /* suspend_cmd() */
|
|
#include "main.h" /* slow_terminal */
|
|
|
|
#define waddc(w,y1,x1,c) move (w->y+y1, w->x+x1); addch (c)
|
|
|
|
/* Primitive way to check if the the current dialog is our dialog */
|
|
/* This is needed by async routines like load_prompt */
|
|
Dlg_head *current_dlg = 0;
|
|
|
|
/* A hook list for idle events */
|
|
Hook *idle_hook = 0;
|
|
|
|
static void dlg_broadcast_msg_to (Dlg_head * h, widget_msg_t message,
|
|
int reverse, int flags);
|
|
|
|
static void slow_box (Dlg_head *h, int y, int x, int ys, int xs)
|
|
{
|
|
move (h->y+y, h->x+x);
|
|
hline (' ', xs);
|
|
vline (' ', ys);
|
|
move (h->y+y, h->x+x+xs-1);
|
|
vline (' ', ys);
|
|
move (h->y+y+ys-1, h->x+x);
|
|
hline (' ', xs);
|
|
}
|
|
|
|
/* draw box in window */
|
|
void draw_box (Dlg_head *h, int y, int x, int ys, int xs)
|
|
{
|
|
if (slow_terminal){
|
|
slow_box (h, y, x, ys, xs);
|
|
return;
|
|
}
|
|
|
|
#ifndef HAVE_SLANG
|
|
waddc (h, y, x, ACS_ULCORNER);
|
|
hline (ACS_HLINE, xs - 2);
|
|
waddc (h, y + ys - 1, x, ACS_LLCORNER);
|
|
hline (ACS_HLINE, xs - 2);
|
|
|
|
waddc (h, y, x + xs - 1, ACS_URCORNER);
|
|
waddc (h, y + ys - 1, x + xs - 1, ACS_LRCORNER);
|
|
|
|
move (h->y+y+1, h->x+x);
|
|
vline (ACS_VLINE, ys - 2);
|
|
move (h->y+y+1, h->x+x+xs-1);
|
|
vline (ACS_VLINE, ys - 2);
|
|
#else
|
|
SLsmg_draw_box (h->y+y, h->x+x, ys, xs);
|
|
#endif /* HAVE_SLANG */
|
|
}
|
|
|
|
/* draw box in window */
|
|
void draw_double_box (Dlg_head *h, int y, int x, int ys, int xs)
|
|
{
|
|
#ifndef HAVE_SLANG
|
|
draw_box (h, y, x, ys, xs);
|
|
#else
|
|
SLsmg_draw_double_box (h->y+y, h->x+x, ys, xs);
|
|
#endif /* HAVE_SLANG */
|
|
}
|
|
|
|
void widget_erase (Widget *w)
|
|
{
|
|
int x, y;
|
|
|
|
for (y = 0; y < w->lines; y++){
|
|
widget_move (w, y, 0);
|
|
for (x = 0; x < w->cols; x++)
|
|
addch (' ');
|
|
}
|
|
}
|
|
|
|
void dlg_erase (Dlg_head *h)
|
|
{
|
|
int x, y;
|
|
|
|
for (y = 0; y < h->lines; y++){
|
|
move (y+h->y, h->x); /* FIXME: should test if ERR */
|
|
for (x = 0; x < h->cols; x++){
|
|
addch (' ');
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
init_widget (Widget *w, int y, int x, int lines, int cols,
|
|
callback_fn callback, mouse_h mouse_handler)
|
|
{
|
|
w->x = x;
|
|
w->y = y;
|
|
w->cols = cols;
|
|
w->lines = lines;
|
|
w->callback = callback;
|
|
w->mouse = mouse_handler;
|
|
w->parent = 0;
|
|
|
|
/* Almost all widgets want to put the cursor in a suitable place */
|
|
w->options = W_WANT_CURSOR;
|
|
}
|
|
|
|
/* Default callback for widgets */
|
|
cb_ret_t
|
|
default_proc (widget_msg_t msg, int parm)
|
|
{
|
|
(void) parm;
|
|
|
|
switch (msg) {
|
|
case WIDGET_INIT:
|
|
case WIDGET_FOCUS:
|
|
case WIDGET_UNFOCUS:
|
|
case WIDGET_DRAW:
|
|
case WIDGET_DESTROY:
|
|
case WIDGET_CURSOR:
|
|
case WIDGET_IDLE:
|
|
return MSG_HANDLED;
|
|
|
|
default:
|
|
return MSG_NOT_HANDLED;
|
|
}
|
|
}
|
|
|
|
/* Clean the dialog area, draw the frame and the title */
|
|
void
|
|
common_dialog_repaint (struct Dlg_head *h)
|
|
{
|
|
int space;
|
|
|
|
space = (h->flags & DLG_COMPACT) ? 0 : 1;
|
|
|
|
attrset (DLG_NORMALC (h));
|
|
dlg_erase (h);
|
|
draw_box (h, space, space, h->lines - 2 * space, h->cols - 2 * space);
|
|
|
|
if (h->title) {
|
|
attrset (DLG_HOT_NORMALC (h));
|
|
dlg_move (h, space, (h->cols - strlen (h->title)) / 2);
|
|
addstr (h->title);
|
|
}
|
|
}
|
|
|
|
/* Default dialog callback */
|
|
cb_ret_t default_dlg_callback (Dlg_head *h, dlg_msg_t msg, int parm)
|
|
{
|
|
(void) parm;
|
|
|
|
if (msg == DLG_DRAW && h->color) {
|
|
common_dialog_repaint (h);
|
|
return MSG_HANDLED;
|
|
}
|
|
if (msg == DLG_IDLE){
|
|
dlg_broadcast_msg_to (h, WIDGET_IDLE, 0, W_WANT_IDLE);
|
|
return MSG_HANDLED;
|
|
}
|
|
return MSG_NOT_HANDLED;
|
|
}
|
|
|
|
Dlg_head *
|
|
create_dlg (int y1, int x1, int lines, int cols, const int *color_set,
|
|
dlg_cb_fn callback, const char *help_ctx, const char *title,
|
|
int flags)
|
|
{
|
|
Dlg_head *new_d;
|
|
|
|
if (flags & DLG_CENTER) {
|
|
y1 = (LINES - lines) / 2;
|
|
x1 = (COLS - cols) / 2;
|
|
}
|
|
|
|
if ((flags & DLG_TRYUP) && (y1 > 3))
|
|
y1 -= 2;
|
|
|
|
new_d = g_new0 (Dlg_head, 1);
|
|
new_d->color = color_set;
|
|
new_d->help_ctx = help_ctx;
|
|
new_d->callback = callback ? callback : default_dlg_callback;
|
|
new_d->x = x1;
|
|
new_d->y = y1;
|
|
new_d->cols = cols;
|
|
new_d->lines = lines;
|
|
new_d->flags = flags;
|
|
|
|
/* Strip existing spaces, add one space before and after the title */
|
|
if (title) {
|
|
char *t;
|
|
t = g_strstrip (g_strdup (title));
|
|
new_d->title = g_strconcat (" ", t, " ", (char *) NULL);
|
|
g_free (t);
|
|
}
|
|
|
|
return (new_d);
|
|
}
|
|
|
|
void
|
|
set_idle_proc (Dlg_head *d, int enable)
|
|
{
|
|
if (enable)
|
|
d->flags |= DLG_WANT_IDLE;
|
|
else
|
|
d->flags &= ~DLG_WANT_IDLE;
|
|
}
|
|
|
|
/*
|
|
* Insert widget to dialog before current widget. For dialogs populated
|
|
* from the bottom, make the widget current. Return widget number.
|
|
*/
|
|
int
|
|
add_widget (Dlg_head *h, void *w)
|
|
{
|
|
Widget *widget = (Widget *) w;
|
|
|
|
/* Don't accept 0 widgets, and running dialogs */
|
|
if (!widget || h->running)
|
|
abort ();
|
|
|
|
widget->x += h->x;
|
|
widget->y += h->y;
|
|
widget->parent = h;
|
|
widget->dlg_id = h->count++;
|
|
|
|
if (h->current) {
|
|
widget->next = h->current;
|
|
widget->prev = h->current->prev;
|
|
h->current->prev->next = widget;
|
|
h->current->prev = widget;
|
|
} else {
|
|
widget->prev = widget;
|
|
widget->next = widget;
|
|
}
|
|
|
|
if ((h->flags & DLG_REVERSE) || !h->current)
|
|
h->current = widget;
|
|
|
|
return widget->dlg_id;
|
|
}
|
|
|
|
enum {
|
|
REFRESH_COVERS_PART, /* If the refresh fn convers only a part */
|
|
REFRESH_COVERS_ALL /* If the refresh fn convers all the screen */
|
|
};
|
|
|
|
static void
|
|
do_complete_refresh (Dlg_head *dlg)
|
|
{
|
|
if (!dlg->fullscreen && dlg->parent)
|
|
do_complete_refresh (dlg->parent);
|
|
|
|
dlg_redraw (dlg);
|
|
}
|
|
|
|
void
|
|
do_refresh (void)
|
|
{
|
|
if (!current_dlg)
|
|
return;
|
|
|
|
if (fast_refresh)
|
|
dlg_redraw (current_dlg);
|
|
else {
|
|
do_complete_refresh (current_dlg);
|
|
}
|
|
}
|
|
|
|
/* broadcast a message to all the widgets in a dialog that have
|
|
* the options set to flags. If flags is zero, the message is sent
|
|
* to all widgets.
|
|
*/
|
|
static void
|
|
dlg_broadcast_msg_to (Dlg_head *h, widget_msg_t message, int reverse,
|
|
int flags)
|
|
{
|
|
Widget *p, *first, *wi;
|
|
|
|
if (!h->current)
|
|
return;
|
|
|
|
if (reverse)
|
|
first = p = h->current->prev;
|
|
else
|
|
first = p = h->current->next;
|
|
|
|
do {
|
|
wi = p;
|
|
if (reverse)
|
|
p = p->prev;
|
|
else
|
|
p = p->next;
|
|
if (flags == 0 || (flags & wi->options))
|
|
send_message (wi, message, 0);
|
|
} while (first != p);
|
|
}
|
|
|
|
/* broadcast a message to all the widgets in a dialog */
|
|
void
|
|
dlg_broadcast_msg (Dlg_head *h, widget_msg_t message, int reverse)
|
|
{
|
|
dlg_broadcast_msg_to (h, message, reverse, 0);
|
|
}
|
|
|
|
int dlg_focus (Dlg_head *h)
|
|
{
|
|
if (!h->current)
|
|
return 0;
|
|
|
|
if (send_message (h->current, WIDGET_FOCUS, 0)){
|
|
(*h->callback) (h, DLG_FOCUS, 0);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
dlg_unfocus (Dlg_head *h)
|
|
{
|
|
if (!h->current)
|
|
return 0;
|
|
|
|
if (send_message (h->current, WIDGET_UNFOCUS, 0)){
|
|
(*h->callback) (h, DLG_UNFOCUS, 0);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Return true if the windows overlap */
|
|
int dlg_overlap (Widget *a, Widget *b)
|
|
{
|
|
if ((b->x >= a->x + a->cols)
|
|
|| (a->x >= b->x + b->cols)
|
|
|| (b->y >= a->y + a->lines)
|
|
|| (a->y >= b->y + b->lines))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* Find the widget with the given callback in the dialog h */
|
|
Widget *
|
|
find_widget_type (Dlg_head *h, callback_fn callback)
|
|
{
|
|
Widget *w;
|
|
Widget *item;
|
|
int i;
|
|
|
|
if (!h)
|
|
return 0;
|
|
if (!h->current)
|
|
return 0;
|
|
|
|
w = 0;
|
|
for (i = 0, item = h->current; i < h->count; i++, item = item->next) {
|
|
if (item->callback == callback) {
|
|
w = item;
|
|
break;
|
|
}
|
|
}
|
|
return w;
|
|
}
|
|
|
|
/* Find the widget with the given dialog id in the dialog h and select it */
|
|
void
|
|
dlg_select_by_id (Dlg_head *h, int id)
|
|
{
|
|
Widget *w, *w_found;
|
|
|
|
if (!h->current)
|
|
return;
|
|
|
|
w = h->current;
|
|
w_found = NULL;
|
|
|
|
do {
|
|
if (w->dlg_id == id) {
|
|
w_found = w;
|
|
break;
|
|
}
|
|
w = w->next;
|
|
} while (w != h->current);
|
|
|
|
if (w_found)
|
|
dlg_select_widget(w_found);
|
|
}
|
|
|
|
|
|
/* What to do if the requested widget doesn't take focus */
|
|
typedef enum {
|
|
SELECT_NEXT, /* go the the next widget */
|
|
SELECT_PREV, /* go the the previous widget */
|
|
SELECT_EXACT /* use current widget */
|
|
} select_dir_t;
|
|
|
|
/*
|
|
* Try to select another widget. If forward is set, follow tab order.
|
|
* Otherwise go to the previous widget.
|
|
*/
|
|
static void
|
|
do_select_widget (Dlg_head *h, Widget *w, select_dir_t dir)
|
|
{
|
|
Widget *w0 = h->current;
|
|
|
|
if (!dlg_unfocus (h))
|
|
return;
|
|
|
|
h->current = w;
|
|
do {
|
|
if (dlg_focus (h))
|
|
break;
|
|
|
|
switch (dir) {
|
|
case SELECT_NEXT:
|
|
h->current = h->current->next;
|
|
break;
|
|
case SELECT_PREV:
|
|
h->current = h->current->prev;
|
|
break;
|
|
case SELECT_EXACT:
|
|
h->current = w0;
|
|
dlg_focus (h);
|
|
return;
|
|
}
|
|
} while (h->current != w);
|
|
|
|
if (dlg_overlap (w0, h->current)) {
|
|
send_message (h->current, WIDGET_DRAW, 0);
|
|
send_message (h->current, WIDGET_FOCUS, 0);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Try to select widget in the dialog.
|
|
*/
|
|
void
|
|
dlg_select_widget (void *w)
|
|
{
|
|
do_select_widget (((Widget *) w)->parent, w, SELECT_NEXT);
|
|
}
|
|
|
|
|
|
/* Try to select previous widget in the tab order */
|
|
void
|
|
dlg_one_up (Dlg_head *h)
|
|
{
|
|
if (h->current)
|
|
do_select_widget (h, h->current->prev, SELECT_PREV);
|
|
}
|
|
|
|
|
|
/* Try to select next widget in the tab order */
|
|
void
|
|
dlg_one_down (Dlg_head *h)
|
|
{
|
|
if (h->current)
|
|
do_select_widget (h, h->current->next, SELECT_NEXT);
|
|
}
|
|
|
|
|
|
void update_cursor (Dlg_head *h)
|
|
{
|
|
if (!h->current)
|
|
return;
|
|
if (h->current->options & W_WANT_CURSOR)
|
|
send_message (h->current, WIDGET_CURSOR, 0);
|
|
else {
|
|
Widget *p = h->current;
|
|
|
|
do {
|
|
if (p->options & W_WANT_CURSOR)
|
|
if ((*p->callback)(p, WIDGET_CURSOR, 0)){
|
|
break;
|
|
}
|
|
p = p->next;
|
|
} while (h->current != p);
|
|
}
|
|
}
|
|
|
|
/* Redraw the widgets in reverse order, leaving the current widget
|
|
* as the last one
|
|
*/
|
|
void dlg_redraw (Dlg_head *h)
|
|
{
|
|
(h->callback)(h, DLG_DRAW, 0);
|
|
|
|
dlg_broadcast_msg (h, WIDGET_DRAW, 1);
|
|
|
|
update_cursor (h);
|
|
}
|
|
|
|
void dlg_stop (Dlg_head *h)
|
|
{
|
|
h->running = 0;
|
|
}
|
|
|
|
static inline void dialog_handle_key (Dlg_head *h, int d_key)
|
|
{
|
|
switch (d_key){
|
|
case KEY_LEFT:
|
|
case KEY_UP:
|
|
dlg_one_up (h);
|
|
break;
|
|
|
|
case KEY_RIGHT:
|
|
case KEY_DOWN:
|
|
dlg_one_down (h);
|
|
break;
|
|
|
|
case KEY_F(1):
|
|
interactive_display (NULL, h->help_ctx);
|
|
do_refresh ();
|
|
break;
|
|
|
|
case XCTRL('z'):
|
|
suspend_cmd ();
|
|
/* Fall through */
|
|
|
|
case XCTRL('l'):
|
|
#ifndef HAVE_SLANG
|
|
/* Use this if the refreshes fail */
|
|
clr_scr ();
|
|
do_refresh ();
|
|
#else
|
|
touchwin (stdscr);
|
|
#endif /* HAVE_SLANG */
|
|
mc_refresh ();
|
|
doupdate ();
|
|
break;
|
|
|
|
case '\n':
|
|
case KEY_ENTER:
|
|
h->ret_value = B_ENTER;
|
|
h->running = 0;
|
|
break;
|
|
|
|
case ESC_CHAR:
|
|
case KEY_F (10):
|
|
case XCTRL ('c'):
|
|
case XCTRL ('g'):
|
|
h->ret_value = B_CANCEL;
|
|
dlg_stop (h);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int
|
|
dlg_try_hotkey (Dlg_head *h, int d_key)
|
|
{
|
|
Widget *hot_cur;
|
|
int handled, c;
|
|
|
|
if (!h->current)
|
|
return 0;
|
|
|
|
/*
|
|
* Explanation: we don't send letter hotkeys to other widgets if
|
|
* the currently selected widget is an input line
|
|
*/
|
|
|
|
if (h->current->options & W_IS_INPUT) {
|
|
if (d_key < 255 && isalpha (d_key))
|
|
return 0;
|
|
}
|
|
|
|
/* If it's an alt key, send the message */
|
|
c = d_key & ~ALT (0);
|
|
if (d_key & ALT (0) && c < 255 && isalpha (c))
|
|
d_key = tolower (c);
|
|
|
|
handled = 0;
|
|
if (h->current->options & W_WANT_HOTKEY)
|
|
handled = h->current->callback (h->current, WIDGET_HOTKEY, d_key);
|
|
|
|
/* If not used, send hotkey to other widgets */
|
|
if (handled)
|
|
return handled;
|
|
|
|
hot_cur = h->current;
|
|
|
|
/* send it to all widgets */
|
|
do {
|
|
if (hot_cur->options & W_WANT_HOTKEY)
|
|
handled |=
|
|
(*hot_cur->callback) (hot_cur, WIDGET_HOTKEY, d_key);
|
|
|
|
if (!handled)
|
|
hot_cur = hot_cur->next;
|
|
} while (h->current != hot_cur && !handled);
|
|
|
|
if (!handled)
|
|
return 0;
|
|
|
|
do_select_widget (h, hot_cur, SELECT_EXACT);
|
|
return handled;
|
|
}
|
|
|
|
static void
|
|
dlg_key_event (Dlg_head *h, int d_key)
|
|
{
|
|
int handled;
|
|
|
|
if (!h->current)
|
|
return;
|
|
|
|
/* TAB used to cycle */
|
|
if (!(h->flags & DLG_WANT_TAB)) {
|
|
if (d_key == '\t') {
|
|
dlg_one_down (h);
|
|
return;
|
|
} else if (d_key == KEY_BTAB) {
|
|
dlg_one_up (h);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* first can dlg_callback handle the key */
|
|
handled = (*h->callback) (h, DLG_KEY, d_key);
|
|
|
|
/* next try the hotkey */
|
|
if (!handled)
|
|
handled = dlg_try_hotkey (h, d_key);
|
|
|
|
if (handled)
|
|
(*h->callback) (h, DLG_HOTKEY_HANDLED, 0);
|
|
|
|
/* not used - then try widget_callback */
|
|
if (!handled)
|
|
handled = h->current->callback (h->current, WIDGET_KEY, d_key);
|
|
|
|
/* not used- try to use the unhandled case */
|
|
if (!handled)
|
|
handled = (*h->callback) (h, DLG_UNHANDLED_KEY, d_key);
|
|
|
|
if (!handled)
|
|
dialog_handle_key (h, d_key);
|
|
|
|
(*h->callback) (h, DLG_POST_KEY, d_key);
|
|
}
|
|
|
|
static inline int
|
|
dlg_mouse_event (Dlg_head * h, Gpm_Event * event)
|
|
{
|
|
Widget *item;
|
|
Widget *starting_widget = h->current;
|
|
Gpm_Event new_event;
|
|
int x = event->x;
|
|
int y = event->y;
|
|
|
|
item = starting_widget;
|
|
do {
|
|
Widget *widget = item;
|
|
|
|
item = item->next;
|
|
|
|
if (!((x > widget->x) && (x <= widget->x + widget->cols)
|
|
&& (y > widget->y) && (y <= widget->y + widget->lines)))
|
|
continue;
|
|
|
|
new_event = *event;
|
|
new_event.x -= widget->x;
|
|
new_event.y -= widget->y;
|
|
|
|
if (!widget->mouse)
|
|
return MOU_NORMAL;
|
|
|
|
return (*widget->mouse) (&new_event, widget);
|
|
} while (item != starting_widget);
|
|
|
|
return MOU_NORMAL;
|
|
}
|
|
|
|
/* Run dialog routines */
|
|
|
|
/* Init the process */
|
|
void init_dlg (Dlg_head *h)
|
|
{
|
|
/* Initialize dialog manager and widgets */
|
|
(*h->callback) (h, DLG_INIT, 0);
|
|
dlg_broadcast_msg (h, WIDGET_INIT, 0);
|
|
|
|
if (h->x == 0 && h->y == 0 && h->cols == COLS && h->lines == LINES)
|
|
h->fullscreen = 1;
|
|
|
|
h->parent = current_dlg;
|
|
current_dlg = h;
|
|
|
|
/* Initialize the mouse status */
|
|
h->mouse_status = MOU_NORMAL;
|
|
|
|
/* Select the first widget that takes focus */
|
|
while (!dlg_focus (h) && h->current)
|
|
h->current = h->current->next;
|
|
|
|
/* Redraw the screen */
|
|
dlg_redraw (h);
|
|
|
|
h->ret_value = 0;
|
|
h->running = 1;
|
|
}
|
|
|
|
/* Shutdown the run_dlg */
|
|
void dlg_run_done (Dlg_head *h)
|
|
{
|
|
if (h->current)
|
|
(*h->callback) (h, DLG_END, 0);
|
|
|
|
current_dlg = h->parent;
|
|
}
|
|
|
|
void dlg_process_event (Dlg_head *h, int key, Gpm_Event *event)
|
|
{
|
|
if (key == EV_NONE){
|
|
if (got_interrupt ())
|
|
key = XCTRL('g');
|
|
else
|
|
return;
|
|
}
|
|
|
|
if (key == EV_MOUSE)
|
|
h->mouse_status = dlg_mouse_event (h, event);
|
|
else
|
|
dlg_key_event (h, key);
|
|
}
|
|
|
|
static inline void
|
|
frontend_run_dlg (Dlg_head *h)
|
|
{
|
|
int d_key;
|
|
Gpm_Event event;
|
|
|
|
event.x = -1;
|
|
while (h->running) {
|
|
if (winch_flag)
|
|
change_screen_size ();
|
|
|
|
if (is_idle ()) {
|
|
if (idle_hook)
|
|
execute_hooks (idle_hook);
|
|
|
|
while ((h->flags & DLG_WANT_IDLE) && is_idle ())
|
|
(*h->callback) (h, DLG_IDLE, 0);
|
|
|
|
/* Allow terminating the dialog from the idle handler */
|
|
if (!h->running)
|
|
break;
|
|
}
|
|
|
|
update_cursor (h);
|
|
|
|
/* Clear interrupt flag */
|
|
got_interrupt ();
|
|
d_key = get_event (&event, h->mouse_status == MOU_REPEAT, 1);
|
|
|
|
dlg_process_event (h, d_key, &event);
|
|
|
|
if (!h->running)
|
|
(*h->callback) (h, DLG_VALIDATE, 0);
|
|
}
|
|
}
|
|
|
|
/* Standard run dialog routine
|
|
* We have to keep this routine small so that we can duplicate it's
|
|
* behavior on complex routines like the file routines, this way,
|
|
* they can call the dlg_process_event without rewriting all the code
|
|
*/
|
|
int run_dlg (Dlg_head *h)
|
|
{
|
|
init_dlg (h);
|
|
frontend_run_dlg (h);
|
|
dlg_run_done (h);
|
|
return h->ret_value;
|
|
}
|
|
|
|
void
|
|
destroy_dlg (Dlg_head *h)
|
|
{
|
|
int i;
|
|
Widget *c;
|
|
|
|
dlg_broadcast_msg (h, WIDGET_DESTROY, 0);
|
|
c = h->current;
|
|
for (i = 0; i < h->count; i++) {
|
|
c = c->next;
|
|
g_free (h->current);
|
|
h->current = c;
|
|
}
|
|
g_free (h->title);
|
|
g_free (h);
|
|
|
|
do_refresh ();
|
|
}
|
|
|
|
void widget_set_size (Widget *widget, int y, int x, int lines, int cols)
|
|
{
|
|
widget->x = x;
|
|
widget->y = y;
|
|
widget->cols = cols;
|
|
widget->lines = lines;
|
|
send_message (widget, WIDGET_RESIZED, 0 /* unused */);
|
|
}
|
|
|
|
/* Replace widget old_w for widget new_w in the dialog */
|
|
void
|
|
dlg_replace_widget (Widget *old_w, Widget *new_w)
|
|
{
|
|
Dlg_head *h = old_w->parent;
|
|
int should_focus = 0;
|
|
|
|
if (!h->current)
|
|
return;
|
|
|
|
if (old_w == h->current)
|
|
should_focus = 1;
|
|
|
|
new_w->parent = h;
|
|
new_w->dlg_id = old_w->dlg_id;
|
|
|
|
if (old_w == old_w->next) {
|
|
/* just one widget */
|
|
new_w->prev = new_w;
|
|
new_w->next = new_w;
|
|
} else {
|
|
new_w->prev = old_w->prev;
|
|
new_w->next = old_w->next;
|
|
old_w->prev->next = new_w;
|
|
old_w->next->prev = new_w;
|
|
}
|
|
|
|
if (should_focus)
|
|
h->current = new_w;
|
|
|
|
send_message (old_w, WIDGET_DESTROY, 0);
|
|
send_message (new_w, WIDGET_INIT, 0);
|
|
|
|
if (should_focus)
|
|
dlg_select_widget (new_w);
|
|
|
|
send_message (new_w, WIDGET_DRAW, 0);
|
|
}
|