2011-10-15 14:56:47 +04:00
|
|
|
/*
|
|
|
|
Widgets for the Midnight Commander
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2023-01-03 11:30:57 +03:00
|
|
|
Copyright (C) 1994-2023
|
2014-02-12 10:33:10 +04:00
|
|
|
Free Software Foundation, Inc.
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2011-10-15 14:56:47 +04:00
|
|
|
Authors:
|
|
|
|
Radek Doulik, 1994, 1995
|
|
|
|
Miguel de Icaza, 1994, 1995
|
|
|
|
Jakub Jelinek, 1995
|
|
|
|
Andrej Borsenkow, 1996
|
|
|
|
Norbert Warmuth, 1997
|
2022-05-01 10:43:33 +03:00
|
|
|
Andrew Borodin <aborodin@vmail.ru>, 2009-2022
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2011-10-15 14:56:47 +04:00
|
|
|
This file is part of the Midnight Commander.
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2011-10-15 14:56:47 +04:00
|
|
|
The Midnight Commander 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 3 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
The Midnight Commander is distributed in the hope that it will be useful,
|
2010-11-12 11:03:57 +03:00
|
|
|
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
|
2011-10-15 14:56:47 +04:00
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2010-11-12 11:03:57 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file listbox.c
|
|
|
|
* \brief Source: WListbox widget
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "lib/global.h"
|
|
|
|
|
|
|
|
#include "lib/tty/tty.h"
|
|
|
|
#include "lib/skin.h"
|
|
|
|
#include "lib/strutil.h"
|
2010-11-18 12:39:09 +03:00
|
|
|
#include "lib/util.h" /* Q_() */
|
2010-11-12 11:03:57 +03:00
|
|
|
#include "lib/widget.h"
|
|
|
|
|
|
|
|
/*** global variables ****************************************************************************/
|
|
|
|
|
2011-07-14 21:34:55 +04:00
|
|
|
const global_keymap_t *listbox_map = NULL;
|
2011-02-16 18:19:48 +03:00
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
/*** file scope macro definitions ****************************************************************/
|
|
|
|
|
2015-11-17 23:31:17 +03:00
|
|
|
/* Gives the position of the last item. */
|
2016-06-08 14:44:25 +03:00
|
|
|
#define LISTBOX_LAST(l) (listbox_is_empty (l) ? 0 : (int) g_queue_get_length ((l)->list) - 1)
|
2015-11-17 23:31:17 +03:00
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
/*** file scope type declarations ****************************************************************/
|
|
|
|
|
Update template for .c files.
Add section for forward declarations of local functions. This section is
located before file scope variables because functions can be used in
strucutres (see find.c for example):
/*** forward declarations (file scope functions) *************************************************/
/* button callbacks */
static int start_stop (WButton * button, int action);
static int find_do_view_file (WButton * button, int action);
static int find_do_edit_file (WButton * button, int action);
/*** file scope variables ************************************************************************/
static struct
{
...
bcback_fn callback;
} fbuts[] =
{
...
{ B_STOP, NORMAL_BUTTON, N_("S&uspend"), 0, 0, NULL, start_stop },
...
{ B_VIEW, NORMAL_BUTTON, N_("&View - F3"), 0, 0, NULL, find_do_view_file },
{ B_VIEW, NORMAL_BUTTON, N_("&Edit - F4"), 0, 0, NULL, find_do_edit_file }
};
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
2023-02-24 09:27:11 +03:00
|
|
|
/*** forward declarations (file scope functions) *************************************************/
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
/*** file scope variables ************************************************************************/
|
|
|
|
|
Update template for .c files.
Add section for forward declarations of local functions. This section is
located before file scope variables because functions can be used in
strucutres (see find.c for example):
/*** forward declarations (file scope functions) *************************************************/
/* button callbacks */
static int start_stop (WButton * button, int action);
static int find_do_view_file (WButton * button, int action);
static int find_do_edit_file (WButton * button, int action);
/*** file scope variables ************************************************************************/
static struct
{
...
bcback_fn callback;
} fbuts[] =
{
...
{ B_STOP, NORMAL_BUTTON, N_("S&uspend"), 0, 0, NULL, start_stop },
...
{ B_VIEW, NORMAL_BUTTON, N_("&View - F3"), 0, 0, NULL, find_do_view_file },
{ B_VIEW, NORMAL_BUTTON, N_("&Edit - F4"), 0, 0, NULL, find_do_edit_file }
};
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
2023-02-24 09:27:11 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2010-11-12 11:03:57 +03:00
|
|
|
/*** file scope functions ************************************************************************/
|
Update template for .c files.
Add section for forward declarations of local functions. This section is
located before file scope variables because functions can be used in
strucutres (see find.c for example):
/*** forward declarations (file scope functions) *************************************************/
/* button callbacks */
static int start_stop (WButton * button, int action);
static int find_do_view_file (WButton * button, int action);
static int find_do_edit_file (WButton * button, int action);
/*** file scope variables ************************************************************************/
static struct
{
...
bcback_fn callback;
} fbuts[] =
{
...
{ B_STOP, NORMAL_BUTTON, N_("S&uspend"), 0, 0, NULL, start_stop },
...
{ B_VIEW, NORMAL_BUTTON, N_("&View - F3"), 0, 0, NULL, find_do_view_file },
{ B_VIEW, NORMAL_BUTTON, N_("&Edit - F4"), 0, 0, NULL, find_do_edit_file }
};
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
2023-02-24 09:27:11 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
static int
|
2013-12-02 10:27:32 +04:00
|
|
|
listbox_entry_cmp (const void *a, const void *b, void *user_data)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
|
|
|
const WLEntry *ea = (const WLEntry *) a;
|
|
|
|
const WLEntry *eb = (const WLEntry *) b;
|
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
(void) user_data;
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
return strcmp (ea->text, eb->text);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
|
|
|
listbox_entry_free (void *data)
|
|
|
|
{
|
|
|
|
WLEntry *e = data;
|
2015-10-04 15:14:16 +03:00
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
g_free (e->text);
|
2015-10-04 15:14:16 +03:00
|
|
|
if (e->free_data)
|
|
|
|
g_free (e->data);
|
2010-11-12 11:03:57 +03:00
|
|
|
g_free (e);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
2022-05-01 10:43:33 +03:00
|
|
|
listbox_drawscroll (const WListbox * l)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2022-05-01 10:43:33 +03:00
|
|
|
const WRect *w = &CONST_WIDGET (l)->rect;
|
2012-06-20 15:09:44 +04:00
|
|
|
int max_line = w->lines - 1;
|
2010-11-12 11:03:57 +03:00
|
|
|
int line = 0;
|
|
|
|
int i;
|
2013-12-02 10:27:32 +04:00
|
|
|
int length;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
/* Are we at the top? */
|
2022-05-01 10:43:33 +03:00
|
|
|
widget_gotoyx (l, 0, w->cols);
|
2010-11-12 11:03:57 +03:00
|
|
|
if (l->top == 0)
|
|
|
|
tty_print_one_vline (TRUE);
|
|
|
|
else
|
|
|
|
tty_print_char ('^');
|
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
length = g_queue_get_length (l->list);
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
/* Are we at the bottom? */
|
2019-10-16 13:07:24 +03:00
|
|
|
widget_gotoyx (w, max_line, w->cols);
|
2013-12-02 10:27:32 +04:00
|
|
|
if (l->top + w->lines == length || w->lines >= length)
|
2010-11-12 11:03:57 +03:00
|
|
|
tty_print_one_vline (TRUE);
|
|
|
|
else
|
|
|
|
tty_print_char ('v');
|
|
|
|
|
|
|
|
/* Now draw the nice relative pointer */
|
2013-12-02 10:27:32 +04:00
|
|
|
if (!g_queue_is_empty (l->list))
|
|
|
|
line = 1 + ((l->pos * (w->lines - 2)) / length);
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
for (i = 1; i < max_line; i++)
|
|
|
|
{
|
2022-05-01 10:43:33 +03:00
|
|
|
widget_gotoyx (l, i, w->cols);
|
2010-11-12 11:03:57 +03:00
|
|
|
if (i != line)
|
|
|
|
tty_print_one_vline (TRUE);
|
|
|
|
else
|
|
|
|
tty_print_char ('*');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
|
|
|
listbox_draw (WListbox * l, gboolean focused)
|
|
|
|
{
|
2022-05-01 10:43:33 +03:00
|
|
|
Widget *wl = WIDGET (l);
|
|
|
|
const WRect *w = &CONST_WIDGET (l)->rect;
|
2019-11-17 17:58:52 +03:00
|
|
|
const int *colors;
|
2016-04-10 10:49:31 +03:00
|
|
|
gboolean disabled;
|
|
|
|
int normalc, selc;
|
|
|
|
int length = 0;
|
|
|
|
GList *le = NULL;
|
|
|
|
int pos;
|
|
|
|
int i;
|
|
|
|
int sel_line = -1;
|
|
|
|
|
2022-05-01 10:43:33 +03:00
|
|
|
colors = widget_get_colors (wl);
|
2019-11-17 17:58:52 +03:00
|
|
|
|
2022-05-01 10:43:33 +03:00
|
|
|
disabled = widget_get_state (wl, WST_DISABLED);
|
2019-11-17 17:58:52 +03:00
|
|
|
normalc = disabled ? DISABLED_COLOR : colors[DLG_COLOR_NORMAL];
|
|
|
|
selc = disabled ? DISABLED_COLOR : colors[focused ? DLG_COLOR_HOT_FOCUS : DLG_COLOR_FOCUS];
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
if (l->list != NULL)
|
|
|
|
{
|
|
|
|
length = g_queue_get_length (l->list);
|
|
|
|
le = g_queue_peek_nth_link (l->list, (guint) l->top);
|
|
|
|
}
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
/* pos = (le == NULL) ? 0 : g_list_position (l->list, le); */
|
|
|
|
pos = (le == NULL) ? 0 : l->top;
|
|
|
|
|
2012-06-20 15:09:44 +04:00
|
|
|
for (i = 0; i < w->lines; i++)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2013-12-02 10:27:32 +04:00
|
|
|
const char *text = "";
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
/* Display the entry */
|
|
|
|
if (pos == l->pos && sel_line == -1)
|
|
|
|
{
|
|
|
|
sel_line = i;
|
|
|
|
tty_setcolor (selc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tty_setcolor (normalc);
|
|
|
|
|
2019-10-16 13:07:24 +03:00
|
|
|
widget_gotoyx (l, i, 1);
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
if (l->list != NULL && le != NULL && (i == 0 || pos < length))
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2012-10-11 12:25:07 +04:00
|
|
|
WLEntry *e = LENTRY (le->data);
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
text = e->text;
|
|
|
|
le = g_list_next (le);
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
|
2012-06-20 15:09:44 +04:00
|
|
|
tty_print_string (str_fit_to_term (text, w->cols - 2, J_LEFT_FIT));
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
l->cursor_y = sel_line;
|
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
if (l->scrollbar && length > w->lines)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
|
|
|
tty_setcolor (normalc);
|
|
|
|
listbox_drawscroll (l);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static int
|
|
|
|
listbox_check_hotkey (WListbox * l, int key)
|
|
|
|
{
|
2013-12-02 10:27:32 +04:00
|
|
|
if (!listbox_is_empty (l))
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2013-12-02 10:27:32 +04:00
|
|
|
int i;
|
|
|
|
GList *le;
|
|
|
|
|
|
|
|
for (i = 0, le = g_queue_peek_head_link (l->list); le != NULL; i++, le = g_list_next (le))
|
|
|
|
{
|
|
|
|
WLEntry *e = LENTRY (le->data);
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
if (e->hotkey == key)
|
|
|
|
return i;
|
|
|
|
}
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2015-11-17 23:31:17 +03:00
|
|
|
/* Calculates the item displayed at screen row 'y' (y==0 being the widget's 1st row). */
|
2010-11-12 11:03:57 +03:00
|
|
|
static int
|
2015-11-17 23:31:17 +03:00
|
|
|
listbox_y_pos (WListbox * l, int y)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2016-04-07 10:52:04 +03:00
|
|
|
return MIN (l->top + y, LISTBOX_LAST (l));
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
2015-11-18 21:21:06 +03:00
|
|
|
listbox_fwd (WListbox * l, gboolean wrap)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2016-06-08 14:44:25 +03:00
|
|
|
if (!listbox_is_empty (l))
|
|
|
|
{
|
|
|
|
if ((guint) l->pos + 1 < g_queue_get_length (l->list))
|
|
|
|
listbox_select_entry (l, l->pos + 1);
|
|
|
|
else if (wrap)
|
|
|
|
listbox_select_first (l);
|
|
|
|
}
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2015-11-17 23:31:17 +03:00
|
|
|
static void
|
|
|
|
listbox_fwd_n (WListbox * l, int n)
|
|
|
|
{
|
2016-04-07 10:52:04 +03:00
|
|
|
listbox_select_entry (l, MIN (l->pos + n, LISTBOX_LAST (l)));
|
2015-11-17 23:31:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
static void
|
2015-11-18 21:21:06 +03:00
|
|
|
listbox_back (WListbox * l, gboolean wrap)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2016-06-08 14:44:25 +03:00
|
|
|
if (!listbox_is_empty (l))
|
|
|
|
{
|
|
|
|
if (l->pos > 0)
|
|
|
|
listbox_select_entry (l, l->pos - 1);
|
|
|
|
else if (wrap)
|
|
|
|
listbox_select_last (l);
|
|
|
|
}
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2015-11-17 23:31:17 +03:00
|
|
|
static void
|
|
|
|
listbox_back_n (WListbox * l, int n)
|
|
|
|
{
|
2016-04-07 10:52:04 +03:00
|
|
|
listbox_select_entry (l, MAX (l->pos - n, 0));
|
2015-11-17 23:31:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
static cb_ret_t
|
2015-11-21 18:15:11 +03:00
|
|
|
listbox_execute_cmd (WListbox * l, long command)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
|
|
|
cb_ret_t ret = MSG_HANDLED;
|
2022-05-01 10:43:33 +03:00
|
|
|
const WRect *w = &CONST_WIDGET (l)->rect;
|
2013-12-02 10:27:32 +04:00
|
|
|
|
|
|
|
if (l->list == NULL || g_queue_is_empty (l->list))
|
|
|
|
return MSG_NOT_HANDLED;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
switch (command)
|
|
|
|
{
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Up:
|
2015-11-18 21:21:06 +03:00
|
|
|
listbox_back (l, TRUE);
|
2010-11-12 11:03:57 +03:00
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Down:
|
2015-11-18 21:21:06 +03:00
|
|
|
listbox_fwd (l, TRUE);
|
2010-11-12 11:03:57 +03:00
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Top:
|
2010-11-12 11:03:57 +03:00
|
|
|
listbox_select_first (l);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Bottom:
|
2010-11-12 11:03:57 +03:00
|
|
|
listbox_select_last (l);
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_PageUp:
|
2015-11-17 23:31:17 +03:00
|
|
|
listbox_back_n (l, w->lines - 1);
|
2010-11-12 11:03:57 +03:00
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_PageDown:
|
2015-11-17 23:31:17 +03:00
|
|
|
listbox_fwd_n (l, w->lines - 1);
|
2010-11-12 11:03:57 +03:00
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Delete:
|
2010-11-12 11:03:57 +03:00
|
|
|
if (l->deletable)
|
|
|
|
{
|
2013-12-02 10:27:32 +04:00
|
|
|
gboolean is_last, is_more;
|
2015-11-17 23:31:17 +03:00
|
|
|
int length;
|
2013-12-02 10:27:32 +04:00
|
|
|
|
|
|
|
length = g_queue_get_length (l->list);
|
|
|
|
|
|
|
|
is_last = (l->pos + 1 >= length);
|
|
|
|
is_more = (l->top + w->lines >= length);
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
listbox_remove_current (l);
|
|
|
|
if ((l->top > 0) && (is_last || is_more))
|
|
|
|
l->top--;
|
|
|
|
}
|
|
|
|
break;
|
2011-01-21 11:47:27 +03:00
|
|
|
case CK_Clear:
|
2011-02-10 18:02:54 +03:00
|
|
|
if (l->deletable && mc_global.widget.confirm_history_cleanup
|
2010-11-12 11:03:57 +03:00
|
|
|
/* TRANSLATORS: no need to translate 'DialogTitle', it's just a context prefix */
|
|
|
|
&& (query_dialog (Q_ ("DialogTitle|History cleanup"),
|
|
|
|
_("Do you want clean this history?"),
|
|
|
|
D_ERROR, 2, _("&Yes"), _("&No")) == 0))
|
|
|
|
listbox_remove_list (l);
|
|
|
|
break;
|
2019-07-14 11:16:41 +03:00
|
|
|
case CK_View:
|
|
|
|
case CK_Edit:
|
|
|
|
case CK_Enter:
|
|
|
|
ret = send_message (WIDGET (l)->owner, l, MSG_NOTIFY, command, NULL);
|
|
|
|
break;
|
2010-11-12 11:03:57 +03:00
|
|
|
default:
|
|
|
|
ret = MSG_NOT_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/* Return MSG_HANDLED if we want a redraw */
|
|
|
|
static cb_ret_t
|
|
|
|
listbox_key (WListbox * l, int key)
|
|
|
|
{
|
2015-11-21 18:15:11 +03:00
|
|
|
long command;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
if (l->list == NULL)
|
|
|
|
return MSG_NOT_HANDLED;
|
|
|
|
|
|
|
|
/* focus on listbox item N by '0'..'9' keys */
|
|
|
|
if (key >= '0' && key <= '9')
|
|
|
|
{
|
|
|
|
listbox_select_entry (l, key - '0');
|
|
|
|
return MSG_HANDLED;
|
|
|
|
}
|
|
|
|
|
2017-03-08 14:41:35 +03:00
|
|
|
command = widget_lookup_key (WIDGET (l), key);
|
2011-02-20 18:23:32 +03:00
|
|
|
if (command == CK_IgnoreKey)
|
2010-11-12 11:03:57 +03:00
|
|
|
return MSG_NOT_HANDLED;
|
|
|
|
return listbox_execute_cmd (l, command);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/* Listbox item adding function */
|
|
|
|
static inline void
|
|
|
|
listbox_append_item (WListbox * l, WLEntry * e, listbox_append_t pos)
|
|
|
|
{
|
2013-12-02 10:27:32 +04:00
|
|
|
if (l->list == NULL)
|
2014-02-18 09:41:02 +04:00
|
|
|
{
|
2013-12-02 10:27:32 +04:00
|
|
|
l->list = g_queue_new ();
|
2014-02-18 09:41:02 +04:00
|
|
|
pos = LISTBOX_APPEND_AT_END;
|
|
|
|
}
|
2013-12-02 10:27:32 +04:00
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
switch (pos)
|
|
|
|
{
|
|
|
|
case LISTBOX_APPEND_AT_END:
|
2013-12-02 10:27:32 +04:00
|
|
|
g_queue_push_tail (l->list, e);
|
2010-11-12 11:03:57 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LISTBOX_APPEND_BEFORE:
|
2013-12-02 10:27:32 +04:00
|
|
|
g_queue_insert_before (l->list, g_queue_peek_nth_link (l->list, (guint) l->pos), e);
|
2010-11-12 11:03:57 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LISTBOX_APPEND_AFTER:
|
2013-12-02 10:27:32 +04:00
|
|
|
g_queue_insert_after (l->list, g_queue_peek_nth_link (l->list, (guint) l->pos), e);
|
2010-11-12 11:03:57 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LISTBOX_APPEND_SORTED:
|
2013-12-02 10:27:32 +04:00
|
|
|
g_queue_insert_sorted (l->list, e, (GCompareDataFunc) listbox_entry_cmp, NULL);
|
2010-11-12 11:03:57 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2013-12-02 10:27:32 +04:00
|
|
|
break;
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2015-11-21 22:00:46 +03:00
|
|
|
/* Call this whenever the user changes the selected item. */
|
|
|
|
static void
|
|
|
|
listbox_on_change (WListbox * l)
|
|
|
|
{
|
|
|
|
listbox_draw (l, TRUE);
|
2019-07-14 11:16:41 +03:00
|
|
|
send_message (WIDGET (l)->owner, l, MSG_NOTIFY, 0, NULL);
|
2015-11-21 22:00:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
2016-01-19 15:02:43 +03:00
|
|
|
listbox_do_action (WListbox * l)
|
2015-11-21 22:00:46 +03:00
|
|
|
{
|
|
|
|
int action;
|
|
|
|
|
2016-06-08 14:44:25 +03:00
|
|
|
if (listbox_is_empty (l))
|
|
|
|
return;
|
|
|
|
|
2015-11-21 22:00:46 +03:00
|
|
|
if (l->callback != NULL)
|
|
|
|
action = l->callback (l);
|
|
|
|
else
|
|
|
|
action = LISTBOX_DONE;
|
|
|
|
|
|
|
|
if (action == LISTBOX_DONE)
|
|
|
|
{
|
2016-09-27 13:53:17 +03:00
|
|
|
WDialog *h = DIALOG (WIDGET (l)->owner);
|
2016-01-19 15:02:43 +03:00
|
|
|
|
2015-11-21 22:00:46 +03:00
|
|
|
h->ret_value = B_ENTER;
|
2023-04-15 10:17:41 +03:00
|
|
|
dlg_close (h);
|
2015-11-21 22:00:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2016-01-19 15:02:43 +03:00
|
|
|
static void
|
|
|
|
listbox_run_hotkey (WListbox * l, int pos)
|
|
|
|
{
|
|
|
|
listbox_select_entry (l, pos);
|
|
|
|
listbox_on_change (l);
|
|
|
|
listbox_do_action (l);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
static inline void
|
|
|
|
listbox_destroy (WListbox * l)
|
|
|
|
{
|
|
|
|
listbox_remove_list (l);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static cb_ret_t
|
2012-06-26 11:52:21 +04:00
|
|
|
listbox_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2012-10-11 12:25:07 +04:00
|
|
|
WListbox *l = LISTBOX (w);
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
switch (msg)
|
|
|
|
{
|
2012-09-28 15:05:43 +04:00
|
|
|
case MSG_HOTKEY:
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2015-11-21 22:00:46 +03:00
|
|
|
int pos;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
pos = listbox_check_hotkey (l, parm);
|
|
|
|
if (pos < 0)
|
|
|
|
return MSG_NOT_HANDLED;
|
|
|
|
|
2015-11-21 22:00:46 +03:00
|
|
|
listbox_run_hotkey (l, pos);
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
return MSG_HANDLED;
|
|
|
|
}
|
|
|
|
|
2012-09-28 15:05:43 +04:00
|
|
|
case MSG_KEY:
|
2020-04-09 08:37:45 +03:00
|
|
|
{
|
|
|
|
cb_ret_t ret_code;
|
|
|
|
|
|
|
|
ret_code = listbox_key (l, parm);
|
|
|
|
if (ret_code != MSG_NOT_HANDLED)
|
|
|
|
listbox_on_change (l);
|
|
|
|
return ret_code;
|
|
|
|
}
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2012-09-28 15:05:43 +04:00
|
|
|
case MSG_ACTION:
|
2010-11-12 11:03:57 +03:00
|
|
|
return listbox_execute_cmd (l, parm);
|
|
|
|
|
2012-09-28 15:05:43 +04:00
|
|
|
case MSG_CURSOR:
|
2019-10-16 13:07:24 +03:00
|
|
|
widget_gotoyx (l, l->cursor_y, 0);
|
2010-11-12 11:03:57 +03:00
|
|
|
return MSG_HANDLED;
|
|
|
|
|
2012-09-28 15:05:43 +04:00
|
|
|
case MSG_DRAW:
|
2016-06-12 18:32:02 +03:00
|
|
|
listbox_draw (l, widget_get_state (w, WST_FOCUSED));
|
2010-11-12 11:03:57 +03:00
|
|
|
return MSG_HANDLED;
|
|
|
|
|
2012-09-28 15:05:43 +04:00
|
|
|
case MSG_DESTROY:
|
2010-11-12 11:03:57 +03:00
|
|
|
listbox_destroy (l);
|
|
|
|
return MSG_HANDLED;
|
|
|
|
|
|
|
|
default:
|
2012-09-28 15:05:43 +04:00
|
|
|
return widget_default_callback (w, sender, msg, parm, data);
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2015-11-26 01:31:53 +03:00
|
|
|
static void
|
|
|
|
listbox_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2015-11-26 01:31:53 +03:00
|
|
|
WListbox *l = LISTBOX (w);
|
2016-01-19 15:02:43 +03:00
|
|
|
int old_pos;
|
|
|
|
|
|
|
|
old_pos = l->pos;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2015-11-26 01:31:53 +03:00
|
|
|
switch (msg)
|
|
|
|
{
|
|
|
|
case MSG_MOUSE_DOWN:
|
2016-08-09 09:35:27 +03:00
|
|
|
widget_select (w);
|
2015-11-26 01:31:53 +03:00
|
|
|
listbox_select_entry (l, listbox_y_pos (l, event->y));
|
|
|
|
break;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2015-11-26 01:31:53 +03:00
|
|
|
case MSG_MOUSE_SCROLL_UP:
|
|
|
|
listbox_back (l, FALSE);
|
|
|
|
break;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2015-11-26 01:31:53 +03:00
|
|
|
case MSG_MOUSE_SCROLL_DOWN:
|
|
|
|
listbox_fwd (l, FALSE);
|
|
|
|
break;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2015-11-26 01:31:53 +03:00
|
|
|
case MSG_MOUSE_DRAG:
|
|
|
|
event->result.repeat = TRUE; /* It'd be functional even without this. */
|
|
|
|
listbox_select_entry (l, listbox_y_pos (l, event->y));
|
|
|
|
break;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2015-11-26 01:31:53 +03:00
|
|
|
case MSG_MOUSE_CLICK:
|
2016-01-19 15:02:43 +03:00
|
|
|
/* We don't call listbox_select_entry() here: MSG_MOUSE_DOWN/DRAG did this already. */
|
|
|
|
if (event->count == GPM_DOUBLE) /* Double click */
|
|
|
|
listbox_do_action (l);
|
2015-11-26 01:31:53 +03:00
|
|
|
break;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2015-11-26 01:31:53 +03:00
|
|
|
default:
|
|
|
|
break;
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
2011-03-21 16:43:56 +03:00
|
|
|
|
2016-01-19 15:02:43 +03:00
|
|
|
/* If the selection has changed, we redraw the widget and notify the dialog. */
|
|
|
|
if (l->pos != old_pos)
|
|
|
|
listbox_on_change (l);
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/*** public functions ****************************************************************************/
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
WListbox *
|
|
|
|
listbox_new (int y, int x, int height, int width, gboolean deletable, lcback_fn callback)
|
|
|
|
{
|
2022-05-21 16:11:06 +03:00
|
|
|
WRect r = { y, x, 1, width };
|
2010-11-12 11:03:57 +03:00
|
|
|
WListbox *l;
|
2012-06-20 15:09:44 +04:00
|
|
|
Widget *w;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
l = g_new (WListbox, 1);
|
2012-06-20 15:09:44 +04:00
|
|
|
w = WIDGET (l);
|
2022-05-21 16:11:06 +03:00
|
|
|
r.lines = height > 0 ? height : 1;
|
|
|
|
widget_init (w, &r, listbox_callback, listbox_mouse_callback);
|
2016-06-07 15:03:20 +03:00
|
|
|
w->options |= WOP_SELECTABLE | WOP_WANT_HOTKEY;
|
2017-03-08 14:41:35 +03:00
|
|
|
w->keymap = listbox_map;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
l->list = NULL;
|
|
|
|
l->top = l->pos = 0;
|
|
|
|
l->deletable = deletable;
|
|
|
|
l->callback = callback;
|
|
|
|
l->allow_duplicates = TRUE;
|
2011-09-06 19:24:18 +04:00
|
|
|
l->scrollbar = !mc_global.tty.slow_terminal;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2017-01-25 15:07:18 +03:00
|
|
|
/**
|
|
|
|
* Finds item by its label.
|
|
|
|
*/
|
2010-11-12 11:03:57 +03:00
|
|
|
int
|
|
|
|
listbox_search_text (WListbox * l, const char *text)
|
|
|
|
{
|
2013-12-02 10:27:32 +04:00
|
|
|
if (!listbox_is_empty (l))
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
GList *le;
|
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
for (i = 0, le = g_queue_peek_head_link (l->list); le != NULL; i++, le = g_list_next (le))
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2012-10-11 12:25:07 +04:00
|
|
|
WLEntry *e = LENTRY (le->data);
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
if (strcmp (e->text, text) == 0)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2017-01-25 15:07:18 +03:00
|
|
|
/**
|
|
|
|
* Finds item by its 'data' slot.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
listbox_search_data (WListbox * l, const void *data)
|
|
|
|
{
|
|
|
|
if (!listbox_is_empty (l))
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
GList *le;
|
|
|
|
|
|
|
|
for (i = 0, le = g_queue_peek_head_link (l->list); le != NULL; i++, le = g_list_next (le))
|
|
|
|
{
|
|
|
|
WLEntry *e = LENTRY (le->data);
|
|
|
|
|
|
|
|
if (e->data == data)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
/* Selects the first entry and scrolls the list to the top */
|
|
|
|
void
|
|
|
|
listbox_select_first (WListbox * l)
|
|
|
|
{
|
|
|
|
l->pos = l->top = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/* Selects the last entry and scrolls the list to the bottom */
|
|
|
|
void
|
|
|
|
listbox_select_last (WListbox * l)
|
|
|
|
{
|
2022-05-01 10:43:33 +03:00
|
|
|
int lines = WIDGET (l)->rect.lines;
|
2019-07-06 19:36:56 +03:00
|
|
|
int length;
|
2012-06-20 15:09:44 +04:00
|
|
|
|
2019-07-06 19:36:56 +03:00
|
|
|
length = listbox_get_length (l);
|
2013-12-02 10:27:32 +04:00
|
|
|
|
2021-05-16 14:10:30 +03:00
|
|
|
l->pos = DOZ (length, 1);
|
|
|
|
l->top = DOZ (length, lines);
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
void
|
|
|
|
listbox_select_entry (WListbox * l, int dest)
|
|
|
|
{
|
|
|
|
GList *le;
|
|
|
|
int pos;
|
|
|
|
gboolean top_seen = FALSE;
|
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
if (listbox_is_empty (l) || dest < 0)
|
2010-11-12 11:03:57 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Special case */
|
2013-12-02 10:27:32 +04:00
|
|
|
for (pos = 0, le = g_queue_peek_head_link (l->list); le != NULL; pos++, le = g_list_next (le))
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
|
|
|
if (pos == l->top)
|
|
|
|
top_seen = TRUE;
|
|
|
|
|
|
|
|
if (pos == dest)
|
|
|
|
{
|
|
|
|
l->pos = dest;
|
|
|
|
if (!top_seen)
|
|
|
|
l->top = l->pos;
|
2012-06-20 15:09:44 +04:00
|
|
|
else
|
|
|
|
{
|
2022-05-01 10:43:33 +03:00
|
|
|
int lines = WIDGET (l)->rect.lines;
|
2012-06-20 15:09:44 +04:00
|
|
|
|
|
|
|
if (l->pos - l->top >= lines)
|
|
|
|
l->top = l->pos - lines + 1;
|
|
|
|
}
|
2010-11-12 11:03:57 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we are unable to find it, set decent values */
|
|
|
|
l->pos = l->top = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2019-07-06 19:36:56 +03:00
|
|
|
int
|
|
|
|
listbox_get_length (const WListbox * l)
|
|
|
|
{
|
|
|
|
return listbox_is_empty (l) ? 0 : (int) g_queue_get_length (l->list);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
/* Returns the current string text as well as the associated extra data */
|
|
|
|
void
|
|
|
|
listbox_get_current (WListbox * l, char **string, void **extra)
|
|
|
|
{
|
2014-01-22 13:59:54 +04:00
|
|
|
WLEntry *e = NULL;
|
2010-11-12 11:03:57 +03:00
|
|
|
gboolean ok;
|
|
|
|
|
2014-01-22 13:59:54 +04:00
|
|
|
if (l != NULL)
|
|
|
|
e = listbox_get_nth_item (l, l->pos);
|
2010-11-12 11:03:57 +03:00
|
|
|
|
|
|
|
ok = (e != NULL);
|
|
|
|
|
|
|
|
if (string != NULL)
|
|
|
|
*string = ok ? e->text : NULL;
|
|
|
|
|
|
|
|
if (extra != NULL)
|
|
|
|
*extra = ok ? e->data : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
WLEntry *
|
|
|
|
listbox_get_nth_item (const WListbox * l, int pos)
|
|
|
|
{
|
|
|
|
if (!listbox_is_empty (l) && pos >= 0)
|
|
|
|
{
|
|
|
|
GList *item;
|
|
|
|
|
|
|
|
item = g_queue_peek_nth_link (l->list, (guint) pos);
|
|
|
|
if (item != NULL)
|
|
|
|
return LENTRY (item->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
GList *
|
|
|
|
listbox_get_first_link (const WListbox * l)
|
|
|
|
{
|
|
|
|
return (l == NULL || l->list == NULL) ? NULL : g_queue_peek_head_link (l->list);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
void
|
|
|
|
listbox_remove_current (WListbox * l)
|
|
|
|
{
|
2013-12-02 10:27:32 +04:00
|
|
|
if (!listbox_is_empty (l))
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
|
|
|
GList *current;
|
2013-12-02 10:27:32 +04:00
|
|
|
int length;
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
current = g_queue_peek_nth_link (l->list, (guint) l->pos);
|
2020-04-11 12:44:20 +03:00
|
|
|
listbox_entry_free (current->data);
|
2013-12-02 10:27:32 +04:00
|
|
|
g_queue_delete_link (l->list, current);
|
|
|
|
|
|
|
|
length = g_queue_get_length (l->list);
|
2010-11-12 11:03:57 +03:00
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
if (length == 0)
|
2010-11-12 11:03:57 +03:00
|
|
|
l->top = l->pos = 0;
|
2013-12-02 10:27:32 +04:00
|
|
|
else if (l->pos >= length)
|
|
|
|
l->pos = length - 1;
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2013-12-02 10:27:32 +04:00
|
|
|
gboolean
|
|
|
|
listbox_is_empty (const WListbox * l)
|
|
|
|
{
|
|
|
|
return (l == NULL || l->list == NULL || g_queue_is_empty (l->list));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2019-07-20 20:15:43 +03:00
|
|
|
/**
|
|
|
|
* Set new listbox items list.
|
|
|
|
*
|
|
|
|
* @param l WListbox object
|
|
|
|
* @param list list of WLEntry objects
|
|
|
|
*/
|
2010-11-12 11:03:57 +03:00
|
|
|
void
|
2019-07-20 20:15:43 +03:00
|
|
|
listbox_set_list (WListbox * l, GQueue * list)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
|
|
|
listbox_remove_list (l);
|
|
|
|
|
|
|
|
if (l != NULL)
|
2019-07-20 20:15:43 +03:00
|
|
|
l->list = list;
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
void
|
|
|
|
listbox_remove_list (WListbox * l)
|
|
|
|
{
|
2013-12-02 10:27:32 +04:00
|
|
|
if (l != NULL)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
2013-12-02 10:27:32 +04:00
|
|
|
if (l->list != NULL)
|
|
|
|
{
|
2016-12-03 20:17:21 +03:00
|
|
|
g_queue_free_full (l->list, (GDestroyNotify) listbox_entry_free);
|
|
|
|
l->list = NULL;
|
2013-12-02 10:27:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
l->pos = l->top = 0;
|
2010-11-12 11:03:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
char *
|
2015-10-04 15:14:16 +03:00
|
|
|
listbox_add_item (WListbox * l, listbox_append_t pos, int hotkey, const char *text, void *data,
|
|
|
|
gboolean free_data)
|
2010-11-12 11:03:57 +03:00
|
|
|
{
|
|
|
|
WLEntry *entry;
|
|
|
|
|
|
|
|
if (l == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!l->allow_duplicates && (listbox_search_text (l, text) >= 0))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
entry = g_new (WLEntry, 1);
|
|
|
|
entry->text = g_strdup (text);
|
|
|
|
entry->data = data;
|
2015-10-04 15:14:16 +03:00
|
|
|
entry->free_data = free_data;
|
2010-11-12 11:03:57 +03:00
|
|
|
entry->hotkey = hotkey;
|
|
|
|
|
|
|
|
listbox_append_item (l, entry, pos);
|
|
|
|
|
|
|
|
return entry->text;
|
|
|
|
}
|
2010-11-22 17:15:28 +03:00
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|