📄 widget.c
字号:
/* Widgets for the Midnight Commander
Copyright (C) 1994, 1995, 1996 the Free Software Foundation
Authors: 1994, 1995 Radek Doulik
1994, 1995 Miguel de Icaza
1995 Jakub Jelinek
1996 Andrej Borsenkow
1997 Norbert Warmuth
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* "$Id: widget.c 15218 2005-05-11 16:50:39Z weiden $" */
#include <config.h>
#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include "tty.h"
#include <ctype.h>
#include "mad.h"
#include "global.h"
#include "util.h"
#include "color.h"
#include "mouse.h"
#include "dlg.h"
#include "widget.h"
#include "win.h"
#include "complete.h"
#include "key.h" /* XCTRL and ALT macros */
#include "x.h"
#include "profile.h" /* for history loading and saving */
#ifndef HAVE_X
# define x_create_button(a,b,c) 1
# define x_create_radio(a,b,c) 1
# define x_create_check(a,b,c) 1
# define x_create_label(a,b,c) 1
# define x_create_input(a,b,c) 1
# define x_create_listbox(a,b,c) 1
# define x_create_buttonbar(a,b,c) 1
# define x_create_gauge(a,b,c) 1
# define x_listbox_select_nth(a,b)
# define x_list_insert(a,b,c)
# define x_redefine_label(a,b)
#endif
#ifndef PORT_HAS_DESTROY_CMD
# define x_destroy_cmd(w)
#endif
#ifndef PORT_HAS_RADIO_FOCUS_ITEM
# define x_radio_focus_item(r)
#endif
#ifndef PORT_HAS_RADIO_TOGGLE
# define x_radio_toggle
#endif
static int button_event (Gpm_Event *event, WButton *b);
int quote = 0;
static int
button_callback (Dlg_head *h, WButton *b, int Msg, int Par)
{
char *txt, buf[256];
int stop = 0;
int off = 0;
switch (Msg){
case WIDGET_INIT:
return x_create_button (h, h->wdata, b);
#ifndef HAVE_XVIEW
case WIDGET_HOTKEY:
if (b->hotkey == Par || toupper(b->hotkey) == Par){
button_callback (h, b, WIDGET_KEY, ' '); /* to make action */
return 1;
} else
return 0;
case WIDGET_KEY:
if (Par != ' ' && Par != '\n')
break;
if (b->callback)
stop = (*b->callback)(b->action, b->callback_data);
if (!b->callback || stop){
h->ret_value = b->action;
dlg_stop (h);
}
return 1;
#ifdef HAVE_TK
case WIDGET_FOCUS:
case WIDGET_CURSOR:
{
char *s = b->action == B_ENTER ? ".button" : "";
tk_evalf ("focus %s%s", (char *)(b->widget.wdata)+1, s);
/* Do not call default_proc: we did the tk focus command */
return 1;
}
#else
case WIDGET_CURSOR:
switch (b->flags) {
case DEFPUSH_BUTTON:
off = 3;
break;
case NORMAL_BUTTON:
off = 2;
break;
case NARROW_BUTTON:
off = 1;
break;
case HIDDEN_BUTTON:
default:
off = 0;
break;
}
widget_move (&b->widget, 0, b->hotpos + off);
return 1;
case WIDGET_UNFOCUS:
case WIDGET_FOCUS:
case WIDGET_DRAW:
if (Msg==WIDGET_UNFOCUS)
b->selected = 0;
else if (Msg==WIDGET_FOCUS)
b->selected = 1;
switch (b->flags){
case DEFPUSH_BUTTON:
sprintf (buf, "[< %s >]", b->text);
off = 3;
break;
case NORMAL_BUTTON:
sprintf (buf, "[ %s ]", b->text);
off = 2;
break;
case NARROW_BUTTON:
sprintf (buf, "[%s]", b->text);
off = 1;
break;
case HIDDEN_BUTTON:
default:
buf[0] = '\0';
off = 0;
break;
}
txt = buf;
attrset ((b->selected) ? FOCUSC : NORMALC);
widget_move (&b->widget, 0, 0);
addstr (txt);
if (b->hotpos >= 0){
attrset ((b->selected) ? HOT_FOCUSC : HOT_NORMALC);
widget_move (&b->widget, 0, b->hotpos+off);
addch ((unsigned char)b->text [b->hotpos]);
}
if (Msg == WIDGET_FOCUS)
break;
else
return 1;
break;
#endif
#endif /* !HAVE_XVIEW */
}
return default_proc (h, Msg, Par);
}
static int
button_event (Gpm_Event *event, WButton *b)
{
#ifndef HAVE_X
if (event->type & (GPM_DOWN|GPM_UP)){
Dlg_head *h=b->widget.parent;
dlg_select_widget (h, b);
if (event->type & GPM_UP){
button_callback (h, b, WIDGET_KEY, ' ');
(*h->callback) (h, ' ', DLG_POST_KEY);
return MOU_NORMAL;
}
}
#endif
return MOU_NORMAL;
}
static void
button_destroy (WButton *b)
{
x_destroy_cmd (b);
free (b->text);
}
static int
button_len (const char *text, unsigned int flags)
{
#ifndef HAVE_X
int ret = strlen (text);
switch (flags){
case DEFPUSH_BUTTON:
ret += 6;
break;
case NORMAL_BUTTON:
ret += 4;
break;
case NARROW_BUTTON:
ret += 2;
break;
case HIDDEN_BUTTON:
default:
return 0;
}
return ret;
#else
return strlen (text);
#endif
}
/*
* Assuming that button text is malloc'ed, we may safely change it
* (as opposed to statically allocated); from other hand, excluding &
* and shifting data past it to the left results to one unused byte.
* This does not harm though :)
*/
void
button_scan_hotkey(WButton* b)
{
char* cp = strchr (b->text, '&');
if (cp != NULL && cp[1] != '\0'){
strcpy (cp, cp+1);
b->hotkey = tolower (*cp);
b->hotpos = cp - b->text;
}
}
WButton *
button_new (int y, int x, int action, int flags, char *text,
int (*callback)(int, void *), void *callback_data, char *tkname)
{
WButton *b = xmalloc (sizeof (WButton), "new_button");
init_widget (&b->widget, y, x, 1, button_len (text, flags),
(callback_fn) button_callback,
(destroy_fn) button_destroy, (mouse_h)button_event, tkname);
b->action = action;
b->flags = flags;
b->selected = 0;
b->text = strdup (text);
b->callback = callback;
b->callback_data = callback_data;
widget_want_hotkey (b->widget, 1);
b->hotkey = 0;
b->hotpos = -1;
button_scan_hotkey(b);
return b;
}
void
button_set_text (WButton *b, char *text)
{
free (b->text);
b->text = strdup (text);
b->widget.cols = button_len (text, b->flags);
button_scan_hotkey(b);
#ifdef HAVE_X
x_button_set (b, b->text);
#else
dlg_redraw (b->widget.parent);
#endif
}
/* Radio button widget */
static int radio_event (Gpm_Event *event, WRadio *r);
static int
radio_callback (Dlg_head *h, WRadio *r, int Msg, int Par)
{
int i;
switch (Msg) {
case WIDGET_INIT:
return x_create_radio (h, h->wdata, r);
#ifndef HAVE_XVIEW
case WIDGET_HOTKEY:
{
int i, lp = tolower(Par);
char *cp;
for (i = 0; i < r->count; i++){
cp = strchr (r->texts [i], '&');
if (cp != NULL && cp[1] != '\0'){
int c = tolower (cp [1]);
if (c != lp)
continue;
r->pos = i;
radio_callback (h, r, WIDGET_KEY, ' '); /* Take action */
return 1;
}
}
}
return 0;
case WIDGET_KEY:
switch (Par){
case ' ':
r->sel = r->pos;
(*h->callback) (h, h->current->dlg_id, DLG_ACTION);
radio_callback (h, r, WIDGET_FOCUS, ' ');
x_radio_toggle (r);
return 1;
case KEY_UP:
case KEY_LEFT:
if (r->pos > 0){
r->pos--;
x_radio_focus_item (r);
return 1;
}
return 0;
case KEY_DOWN:
case KEY_RIGHT:
if (r->count - 1 > r->pos) {
r->pos++;
x_radio_focus_item (r);
return 1;
}
}
return 0;
#ifdef HAVE_X
case WIDGET_FOCUS:
case WIDGET_CURSOR:
x_radio_focus_item (r);
return 1;
#endif
#endif
#ifndef HAVE_X
case WIDGET_CURSOR:
(*h->callback) (h, h->current->dlg_id, DLG_ACTION);
radio_callback (h, r, WIDGET_FOCUS, ' ');
widget_move (&r->widget, r->pos, 1);
break;
case WIDGET_UNFOCUS:
case WIDGET_FOCUS:
case WIDGET_DRAW:
for (i = 0; i < r->count; i++){
register char* cp;
attrset ((i==r->pos && Msg==WIDGET_FOCUS) ? FOCUSC :NORMALC);
widget_move (&r->widget, i, 0);
printw("(%c) ", (r->sel == i) ? '*' : ' ');
for (cp = r->texts[i]; *cp; cp++)
{
if (*cp == '&')
{
attrset ((i==r->pos && Msg==WIDGET_FOCUS)
? HOT_FOCUSC : HOT_NORMALC);
addch(*++cp);
attrset ((i==r->pos && Msg==WIDGET_FOCUS) ? FOCUSC : NORMALC);
}
else
addch(*cp);
}
}
return 1;
break;
#endif
}
return default_proc (h, Msg, Par);
}
#ifdef HAVE_TK
static void Radio_destroy (WRadio *r)
{
x_destroy_cmd (r);
}
# define radio_destroy (destroy_fn) Radio_destroy
#else
# define radio_destroy 0
#endif
static int
radio_event (Gpm_Event *event, WRadio *r)
{
#ifndef HAVE_X
if (event->type & (GPM_DOWN|GPM_UP)){
Dlg_head *h = r->widget.parent;
r->pos = event->y - 1;
dlg_select_widget (h, r);
if (event->type & GPM_UP){
radio_callback (h, r, WIDGET_KEY, ' ');
radio_callback (h, r, WIDGET_FOCUS, 0);
(*h->callback) (h, ' ', DLG_POST_KEY);
return MOU_NORMAL;
}
}
#endif
return MOU_NORMAL;
}
WRadio *
radio_new (int y, int x, int count, char **texts, int use_hotkey, char *tkname)
{
WRadio *r = xmalloc (sizeof (WRadio), "radio_new");
int i, max, m;
/* Compute the longest string */
max = 0;
for (i = 0; i < count; i++){
m = strlen (texts [i]);
if (m > max)
max = m;
}
init_widget (&r->widget, y, x, count, max, (callback_fn) radio_callback,
radio_destroy, (mouse_h) radio_event, tkname);
r->state = 1;
r->pos = 0;
r->sel = 0;
r->count = count;
r->texts = texts;
r->upper_letter_is_hotkey = use_hotkey;
widget_want_hotkey (r->widget, 1);
return r;
}
/* Checkbutton widget */
static int check_event (Gpm_Event *event, WCheck *b);
static int
check_callback (Dlg_head *h, WCheck *c, int Msg, int Par)
{
switch (Msg) {
case WIDGET_INIT:
return x_create_check (h, h->wdata, c);
#ifndef HAVE_XVIEW
case WIDGET_HOTKEY:
if (c->hotkey==Par ||
(c->hotkey>='a' && c->hotkey<='z' && c->hotkey-32==Par)){
check_callback (h, c, WIDGET_KEY, ' '); /* make action */
return 1;
} else
return 0;
case WIDGET_KEY:
if (Par != ' ')
break;
c->state ^= C_BOOL;
c->state ^= C_CHANGE;
(*h->callback) (h, h->current->dlg_id, DLG_ACTION);
check_callback (h, c, WIDGET_FOCUS, ' ');
return 1;
#ifndef HAVE_X
case WIDGET_CURSOR:
widget_move (&c->widget, 0, 1);
break;
case WIDGET_FOCUS:
case WIDGET_UNFOCUS:
case WIDGET_DRAW:
attrset ((Msg == WIDGET_FOCUS) ? FOCUSC : NORMALC);
widget_move (&c->widget, 0, 0);
printw ("[%c] %s", (c->state & C_BOOL) ? 'x' : ' ', c->text);
if (c->hotpos >= 0){
attrset ((Msg == WIDGET_FOCUS) ? HOT_FOCUSC : HOT_NORMALC);
widget_move (&c->widget, 0, + c->hotpos+4);
addch ((unsigned char)c->text [c->hotpos]);
}
return 1;
#endif /* !HAVE_X */
#endif /* !HAVE_XVIEW */
}
return default_proc (h, Msg, Par);
}
static int
check_event (Gpm_Event *event, WCheck *c)
{
#ifndef HAVE_X
if (event->type & (GPM_DOWN|GPM_UP)){
Dlg_head *h = c->widget.parent;
dlg_select_widget (h, c);
if (event->type & GPM_UP){
check_callback (h, c, WIDGET_KEY, ' ');
check_callback (h, c, WIDGET_FOCUS, 0);
(*h->callback) (h, ' ', DLG_POST_KEY);
return MOU_NORMAL;
}
}
#endif
return MOU_NORMAL;
}
static void
check_destroy (WCheck *c)
{
x_destroy_cmd (c);
free (c->text);
}
WCheck *
check_new (int y, int x, int state, char *text, char *tkname)
{
WCheck *c = xmalloc (sizeof (WCheck), "check_new");
char *s, *t;
init_widget (&c->widget, y, x, 1, strlen (text),
(callback_fn)check_callback,
(destroy_fn)check_destroy, (mouse_h) check_event, tkname);
c->state = state ? C_BOOL : 0;
c->text = strdup (text);
c->hotkey = 0;
c->hotpos = -1;
widget_want_hotkey (c->widget, 1);
/* Scan for the hotkey */
for (s = text, t = c->text; *s; s++, t++){
if (*s != '&'){
*t = *s;
continue;
}
s++;
if (*s){
c->hotkey = tolower (*s);
c->hotpos = t - c->text;
}
*t = *s;
}
*t = 0;
return c;
}
/* Label widget */
static int
label_callback (Dlg_head *h, WLabel *l, int Msg, int Par)
{
if (Msg == WIDGET_INIT)
return x_create_label (h, h->wdata, l);
/* We don't want to get the focus */
if (Msg == WIDGET_FOCUS)
return 0;
#ifndef HAVE_X
if (Msg == WIDGET_DRAW && l->text){
char *p = l->text, *q, c = 0;
int y = 0;
if (l->transparent)
attrset (DEFAULT_COLOR);
else
attrset (NORMALC);
for (;;){
int xlen;
q = strchr (p, '\n');
if (q){
c = *q;
*q = 0;
}
widget_move (&l->widget, y, 0);
printw ("%s", p);
xlen = l->widget.cols - strlen (p);
if (xlen > 0)
printw ("%*s", xlen, " ");
if (!q)
break;
*q = c;
p = q + 1;
y++;
}
return 1;
}
#endif
return default_proc (h, Msg, Par);
}
void
label_set_text (WLabel *label, char *text)
{
int newcols = label->widget.cols;
if (label->text && text && !strcmp (label->text, text))
return; /* Flickering is not nice */
if (label->text){
free (label->text);
}
if (text){
label->text = strdup (text);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -