diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-09-25 09:01:41 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-09-25 09:01:41 +0300 |
commit | 242e8231ea61278fe482020658be86c2dec0ae53 (patch) | |
tree | bb88541f9f808cb5a3af769fe265439341e97237 | |
parent | ed2c4a872dbddd2eaa13b280543ffabb0d197851 (diff) |
Persistent bookmark folder state
Incremented the version of state.lgr so it can include bookmark folder open/closed state for each of the two/four sidebars.
-rw-r--r-- | src/app.c | 12 | ||||
-rw-r--r-- | src/defs.h | 3 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 31 | ||||
-rw-r--r-- | src/ui/sidebarwidget.h | 6 | ||||
-rw-r--r-- | src/ui/window.c | 10 |
5 files changed, 50 insertions, 12 deletions
@@ -425,12 +425,22 @@ static iBool loadState_App_(iApp *d) { | |||
425 | readf_Stream(stream_File(f)), | 425 | readf_Stream(stream_File(f)), |
426 | readf_Stream(stream_File(f)) | 426 | readf_Stream(stream_File(f)) |
427 | }; | 427 | }; |
428 | iIntSet *closedFolders[2] = { | ||
429 | collectNew_IntSet(), | ||
430 | collectNew_IntSet() | ||
431 | }; | ||
432 | if (version >= bookmarkFolderState_FileVersion) { | ||
433 | deserialize_IntSet(closedFolders[0], stream_File(f)); | ||
434 | deserialize_IntSet(closedFolders[1], stream_File(f)); | ||
435 | } | ||
428 | const uint8_t rootIndex = bits & 0xff; | 436 | const uint8_t rootIndex = bits & 0xff; |
429 | const uint8_t flags = bits >> 8; | 437 | const uint8_t flags = bits >> 8; |
430 | iRoot *root = d->window->base.roots[rootIndex]; | 438 | iRoot *root = d->window->base.roots[rootIndex]; |
431 | if (root) { | 439 | if (root) { |
432 | iSidebarWidget *sidebar = findChild_Widget(root->widget, "sidebar"); | 440 | iSidebarWidget *sidebar = findChild_Widget(root->widget, "sidebar"); |
433 | iSidebarWidget *sidebar2 = findChild_Widget(root->widget, "sidebar2"); | 441 | iSidebarWidget *sidebar2 = findChild_Widget(root->widget, "sidebar2"); |
442 | setClosedFolders_SidebarWidget(sidebar, closedFolders[0]); | ||
443 | setClosedFolders_SidebarWidget(sidebar2, closedFolders[1]); | ||
434 | postCommandf_Root(root, "sidebar.mode arg:%u", modes & 0xf); | 444 | postCommandf_Root(root, "sidebar.mode arg:%u", modes & 0xf); |
435 | postCommandf_Root(root, "sidebar2.mode arg:%u", modes >> 4); | 445 | postCommandf_Root(root, "sidebar2.mode arg:%u", modes >> 4); |
436 | if (deviceType_App() != phone_AppDeviceType) { | 446 | if (deviceType_App() != phone_AppDeviceType) { |
@@ -513,6 +523,8 @@ static void saveState_App_(const iApp *d) { | |||
513 | (mode_SidebarWidget(sidebar2) << 4)); | 523 | (mode_SidebarWidget(sidebar2) << 4)); |
514 | writef_Stream(stream_File(f), width_SidebarWidget(sidebar)); | 524 | writef_Stream(stream_File(f), width_SidebarWidget(sidebar)); |
515 | writef_Stream(stream_File(f), width_SidebarWidget(sidebar2)); | 525 | writef_Stream(stream_File(f), width_SidebarWidget(sidebar2)); |
526 | serialize_IntSet(closedFolders_SidebarWidget(sidebar), stream_File(f)); | ||
527 | serialize_IntSet(closedFolders_SidebarWidget(sidebar2), stream_File(f)); | ||
516 | } | 528 | } |
517 | } | 529 | } |
518 | } | 530 | } |
@@ -36,9 +36,10 @@ enum iFileVersion { | |||
36 | multipleRoots_FileVersion = 2, | 36 | multipleRoots_FileVersion = 2, |
37 | serializedSidebarState_FileVersion = 3, | 37 | serializedSidebarState_FileVersion = 3, |
38 | addedRecentUrlFlags_FileVersion = 4, | 38 | addedRecentUrlFlags_FileVersion = 4, |
39 | bookmarkFolderState_FileVersion = 5, | ||
39 | /* meta */ | 40 | /* meta */ |
40 | idents_FileVersion = 1, /* version used by GmCerts/idents.lgr */ | 41 | idents_FileVersion = 1, /* version used by GmCerts/idents.lgr */ |
41 | latest_FileVersion = 4, | 42 | latest_FileVersion = 5, |
42 | }; | 43 | }; |
43 | 44 | ||
44 | enum iImageStyle { | 45 | enum iImageStyle { |
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 8e38dcb8..3018f16d 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -108,7 +108,7 @@ struct Impl_SidebarWidget { | |||
108 | iWidget * menu; | 108 | iWidget * menu; |
109 | iSidebarItem * contextItem; /* list item accessed in the context menu */ | 109 | iSidebarItem * contextItem; /* list item accessed in the context menu */ |
110 | size_t contextIndex; /* index of list item accessed in the context menu */ | 110 | size_t contextIndex; /* index of list item accessed in the context menu */ |
111 | iIntSet closedFolders; /* otherwise open */ | 111 | iIntSet * closedFolders; /* otherwise open */ |
112 | }; | 112 | }; |
113 | 113 | ||
114 | iDefineObjectConstructionArgs(SidebarWidget, (enum iSidebarSide side), side) | 114 | iDefineObjectConstructionArgs(SidebarWidget, (enum iSidebarSide side), side) |
@@ -255,7 +255,7 @@ static void updateContextMenu_SidebarWidget_(iSidebarWidget *d) { | |||
255 | 255 | ||
256 | static iBool isBookmarkFolded_SidebarWidget_(const iSidebarWidget *d, const iBookmark *bm) { | 256 | static iBool isBookmarkFolded_SidebarWidget_(const iSidebarWidget *d, const iBookmark *bm) { |
257 | while (bm->parentId) { | 257 | while (bm->parentId) { |
258 | if (contains_IntSet(&d->closedFolders, bm->parentId)) { | 258 | if (contains_IntSet(d->closedFolders, bm->parentId)) { |
259 | return iTrue; | 259 | return iTrue; |
260 | } | 260 | } |
261 | bm = get_Bookmarks(bookmarks_App(), bm->parentId); | 261 | bm = get_Bookmarks(bookmarks_App(), bm->parentId); |
@@ -397,7 +397,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
397 | item->id = id_Bookmark(bm); | 397 | item->id = id_Bookmark(bm); |
398 | item->indent = depth_Bookmark(bm); | 398 | item->indent = depth_Bookmark(bm); |
399 | if (isFolder_Bookmark(bm)) { | 399 | if (isFolder_Bookmark(bm)) { |
400 | item->icon = contains_IntSet(&d->closedFolders, item->id) ? 0x27e9 : 0xfe40; | 400 | item->icon = contains_IntSet(d->closedFolders, item->id) ? 0x27e9 : 0xfe40; |
401 | } | 401 | } |
402 | else { | 402 | else { |
403 | item->icon = bm->icon; | 403 | item->icon = bm->icon; |
@@ -655,6 +655,11 @@ iBool setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) { | |||
655 | return iTrue; | 655 | return iTrue; |
656 | } | 656 | } |
657 | 657 | ||
658 | void setClosedFolders_SidebarWidget(iSidebarWidget *d, const iIntSet *closedFolders) { | ||
659 | delete_IntSet(d->closedFolders); | ||
660 | d->closedFolders = copy_IntSet(closedFolders); | ||
661 | } | ||
662 | |||
658 | enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) { | 663 | enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) { |
659 | return d ? d->mode : 0; | 664 | return d ? d->mode : 0; |
660 | } | 665 | } |
@@ -663,6 +668,10 @@ float width_SidebarWidget(const iSidebarWidget *d) { | |||
663 | return d ? d->widthAsGaps : 0; | 668 | return d ? d->widthAsGaps : 0; |
664 | } | 669 | } |
665 | 670 | ||
671 | const iIntSet *closedFolders_SidebarWidget(const iSidebarWidget *d) { | ||
672 | return d->closedFolders; | ||
673 | } | ||
674 | |||
666 | static const char *normalModeLabels_[max_SidebarMode] = { | 675 | static const char *normalModeLabels_[max_SidebarMode] = { |
667 | book_Icon " ${sidebar.bookmarks}", | 676 | book_Icon " ${sidebar.bookmarks}", |
668 | star_Icon " ${sidebar.feeds}", | 677 | star_Icon " ${sidebar.feeds}", |
@@ -736,7 +745,7 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
736 | d->resizer = NULL; | 745 | d->resizer = NULL; |
737 | d->list = NULL; | 746 | d->list = NULL; |
738 | d->actions = NULL; | 747 | d->actions = NULL; |
739 | init_IntSet(&d->closedFolders); | 748 | d->closedFolders = new_IntSet(); |
740 | /* On a phone, the right sidebar is used exclusively for Identities. */ | 749 | /* On a phone, the right sidebar is used exclusively for Identities. */ |
741 | const iBool isPhone = deviceType_App() == phone_AppDeviceType; | 750 | const iBool isPhone = deviceType_App() == phone_AppDeviceType; |
742 | if (!isPhone || d->side == left_SidebarSide) { | 751 | if (!isPhone || d->side == left_SidebarSide) { |
@@ -820,7 +829,7 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
820 | 829 | ||
821 | void deinit_SidebarWidget(iSidebarWidget *d) { | 830 | void deinit_SidebarWidget(iSidebarWidget *d) { |
822 | deinit_String(&d->cmdPrefix); | 831 | deinit_String(&d->cmdPrefix); |
823 | deinit_IntSet(&d->closedFolders); | 832 | delete_IntSet(d->closedFolders); |
824 | } | 833 | } |
825 | 834 | ||
826 | iBool setButtonFont_SidebarWidget(iSidebarWidget *d, int font) { | 835 | iBool setButtonFont_SidebarWidget(iSidebarWidget *d, int font) { |
@@ -869,11 +878,11 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si | |||
869 | } | 878 | } |
870 | case bookmarks_SidebarMode: | 879 | case bookmarks_SidebarMode: |
871 | if (isEmpty_String(&item->url)) /* a folder */ { | 880 | if (isEmpty_String(&item->url)) /* a folder */ { |
872 | if (contains_IntSet(&d->closedFolders, item->id)) { | 881 | if (contains_IntSet(d->closedFolders, item->id)) { |
873 | remove_IntSet(&d->closedFolders, item->id); | 882 | remove_IntSet(d->closedFolders, item->id); |
874 | } | 883 | } |
875 | else { | 884 | else { |
876 | insert_IntSet(&d->closedFolders, item->id); | 885 | insert_IntSet(d->closedFolders, item->id); |
877 | } | 886 | } |
878 | updateItems_SidebarWidget_(d); | 887 | updateItems_SidebarWidget_(d); |
879 | break; | 888 | break; |
@@ -956,8 +965,8 @@ void setWidth_SidebarWidget(iSidebarWidget *d, float widthAsGaps) { | |||
956 | int width = widthAsGaps * gap_UI; /* in pixels */ | 965 | int width = widthAsGaps * gap_UI; /* in pixels */ |
957 | if (!isFixedWidth) { | 966 | if (!isFixedWidth) { |
958 | /* Even less space if the other sidebar is visible, too. */ | 967 | /* Even less space if the other sidebar is visible, too. */ |
959 | const int otherWidth = | 968 | const iWidget *other = findWidget_App(d->side == left_SidebarSide ? "sidebar2" : "sidebar"); |
960 | width_Widget(findWidget_App(d->side == left_SidebarSide ? "sidebar2" : "sidebar")); | 969 | const int otherWidth = isVisible_Widget(other) ? width_Widget(other) : 0; |
961 | width = iClamp(width, 30 * gap_UI, size_Root(w->root).x - 50 * gap_UI - otherWidth); | 970 | width = iClamp(width, 30 * gap_UI, size_Root(w->root).x - 50 * gap_UI - otherWidth); |
962 | } | 971 | } |
963 | d->widthAsGaps = (float) width / (float) gap_UI; | 972 | d->widthAsGaps = (float) width / (float) gap_UI; |
@@ -1328,6 +1337,8 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
1328 | if (isFolder_Bookmark(bm)) { | 1337 | if (isFolder_Bookmark(bm)) { |
1329 | const iPtrArray *list = list_Bookmarks(bookmarks_App(), NULL, | 1338 | const iPtrArray *list = list_Bookmarks(bookmarks_App(), NULL, |
1330 | filterInsideFolder_Bookmark, bm); | 1339 | filterInsideFolder_Bookmark, bm); |
1340 | /* Folder deletion requires confirmation because folders can contain | ||
1341 | any number of bookmarks and other folders. */ | ||
1331 | if (argLabel_Command(cmd, "confirmed") || isEmpty_PtrArray(list)) { | 1342 | if (argLabel_Command(cmd, "confirmed") || isEmpty_PtrArray(list)) { |
1332 | iConstForEach(PtrArray, i, list) { | 1343 | iConstForEach(PtrArray, i, list) { |
1333 | removeEntries_Feeds(id_Bookmark(i.ptr)); | 1344 | removeEntries_Feeds(id_Bookmark(i.ptr)); |
diff --git a/src/ui/sidebarwidget.h b/src/ui/sidebarwidget.h index 2894a951..638a1f2f 100644 --- a/src/ui/sidebarwidget.h +++ b/src/ui/sidebarwidget.h | |||
@@ -24,6 +24,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
24 | 24 | ||
25 | #include "widget.h" | 25 | #include "widget.h" |
26 | 26 | ||
27 | #include <the_Foundation/intset.h> | ||
28 | |||
27 | enum iSidebarMode { | 29 | enum iSidebarMode { |
28 | bookmarks_SidebarMode, | 30 | bookmarks_SidebarMode, |
29 | feeds_SidebarMode, | 31 | feeds_SidebarMode, |
@@ -49,8 +51,10 @@ iDeclareWidgetClass(SidebarWidget) | |||
49 | iDeclareObjectConstructionArgs(SidebarWidget, enum iSidebarSide side) | 51 | iDeclareObjectConstructionArgs(SidebarWidget, enum iSidebarSide side) |
50 | 52 | ||
51 | iBool setMode_SidebarWidget (iSidebarWidget *, enum iSidebarMode mode); | 53 | iBool setMode_SidebarWidget (iSidebarWidget *, enum iSidebarMode mode); |
54 | void setWidth_SidebarWidget (iSidebarWidget *, float widthAsGaps); | ||
52 | iBool setButtonFont_SidebarWidget (iSidebarWidget *, int font); | 55 | iBool setButtonFont_SidebarWidget (iSidebarWidget *, int font); |
56 | void setClosedFolders_SidebarWidget (iSidebarWidget *, const iIntSet *closedFolders); | ||
53 | 57 | ||
54 | enum iSidebarMode mode_SidebarWidget (const iSidebarWidget *); | 58 | enum iSidebarMode mode_SidebarWidget (const iSidebarWidget *); |
55 | float width_SidebarWidget (const iSidebarWidget *); | 59 | float width_SidebarWidget (const iSidebarWidget *); |
56 | void setWidth_SidebarWidget (iSidebarWidget *, float widthAsGaps); | 60 | const iIntSet * closedFolders_SidebarWidget (const iSidebarWidget *); |
diff --git a/src/ui/window.c b/src/ui/window.c index 5941ef5f..066ea102 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
30 | #include "keys.h" | 30 | #include "keys.h" |
31 | #include "labelwidget.h" | 31 | #include "labelwidget.h" |
32 | #include "documentwidget.h" | 32 | #include "documentwidget.h" |
33 | #include "sidebarwidget.h" | ||
33 | #include "paint.h" | 34 | #include "paint.h" |
34 | #include "root.h" | 35 | #include "root.h" |
35 | #include "touch.h" | 36 | #include "touch.h" |
@@ -1421,6 +1422,15 @@ void setSplitMode_MainWindow(iMainWindow *d, int splitFlags) { | |||
1421 | w->keyRoot->window = w; | 1422 | w->keyRoot->window = w; |
1422 | setCurrent_Root(w->roots[newRootIndex]); | 1423 | setCurrent_Root(w->roots[newRootIndex]); |
1423 | createUserInterface_Root(w->roots[newRootIndex]); | 1424 | createUserInterface_Root(w->roots[newRootIndex]); |
1425 | /* Bookmark folder state will match the old root's state. */ { | ||
1426 | for (int sb = 0; sb < 2; sb++) { | ||
1427 | const char *sbId = (sb == 0 ? "sidebar" : "sidebar2"); | ||
1428 | setClosedFolders_SidebarWidget( | ||
1429 | findChild_Widget(w->roots[newRootIndex]->widget, sbId), | ||
1430 | closedFolders_SidebarWidget( | ||
1431 | findChild_Widget(w->roots[newRootIndex ^ 1]->widget, sbId))); | ||
1432 | } | ||
1433 | } | ||
1424 | if (!isEmpty_String(d->pendingSplitUrl)) { | 1434 | if (!isEmpty_String(d->pendingSplitUrl)) { |
1425 | postCommandf_Root(w->roots[newRootIndex], "open url:%s", | 1435 | postCommandf_Root(w->roots[newRootIndex], "open url:%s", |
1426 | cstr_String(d->pendingSplitUrl)); | 1436 | cstr_String(d->pendingSplitUrl)); |