Lagrange [work/v1.7]

Persistent bookmark folder state

=> 242e8231ea61278fe482020658be86c2dec0ae53

diff --git a/src/app.c b/src/app.c
index 2f4b4fb8..2bad3cb6 100644
--- a/src/app.c
+++ b/src/app.c
@@ -425,12 +425,22 @@ static iBool loadState_App_(iApp *d) {
                     readf_Stream(stream_File(f)),
                     readf_Stream(stream_File(f))
                 };
+                iIntSet *closedFolders[2] = {
+                    collectNew_IntSet(),
+                    collectNew_IntSet()
+                };
+                if (version >= bookmarkFolderState_FileVersion) {
+                    deserialize_IntSet(closedFolders[0], stream_File(f));
+                    deserialize_IntSet(closedFolders[1], stream_File(f));
+                }
                 const uint8_t rootIndex = bits & 0xff;
                 const uint8_t flags     = bits >> 8;
                 iRoot *root = d->window->base.roots[rootIndex];
                 if (root) {
                     iSidebarWidget *sidebar  = findChild_Widget(root->widget, "sidebar");
                     iSidebarWidget *sidebar2 = findChild_Widget(root->widget, "sidebar2");
+                    setClosedFolders_SidebarWidget(sidebar, closedFolders[0]);
+                    setClosedFolders_SidebarWidget(sidebar2, closedFolders[1]);
                     postCommandf_Root(root, "sidebar.mode arg:%u", modes & 0xf);
                     postCommandf_Root(root, "sidebar2.mode arg:%u", modes >> 4);
                     if (deviceType_App() != phone_AppDeviceType) {
@@ -513,6 +523,8 @@ static void saveState_App_(const iApp *d) {
                                  (mode_SidebarWidget(sidebar2) << 4));
                     writef_Stream(stream_File(f), width_SidebarWidget(sidebar));
                     writef_Stream(stream_File(f), width_SidebarWidget(sidebar2));
+                    serialize_IntSet(closedFolders_SidebarWidget(sidebar), stream_File(f));
+                    serialize_IntSet(closedFolders_SidebarWidget(sidebar2), stream_File(f));
                 }
             }
         }
diff --git a/src/defs.h b/src/defs.h
index a81d57f1..e1c0a125 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -36,9 +36,10 @@ enum iFileVersion {
     multipleRoots_FileVersion           = 2,
     serializedSidebarState_FileVersion  = 3,
     addedRecentUrlFlags_FileVersion     = 4,
+    bookmarkFolderState_FileVersion     = 5,
     /* meta */
     idents_FileVersion = 1, /* version used by GmCerts/idents.lgr */
-    latest_FileVersion = 4,
+    latest_FileVersion = 5,
 };
 
 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 {
     iWidget *         menu;
     iSidebarItem *    contextItem;  /* list item accessed in the context menu */
     size_t            contextIndex; /* index of list item accessed in the context menu */
-    iIntSet           closedFolders; /* otherwise open */
+    iIntSet *         closedFolders; /* otherwise open */
 };
 
 iDefineObjectConstructionArgs(SidebarWidget, (enum iSidebarSide side), side)
@@ -255,7 +255,7 @@ static void updateContextMenu_SidebarWidget_(iSidebarWidget *d) {
 
 static iBool isBookmarkFolded_SidebarWidget_(const iSidebarWidget *d, const iBookmark *bm) {
     while (bm->parentId) {
-        if (contains_IntSet(&d->closedFolders, bm->parentId)) {
+        if (contains_IntSet(d->closedFolders, bm->parentId)) {
             return iTrue;
         }
         bm = get_Bookmarks(bookmarks_App(), bm->parentId);
@@ -397,7 +397,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
                 item->id = id_Bookmark(bm);
                 item->indent = depth_Bookmark(bm);
                 if (isFolder_Bookmark(bm)) {
-                    item->icon = contains_IntSet(&d->closedFolders, item->id) ? 0x27e9 : 0xfe40;
+                    item->icon = contains_IntSet(d->closedFolders, item->id) ? 0x27e9 : 0xfe40;
                 }
                 else {
                     item->icon = bm->icon;
@@ -655,6 +655,11 @@ iBool setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) {
     return iTrue;
 }
 
+void setClosedFolders_SidebarWidget(iSidebarWidget *d, const iIntSet *closedFolders) {
+    delete_IntSet(d->closedFolders);
+    d->closedFolders = copy_IntSet(closedFolders);
+}
+
 enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) {
     return d ? d->mode : 0;
 }
@@ -663,6 +668,10 @@ float width_SidebarWidget(const iSidebarWidget *d) {
     return d ? d->widthAsGaps : 0;
 }
 
+const iIntSet *closedFolders_SidebarWidget(const iSidebarWidget *d) {
+    return d->closedFolders;
+}
+
 static const char *normalModeLabels_[max_SidebarMode] = {
     book_Icon   " ${sidebar.bookmarks}",
     star_Icon   " ${sidebar.feeds}",
@@ -736,7 +745,7 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) {
     d->resizer = NULL;
     d->list = NULL;
     d->actions = NULL;
-    init_IntSet(&d->closedFolders);
+    d->closedFolders = new_IntSet();
     /* On a phone, the right sidebar is used exclusively for Identities. */
     const iBool isPhone = deviceType_App() == phone_AppDeviceType;
     if (!isPhone || d->side == left_SidebarSide) {
@@ -820,7 +829,7 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) {
 
 void deinit_SidebarWidget(iSidebarWidget *d) {
     deinit_String(&d->cmdPrefix);
-    deinit_IntSet(&d->closedFolders);
+    delete_IntSet(d->closedFolders);
 }
 
 iBool setButtonFont_SidebarWidget(iSidebarWidget *d, int font) {
@@ -869,11 +878,11 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si
         }
         case bookmarks_SidebarMode:
             if (isEmpty_String(&item->url)) /* a folder */ {
-                if (contains_IntSet(&d->closedFolders, item->id)) {
-                    remove_IntSet(&d->closedFolders, item->id);
+                if (contains_IntSet(d->closedFolders, item->id)) {
+                    remove_IntSet(d->closedFolders, item->id);
                 }
                 else {
-                    insert_IntSet(&d->closedFolders, item->id);
+                    insert_IntSet(d->closedFolders, item->id);
                 }
                 updateItems_SidebarWidget_(d);
                 break;
@@ -956,8 +965,8 @@ void setWidth_SidebarWidget(iSidebarWidget *d, float widthAsGaps) {
     int width = widthAsGaps * gap_UI; /* in pixels */
     if (!isFixedWidth) {
         /* Even less space if the other sidebar is visible, too. */
-        const int otherWidth =
-            width_Widget(findWidget_App(d->side == left_SidebarSide ? "sidebar2" : "sidebar"));
+        const iWidget *other = findWidget_App(d->side == left_SidebarSide ? "sidebar2" : "sidebar");
+        const int otherWidth = isVisible_Widget(other) ? width_Widget(other) : 0;
         width = iClamp(width, 30 * gap_UI, size_Root(w->root).x - 50 * gap_UI - otherWidth);
     }
     d->widthAsGaps = (float) width / (float) gap_UI;
@@ -1328,6 +1337,8 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
                 if (isFolder_Bookmark(bm)) {
                     const iPtrArray *list = list_Bookmarks(bookmarks_App(), NULL,
                                                            filterInsideFolder_Bookmark, bm);
+                    /* Folder deletion requires confirmation because folders can contain
+                       any number of bookmarks and other folders. */
                     if (argLabel_Command(cmd, "confirmed") || isEmpty_PtrArray(list)) {
                         iConstForEach(PtrArray, i, list) {
                             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. */
 
 #include "widget.h"
 
+#include 
+
 enum iSidebarMode {
     bookmarks_SidebarMode,
     feeds_SidebarMode,
@@ -49,8 +51,10 @@ iDeclareWidgetClass(SidebarWidget)
 iDeclareObjectConstructionArgs(SidebarWidget, enum iSidebarSide side)
 
 iBool               setMode_SidebarWidget       (iSidebarWidget *, enum iSidebarMode mode);
+void                setWidth_SidebarWidget      (iSidebarWidget *, float widthAsGaps);
 iBool               setButtonFont_SidebarWidget (iSidebarWidget *, int font);
+void                setClosedFolders_SidebarWidget  (iSidebarWidget *, const iIntSet *closedFolders);
 
 enum iSidebarMode   mode_SidebarWidget          (const iSidebarWidget *);
 float               width_SidebarWidget         (const iSidebarWidget *);
-void                setWidth_SidebarWidget      (iSidebarWidget *, float widthAsGaps);
+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. */
 #include "keys.h"
 #include "labelwidget.h"
 #include "documentwidget.h"
+#include "sidebarwidget.h"
 #include "paint.h"
 #include "root.h"
 #include "touch.h"
@@ -1421,6 +1422,15 @@ void setSplitMode_MainWindow(iMainWindow *d, int splitFlags) {
             w->keyRoot->window     = w;
             setCurrent_Root(w->roots[newRootIndex]);
             createUserInterface_Root(w->roots[newRootIndex]);
+            /* Bookmark folder state will match the old root's state. */ {
+                for (int sb = 0; sb < 2; sb++) {
+                    const char *sbId = (sb == 0 ? "sidebar" : "sidebar2");
+                    setClosedFolders_SidebarWidget(
+                        findChild_Widget(w->roots[newRootIndex]->widget, sbId),
+                        closedFolders_SidebarWidget(
+                            findChild_Widget(w->roots[newRootIndex ^ 1]->widget, sbId)));
+                }
+            }
             if (!isEmpty_String(d->pendingSplitUrl)) {
                 postCommandf_Root(w->roots[newRootIndex], "open url:%s",
                                   cstr_String(d->pendingSplitUrl));
Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.7/cdiff/242e8231ea61278fe482020658be86c2dec0ae53
Status Code
Success (20)
Meta
text/gemini; charset=utf-8
Capsule Response Time
35.778033 milliseconds
Gemini-to-HTML Time
0.490383 milliseconds

This content has been proxied by September (ba2dc).