From f8f382ed14151d3c293a9ee754f0a66f513fb7d3 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Fri, 14 Aug 2020 15:07:49 +0300 Subject: Bookmarks: Store in a hash with unique IDs --- src/bookmarks.c | 66 +++++++++++++++++++++++++++++--------------------- src/bookmarks.h | 5 ++++ src/ui/sidebarwidget.c | 39 ++++++++++++++++++++--------- src/ui/util.c | 2 +- src/ui/widget.c | 19 +++++++++++---- 5 files changed, 87 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/bookmarks.c b/src/bookmarks.c index b023e90a..96a2b6a0 100644 --- a/src/bookmarks.c +++ b/src/bookmarks.c @@ -2,6 +2,7 @@ #include #include +#include void init_Bookmark(iBookmark *d) { init_String(&d->url); @@ -27,25 +28,33 @@ static int cmpTimeDescending_Bookmark_(const iBookmark **a, const iBookmark **b) static const char *fileName_Bookmarks_ = "bookmarks.txt"; struct Impl_Bookmarks { - iArray bookmarks; + int idEnum; + iHash bookmarks; }; iDefineTypeConstruction(Bookmarks) void init_Bookmarks(iBookmarks *d) { - init_Array(&d->bookmarks, sizeof(iBookmark)); + d->idEnum = 0; + init_Hash(&d->bookmarks); } void deinit_Bookmarks(iBookmarks *d) { clear_Bookmarks(d); - deinit_Array(&d->bookmarks); + deinit_Hash(&d->bookmarks); } void clear_Bookmarks(iBookmarks *d) { - iForEach(Array, i, &d->bookmarks) { - deinit_Bookmark(i.value); + iForEach(Hash, i, &d->bookmarks) { + delete_Bookmark((iBookmark *) i.value); } - clear_Array(&d->bookmarks); + clear_Hash(&d->bookmarks); + d->idEnum = 0; +} + +static void insert_Bookmarks_(iBookmarks *d, iBookmark *bookmark) { + bookmark->node.key = ++d->idEnum; + insert_Hash(&d->bookmarks, &bookmark->node); } void load_Bookmarks(iBookmarks *d, const char *dirPath) { @@ -62,19 +71,18 @@ void load_Bookmarks(iBookmarks *d, const char *dirPath) { continue; } } - iBookmark bm; - init_Bookmark(&bm); - bm.icon = strtoul(line.start, NULL, 16); + iBookmark *bm = new_Bookmark(); + bm->icon = strtoul(line.start, NULL, 16); line.start += 9; char *endPos; - initSeconds_Time(&bm.when, strtod(line.start, &endPos)); + initSeconds_Time(&bm->when, strtod(line.start, &endPos)); line.start = skipSpace_CStr(endPos); - setRange_String(&bm.url, line); + setRange_String(&bm->url, line); nextSplit_Rangecc(&src, "\n", &line); - setRange_String(&bm.title, line); + setRange_String(&bm->title, line); nextSplit_Rangecc(&src, "\n", &line); - setRange_String(&bm.tags, line); - pushBack_Array(&d->bookmarks, &bm); + setRange_String(&bm->tags, line); + insert_Bookmarks_(d, bm); } } iRelease(f); @@ -84,8 +92,8 @@ void save_Bookmarks(const iBookmarks *d, const char *dirPath) { iFile *f = newCStr_File(concatPath_CStr(dirPath, fileName_Bookmarks_)); if (open_File(f, writeOnly_FileMode | text_FileMode)) { iString *str = collectNew_String(); - iConstForEach(Array, i, &d->bookmarks) { - const iBookmark *bm = i.value; + iConstForEach(Hash, i, &d->bookmarks) { + const iBookmark *bm = (const iBookmark *) i.value; format_String(str, "%08x %lf %s\n%s\n%s\n", bm->icon, @@ -101,22 +109,26 @@ void save_Bookmarks(const iBookmarks *d, const char *dirPath) { void add_Bookmarks(iBookmarks *d, const iString *url, const iString *title, const iString *tags, iChar icon) { - iBookmark bm; - init_Bookmark(&bm); - set_String(&bm.url, url); - set_String(&bm.title, title); - set_String(&bm.tags, tags); - bm.icon = icon; - initCurrent_Time(&bm.when); - pushBack_Array(&d->bookmarks, &bm); + iBookmark *bm = new_Bookmark(); + set_String(&bm->url, url); + set_String(&bm->title, title); + set_String(&bm->tags, tags); + bm->icon = icon; + initCurrent_Time(&bm->when); + insert_Bookmarks_(d, bm); +} + +void remove_Bookmarks(iBookmarks *d, uint32_t id) { + delete_Bookmark((iBookmark *) remove_Hash(&d->bookmarks, id)); } const iPtrArray *list_Bookmarks(const iBookmarks *d, iBookmarksFilterFunc filter, iBookmarksCompareFunc cmp) { iPtrArray *list = collectNew_PtrArray(); - iConstForEach(Array, i, &d->bookmarks) { - if (!filter || filter(i.value)) { - pushBack_PtrArray(list, i.value); + iConstForEach(Hash, i, &d->bookmarks) { + const iBookmark *bm = (const iBookmark *) i.value; + if (!filter || filter(bm)) { + pushBack_PtrArray(list, bm); } } if (!cmp) cmp = cmpTimeDescending_Bookmark_; diff --git a/src/bookmarks.h b/src/bookmarks.h index 2572e3b2..e1f517ad 100644 --- a/src/bookmarks.h +++ b/src/bookmarks.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -8,6 +9,7 @@ iDeclareType(Bookmark) iDeclareTypeConstruction(Bookmark) struct Impl_Bookmark { + iHashNode node; iString url; iString title; iString tags; @@ -15,6 +17,8 @@ struct Impl_Bookmark { iTime when; }; +iLocalDef uint32_t id_Bookmark (const iBookmark *d) { return d->node.key; } + iDeclareType(Bookmarks) iDeclareTypeConstruction(Bookmarks) @@ -23,6 +27,7 @@ void load_Bookmarks (iBookmarks *, const char *dirPath); void save_Bookmarks (const iBookmarks *, const char *dirPath); void add_Bookmarks (iBookmarks *, const iString *url, const iString *title, const iString *tags, iChar icon); +void remove_Bookmarks (iBookmarks *, uint32_t id); typedef iBool (*iBookmarksFilterFunc) (const iBookmark *); typedef int (*iBookmarksCompareFunc)(const iBookmark **, const iBookmark **); diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 8108c797..b8e29a7d 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -15,18 +15,20 @@ iDeclareType(SidebarItem) struct Impl_SidebarItem { - int indent; - iChar icon; - iString label; - iString meta; - iString url; - size_t index; + int indent; + iChar icon; + iString label; + iString meta; + iString url; + size_t index; + const void *src; }; void init_SidebarItem(iSidebarItem *d) { d->indent = 0; d->icon = 0; d->index = 0; + d->src = NULL; init_String(&d->label); init_String(&d->meta); init_String(&d->url); @@ -56,6 +58,7 @@ struct Impl_SidebarWidget { iClick click; iWidget *resizer; SDL_Cursor *resizeCursor; + iWidget *menu; }; iDefineObjectConstruction(SidebarWidget) @@ -85,7 +88,6 @@ static int scrollMax_SidebarWidget_(const iSidebarWidget *d) { } static void updateVisible_SidebarWidget_(iSidebarWidget *d) { - // iWidget *w = as_Widget(d); const int contentSize = size_Array(&d->items) * d->itemHeight; const iRect bounds = contentBounds_SidebarWidget_(d); setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_SidebarWidget_(d) }); @@ -98,6 +100,9 @@ static void updateVisible_SidebarWidget_(iSidebarWidget *d) { static void updateItems_SidebarWidget_(iSidebarWidget *d) { clearItems_SidebarWidget_(d); + destroy_Widget(d->menu); + d->menu = NULL; + d->hoverItem = iInvalidPos; switch (d->mode) { case documentOutline_SidebarMode: { const iGmDocument *doc = document_DocumentWidget(document_App()); @@ -124,9 +129,12 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { init_Date(&date, &bm->when); iString *ds = format_Date(&date, "%Y %b %d"); set_String(&item.meta, ds); + item.src = bm; delete_String(ds); pushBack_Array(&d->items, &item); } + d->menu = makeMenu_Widget( + as_Widget(d), (iMenuItem[]){ { "Delete Bookmark", 0, 0, "bookmark.delete" } }, 1); break; } case history_SidebarMode: @@ -209,6 +217,7 @@ void init_SidebarWidget(iSidebarWidget *d) { d->resizer->rect.size.x = gap_UI; setBackgroundColor_Widget(d->resizer, none_ColorId); d->resizeCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); + d->menu = NULL; } void deinit_SidebarWidget(iSidebarWidget *d) { @@ -356,11 +365,16 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) d->scrollY = 0; updateItems_SidebarWidget_(d); } + else if (equal_Command(cmd, "bookmark.delete")) { + if (d->mode == bookmarks_SidebarMode && d->hoverItem < size_Array(&d->items)) { + + } + } else if (equal_Command(cmd, "bookmarks.changed")) { updateItems_SidebarWidget_(d); } } - if (ev->type == SDL_MOUSEMOTION) { + if (ev->type == SDL_MOUSEMOTION && !isVisible_Widget(d->menu)) { const iInt2 mouse = init_I2(ev->motion.x, ev->motion.y); size_t hover = iInvalidPos; if (contains_Widget(d->resizer, mouse)) { @@ -388,6 +402,9 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) refresh_Widget(w); return iTrue; } + if (d->menu && ev->type == SDL_MOUSEBUTTONDOWN) { + processContextMenuEvent_Widget(d->menu, ev, {}); + } switch (processEvent_Click(&d->click, ev)) { case started_ClickResult: refresh_Widget(w); @@ -416,9 +433,9 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) { const iRanges visRange = visRange_SidebarWidget_(d); iInt2 pos = addY_I2(topLeft_Rect(bounds), -(d->scrollY % d->itemHeight)); for (size_t i = visRange.start; i < visRange.end; i++) { - const iSidebarItem *item = constAt_Array(&d->items, i); - const iRect itemRect = { pos, init_I2(width_Rect(bounds), d->itemHeight) }; - const iBool isHover = (d->hoverItem == i); + const iSidebarItem *item = constAt_Array(&d->items, i); + const iRect itemRect = { pos, init_I2(width_Rect(bounds), d->itemHeight) }; + const iBool isHover = (d->hoverItem == i); setClip_Paint(&p, intersect_Rect(itemRect, bounds)); if (isHover) { fillRect_Paint(&p, itemRect, isPressing ? orange_ColorId : teal_ColorId); diff --git a/src/ui/util.c b/src/ui/util.c index 1d14ec99..185d37f3 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -240,8 +240,8 @@ int checkContextMenu_Widget(iWidget *menu, const SDL_Event *ev) { const iInt2 mousePos = init_I2(ev->button.x, ev->button.y); if (contains_Widget(menu->parent, mousePos)) { openMenu_Widget(menu, localCoord_Widget(menu->parent, mousePos)); + return 0x2; } - return 0x2; } return 0; } diff --git a/src/ui/widget.c b/src/ui/widget.c index 07f1f17d..cfd8304b 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -75,12 +75,16 @@ static void aboutToBeDestroyed_Widget_(iWidget *d) { } void destroy_Widget(iWidget *d) { - aboutToBeDestroyed_Widget_(d); - if (!rootData_.pendingDestruction) { - rootData_.pendingDestruction = new_PtrSet(); + if (d) { + if (isVisible_Widget(d)) { + postRefresh_App(); + } + aboutToBeDestroyed_Widget_(d); + if (!rootData_.pendingDestruction) { + rootData_.pendingDestruction = new_PtrSet(); + } + insert_PtrSet(rootData_.pendingDestruction, d); } - insert_PtrSet(rootData_.pendingDestruction, d); - postRefresh_App(); } void setId_Widget(iWidget *d, const char *id) { @@ -408,6 +412,10 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { } } if (class_Widget(d)->processEvent(d, ev)) { + if (ev->type == SDL_MOUSEBUTTONDOWN) { + printf("mb.down eaten by %p '%s'\n", d, cstr_String(id_Widget(d))); + fflush(stdout); + } return iTrue; } } @@ -560,6 +568,7 @@ size_t childCount_Widget(const iWidget *d) { } iBool isVisible_Widget(const iWidget *d) { + if (!d) return iFalse; for (const iWidget *w = d; w; w = w->parent) { if (w->flags & hidden_WidgetFlag) { return iFalse; -- cgit v1.2.3