diff options
-rw-r--r-- | src/bookmarks.c | 66 | ||||
-rw-r--r-- | src/bookmarks.h | 5 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 39 | ||||
-rw-r--r-- | src/ui/util.c | 2 | ||||
-rw-r--r-- | src/ui/widget.c | 19 |
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 | ||
6 | void init_Bookmark(iBookmark *d) { | 7 | void 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) | |||
27 | static const char *fileName_Bookmarks_ = "bookmarks.txt"; | 28 | static const char *fileName_Bookmarks_ = "bookmarks.txt"; |
28 | 29 | ||
29 | struct Impl_Bookmarks { | 30 | struct Impl_Bookmarks { |
30 | iArray bookmarks; | 31 | int idEnum; |
32 | iHash bookmarks; | ||
31 | }; | 33 | }; |
32 | 34 | ||
33 | iDefineTypeConstruction(Bookmarks) | 35 | iDefineTypeConstruction(Bookmarks) |
34 | 36 | ||
35 | void init_Bookmarks(iBookmarks *d) { | 37 | void init_Bookmarks(iBookmarks *d) { |
36 | init_Array(&d->bookmarks, sizeof(iBookmark)); | 38 | d->idEnum = 0; |
39 | init_Hash(&d->bookmarks); | ||
37 | } | 40 | } |
38 | 41 | ||
39 | void deinit_Bookmarks(iBookmarks *d) { | 42 | void 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 | ||
44 | void clear_Bookmarks(iBookmarks *d) { | 47 | void 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 | |||
55 | static void insert_Bookmarks_(iBookmarks *d, iBookmark *bookmark) { | ||
56 | bookmark->node.key = ++d->idEnum; | ||
57 | insert_Hash(&d->bookmarks, &bookmark->node); | ||
49 | } | 58 | } |
50 | 59 | ||
51 | void load_Bookmarks(iBookmarks *d, const char *dirPath) { | 60 | void 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 | ||
102 | void add_Bookmarks(iBookmarks *d, const iString *url, const iString *title, const iString *tags, | 110 | void 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 | |||
121 | void remove_Bookmarks(iBookmarks *d, uint32_t id) { | ||
122 | delete_Bookmark((iBookmark *) remove_Hash(&d->bookmarks, id)); | ||
112 | } | 123 | } |
113 | 124 | ||
114 | const iPtrArray *list_Bookmarks(const iBookmarks *d, iBookmarksFilterFunc filter, | 125 | const 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) | |||
8 | iDeclareTypeConstruction(Bookmark) | 9 | iDeclareTypeConstruction(Bookmark) |
9 | 10 | ||
10 | struct Impl_Bookmark { | 11 | struct 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 | ||
20 | iLocalDef uint32_t id_Bookmark (const iBookmark *d) { return d->node.key; } | ||
21 | |||
18 | iDeclareType(Bookmarks) | 22 | iDeclareType(Bookmarks) |
19 | iDeclareTypeConstruction(Bookmarks) | 23 | iDeclareTypeConstruction(Bookmarks) |
20 | 24 | ||
@@ -23,6 +27,7 @@ void load_Bookmarks (iBookmarks *, const char *dirPath); | |||
23 | void save_Bookmarks (const iBookmarks *, const char *dirPath); | 27 | void save_Bookmarks (const iBookmarks *, const char *dirPath); |
24 | 28 | ||
25 | void add_Bookmarks (iBookmarks *, const iString *url, const iString *title, const iString *tags, iChar icon); | 29 | void add_Bookmarks (iBookmarks *, const iString *url, const iString *title, const iString *tags, iChar icon); |
30 | void remove_Bookmarks (iBookmarks *, uint32_t id); | ||
26 | 31 | ||
27 | typedef iBool (*iBookmarksFilterFunc) (const iBookmark *); | 32 | typedef iBool (*iBookmarksFilterFunc) (const iBookmark *); |
28 | typedef int (*iBookmarksCompareFunc)(const iBookmark **, const iBookmark **); | 33 | 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 @@ | |||
15 | iDeclareType(SidebarItem) | 15 | iDeclareType(SidebarItem) |
16 | 16 | ||
17 | struct Impl_SidebarItem { | 17 | struct 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 | ||
26 | void init_SidebarItem(iSidebarItem *d) { | 27 | void 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 | ||
61 | iDefineObjectConstruction(SidebarWidget) | 64 | iDefineObjectConstruction(SidebarWidget) |
@@ -85,7 +88,6 @@ static int scrollMax_SidebarWidget_(const iSidebarWidget *d) { | |||
85 | } | 88 | } |
86 | 89 | ||
87 | static void updateVisible_SidebarWidget_(iSidebarWidget *d) { | 90 | static 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 | ||
99 | static void updateItems_SidebarWidget_(iSidebarWidget *d) { | 101 | static 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 | ||
214 | void deinit_SidebarWidget(iSidebarWidget *d) { | 223 | void 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 | ||
77 | void destroy_Widget(iWidget *d) { | 77 | void 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 | ||
86 | void setId_Widget(iWidget *d, const char *id) { | 90 | void 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 | ||
562 | iBool isVisible_Widget(const iWidget *d) { | 570 | iBool 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; |