summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2014-04-10 20:04:06 +0300
committerJari Vetoniemi <mailroxas@gmail.com>2014-04-10 20:04:06 +0300
commita6d0413b972580f3bbfde8750090270b0d8d463e (patch)
tree7ed26f9c4978dfc213c89a6ec2008cccc9670dbb
parent16e023aa3eb495a4b48af1784e5e78dcf4e9ba0b (diff)
downloadbemenu-a6d0413b972580f3bbfde8750090270b0d8d463e.tar.gz
bemenu-a6d0413b972580f3bbfde8750090270b0d8d463e.tar.bz2
bemenu-a6d0413b972580f3bbfde8750090270b0d8d463e.zip
Implement list structure, and feature for multiple selections.
-rw-r--r--client/client.c8
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/bemenu.h56
-rw-r--r--lib/draw/curses.c8
-rw-r--r--lib/filter.c28
-rw-r--r--lib/internal.h64
-rw-r--r--lib/list.c135
-rw-r--r--lib/menu.c223
8 files changed, 386 insertions, 137 deletions
diff --git a/client/client.c b/client/client.c
index 4bdfdc6..ecaed25 100644
--- a/client/client.c
+++ b/client/client.c
@@ -101,10 +101,10 @@ int main(int argc, char **argv)
} while ((status = bmMenuRunWithKey(menu, key, unicode)) == BM_RUN_RESULT_RUNNING);
if (status == BM_RUN_RESULT_SELECTED) {
- bmItem *item = bmMenuGetSelectedItem(menu);
-
- if (item)
- printf("%s\n", bmItemGetText(item));
+ unsigned int i, count;
+ bmItem **items = bmMenuGetSelectedItems(menu, &count);
+ for (i = 0; i < count; ++i)
+ printf("%s\n", bmItemGetText(items[i]));
}
bmMenuFree(menu);
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index e669ef5..f53dfc6 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -3,6 +3,7 @@ SET(BEMENU_SOURCE
menu.c
item.c
filter.c
+ list.c
util.c
draw/curses.c
)
diff --git a/lib/bemenu.h b/lib/bemenu.h
index f2f0372..250ad53 100644
--- a/lib/bemenu.h
+++ b/lib/bemenu.h
@@ -85,6 +85,7 @@ typedef enum bmKey {
BM_KEY_TAB,
BM_KEY_ESCAPE,
BM_KEY_RETURN,
+ BM_KEY_SHIFT_RETURN,
BM_KEY_UNICODE,
BM_KEY_LAST
} bmKey;
@@ -200,24 +201,52 @@ int bmMenuRemoveItemAt(bmMenu *menu, unsigned int index);
*/
int bmMenuRemoveItem(bmMenu *menu, bmItem *item);
+
/**
- * Get selected item from bmMenu instance.
+ * Get highlighted item from bmMenu instance.
*
- * @param menu bmMenu instance from where to get selected item.
- * @return Selected bmItem instance, **NULL** if none selected.
+ * @param menu bmMenu instance from where to get highlighted item.
+ * @return Selected bmItem instance, **NULL** if none highlighted.
*/
-bmItem* bmMenuGetSelectedItem(const bmMenu *menu);
+bmItem* bmMenuGetHighlightedItem(const bmMenu *menu);
/**
- * Get items from bmMenu instance.
+ * Highlight item in menu by index.
*
- * @warning The pointer returned by this function may be invalid after removing or adding new items.
+ * @param menu bmMenu instance from where to highlight item.
+ * @return 1 on successful highlight, 0 on failure.
+ */
+int bmMenuSetHighlightedIndex(bmMenu *menu, unsigned int index);
+
+/**
+ * Highlight item in menu.
*
- * @param menu bmMenu instance from where to get items.
+ * @param menu bmMenu instance from where to highlight item.
+ * @param item bmItem instance to highlight.
+ * @return 1 on successful highlight, 0 on failure.
+ */
+int bmMenuSetHighlighted(bmMenu *menu, bmItem *item);
+
+/**
+ * Get selected items from bmMenu instance.
+ *
+ * @param menu bmMenu instance from where to get selected items.
* @param outNmemb Reference to unsigned int where total count of returned items will be stored.
* @return Pointer to array of bmItem pointers.
*/
-bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb);
+bmItem** bmMenuGetSelectedItems(const bmMenu *menu, unsigned int *outNmemb);
+
+/**
+ * Set selected items to bmMenu instance.
+ *
+ * @warning The list won't be copied.
+ *
+ * @param menu bmMenu instance where items will be set.
+ * @param items Array of bmItem pointers to set.
+ * @param nmemb Total count of items in array.
+ * @return 1 on successful set, 0 on failure.
+ */
+int bmMenuSetSelectedItems(bmMenu *menu, bmItem **items, unsigned int nmemb);
/**
* Get filtered (displayed) items from bmMenu instance.
@@ -232,6 +261,17 @@ bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb);
bmItem** bmMenuGetFilteredItems(const bmMenu *menu, unsigned int *outNmemb);
/**
+ * Get items from bmMenu instance.
+ *
+ * @warning The pointer returned by this function may be invalid after removing or adding new items.
+ *
+ * @param menu bmMenu instance from where to get items.
+ * @param outNmemb Reference to unsigned int where total count of returned items will be stored.
+ * @return Pointer to array of bmItem pointers.
+ */
+bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb);
+
+/**
* Set items to bmMenu instance.
* Will replace all the old items on bmMenu instance.
*
diff --git a/lib/draw/curses.c b/lib/draw/curses.c
index 0e19538..336b21d 100644
--- a/lib/draw/curses.c
+++ b/lib/draw/curses.c
@@ -120,8 +120,9 @@ static void _bmDrawCursesRender(const bmMenu *menu)
unsigned int itemsCount;
bmItem **items = bmMenuGetFilteredItems(menu, &itemsCount);
for (i = (menu->index / (lines - 1)) * (lines - 1); i < itemsCount && cl < lines; ++i) {
- int selected = (items[i] == bmMenuGetSelectedItem(menu));
- _bmDrawCursesDrawLine((selected ? 2 : 0), cl++, "%s%s", (selected ? ">> " : " "), items[i]->text);
+ int highlighted = (items[i] == bmMenuGetHighlightedItem(menu));
+ int color = (highlighted ? 2 : (_bmMenuItemIsSelected(menu, items[i]) ? 1 : 0));
+ _bmDrawCursesDrawLine(color, cl++, "%s%s", (highlighted ? ">> " : " "), items[i]->text);
}
curses.move(0, titleLen + menu->cursesCursor);
@@ -200,6 +201,9 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode)
case 9: /* Tab */
return BM_KEY_TAB;
+ case 18: /* C-r */
+ return BM_KEY_SHIFT_RETURN;
+
case 10: /* Return */
_bmDrawCursesEndWin();
return BM_KEY_RETURN;
diff --git a/lib/filter.c b/lib/filter.c
index 33126c0..4677e73 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -8,33 +8,33 @@
*
* @param menu bmMenu instance to filter.
* @param outNmemb unsigned int reference to filtered items outNmemb.
- * @param outSelected unsigned int reference to new outSelected item index.
+ * @param outHighlighted unsigned int reference to new outHighlighted item index.
* @return Pointer to array of bmItem pointers.
*/
-bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outSelected)
+bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted)
{
assert(menu);
assert(outNmemb);
- assert(outSelected);
- *outNmemb = *outSelected = 0;
+ assert(outHighlighted);
+ *outNmemb = *outHighlighted = 0;
/* FIXME: not real dmenu like filtering at all */
- bmItem **filtered = calloc(menu->itemsCount, sizeof(bmItem*));
+ bmItem **filtered = calloc(menu->items.count, sizeof(bmItem*));
if (!filtered)
return NULL;
unsigned int i, f;
- for (f = i = 0; i < menu->itemsCount; ++i) {
- bmItem *item = menu->items[i];
+ for (f = i = 0; i < menu->items.count; ++i) {
+ bmItem *item = menu->items.list[i];
if (item->text && strstr(item->text, menu->filter)) {
- if (f == 0 || item == bmMenuGetSelectedItem(menu))
- *outSelected = f;
+ if (f == 0 || item == bmMenuGetHighlightedItem(menu))
+ *outHighlighted = f;
filtered[f++] = item;
}
}
- return _bmShrinkItemList(&filtered, menu->itemsCount, (*outNmemb = f));
+ return _bmShrinkItemList(&filtered, menu->items.count, (*outNmemb = f));
}
/**
@@ -42,15 +42,15 @@ bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outS
*
* @param menu bmMenu instance to filter.
* @param outNmemb unsigned int reference to filtered items outNmemb.
- * @param outSelected unsigned int reference to new outSelected item index.
+ * @param outHighlighted unsigned int reference to new outHighlighted item index.
* @return Pointer to array of bmItem pointers.
*/
-bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, unsigned int *outNmemb, unsigned int *outSelected)
+bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted)
{
assert(menu);
assert(outNmemb);
- assert(outSelected);
- *outNmemb = *outSelected = 0;
+ assert(outHighlighted);
+ *outNmemb = *outHighlighted = 0;
/* FIXME: stub */
diff --git a/lib/internal.h b/lib/internal.h
index 66eabbc..d0a9848 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -38,6 +38,23 @@ struct _bmRenderApi {
void (*free)(void);
};
+struct _bmItemList {
+ /**
+ * Items in the list.
+ */
+ struct _bmItem **list;
+
+ /**
+ * Number of items.
+ */
+ unsigned int count;
+
+ /**
+ * Number of allocated items.
+ */
+ unsigned int allocated;
+};
+
/**
* Internal bmMenu struct that is not exposed to public.
*/
@@ -48,14 +65,19 @@ struct _bmMenu {
struct _bmRenderApi renderApi;
/**
- * All items contained in menu instance.
+ * Items contained in menu instance.
*/
- struct _bmItem **items;
+ struct _bmItemList items;
/**
* Filtered/displayed items contained in menu instance.
*/
- struct _bmItem **filteredItems;
+ struct _bmItemList filtered;
+
+ /**
+ * Selected items.
+ */
+ struct _bmItemList selection;
/**
* Menu instance title.
@@ -79,22 +101,7 @@ struct _bmMenu {
unsigned int cursesCursor;
/**
- * Number of items in menu instance.
- */
- unsigned int itemsCount;
-
- /**
- * Number of filtered items in menu instance.
- */
- unsigned int filteredCount;
-
- /**
- * Number of allocated items in menu instance.
- */
- unsigned int allocatedCount;
-
- /**
- * Current filtered item index in menu instance.
+ * Current filtered/highlighted item index in menu instance.
* This index is valid for the list returned by bmMenuGetFilteredItems.
*/
unsigned int index;
@@ -113,9 +120,24 @@ struct _bmMenu {
/* draw/curses.c */
int _bmDrawCursesInit(struct _bmRenderApi *api);
+/* menu.c */
+int _bmMenuItemIsSelected(const bmMenu *menu, const bmItem *item);
+
/* filter.c */
-bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outSelected);
-bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, unsigned int *outNmemb, unsigned int *outSelected);
+bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted);
+bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted);
+
+/* list.c */
+void _bmItemListFreeList(struct _bmItemList *list);
+void _bmItemListFreeItems(struct _bmItemList *list);
+bmItem** _bmItemListGetItems(const struct _bmItemList *list, unsigned int *outNmemb);
+int _bmItemListSetItemsNoCopy(struct _bmItemList *list, bmItem **items, unsigned int nmemb);
+int _bmItemListSetItems(struct _bmItemList *list, const bmItem **items, unsigned int nmemb);
+int _bmItemListGrow(struct _bmItemList *list, unsigned int step);
+int _bmItemListAddItemAt(struct _bmItemList *list, bmItem *item, unsigned int index);
+int _bmItemListAddItem(struct _bmItemList *list, bmItem *item);
+int _bmItemListRemoveItemAt(struct _bmItemList *list, unsigned int index);
+int _bmItemListRemoveItem(struct _bmItemList *list, const bmItem *item);
/* util.c */
char* _bmStrdup(const char *s);
diff --git a/lib/list.c b/lib/list.c
new file mode 100644
index 0000000..2123818
--- /dev/null
+++ b/lib/list.c
@@ -0,0 +1,135 @@
+#include "internal.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+void _bmItemListFreeList(struct _bmItemList *list)
+{
+ assert(list);
+
+ if (list->list)
+ free(list->list);
+
+ list->allocated = list->count = 0;
+ list->list = NULL;
+}
+
+void _bmItemListFreeItems(struct _bmItemList *list)
+{
+ assert(list);
+
+ unsigned int i;
+ for (i = 0; i < list->count; ++i)
+ bmItemFree(list->list[i]);
+
+ _bmItemListFreeList(list);
+}
+
+bmItem** _bmItemListGetItems(const struct _bmItemList *list, unsigned int *outNmemb)
+{
+ assert(list);
+
+ if (outNmemb)
+ *outNmemb = list->count;
+
+ return list->list;
+}
+
+int _bmItemListSetItemsNoCopy(struct _bmItemList *list, bmItem **items, unsigned int nmemb)
+{
+ assert(list);
+
+ _bmItemListFreeList(list);
+
+ if (!items || nmemb == 0) {
+ items = NULL;
+ nmemb = 0;
+ }
+
+ list->list = items;
+ list->allocated = list->count = nmemb;
+ return 1;
+}
+
+int _bmItemListSetItems(struct _bmItemList *list, const bmItem **items, unsigned int nmemb)
+{
+ assert(list);
+
+ if (!items || nmemb == 0) {
+ _bmItemListFreeItems(list);
+ return 1;
+ }
+
+ bmItem **newItems;
+ if (!(newItems = calloc(sizeof(bmItem*), nmemb)))
+ return 0;
+
+ memcpy(newItems, items, sizeof(bmItem*) * nmemb);
+ return _bmItemListSetItemsNoCopy(list, newItems, nmemb);
+}
+
+int _bmItemListGrow(struct _bmItemList *list, unsigned int step)
+{
+ assert(list);
+
+ void *tmp;
+ unsigned int nsize = sizeof(bmItem*) * (list->allocated + step);
+
+ if (!list->list || !(tmp = realloc(list->list, nsize))) {
+ if (!(tmp = malloc(nsize)))
+ return 0;
+
+ if (list->list)
+ memcpy(tmp, list->list, sizeof(bmItem*) * list->allocated);
+ }
+
+ list->list = tmp;
+ list->allocated += step;
+ memset(&list->list[list->count], 0, sizeof(bmItem*) * (list->allocated - list->count));
+ return 1;
+}
+
+int _bmItemListAddItemAt(struct _bmItemList *list, bmItem *item, unsigned int index)
+{
+ assert(list);
+ assert(item);
+
+ if ((!list->list || list->allocated <= list->count) && !_bmItemListGrow(list, 32))
+ return 0;
+
+ if (index + 1 != list->count) {
+ unsigned int i = index;
+ memmove(&list->list[i + 1], &list->list[i], sizeof(bmItem*) * (list->count - i));
+ }
+
+ list->list[index] = item;
+ list->count++;
+ return 1;
+}
+
+int _bmItemListAddItem(struct _bmItemList *list, bmItem *item)
+{
+ assert(list);
+ return _bmItemListAddItemAt(list, item, list->count);
+}
+
+int _bmItemListRemoveItemAt(struct _bmItemList *list, unsigned int index)
+{
+ assert(list);
+
+ unsigned int i = index;
+ if (!list->list || list->count <= i)
+ return 0;
+
+ memmove(&list->list[i], &list->list[i], sizeof(bmItem*) * (list->count - i));
+ return 1;
+}
+
+int _bmItemListRemoveItem(struct _bmItemList *list, const bmItem *item)
+{
+ unsigned int i;
+ for (i = 0; i < list->count && list->list[i] != item; ++i);
+ return _bmItemListRemoveItemAt(list, i);
+}
+
+/* vim: set ts=8 sw=4 tw=0 :*/
diff --git a/lib/menu.c b/lib/menu.c
index 3d41121..6274fe3 100644
--- a/lib/menu.c
+++ b/lib/menu.c
@@ -7,7 +7,7 @@
/**
* Filter function map.
*/
-static bmItem** (*filterFunc[BM_FILTER_MODE_LAST])(bmMenu *menu, unsigned int *outNmemb, unsigned int *outSelected) = {
+static bmItem** (*filterFunc[BM_FILTER_MODE_LAST])(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted) = {
_bmFilterDmenu, /* BM_FILTER_DMENU */
_bmFilterDmenuCaseInsensitive /* BM_FILTER_DMENU_CASE_INSENSITIVE */
};
@@ -16,37 +16,22 @@ static void _bmMenuFilter(bmMenu *menu)
{
assert(menu);
- if (menu->filteredItems)
- free(menu->filteredItems);
-
- menu->filteredCount = 0;
- menu->filteredItems = NULL;
-
unsigned int count, selected;
bmItem **filtered = filterFunc[menu->filterMode](menu, &count, &selected);
- menu->filteredItems = filtered;
- menu->filteredCount = count;
+ _bmItemListSetItemsNoCopy(&menu->filtered, filtered, count);
menu->index = selected;
}
-static int _bmMenuGrowItems(bmMenu *menu)
+int _bmMenuItemIsSelected(const bmMenu *menu, const bmItem *item)
{
- void *tmp;
- static const unsigned int step = 32;
- unsigned int nsize = sizeof(bmItem*) * (menu->allocatedCount + step);
-
- if (!(tmp = realloc(menu->items, nsize))) {
- if (!(tmp = malloc(nsize)))
- return 0;
-
- memcpy(tmp, menu->items, sizeof(bmItem*) * menu->allocatedCount);
- }
+ assert(menu);
+ assert(item);
- menu->items = tmp;
- menu->allocatedCount += step;
- memset(&menu->items[menu->itemsCount], 0, sizeof(bmItem*) * (menu->allocatedCount - menu->itemsCount));
- return 1;
+ unsigned int i, count;
+ bmItem **items = bmMenuGetSelectedItems(menu, &count);
+ for (i = 0; i < count && items[i] != item; ++i);
+ return (i < count);
}
/**
@@ -97,8 +82,8 @@ void bmMenuFree(bmMenu *menu)
if (menu->title)
free(menu->title);
- if (menu->filteredItems)
- free(menu->filteredItems);
+ if (menu->filtered.list)
+ free(menu->filtered.list);
bmMenuFreeItems(menu);
free(menu);
@@ -112,14 +97,9 @@ void bmMenuFree(bmMenu *menu)
void bmMenuFreeItems(bmMenu *menu)
{
assert(menu);
-
- unsigned int i;
- for (i = 0; i < menu->itemsCount; ++i)
- bmItemFree(menu->items[i]);
-
- free(menu->items);
- menu->allocatedCount = menu->itemsCount = 0;
- menu->items = NULL;
+ _bmItemListFreeList(&menu->selection);
+ _bmItemListFreeList(&menu->filtered);
+ _bmItemListFreeItems(&menu->items);
}
/**
@@ -195,19 +175,7 @@ const char* bmMenuGetTitle(const bmMenu *menu)
int bmMenuAddItemAt(bmMenu *menu, bmItem *item, unsigned int index)
{
assert(menu);
- assert(item);
-
- if (menu->itemsCount >= menu->allocatedCount && !_bmMenuGrowItems(menu))
- return 0;
-
- if (index + 1 != menu->itemsCount) {
- unsigned int i = index;
- memmove(&menu->items[i + 1], &menu->items[i], sizeof(bmItem*) * (menu->itemsCount - i));
- }
-
- menu->items[index] = item;
- menu->itemsCount++;
- return 1;
+ return _bmItemListAddItemAt(&menu->items, item, index);;
}
/**
@@ -219,7 +187,7 @@ int bmMenuAddItemAt(bmMenu *menu, bmItem *item, unsigned int index)
*/
int bmMenuAddItem(bmMenu *menu, bmItem *item)
{
- return bmMenuAddItemAt(menu, item, menu->itemsCount);
+ return _bmItemListAddItem(&menu->items, item);
}
/**
@@ -235,12 +203,18 @@ int bmMenuRemoveItemAt(bmMenu *menu, unsigned int index)
{
assert(menu);
- unsigned int i = index;
- if (i >= menu->itemsCount)
+ if (!menu->items.list || menu->items.count <= index)
return 0;
- memmove(&menu->items[i], &menu->items[i], sizeof(bmItem*) * (menu->itemsCount - i));
- return 1;
+ bmItem *item = menu->items.list[index];
+ int ret = _bmItemListRemoveItemAt(&menu->items, index);
+
+ if (ret) {
+ _bmItemListRemoveItem(&menu->selection, item);
+ _bmItemListRemoveItem(&menu->filtered, item);
+ }
+
+ return ret;
}
/**
@@ -255,20 +229,24 @@ int bmMenuRemoveItemAt(bmMenu *menu, unsigned int index)
int bmMenuRemoveItem(bmMenu *menu, bmItem *item)
{
assert(menu);
- assert(item);
- unsigned int i;
- for (i = 0; i < menu->itemsCount && menu->items[i] != item; ++i);
- return bmMenuRemoveItemAt(menu, i);
+ int ret = _bmItemListRemoveItem(&menu->items, item);
+
+ if (ret) {
+ _bmItemListRemoveItem(&menu->selection, item);
+ _bmItemListRemoveItem(&menu->filtered, item);
+ }
+
+ return ret;
}
/**
- * Get selected item from bmMenu instance.
+ * Get highlighted item from bmMenu instance.
*
- * @param menu bmMenu instance from where to get selected item.
- * @return Selected bmItem instance, **NULL** if none selected.
+ * @param menu bmMenu instance from where to get highlighted item.
+ * @return Selected bmItem instance, **NULL** if none highlighted.
*/
-bmItem* bmMenuGetSelectedItem(const bmMenu *menu)
+bmItem* bmMenuGetHighlightedItem(const bmMenu *menu)
{
assert(menu);
@@ -282,22 +260,70 @@ bmItem* bmMenuGetSelectedItem(const bmMenu *menu)
}
/**
- * Get items from bmMenu instance.
+ * Highlight item in menu by index.
*
- * @warning The pointer returned by this function may be invalid after removing or adding new items.
+ * @param menu bmMenu instance from where to highlight item.
+ * @return 1 on successful highlight, 0 on failure.
+ */
+int bmMenuSetHighlightedIndex(bmMenu *menu, unsigned int index)
+{
+ assert(menu);
+ unsigned int itemsCount = (menu->filtered.list ? menu->filtered.count : menu->items.count);
+
+ if (itemsCount <= index)
+ return 0;
+
+ return (menu->index = index);
+}
+
+/**
+ * Highlight item in menu.
*
- * @param menu bmMenu instance from where to get items.
+ * @param menu bmMenu instance from where to highlight item.
+ * @param item bmItem instance to highlight.
+ * @return 1 on successful highlight, 0 on failure.
+ */
+int bmMenuSetHighlighted(bmMenu *menu, bmItem *item)
+{
+ assert(menu);
+
+ unsigned int i, itemsCount;
+ bmItem **items = bmMenuGetFilteredItems(menu, &itemsCount);
+ for (i = 0; i < itemsCount && items[i] != item; ++i);
+
+ if (itemsCount <= i)
+ return 0;
+
+ return (menu->index = i);
+}
+
+/**
+ * Get selected items from bmMenu instance.
+ *
+ * @param menu bmMenu instance from where to get selected items.
* @param outNmemb Reference to unsigned int where total count of returned items will be stored.
* @return Pointer to array of bmItem pointers.
*/
-bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb)
+bmItem** bmMenuGetSelectedItems(const bmMenu *menu, unsigned int *outNmemb)
{
assert(menu);
+ return _bmItemListGetItems(&menu->selection, outNmemb);
+}
- if (outNmemb)
- *outNmemb = menu->itemsCount;
-
- return menu->items;
+/**
+ * Set selected items to bmMenu instance.
+ *
+ * @warning The list won't be copied.
+ *
+ * @param menu bmMenu instance where items will be set.
+ * @param items Array of bmItem pointers to set.
+ * @param nmemb Total count of items in array.
+ * @return 1 on successful set, 0 on failure.
+ */
+int bmMenuSetSelectedItems(bmMenu *menu, bmItem **items, unsigned int nmemb)
+{
+ assert(menu);
+ return _bmItemListSetItemsNoCopy(&menu->selection, items, nmemb);
}
/**
@@ -314,10 +340,25 @@ bmItem** bmMenuGetFilteredItems(const bmMenu *menu, unsigned int *outNmemb)
{
assert(menu);
- if (outNmemb)
- *outNmemb = (menu->filteredItems ? menu->filteredCount : menu->itemsCount);
+ if (menu->filtered.list)
+ return _bmItemListGetItems(&menu->filtered, outNmemb);
- return (menu->filteredItems ? menu->filteredItems : menu->items);
+ return _bmItemListGetItems(&menu->items, outNmemb);
+}
+
+/**
+ * Get items from bmMenu instance.
+ *
+ * @warning The pointer returned by this function may be invalid after removing or adding new items.
+ *
+ * @param menu bmMenu instance from where to get items.
+ * @param outNmemb Reference to unsigned int where total count of returned items will be stored.
+ * @return Pointer to array of bmItem pointers.
+ */
+bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb)
+{
+ assert(menu);
+ return _bmItemListGetItems(&menu->items, outNmemb);
}
/**
@@ -335,21 +376,14 @@ int bmMenuSetItems(bmMenu *menu, const bmItem **items, unsigned int nmemb)
{
assert(menu);
- if (!items || nmemb == 0) {
- bmMenuFreeItems(menu);
- return 1;
- }
+ int ret = _bmItemListSetItems(&menu->items, items, nmemb);
- bmItem **newItems;
- if (!(newItems = calloc(sizeof(bmItem*), nmemb)))
- return 0;
-
- memcpy(newItems, items, sizeof(bmItem*) * nmemb);
- bmMenuFreeItems(menu);
+ if (ret) {
+ _bmItemListFreeList(&menu->selection);
+ _bmItemListFreeList(&menu->filtered);
+ }
- menu->items = newItems;
- menu->allocatedCount = menu->itemsCount = nmemb;
- return 1;
+ return ret;
}
/**
@@ -400,7 +434,7 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode)
{
assert(menu);
char *oldFilter = _bmStrdup(menu->filter);
- unsigned int itemsCount = (menu->filteredItems ? menu->filteredCount : menu->itemsCount);
+ unsigned int itemsCount = (menu->filtered.list ? menu->filtered.count : menu->items.count);
switch (key) {
case BM_KEY_LEFT:
@@ -502,9 +536,9 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode)
case BM_KEY_TAB:
{
- bmItem *selected = bmMenuGetSelectedItem(menu);
- if (selected && bmItemGetText(selected)) {
- const char *text = bmItemGetText(selected);
+ bmItem *highlighted = bmMenuGetHighlightedItem(menu);
+ if (highlighted && bmItemGetText(highlighted)) {
+ const char *text = bmItemGetText(highlighted);
size_t len = strlen(text);
if (len > sizeof(menu->filter) - 1)
@@ -518,6 +552,19 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode)
}
break;
+ case BM_KEY_SHIFT_RETURN:
+ case BM_KEY_RETURN:
+ {
+ bmItem *highlighted = bmMenuGetHighlightedItem(menu);
+ if (highlighted && !_bmMenuItemIsSelected(menu, highlighted))
+ _bmItemListAddItem(&menu->selection, highlighted);
+ }
+ break;
+
+ case BM_KEY_ESCAPE:
+ _bmItemListFreeList(&menu->selection);
+ break;
+
default: break;
}