=> 27ebfc904b9b3eac3ef5479ed0d0ba166fac1543
[1mdiff --git a/src/bookmarks.c b/src/bookmarks.c[m [1mindex c27efbfe..94f4be4e 100644[m [1m--- a/src/bookmarks.c[m [1m+++ b/src/bookmarks.c[m [36m@@ -31,13 +31,15 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m #include[m #include [m #include [m [32m+[m[32m#include [m [m void init_Bookmark(iBookmark *d) {[m init_String(&d->url);[m init_String(&d->title);[m init_String(&d->tags);[m iZap(d->when);[m [31m- d->sourceId = 0;[m [32m+[m[32m d->parentId = 0;[m [32m+[m[32m d->order = 0;[m }[m [m void deinit_Bookmark(iBookmark *d) {[m [36m@@ -83,7 +85,8 @@[m [mstatic int cmpTitleAscending_Bookmark_(const iBookmark **a, const iBookmark **b)[m [m /*----------------------------------------------------------------------------------------------*/[m [m [31m-static const char *fileName_Bookmarks_ = "bookmarks.txt";[m [32m+[m[32mstatic const char *oldFileName_Bookmarks_ = "bookmarks.txt";[m [32m+[m[32mstatic const char *fileName_Bookmarks_ = "bookmarks.ini"; /* since v1.7 (TOML subset) */[m [m struct Impl_Bookmarks {[m iMutex * mtx;[m [36m@@ -123,16 +126,19 @@[m [mvoid clear_Bookmarks(iBookmarks *d) {[m unlock_Mutex(d->mtx);[m }[m [m [32m+[m[32mstatic void insertId_Bookmarks_(iBookmarks *d, iBookmark *bookmark, int id) {[m [32m+[m[32m bookmark->node.key = id;[m [32m+[m[32m insert_Hash(&d->bookmarks, &bookmark->node);[m [32m+[m[32m}[m [32m+[m static void insert_Bookmarks_(iBookmarks *d, iBookmark *bookmark) {[m lock_Mutex(d->mtx);[m [31m- bookmark->node.key = ++d->idEnum;[m [31m- insert_Hash(&d->bookmarks, &bookmark->node);[m [32m+[m[32m insertId_Bookmarks_(d, bookmark, ++d->idEnum);[m unlock_Mutex(d->mtx);[m }[m [m [31m-void load_Bookmarks(iBookmarks *d, const char *dirPath) {[m [31m- clear_Bookmarks(d);[m [31m- iFile *f = newCStr_File(concatPath_CStr(dirPath, fileName_Bookmarks_));[m [32m+[m[32mstatic void loadOldFormat_Bookmarks(iBookmarks *d, const char *dirPath) {[m [32m+[m[32m iFile *f = newCStr_File(concatPath_CStr(dirPath, oldFileName_Bookmarks_));[m if (open_File(f, readOnly_FileMode | text_FileMode)) {[m const iRangecc src = range_Block(collect_Block(readAll_File(f)));[m iRangecc line = iNullRange;[m [36m@@ -170,6 +176,101 @@[m [mvoid load_Bookmarks(iBookmarks *d, const char *dirPath) {[m iRelease(f);[m }[m [m [32m+[m[32m/*----------------------------------------------------------------------------------------------*/[m [32m+[m [32m+[m[32miDeclareType(BookmarkLoader)[m [32m+[m[41m [m [32m+[m[32mstruct Impl_BookmarkLoader {[m [32m+[m[32m iTomlParser *toml;[m [32m+[m[32m iBookmarks * bookmarks;[m [32m+[m[32m iBookmark * bm;[m [32m+[m[32m};[m [32m+[m [32m+[m[32mstatic void handleTable_BookmarkLoader_(void *context, const iString *table, iBool isStart) {[m [32m+[m[32m iBookmarkLoader *d = context;[m [32m+[m[32m if (isStart) {[m [32m+[m[32m iAssert(!d->bm);[m [32m+[m[32m d->bm = new_Bookmark();[m [32m+[m[32m const int id = toInt_String(table);[m [32m+[m[32m d->bookmarks->idEnum = iMax(d->bookmarks->idEnum, id);[m [32m+[m[32m insertId_Bookmarks_(d->bookmarks, d->bm, id);[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m d->bm = NULL;[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void handleKeyValue_BookmarkLoader_(void *context, const iString *table, const iString *key,[m [32m+[m[32m const iTomlValue *tv) {[m [32m+[m[32m iBookmarkLoader *d = context;[m [32m+[m[32m iBookmark *bm = d->bm;[m [32m+[m[32m if (bm) {[m [32m+[m[32m iUnused(table); /* it's the current one */[m [32m+[m[32m if (!cmp_String(key, "url") && tv->type == string_TomlType) {[m [32m+[m[32m set_String(&bm->url, tv->value.string);[m [32m+[m[32m }[m [32m+[m[32m else if (!cmp_String(key, "title") && tv->type == string_TomlType) {[m [32m+[m[32m set_String(&bm->title, tv->value.string);[m [32m+[m[32m }[m [32m+[m[32m else if (!cmp_String(key, "tags") && tv->type == string_TomlType) {[m [32m+[m[32m set_String(&bm->tags, tv->value.string);[m [32m+[m[32m }[m [32m+[m[32m else if (!cmp_String(key, "icon") && tv->type == int64_TomlType) {[m [32m+[m[32m bm->icon = (iChar) tv->value.int64;[m [32m+[m[32m }[m [32m+[m[32m else if (!cmp_String(key, "created") && tv->type == int64_TomlType) {[m [32m+[m[32m initSeconds_Time(&bm->when, tv->value.int64);[m [32m+[m[32m }[m [32m+[m[32m else if (!cmp_String(key, "parent") && tv->type == int64_TomlType) {[m [32m+[m[32m bm->parentId = tv->value.int64;[m [32m+[m[32m }[m [32m+[m[32m else if (!cmp_String(key, "order") && tv->type == int64_TomlType) {[m [32m+[m[32m bm->order = tv->value.int64;[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void init_BookmarkLoader(iBookmarkLoader *d, iBookmarks *bookmarks) {[m [32m+[m[32m d->toml = new_TomlParser();[m [32m+[m[32m setHandlers_TomlParser(d->toml, handleTable_BookmarkLoader_, handleKeyValue_BookmarkLoader_, d);[m [32m+[m[32m d->bookmarks = bookmarks;[m [32m+[m[32m d->bm = NULL;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void deinit_BookmarkLoader(iBookmarkLoader *d) {[m [32m+[m[32m delete_TomlParser(d->toml);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void load_BookmarkLoader(iBookmarkLoader *d, iFile *file) {[m [32m+[m[32m if (!parse_TomlParser(d->toml, collect_String(readString_File(file)))) {[m [32m+[m[32m fprintf(stderr, "[Bookmarks] syntax error(s) in %s\n", cstr_String(path_File(file)));[m [32m+[m[32m }[m[41m [m [32m+[m[32m}[m [32m+[m [32m+[m[32miDefineTypeConstructionArgs(BookmarkLoader, (iBookmarks *b), b)[m [32m+[m[41m [m [32m+[m[32m/*----------------------------------------------------------------------------------------------*/[m [32m+[m[41m [m [32m+[m[32mvoid load_Bookmarks(iBookmarks *d, const char *dirPath) {[m [32m+[m[32m clear_Bookmarks(d);[m [32m+[m[32m /* Load new .ini bookmarks, if present. */[m [32m+[m[32m iFile *f = iClob(newCStr_File(concatPath_CStr(dirPath, fileName_Bookmarks_)));[m [32m+[m[32m if (!open_File(f, readOnly_FileMode | text_FileMode)) {[m [32m+[m[32m /* As a fallback, try loading the v1.6 bookmarks file. */[m [32m+[m[32m loadOldFormat_Bookmarks(d, dirPath);[m [32m+[m[32m /* Set ordering based on titles. */[m [32m+[m[32m iConstForEach(PtrArray, i, list_Bookmarks(d, cmpTitleAscending_Bookmark_, NULL, NULL)) {[m [32m+[m[32m iBookmark *bm = i.ptr;[m [32m+[m[32m bm->order = index_PtrArrayConstIterator(&i) + 1;[m [32m+[m[32m }[m [32m+[m[32m return;[m [32m+[m[32m }[m [32m+[m[32m iBookmarkLoader loader;[m [32m+[m[32m init_BookmarkLoader(&loader, d);[m [32m+[m[32m load_BookmarkLoader(&loader, f);[m [32m+[m[32m deinit_BookmarkLoader(&loader);[m [32m+[m[32m}[m [32m+[m void save_Bookmarks(const iBookmarks *d, const char *dirPath) {[m lock_Mutex(d->mtx);[m iRegExp *remotePattern = iClob(new_RegExp("\\bremote\\b", caseSensitive_RegExpOption));[m [36m@@ -185,12 +286,26 @@[m [mvoid save_Bookmarks(const iBookmarks *d, const char *dirPath) {[m continue;[m }[m format_String(str,[m [31m- "%08x %.0lf %s\n%s\n%s\n",[m [32m+[m[32m "[%d]\n"[m [32m+[m[32m "url = \"%s\"\n"[m [32m+[m[32m "title = \"%s\"\n"[m [32m+[m[32m "tags = \"%s\"\n"[m [32m+[m[32m "icon = 0x%x\n"[m [32m+[m[32m "created = %.0f # %s\n",[m [32m+[m[32m id_Bookmark(bm),[m [32m+[m[32m cstrCollect_String(quote_String(&bm->url, iFalse)),[m [32m+[m[32m cstrCollect_String(quote_String(&bm->title, iFalse)),[m [32m+[m[32m cstrCollect_String(quote_String(&bm->tags, iFalse)),[m bm->icon,[m seconds_Time(&bm->when),[m [31m- cstr_String(&bm->url),[m [31m- cstr_String(&bm->title),[m [31m- cstr_String(&bm->tags));[m [32m+[m[32m cstrCollect_String(format_Time(&bm->when, "%Y-%m-%d")));[m [32m+[m[32m if (bm->parentId) {[m [32m+[m[32m appendFormat_String(str, "parent = %d\n", bm->parentId);[m [32m+[m[32m }[m [32m+[m[32m if (bm->order) {[m [32m+[m[32m appendFormat_String(str, "order = %d\n", bm->order);[m [32m+[m[32m }[m [32m+[m[32m appendCStr_String(str, "\n");[m writeData_File(f, cstr_String(str), size_String(str));[m }[m }[m [36m@@ -223,7 +338,7 @@[m [miBool remove_Bookmarks(iBookmarks *d, uint32_t id) {[m if (hasTag_Bookmark(bm, remoteSource_BookmarkTag)) {[m iForEach(Hash, i, &d->bookmarks) {[m iBookmark *j = (iBookmark *) i.value;[m [31m- if (j->sourceId == id_Bookmark(bm)) {[m [32m+[m[32m if (j->parentId == id_Bookmark(bm)) {[m remove_HashIterator(&i);[m delete_Bookmark(j);[m }[m [36m@@ -452,7 +567,7 @@[m [mvoid requestFinished_Bookmarks(iBookmarks *d, iGmRequest *req) {[m }[m const uint32_t bmId = add_Bookmarks(d, absUrl, titleStr, remoteTag, 0x2913);[m iBookmark *bm = get_Bookmarks(d, bmId);[m [31m- bm->sourceId = *(uint32_t *) userData_Object(req);[m [32m+[m[32m bm->parentId = *(uint32_t *) userData_Object(req);[m delete_String(titleStr);[m }[m delete_String(urlStr);[m [1mdiff --git a/src/bookmarks.h b/src/bookmarks.h[m [1mindex 353b4197..dc7eca9a 100644[m [1m--- a/src/bookmarks.h[m [1m+++ b/src/bookmarks.h[m [36m@@ -47,7 +47,8 @@[m [mstruct Impl_Bookmark {[m iString tags;[m iChar icon;[m iTime when;[m [31m- uint32_t sourceId; /* remote */[m [32m+[m[32m uint32_t parentId; /* remote source or folder */[m [32m+[m[32m int order; /* sort order */[m };[m [m iLocalDef uint32_t id_Bookmark (const iBookmark *d) { return d->node.key; }[m [1mdiff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c[m [1mindex ffedfeeb..3463f1a5 100644[m [1m--- a/src/ui/sidebarwidget.c[m [1m+++ b/src/ui/sidebarwidget.c[m [36m@@ -116,24 +116,26 @@[m [mstatic iBool isResizing_SidebarWidget_(const iSidebarWidget *d) {[m return (flags_Widget(d->resizer) & pressed_WidgetFlag) != 0;[m }[m [m [31m-static int cmpTitle_Bookmark_(const iBookmark **a, const iBookmark **b) {[m [32m+[m[32mstatic int cmpTree_Bookmark_(const iBookmark **a, const iBookmark **b) {[m const iBookmark *bm1 = *a, *bm2 = *b;[m [31m- if (bm2->sourceId == id_Bookmark(bm1)) {[m [32m+[m[32m if (bm2->parentId == id_Bookmark(bm1)) {[m return -1;[m }[m [31m- if (bm1->sourceId == id_Bookmark(bm2)) {[m [32m+[m[32m if (bm1->parentId == id_Bookmark(bm2)) {[m return 1;[m }[m [31m- if (bm1->sourceId == bm2->sourceId) {[m [31m- return cmpStringCase_String(&bm1->title, &bm2->title);[m [32m+[m[32m if (bm1->parentId == bm2->parentId) {[m [32m+[m[32m //return cmpStringCase_String(&bm1->title, &bm2->title);[m [32m+[m[32m return iCmp(bm1->order, bm2->order);[m }[m [31m- if (bm1->sourceId) {[m [31m- bm1 = get_Bookmarks(bookmarks_App(), bm1->sourceId);[m [32m+[m[32m if (bm1->parentId) {[m [32m+[m[32m bm1 = get_Bookmarks(bookmarks_App(), bm1->parentId);[m }[m [31m- if (bm2->sourceId) {[m [31m- bm2 = get_Bookmarks(bookmarks_App(), bm2->sourceId);[m [32m+[m[32m if (bm2->parentId) {[m [32m+[m[32m bm2 = get_Bookmarks(bookmarks_App(), bm2->parentId);[m }[m [31m- return cmpStringCase_String(&bm1->title, &bm2->title);[m [32m+[m[32m// return cmpStringCase_String(&bm1->title, &bm2->title);[m [32m+[m[32m return iCmp(bm1->order, bm2->order);[m }[m [m static iLabelWidget *addActionButton_SidebarWidget_(iSidebarWidget *d, const char *label,[m [36m@@ -331,9 +333,10 @@[m [mstatic void updateItems_SidebarWidget_(iSidebarWidget *d) {[m iRegExp *subTag = iClob(new_RegExp("\\b" subscribed_BookmarkTag "\\b", caseSensitive_RegExpOption));[m iRegExp *remoteSourceTag = iClob(new_RegExp("\\b" remoteSource_BookmarkTag "\\b", caseSensitive_RegExpOption));[m iRegExp *linkSplitTag = iClob(new_RegExp("\\b" linkSplit_BookmarkTag "\\b", caseSensitive_RegExpOption));[m [31m- iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), cmpTitle_Bookmark_, NULL, NULL)) {[m [32m+[m[32m iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), cmpTree_Bookmark_, NULL, NULL)) {[m const iBookmark *bm = i.ptr;[m iSidebarItem *item = new_SidebarItem();[m [32m+[m[32m item->listItem.isDraggable = iTrue;[m item->id = id_Bookmark(bm);[m item->icon = bm->icon;[m set_String(&item->url, &bm->url);[m [36m@@ -1573,12 +1576,14 @@[m [mstatic void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,[m const iSidebarWidget *sidebar = findParentClass_Widget(constAs_Widget(list),[m &Class_SidebarWidget);[m const iBool isMenuVisible = isVisible_Widget(sidebar->menu);[m [31m- const iBool isPressing = isMouseDown_ListWidget(list);[m [32m+[m[32m const iBool isDragging = constDragItem_ListWidget(list) == d;[m [32m+[m[32m const iBool isPressing = isMouseDown_ListWidget(list) && !isDragging;[m const iBool isHover =[m (!isMenuVisible &&[m isHover_Widget(constAs_Widget(list)) &&[m constHoverItem_ListWidget(list) == d) ||[m [31m- (isMenuVisible && sidebar->contextItem == d);[m [32m+[m[32m (isMenuVisible && sidebar->contextItem == d) ||[m [32m+[m[32m isDragging;[m const int scrollBarWidth = scrollBarWidth_ListWidget(list);[m #if defined (iPlatformApple)[m const int blankWidth = 0;[m [36m@@ -1729,12 +1734,14 @@[m [mstatic void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,[m metaIconWidth[m - 2 * gap_UI - (blankWidth ? blankWidth - 1.5f * gap_UI : (gap_UI / 2)),[m textPos.y);[m [31m- fillRect_Paint(p,[m [31m- init_Rect(metaPos.x,[m [31m- top_Rect(itemRect),[m [31m- right_Rect(itemRect) - metaPos.x,[m [31m- height_Rect(itemRect)),[m [31m- bg);[m [32m+[m[32m if (!isDragging) {[m [32m+[m[32m fillRect_Paint(p,[m [32m+[m[32m init_Rect(metaPos.x,[m [32m+[m[32m top_Rect(itemRect),[m [32m+[m[32m right_Rect(itemRect) - metaPos.x,[m [32m+[m[32m height_Rect(itemRect)),[m [32m+[m[32m bg);[m [32m+[m[32m }[m iInt2 mpos = metaPos;[m iStringConstIterator iter;[m init_StringConstIterator(&iter, &d->meta);[m
text/gemini; charset=utf-8
This content has been proxied by September (3851b).