widget.c

来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 2,500 行 · 第 1/4 页

C
2,500
字号
}

void
listbox_remove_list (WListbox *l)
{
    WLEntry *p, *q;

    if (!l->count)
	return;

#ifdef HAVE_X
    if (l->widget.wdata != (widget_data) NULL) {
	int i;
	for (i = 0; i < l->count; i++)
	    x_listbox_delete_nth (l, i);
    }
#endif
    p = l->list;

    while (l->count--) {
	q = p->next;
	free (p->text);
	free (p);
	p = q;
    }
    l->pos = l->count = 0;
    l->list = l->top = l->current = 0;
}

/*
 * bor 30.10.96: added force flag to remove *last* entry as well
 * bor 30.10.96: corrected selection bug if last entry was removed
 */

void
listbox_remove_current (WListbox *l, int force)
{
    WLEntry *p;

    /* Ok, note: this won't allow for emtpy lists */
    if (!force && (!l->count || l->count == 1))
	return;

#ifdef HAVE_X
    if (l->widget.wdata != (widget_data) NULL) {
        x_listbox_delete_nth (l, l->pos);
	if (l->count > 1)
	    if (l->current->next != l->list)
		x_listbox_select_nth (l, l->pos);
	    else if (l->current != l->list)
		x_listbox_select_nth (l, l->pos - 1);
	else
	    x_listbox_select_nth (l, 0);
    }
#endif
    l->count--;
    p = l->current;

    if (l->count) {
	l->current->next->prev = l->current->prev;
	l->current->prev->next = l->current->next;
	if (p->next == l->list) {
	    l->current = p->prev;
	    l->pos--;
	}
	else
	    l->current = p->next;

	if (p == l->list)
	    l->list = l->top = p->next;
    } else {
	l->pos = 0;
	l->list = l->top = l->current = 0;
    }

    free (p->text);
    free (p);
}

/* Makes *e the selected entry (sets current and pos) */
void
listbox_select_entry (WListbox *l, WLEntry *dest)
{
    WLEntry *e;
    int pos;
    int top_seen;

    top_seen = 0;

    /* Special case */
    for (pos = 0, e = l->list; pos < l->count; e = e->next, pos++){

	if (e == l->top)
	    top_seen = 1;

	if (e == dest){
	    l->current = e;
	    if (top_seen){
		while (listbox_cdiff (l->top, l->current) >= l->height)
		    l->top = l->top->next;
	    } else {
		l->top = l->current;
	    }
	    l->pos = pos;
	    x_listbox_select_nth (l, l->pos);
	    return;
	}
    }
    /* If we are unable to find it, set decent values */
    l->current = l->top = l->list;
    l->pos = 0;
    x_listbox_select_nth (l, l->pos);
}

/* Selects from base the pos element */
static WLEntry *
listbox_select_pos (WListbox *l, WLEntry *base, int pos)
{
    WLEntry *last = l->list->prev;

    if (base == last)
    	return last;
    while (pos--){
	base = base->next;
	if (base == last)
	    break;
    }
    return base;
}

static inline int
listbox_back (WListbox *l)
{
    if (l->pos){
	listbox_select_entry (l, listbox_select_pos (l, l->list, l->pos-1));
	return 1;
    }
    return 0;
}

static inline int
listbox_fwd (WListbox *l)
{
    if (l->current != l->list->prev){
	listbox_select_entry (l, listbox_select_pos (l, l->list, l->pos+1));
	return 1;
    }
    return 0;
}

/* Returns 1 if we want a redraw */
static int
listbox_key (WListbox *l, int key)
{
    int i;
    int j = 0;

    if (!l->list)
	return 0;

    switch (key){
    case KEY_HOME:
    case KEY_A1:
	l->current = l->top = l->list;
	l->pos = 0;
	return 1;

    case KEY_END:
    case KEY_C1:
	l->current = l->top = l->list->prev;
	for (i = min (l->height - 1, l->count - 1); i; i--)
	    l->top = l->top->prev;
	l->pos = l->count - 1;
	return 1;

    case XCTRL('p'):
    case KEY_UP:
	listbox_back (l);
	return 1;

    case XCTRL('n'):
    case KEY_DOWN:
	listbox_fwd (l);
	return 1;

    case KEY_NPAGE:
    case XCTRL('v'):
	for (i = 0; i < l->height-1; i++)
	    j |= listbox_fwd (l);
	return j > 0;

    case KEY_PPAGE:
    case ALT('v'):
	for (i = 0; i < l->height-1; i++)
	    j |= listbox_back (l);
	return j > 0;
    }
    return 0;
}

static int listbox_event (Gpm_Event *event, WListbox *l);
static int
listbox_callback (Dlg_head *h, WListbox *l, int msg, int par)
{
    WLEntry  *e;
    /* int selected_color; Never used */
    int ret_code;

    switch (msg){
    case WIDGET_INIT:
	return x_create_listbox (h, h->wdata, l);

#ifndef	HAVE_XVIEW
    case WIDGET_HOTKEY:
	if ((e = listbox_check_hotkey (l, par)) != NULL){
	    listbox_select_entry (l, e);

	    /* Take the appropriate action */
	    if (l->action == listbox_finish){
		l->widget.parent->running   = 0;
		l->widget.parent->ret_value = B_ENTER;
	    } else if (l->action == listbox_cback){
		if ((*l->cback)(l) == listbox_finish){
		    l->widget.parent->running = 0;
		    l->widget.parent->ret_value = B_ENTER;
		}
	    }
	    return 1;
	} else
	    return 0;

    case WIDGET_KEY:
	if ((ret_code = listbox_key (l, par)))
	    listbox_draw (l, h, 1);
	return ret_code;

#ifndef HAVE_X
    case WIDGET_CURSOR:
	widget_move (&l->widget, l->cursor_y, 0);
	return 1;

    case WIDGET_FOCUS:
    case WIDGET_UNFOCUS:
    case WIDGET_DRAW:
	listbox_draw (l, h, msg != WIDGET_UNFOCUS);
	return 1;
#endif
#endif /* !HAVE_XVIEW */
    }
    return default_proc (h, msg, par);
}

static int
listbox_event (Gpm_Event *event, WListbox *l)
{
#ifndef HAVE_X
    int i;

    Dlg_head *h = l->widget.parent;

    /* Single click */
    if (event->type & GPM_DOWN)
	dlg_select_widget (l->widget.parent, l);
    if (!l->list)
	return MOU_NORMAL;
    if (event->type & (GPM_DOWN|GPM_DRAG)){
	if (event->x < 0 || event->x >= l->width)
	    return MOU_REPEAT;
	if (event->y < 1)
	    for (i = -event->y; i >= 0; i--)
		listbox_back (l);
	else if (event->y > l->height)
	    for (i = event->y - l->height; i > 0; i--)
		listbox_fwd (l);
	else
            listbox_select_entry (l, listbox_select_pos (l, l->top,
	      					         event->y - 1));

	/* We need to refresh ourselves since the dialog manager doesn't */
	/* know about this event */
	listbox_callback (h, l, WIDGET_DRAW, 0);
	mc_refresh ();
	return MOU_REPEAT;
    }

    /* Double click */
    if ((event->type & (GPM_DOUBLE|GPM_UP)) == (GPM_UP|GPM_DOUBLE)){
     	if (event->x < 0 || event->x >= l->width)
     	    return MOU_NORMAL;
     	if (event->y < 1 || event->y > l->height)
     	    return MOU_NORMAL;

	dlg_select_widget (l->widget.parent, l);
	listbox_select_entry (l, listbox_select_pos (l, l->top, event->y - 1));

	switch (l->action){
	case listbox_nothing:
	    break;

	case listbox_finish:
	    h->ret_value = B_ENTER;
	    dlg_stop (h);
	    return MOU_ENDLOOP;

	case listbox_cback:
	    if ((*l->cback)(l) == listbox_finish)
		return MOU_ENDLOOP;
	}
    }
#endif
    return MOU_NORMAL;
}

static void
listbox_destroy (WListbox *l)
{
    WLEntry *n, *p = l->list;
    int i;

    x_destroy_cmd (l);
    for (i = 0; i < l->count; i++){
	n = p->next;
	free (p->text);
	free (p);
	p = n;
    }
}

WListbox *
listbox_new (int y, int x, int width, int height,
	     int action, lcback callback, char *tkname)
{
    WListbox *l = xmalloc (sizeof (WListbox), "listbox_new");
    extern int slow_terminal;

    init_widget (&l->widget, y, x, height, width,
		 (callback_fn)listbox_callback,
		 (destroy_fn) listbox_destroy, (mouse_h)listbox_event, tkname);

    l->list   = l->top = l->current = 0;
    l->pos    = 0;
    l->width  = width;
    l->height = height;
    l->count  = 0;
    l->top    = 0;
    l->current= 0;
    l->cback  = callback;
    l->action = action;
    l->allow_duplicates = 1;
    l->scrollbar = slow_terminal ? 0 : 1;
    widget_want_hotkey (l->widget, 1);

    return l;
}

/* Listbox item adding function.  They still lack a lot of functionality */
/* any takers? */
/* 1.11.96 bor: added pos argument to control placement of new entry */
static void
listbox_append_item (WListbox *l, WLEntry *e, enum append_pos pos)
{
    if (!l->list){
	l->list = e;
	l->top = e;
	l->current = e;
	e->next = l->list;
	e->prev = l->list;
    } else if (pos == LISTBOX_APPEND_AT_END) {
	e->next = l->list;
	e->prev = l->list->prev;
	l->list->prev->next = e;
	l->list->prev = e;
    } else if (pos == LISTBOX_APPEND_BEFORE){
	e->next = l->current;
	e->prev = l->current->prev;
	l->current->prev->next = e;
	l->current->prev = e;
	if (l->list == l->current) {	/* move list one position down */
	    l->list = e;
	    l->top =  e;
	}
    } else if (pos == LISTBOX_APPEND_AFTER) {
	e->prev = l->current;
	e->next = l->current->next;
	l->current->next->prev = e;
	l->current->next = e;
    }
    x_list_insert (l, l->list, e);
    l->count++;
}

char *
listbox_add_item (WListbox *l, enum append_pos pos, int hotkey, char *text,
			void *data)
{
    WLEntry *entry;

    if (!l)
	return 0;

    if (!l->allow_duplicates)
	if (listbox_search_text (l, text))
	    return 0;

    entry = xmalloc (sizeof (WLEntry), "listbox_add_item");
    entry->text = strdup (text);
    entry->data = data;
    entry->hotkey = hotkey;

    listbox_append_item (l, entry, pos);

    return entry->text;
}

/* Selects the nth entry in the listbox */
void
listbox_select_by_number (WListbox *l, int n)
{
    listbox_select_entry (l, listbox_select_pos (l, l->list, n));
}

WLEntry *
listbox_search_text (WListbox *l, char *text)
{
    WLEntry *e;

    e = l->list;
    if (!e)
	return NULL;

    do {
	if(!strcmp (e->text, text))
	    return e;
	e = e->next;
    } while (e!=l->list);

    return NULL;
}

/* Returns the current string text as well as the associated extra data */
void
listbox_get_current (WListbox *l, char **string, char **extra)
{
    if (!l->current){
	*string = 0;
	*extra  = 0;
    }
    if (string && l->current)
	*string = l->current->text;
    if (extra && l->current)
	*extra = l->current->data;
}

int
buttonbar_callback (Dlg_head *h, WButtonBar *bb, int msg, int par)
{
    int i;

    switch (msg){
    case WIDGET_INIT:
	return x_create_buttonbar (h, h->wdata, bb);

    case WIDGET_FOCUS:
	return 0;

#ifndef	HAVE_XVIEW
    case WIDGET_HOTKEY:
	for (i = 0; i < 10; i++){
	    if (par == KEY_F(i+1) && bb->labels [i].function){
		(*bb->labels [i].function)(bb->labels [i].data);
		return 1;
	    }
	}
	return 0;

#ifndef HAVE_X
    case WIDGET_DRAW:
	if (!bb->visible)
	    return 1;
	widget_move (&bb->widget, 0, 0);
	attrset (DEFAULT_COLOR);
	printw ("%-*s", bb->widget.cols - 1, "");
	for (i = 0; i < COLS/8 && i < 10; i++){
	    widget_move (&bb->widget, 0, i*8);
	    attrset (DEFAULT_COLOR);
	    printw ("%d", i+1);
	    attrset (SELECTED_COLOR);
	    printw ("%-*s", ((i+1) * 8 == COLS ? 5 : 6),
		    bb->labels [i].text ? bb->labels [i].text : "");
	    attrset (DEFAULT_COLOR);
	}
	attrset (SELECTED_COLOR);
	return 1;
#endif
#endif /* !HAVE_XVIEW */
    }
    return default_proc (h, msg, par);
}

static void
buttonbar_destroy (WButtonBar *bb)
{
    int i;

    for (i = 0; i < 10; i++){
	if (bb->labels [i].text)
	    free (bb->labels [i].text);
    }
}

static int
buttonbar_event (Gpm_Event *event, WButtonBar *bb)
{
#ifndef HAVE_X
    int button;

    if (!(event->type & GPM_UP))
	return MOU_NORMAL;
    if (event->y == 2)
	return MOU_NORMAL;
    button = event->x / 8;
    if (button < 10 && bb->labels [button].function)
	(*bb->labels [button].function)(bb->labels [button].data);
#endif
    return MOU_NORMAL;
}

WButtonBar *
buttonbar_new (int visible)
{
    int i;
    WButtonBar *bb = xmalloc (sizeof (WButtonBar), "buttonbar_new");

    init_widget (&bb->widget, LINES-1, 0, 1, COLS,
		 (callback_fn) buttonbar_callback,
		 (destroy_fn) buttonbar_destroy, (mouse_h) buttonbar_event, NULL);

    bb->visible = visible;
    for (i = 0; i < 10; i++){
	bb->labels [i].text     = 0;
	bb->labels [i].function = 0;
    }
    widget_want_hotkey (bb->widget, 1);
    widget_want_cursor (bb->widget, 0);

    return bb;
}

void
set_label_text (WButtonBar *bb, int index, char *text)
{
    if (bb->labels [index-1].text)
	free (bb->labels [index-1].text);

    bb->labels [index-1].text = strdup (text);
}

/* paneletc is either the panel widget, or info or view or tree widget */
WButtonBar *
find_buttonbar (Dlg_head *h, Widget *paneletc)
{
    WButtonBar *bb;
    Widget_Item *item;
    int i;

    bb = 0;
    for (i = 0, item = h->current; i < h->count; i++, item = item->next){
	if (item->widget->callback == (callback_fn) buttonbar_callback){
	    bb = (WButtonBar *) item->widget;
#ifdef HAVE_XVIEW
	    /* Jakub: do we really need this routine here?
	     * Does XView hold more that a buttonbar per Dlg_head?
	     */
	    if (x_find_buttonbar_check (bb, paneletc)) {
	        bb = 0;
	        continue;
	    }
#endif
	    break;
	}
    }
    return bb;
}

void
define_label_data (Dlg_head *h, Widget *paneletc, int idx, char *text,
		   buttonbarfn cback, void *data)
{
    WButtonBar *bb = find_buttonbar (h, paneletc);
    if (!bb)
	return;

    set_label_text (bb, idx, text);
    bb->labels [idx-1].function = (void (*)(void *)) cback;
    bb->labels [idx-1].data = data;
    x_redefine_label (bb, idx);
}

void
define_label (Dlg_head *h, Widget *paneletc, int idx, char *text, void (*cback)(void))
{
    define_label_data (h, paneletc, idx, text, (void (*)(void *)) cback, 0);
}

#ifdef HAVE_X
void redraw_labels (Dlg_head *h, Widget *paneletc)
{
}

#else
void
redraw_labels (Dlg_head *h, Widget *paneletc)
{
    Widget_Item *item;
    int i;

    for (i = 0, item = h->current; i < h->count; i++, item = item->next){
	if (item->widget->callback == (callback_fn) buttonbar_callback){
	    widget_redraw (h, item);
	    return;
	}
    }
}
#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?