summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-08-14 15:07:49 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-08-14 15:07:49 +0300
commitf8f382ed14151d3c293a9ee754f0a66f513fb7d3 (patch)
tree68b4ef771460378267b02c0499693751f4fb26ee /src
parent459f73f2623f66e2887aae6feff2ec0fab185b2c (diff)
Bookmarks: Store in a hash with unique IDs
Diffstat (limited to 'src')
-rw-r--r--src/bookmarks.c66
-rw-r--r--src/bookmarks.h5
-rw-r--r--src/ui/sidebarwidget.c39
-rw-r--r--src/ui/util.c2
-rw-r--r--src/ui/widget.c19
5 files changed, 87 insertions, 44 deletions
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 @@
2 2
3#include <the_Foundation/file.h> 3#include <the_Foundation/file.h>
4#include <the_Foundation/path.h> 4#include <the_Foundation/path.h>
5#include <the_Foundation/hash.h>
5 6
6void init_Bookmark(iBookmark *d) { 7void init_Bookmark(iBookmark *d) {
7 init_String(&d->url); 8 init_String(&d->url);
@@ -27,25 +28,33 @@ static int cmpTimeDescending_Bookmark_(const iBookmark **a, const iBookmark **b)
27static const char *fileName_Bookmarks_ = "bookmarks.txt"; 28static const char *fileName_Bookmarks_ = "bookmarks.txt";
28 29
29struct Impl_Bookmarks { 30struct Impl_Bookmarks {
30 iArray bookmarks; 31 int idEnum;
32 iHash bookmarks;
31}; 33};
32 34
33iDefineTypeConstruction(Bookmarks) 35iDefineTypeConstruction(Bookmarks)
34 36
35void init_Bookmarks(iBookmarks *d) { 37void init_Bookmarks(iBookmarks *d) {
36 init_Array(&d->bookmarks, sizeof(iBookmark)); 38 d->idEnum = 0;
39 init_Hash(&d->bookmarks);
37} 40}
38 41
39void deinit_Bookmarks(iBookmarks *d) { 42void deinit_Bookmarks(iBookmarks *d) {
40 clear_Bookmarks(d); 43 clear_Bookmarks(d);
41 deinit_Array(&d->bookmarks); 44 deinit_Hash(&d->bookmarks);
42} 45}
43 46
44void clear_Bookmarks(iBookmarks *d) { 47void clear_Bookmarks(iBookmarks *d) {
45 iForEach(Array, i, &d->bookmarks) { 48 iForEach(Hash, i, &d->bookmarks) {
46 deinit_Bookmark(i.value); 49 delete_Bookmark((iBookmark *) i.value);
47 } 50 }
48 clear_Array(&d->bookmarks); 51 clear_Hash(&d->bookmarks);
52 d->idEnum = 0;
53}
54
55static void insert_Bookmarks_(iBookmarks *d, iBookmark *bookmark) {
56 bookmark->node.key = ++d->idEnum;
57 insert_Hash(&d->bookmarks, &bookmark->node);
49} 58}
50 59
51void load_Bookmarks(iBookmarks *d, const char *dirPath) { 60void load_Bookmarks(iBookmarks *d, const char *dirPath) {
@@ -62,19 +71,18 @@ void load_Bookmarks(iBookmarks *d, const char *dirPath) {
62 continue; 71 continue;
63 } 72 }
64 } 73 }
65 iBookmark bm; 74 iBookmark *bm = new_Bookmark();
66 init_Bookmark(&bm); 75 bm->icon = strtoul(line.start, NULL, 16);
67 bm.icon = strtoul(line.start, NULL, 16);
68 line.start += 9; 76 line.start += 9;
69 char *endPos; 77 char *endPos;
70 initSeconds_Time(&bm.when, strtod(line.start, &endPos)); 78 initSeconds_Time(&bm->when, strtod(line.start, &endPos));
71 line.start = skipSpace_CStr(endPos); 79 line.start = skipSpace_CStr(endPos);
72 setRange_String(&bm.url, line); 80 setRange_String(&bm->url, line);
73 nextSplit_Rangecc(&src, "\n", &line); 81 nextSplit_Rangecc(&src, "\n", &line);
74 setRange_String(&bm.title, line); 82 setRange_String(&bm->title, line);
75 nextSplit_Rangecc(&src, "\n", &line); 83 nextSplit_Rangecc(&src, "\n", &line);
76 setRange_String(&bm.tags, line); 84 setRange_String(&bm->tags, line);
77 pushBack_Array(&d->bookmarks, &bm); 85 insert_Bookmarks_(d, bm);
78 } 86 }
79 } 87 }
80 iRelease(f); 88 iRelease(f);
@@ -84,8 +92,8 @@ void save_Bookmarks(const iBookmarks *d, const char *dirPath) {
84 iFile *f = newCStr_File(concatPath_CStr(dirPath, fileName_Bookmarks_)); 92 iFile *f = newCStr_File(concatPath_CStr(dirPath, fileName_Bookmarks_));
85 if (open_File(f, writeOnly_FileMode | text_FileMode)) { 93 if (open_File(f, writeOnly_FileMode | text_FileMode)) {
86 iString *str = collectNew_String(); 94 iString *str = collectNew_String();
87 iConstForEach(Array, i, &d->bookmarks) { 95 iConstForEach(Hash, i, &d->bookmarks) {
88 const iBookmark *bm = i.value; 96 const iBookmark *bm = (const iBookmark *) i.value;
89 format_String(str, 97 format_String(str,
90 "%08x %lf %s\n%s\n%s\n", 98 "%08x %lf %s\n%s\n%s\n",
91 bm->icon, 99 bm->icon,
@@ -101,22 +109,26 @@ void save_Bookmarks(const iBookmarks *d, const char *dirPath) {
101 109
102void add_Bookmarks(iBookmarks *d, const iString *url, const iString *title, const iString *tags, 110void add_Bookmarks(iBookmarks *d, const iString *url, const iString *title, const iString *tags,
103 iChar icon) { 111 iChar icon) {
104 iBookmark bm; 112 iBookmark *bm = new_Bookmark();
105 init_Bookmark(&bm); 113 set_String(&bm->url, url);
106 set_String(&bm.url, url); 114 set_String(&bm->title, title);
107 set_String(&bm.title, title); 115 set_String(&bm->tags, tags);
108 set_String(&bm.tags, tags); 116 bm->icon = icon;
109 bm.icon = icon; 117 initCurrent_Time(&bm->when);
110 initCurrent_Time(&bm.when); 118 insert_Bookmarks_(d, bm);
111 pushBack_Array(&d->bookmarks, &bm); 119}
120
121void remove_Bookmarks(iBookmarks *d, uint32_t id) {
122 delete_Bookmark((iBookmark *) remove_Hash(&d->bookmarks, id));
112} 123}
113 124
114const iPtrArray *list_Bookmarks(const iBookmarks *d, iBookmarksFilterFunc filter, 125const iPtrArray *list_Bookmarks(const iBookmarks *d, iBookmarksFilterFunc filter,
115 iBookmarksCompareFunc cmp) { 126 iBookmarksCompareFunc cmp) {
116 iPtrArray *list = collectNew_PtrArray(); 127 iPtrArray *list = collectNew_PtrArray();
117 iConstForEach(Array, i, &d->bookmarks) { 128 iConstForEach(Hash, i, &d->bookmarks) {
118 if (!filter || filter(i.value)) { 129 const iBookmark *bm = (const iBookmark *) i.value;
119 pushBack_PtrArray(list, i.value); 130 if (!filter || filter(bm)) {
131 pushBack_PtrArray(list, bm);
120 } 132 }
121 } 133 }
122 if (!cmp) cmp = cmpTimeDescending_Bookmark_; 134 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 @@
1#pragma once 1#pragma once
2 2
3#include <the_Foundation/hash.h>
3#include <the_Foundation/ptrarray.h> 4#include <the_Foundation/ptrarray.h>
4#include <the_Foundation/string.h> 5#include <the_Foundation/string.h>
5#include <the_Foundation/time.h> 6#include <the_Foundation/time.h>
@@ -8,6 +9,7 @@ iDeclareType(Bookmark)
8iDeclareTypeConstruction(Bookmark) 9iDeclareTypeConstruction(Bookmark)
9 10
10struct Impl_Bookmark { 11struct Impl_Bookmark {
12 iHashNode node;
11 iString url; 13 iString url;
12 iString title; 14 iString title;
13 iString tags; 15 iString tags;
@@ -15,6 +17,8 @@ struct Impl_Bookmark {
15 iTime when; 17 iTime when;
16}; 18};
17 19
20iLocalDef uint32_t id_Bookmark (const iBookmark *d) { return d->node.key; }
21
18iDeclareType(Bookmarks) 22iDeclareType(Bookmarks)
19iDeclareTypeConstruction(Bookmarks) 23iDeclareTypeConstruction(Bookmarks)
20 24
@@ -23,6 +27,7 @@ void load_Bookmarks (iBookmarks *, const char *dirPath);
23void save_Bookmarks (const iBookmarks *, const char *dirPath); 27void save_Bookmarks (const iBookmarks *, const char *dirPath);
24 28
25void add_Bookmarks (iBookmarks *, const iString *url, const iString *title, const iString *tags, iChar icon); 29void add_Bookmarks (iBookmarks *, const iString *url, const iString *title, const iString *tags, iChar icon);
30void remove_Bookmarks (iBookmarks *, uint32_t id);
26 31
27typedef iBool (*iBookmarksFilterFunc) (const iBookmark *); 32typedef iBool (*iBookmarksFilterFunc) (const iBookmark *);
28typedef int (*iBookmarksCompareFunc)(const iBookmark **, const iBookmark **); 33typedef 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 @@
15iDeclareType(SidebarItem) 15iDeclareType(SidebarItem)
16 16
17struct Impl_SidebarItem { 17struct Impl_SidebarItem {
18 int indent; 18 int indent;
19 iChar icon; 19 iChar icon;
20 iString label; 20 iString label;
21 iString meta; 21 iString meta;
22 iString url; 22 iString url;
23 size_t index; 23 size_t index;
24 const void *src;
24}; 25};
25 26
26void init_SidebarItem(iSidebarItem *d) { 27void init_SidebarItem(iSidebarItem *d) {
27 d->indent = 0; 28 d->indent = 0;
28 d->icon = 0; 29 d->icon = 0;
29 d->index = 0; 30 d->index = 0;
31 d->src = NULL;
30 init_String(&d->label); 32 init_String(&d->label);
31 init_String(&d->meta); 33 init_String(&d->meta);
32 init_String(&d->url); 34 init_String(&d->url);
@@ -56,6 +58,7 @@ struct Impl_SidebarWidget {
56 iClick click; 58 iClick click;
57 iWidget *resizer; 59 iWidget *resizer;
58 SDL_Cursor *resizeCursor; 60 SDL_Cursor *resizeCursor;
61 iWidget *menu;
59}; 62};
60 63
61iDefineObjectConstruction(SidebarWidget) 64iDefineObjectConstruction(SidebarWidget)
@@ -85,7 +88,6 @@ static int scrollMax_SidebarWidget_(const iSidebarWidget *d) {
85} 88}
86 89
87static void updateVisible_SidebarWidget_(iSidebarWidget *d) { 90static void updateVisible_SidebarWidget_(iSidebarWidget *d) {
88 // iWidget *w = as_Widget(d);
89 const int contentSize = size_Array(&d->items) * d->itemHeight; 91 const int contentSize = size_Array(&d->items) * d->itemHeight;
90 const iRect bounds = contentBounds_SidebarWidget_(d); 92 const iRect bounds = contentBounds_SidebarWidget_(d);
91 setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_SidebarWidget_(d) }); 93 setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_SidebarWidget_(d) });
@@ -98,6 +100,9 @@ static void updateVisible_SidebarWidget_(iSidebarWidget *d) {
98 100
99static void updateItems_SidebarWidget_(iSidebarWidget *d) { 101static void updateItems_SidebarWidget_(iSidebarWidget *d) {
100 clearItems_SidebarWidget_(d); 102 clearItems_SidebarWidget_(d);
103 destroy_Widget(d->menu);
104 d->menu = NULL;
105 d->hoverItem = iInvalidPos;
101 switch (d->mode) { 106 switch (d->mode) {
102 case documentOutline_SidebarMode: { 107 case documentOutline_SidebarMode: {
103 const iGmDocument *doc = document_DocumentWidget(document_App()); 108 const iGmDocument *doc = document_DocumentWidget(document_App());
@@ -124,9 +129,12 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
124 init_Date(&date, &bm->when); 129 init_Date(&date, &bm->when);
125 iString *ds = format_Date(&date, "%Y %b %d"); 130 iString *ds = format_Date(&date, "%Y %b %d");
126 set_String(&item.meta, ds); 131 set_String(&item.meta, ds);
132 item.src = bm;
127 delete_String(ds); 133 delete_String(ds);
128 pushBack_Array(&d->items, &item); 134 pushBack_Array(&d->items, &item);
129 } 135 }
136 d->menu = makeMenu_Widget(
137 as_Widget(d), (iMenuItem[]){ { "Delete Bookmark", 0, 0, "bookmark.delete" } }, 1);
130 break; 138 break;
131 } 139 }
132 case history_SidebarMode: 140 case history_SidebarMode:
@@ -209,6 +217,7 @@ void init_SidebarWidget(iSidebarWidget *d) {
209 d->resizer->rect.size.x = gap_UI; 217 d->resizer->rect.size.x = gap_UI;
210 setBackgroundColor_Widget(d->resizer, none_ColorId); 218 setBackgroundColor_Widget(d->resizer, none_ColorId);
211 d->resizeCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); 219 d->resizeCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
220 d->menu = NULL;
212} 221}
213 222
214void deinit_SidebarWidget(iSidebarWidget *d) { 223void deinit_SidebarWidget(iSidebarWidget *d) {
@@ -356,11 +365,16 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
356 d->scrollY = 0; 365 d->scrollY = 0;
357 updateItems_SidebarWidget_(d); 366 updateItems_SidebarWidget_(d);
358 } 367 }
368 else if (equal_Command(cmd, "bookmark.delete")) {
369 if (d->mode == bookmarks_SidebarMode && d->hoverItem < size_Array(&d->items)) {
370
371 }
372 }
359 else if (equal_Command(cmd, "bookmarks.changed")) { 373 else if (equal_Command(cmd, "bookmarks.changed")) {
360 updateItems_SidebarWidget_(d); 374 updateItems_SidebarWidget_(d);
361 } 375 }
362 } 376 }
363 if (ev->type == SDL_MOUSEMOTION) { 377 if (ev->type == SDL_MOUSEMOTION && !isVisible_Widget(d->menu)) {
364 const iInt2 mouse = init_I2(ev->motion.x, ev->motion.y); 378 const iInt2 mouse = init_I2(ev->motion.x, ev->motion.y);
365 size_t hover = iInvalidPos; 379 size_t hover = iInvalidPos;
366 if (contains_Widget(d->resizer, mouse)) { 380 if (contains_Widget(d->resizer, mouse)) {
@@ -388,6 +402,9 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
388 refresh_Widget(w); 402 refresh_Widget(w);
389 return iTrue; 403 return iTrue;
390 } 404 }
405 if (d->menu && ev->type == SDL_MOUSEBUTTONDOWN) {
406 processContextMenuEvent_Widget(d->menu, ev, {});
407 }
391 switch (processEvent_Click(&d->click, ev)) { 408 switch (processEvent_Click(&d->click, ev)) {
392 case started_ClickResult: 409 case started_ClickResult:
393 refresh_Widget(w); 410 refresh_Widget(w);
@@ -416,9 +433,9 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) {
416 const iRanges visRange = visRange_SidebarWidget_(d); 433 const iRanges visRange = visRange_SidebarWidget_(d);
417 iInt2 pos = addY_I2(topLeft_Rect(bounds), -(d->scrollY % d->itemHeight)); 434 iInt2 pos = addY_I2(topLeft_Rect(bounds), -(d->scrollY % d->itemHeight));
418 for (size_t i = visRange.start; i < visRange.end; i++) { 435 for (size_t i = visRange.start; i < visRange.end; i++) {
419 const iSidebarItem *item = constAt_Array(&d->items, i); 436 const iSidebarItem *item = constAt_Array(&d->items, i);
420 const iRect itemRect = { pos, init_I2(width_Rect(bounds), d->itemHeight) }; 437 const iRect itemRect = { pos, init_I2(width_Rect(bounds), d->itemHeight) };
421 const iBool isHover = (d->hoverItem == i); 438 const iBool isHover = (d->hoverItem == i);
422 setClip_Paint(&p, intersect_Rect(itemRect, bounds)); 439 setClip_Paint(&p, intersect_Rect(itemRect, bounds));
423 if (isHover) { 440 if (isHover) {
424 fillRect_Paint(&p, itemRect, isPressing ? orange_ColorId : teal_ColorId); 441 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) {
240 const iInt2 mousePos = init_I2(ev->button.x, ev->button.y); 240 const iInt2 mousePos = init_I2(ev->button.x, ev->button.y);
241 if (contains_Widget(menu->parent, mousePos)) { 241 if (contains_Widget(menu->parent, mousePos)) {
242 openMenu_Widget(menu, localCoord_Widget(menu->parent, mousePos)); 242 openMenu_Widget(menu, localCoord_Widget(menu->parent, mousePos));
243 return 0x2;
243 } 244 }
244 return 0x2;
245 } 245 }
246 return 0; 246 return 0;
247} 247}
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) {
75} 75}
76 76
77void destroy_Widget(iWidget *d) { 77void destroy_Widget(iWidget *d) {
78 aboutToBeDestroyed_Widget_(d); 78 if (d) {
79 if (!rootData_.pendingDestruction) { 79 if (isVisible_Widget(d)) {
80 rootData_.pendingDestruction = new_PtrSet(); 80 postRefresh_App();
81 }
82 aboutToBeDestroyed_Widget_(d);
83 if (!rootData_.pendingDestruction) {
84 rootData_.pendingDestruction = new_PtrSet();
85 }
86 insert_PtrSet(rootData_.pendingDestruction, d);
81 } 87 }
82 insert_PtrSet(rootData_.pendingDestruction, d);
83 postRefresh_App();
84} 88}
85 89
86void setId_Widget(iWidget *d, const char *id) { 90void setId_Widget(iWidget *d, const char *id) {
@@ -408,6 +412,10 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {
408 } 412 }
409 } 413 }
410 if (class_Widget(d)->processEvent(d, ev)) { 414 if (class_Widget(d)->processEvent(d, ev)) {
415 if (ev->type == SDL_MOUSEBUTTONDOWN) {
416 printf("mb.down eaten by %p '%s'\n", d, cstr_String(id_Widget(d)));
417 fflush(stdout);
418 }
411 return iTrue; 419 return iTrue;
412 } 420 }
413 } 421 }
@@ -560,6 +568,7 @@ size_t childCount_Widget(const iWidget *d) {
560} 568}
561 569
562iBool isVisible_Widget(const iWidget *d) { 570iBool isVisible_Widget(const iWidget *d) {
571 if (!d) return iFalse;
563 for (const iWidget *w = d; w; w = w->parent) { 572 for (const iWidget *w = d; w; w = w->parent) {
564 if (w->flags & hidden_WidgetFlag) { 573 if (w->flags & hidden_WidgetFlag) {
565 return iFalse; 574 return iFalse;