widget.c
来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 2,500 行 · 第 1/4 页
C
2,500 行
p++;
while (*p && isalnum (*p))
p++;
in->point = p - in->buffer;
}
static void
backward_word (WInput *in)
{
char *p = in->buffer+in->point;
while (p-1 > in->buffer-1 && (isspace (*(p-1)) || ispunct (*(p-1))))
p--;
while (p-1 > in->buffer-1 && isalnum (*(p-1)))
p--;
in->point = p - in->buffer;
}
#ifdef __linux__
static void
key_left (WInput *in)
{
if (ctrl_pressed ())
backward_word (in);
else
backward_char (in);
}
static void
key_right (WInput *in)
{
if (ctrl_pressed ())
forward_word (in);
else
forward_char (in);
}
#else
#define key_left backward_char
#define key_right forward_char
#endif
static void
backward_delete (WInput *in)
{
int i;
if (!in->point)
return;
for (i = in->point; in->buffer [i-1]; i++)
in->buffer [i-1] = in->buffer [i];
in->need_push = 1;
in->point--;
}
static void
delete_char (WInput *in)
{
int i;
for (i = in->point; in->buffer [i]; i++)
in->buffer [i] = in->buffer [i+1];
in->need_push = 1;
}
static void
copy_region (WInput *in, int x_first, int x_last)
{
int first = min (x_first, x_last);
int last = max (x_first, x_last);
if (last == first)
return;
if (kill_buffer)
free (kill_buffer);
kill_buffer = xmalloc (last-first + 1, "copy_region");
strncpy (kill_buffer, in->buffer+first, last-first);
kill_buffer [last-first] = 0;
}
static void
delete_region (WInput *in, int x_first, int x_last)
{
int first = min (x_first, x_last);
int last = max (x_first, x_last);
in->point = first;
in->mark = first;
strcpy (&in->buffer [first], &in->buffer [last]);
in->need_push = 1;
}
static void
kill_word (WInput *in)
{
int old_point = in->point;
int new_point;
forward_word (in);
new_point = in->point;
in->point = old_point;
copy_region (in, old_point, new_point);
delete_region (in, old_point, new_point);
in->need_push = 1;
}
static void
back_kill_word (WInput *in)
{
int old_point = in->point;
int new_point;
backward_word (in);
new_point = in->point;
in->point = old_point;
copy_region (in, old_point, new_point);
delete_region (in, old_point, new_point);
in->need_push = 1;
}
static void
set_mark (WInput *in)
{
in->mark = in->point;
}
static void
kill_save (WInput *in)
{
copy_region (in, in->mark, in->point);
}
static void
kill_region (WInput *in)
{
kill_save (in);
delete_region (in, in->point, in->mark);
}
static void
yank (WInput *in)
{
char *p;
if (!kill_buffer)
return;
for (p = kill_buffer; *p; p++)
insert_char (in, *p);
}
static void
kill_line (WInput *in)
{
if (kill_buffer)
free (kill_buffer);
kill_buffer = strdup (&in->buffer [in->point]);
in->buffer [in->point] = 0;
}
void
assign_text (WInput *in, char *text)
{
free_completions (in);
free (in->buffer);
in->buffer = strdup (text); /* was in->buffer->text */
in->current_max_len = strlen (in->buffer) + 1;
in->point = strlen (in->buffer);
in->mark = 0;
in->need_push = 1;
}
static void
hist_prev (WInput *in)
{
if (!in->history)
return;
if (in->need_push) {
switch (push_history (in, in->buffer)) {
case 2: in->history = in->history->prev; break;
case 1: if (in->history->prev) in->history = in->history->prev; break;
case 0: break;
}
} else if (in->history->prev)
in->history = in->history->prev;
else
return;
assign_text (in, in->history->text);
in->need_push = 0;
}
static void
hist_next (WInput *in)
{
if (in->need_push) {
switch (push_history (in, in->buffer)) {
case 2:
assign_text (in, "");
return;
case 0:
return;
}
}
if (!in->history)
return;
if (!in->history->next) {
assign_text (in, "");
return;
}
in->history = in->history->next;
assign_text (in, in->history->text);
in->need_push = 0;
}
static struct {
int key_code;
void (*fn)(WInput *in);
} input_map [] = {
/* Motion */
{ XCTRL('a'), beginning_of_line },
{ KEY_HOME, beginning_of_line },
{ KEY_A1, beginning_of_line },
{ XCTRL('e'), end_of_line },
{ KEY_END, end_of_line },
{ KEY_C1, end_of_line },
{ KEY_LEFT, key_left },
{ XCTRL('b'), backward_char },
{ ALT('b'), backward_word },
{ KEY_RIGHT, key_right },
{ XCTRL('f'), forward_char },
{ ALT('f'), forward_word },
/* Editing */
{ 0177, backward_delete },
{ KEY_BACKSPACE, backward_delete },
{ XCTRL('h'), backward_delete },
{ KEY_DC, delete_char },
{ XCTRL('d'), delete_char },
{ ALT('d'), kill_word },
{ ALT(KEY_BACKSPACE), back_kill_word },
{ ALT(XCTRL('h')), back_kill_word },
{ ALT(127), back_kill_word },
/* Region manipulation */
{ 0, set_mark },
{ XCTRL('w'), kill_region },
{ ALT('w'), kill_save },
{ XCTRL('y'), yank },
{ XCTRL('k'), kill_line },
/* History */
{ ALT('p'), hist_prev },
{ ALT('n'), hist_next },
{ ALT('h'), do_show_hist },
/* Completion */
{ ALT('\t'), complete },
{ 0, 0 }
};
/* This function is a test for a special input key used in complete.c */
/* Returns 0 if it is not a special key, 1 if it is a non-complete key
and 2 if it is a complete key */
int
is_in_input_map (WInput *in, int c_code)
{
int i;
for (i = 0; input_map [i].fn; i++)
if (c_code == input_map [i].key_code)
if (input_map [i].fn == complete)
return 2;
else
return 1;
return 0;
}
#ifdef PORT_WINPUT_DELETES_MARKED
static void
port_region_marked_for_delete (WInput *in)
{
kill_region (in);
}
#else
static void
port_region_marked_for_delete (WInput *in)
{
*in->buffer = 0;
in->point = 0;
in->first = 0;
}
#endif
int
handle_char (WInput *in, int c_code)
{
int i;
int v;
v = 0;
#ifdef HAVE_TK
in->inserted_one = 0;
#endif
if (quote){
free_completions (in);
v = insert_char (in, c_code);
update_input (in, 1);
quote = 0;
return v;
}
for (i = 0; input_map [i].fn; i++){
if (c_code == input_map [i].key_code){
if (input_map [i].fn != complete)
free_completions (in);
(*input_map [i].fn)(in);
v = 1;
break;
}
}
if (!input_map [i].fn){
if (c_code > 255 || !is_printable (c_code))
return 0;
if (in->first){
port_region_marked_for_delete (in);
}
free_completions (in);
v = insert_char (in, c_code);
in->inserted_one = c_code;
}
if (!disable_update)
update_input (in, 1);
return v;
}
/* Inserts text in input line */
void
stuff (WInput *in, char *text, int insert_extra_space)
{
input_disable_update (in);
while (*text)
handle_char (in, *text++);
if (insert_extra_space)
handle_char (in, ' ');
input_enable_update (in);
update_input (in, 1);
}
void
input_set_point (WInput *in, int pos)
{
if (pos > in->current_max_len)
pos = in->current_max_len;
if (pos != in->point)
free_completions (in);
in->point = pos;
update_input (in, 1);
}
int input_event (Gpm_Event *event, WInput *b);
static int
input_callback (Dlg_head *h, WInput *in, int Msg, int Par)
{
switch (Msg){
case WIDGET_INIT:
return x_create_input (h, h->wdata, in);
#ifndef HAVE_XVIEW
case WIDGET_KEY:
if (Par == XCTRL('q')){
int v;
quote = 1;
v = handle_char (in, mi_getch ());
quote = 0;
return v;
}
if (Par == KEY_UP || Par == KEY_DOWN ||
Par == ESC_CHAR || Par == KEY_F(10) ||
Par == XCTRL('g'))
return 0; /* We don't handle up/down */
if (Par == '\n'){
dlg_one_down (h);
return 1;
}
return handle_char (in, Par);
case WIDGET_FOCUS:
case WIDGET_UNFOCUS:
case WIDGET_DRAW:
update_input (in, 0);
break;
#endif /* !HAVE_XVIEW */
#ifndef HAVE_X
case WIDGET_CURSOR:
widget_move (&in->widget, 0, in->point - in->first_shown);
return 1;
#endif
}
return default_proc (h, Msg, Par);
}
/* Not declared static, since we check against this value in dlg.c */
/* FIXME: Declare static again and provide an identification mechanism */
int
input_event (Gpm_Event *event, WInput *in)
{
#ifndef HAVE_X
if (event->type & (GPM_DOWN|GPM_DRAG)){
dlg_select_widget (in->widget.parent, in);
if (event->x >= in->field_len - HISTORY_BUTTON_WIDTH + 1 && should_show_history_button (in)) {
do_show_hist (in);
update_input (in, 1);
} else {
in->point = strlen (in->buffer);
if (event->x - in->first_shown - 1 < in->point)
in->point = event->x - in->first_shown - 1;
if (in->point < 0)
in->point = 0;
update_input (in, 1);
}
}
#endif
return MOU_NORMAL;
}
WInput *
input_new (int y, int x, int color, int len, char *def_text, char *tkname)
{
WInput *in = xmalloc (sizeof (WInput), "input_new");
int initial_buffer_len;
init_widget (&in->widget, y, x, 1, len,
(callback_fn) input_callback,
(destroy_fn) input_destroy, (mouse_h) input_event, tkname);
/* history setup */
in->history = NULL;
in->history_name = 0;
if (tkname && PORT_WIDGET_WANTS_HISTORY){
if (*tkname) {
in->history_name = strdup (tkname);
in->history = history_get (tkname);
}
}
if (def_text == INPUT_LAST_TEXT) {
def_text = "";
if (in->history)
if (in->history->text)
def_text = in->history->text;
}
initial_buffer_len = 1 + max (len, strlen (def_text));
in->widget.options |= W_IS_INPUT;
in->completions = NULL;
in->completion_flags =
INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_HOSTNAMES |
INPUT_COMPLETE_VARIABLES | INPUT_COMPLETE_USERNAMES;
in->current_max_len = initial_buffer_len;
in->buffer = xmalloc (initial_buffer_len, "create_input: in->buffer");
in->color = color;
in->field_len = len;
in->first = 1;
in->first_shown = 0;
in->disable_update = 0;
in->mark = 0;
in->need_push = 1;
in->is_password = 0;
strcpy (in->buffer, def_text);
in->point = strlen (in->buffer);
in->first = 1;
return in;
}
/* Listbox widget */
/* Should draw the scrollbar, but currently draws only
* indications that there is more information
*/
static int listbox_cdiff (WLEntry *s, WLEntry *e);
static void
listbox_drawscroll (WListbox *l)
{
extern int slow_terminal;
int line;
int i, top;
int max_line = l->height-1;
/* Are we at the top? */
widget_move (&l->widget, 0, l->width);
if (l->list == l->top)
one_vline ();
else
addch ('^');
/* Are we at the bottom? */
widget_move (&l->widget, max_line, l->width);
top = listbox_cdiff (l->list, l->top);
if ((top + l->height == l->count) || l->height >= l->count)
one_vline ();
else
addch ('v');
/* Now draw the nice relative pointer */
if (l->count)
line = 1+ ((l->pos * (l->height-2)) / l->count);
else
line = 0;
for (i = 1; i < max_line; i++){
widget_move (&l->widget, i, l->width);
if (i != line)
one_vline ();
else
addch ('*');
}
}
static void
listbox_draw (WListbox *l, Dlg_head *h, int focused)
{
WLEntry *e;
int i;
int sel_line;
int normalc, selc;
char *text;
if (focused){
normalc = NORMALC;
selc = FOCUSC;
} else {
normalc = NORMALC;
selc = HOT_FOCUSC;
}
sel_line = -1;
for (e = l->top, i = 0; (i < l->height); i++){
/* Display the entry */
if (e == l->current && sel_line == -1){
sel_line = i;
attrset (selc);
} else
attrset (normalc);
widget_move (&l->widget, i, 0);
if ((i > 0 && e == l->list) || !l->list)
text = "";
else {
text = e->text;
e = e->next;
}
printw (" %-*s ", l->width-2, name_trunc (text, l->width-2));
}
l->cursor_y = sel_line;
if (!l->scrollbar)
return;
attrset (normalc);
listbox_drawscroll (l);
}
/* Returns the number of items between s and e,
must be on the same linked list */
static int
listbox_cdiff (WLEntry *s, WLEntry *e)
{
int count;
for (count = 0; s != e; count++)
s = s->next;
return count;
}
static WLEntry *
listbox_check_hotkey (WListbox *l, int key)
{
int i;
WLEntry *e;
i = 0;
e = l->list;
if (!e)
return 0;
while (1){
/* If we didn't find anything, return */
if (i && e == l->list)
return 0;
if (e->hotkey == key)
return e;
i++;
e = e->next;
}
}
/* Used only for display updating, for avoiding line at a time scroll */
void
listbox_select_last (WListbox *l, int set_top)
{
if (l->list){
l->current = l->list->prev;
l->pos = l->count - 1;
if (set_top)
l->top = l->list->prev;
x_listbox_select_nth (l, l->pos);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?