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 + -
显示快捷键?