summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/app.c33
-rw-r--r--src/app.h2
-rw-r--r--src/bookmarks.c22
-rw-r--r--src/bookmarks.h3
-rw-r--r--src/ui/documentwidget.c21
-rw-r--r--src/ui/documentwidget.h1
-rw-r--r--src/ui/sidebarwidget.c46
-rw-r--r--src/ui/sidebarwidget.h2
-rw-r--r--src/ui/window.c3
9 files changed, 122 insertions, 11 deletions
diff --git a/src/app.c b/src/app.c
index 488e7b42..cbd2b114 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1,18 +1,20 @@
1#include "app.h" 1#include "app.h"
2#include "bookmarks.h"
2#include "embedded.h" 3#include "embedded.h"
3#include "gmcerts.h" 4#include "gmcerts.h"
5#include "gmdocument.h"
4#include "gmutil.h" 6#include "gmutil.h"
5#include "history.h" 7#include "history.h"
6#include "visited.h" 8#include "ui/color.h"
7#include "ui/command.h" 9#include "ui/command.h"
8#include "ui/window.h" 10#include "ui/documentwidget.h"
9#include "ui/inputwidget.h" 11#include "ui/inputwidget.h"
10#include "ui/labelwidget.h" 12#include "ui/labelwidget.h"
11#include "ui/sidebarwidget.h" 13#include "ui/sidebarwidget.h"
12#include "ui/documentwidget.h"
13#include "ui/util.h"
14#include "ui/text.h" 14#include "ui/text.h"
15#include "ui/color.h" 15#include "ui/util.h"
16#include "ui/window.h"
17#include "visited.h"
16 18
17#include <the_Foundation/commandline.h> 19#include <the_Foundation/commandline.h>
18#include <the_Foundation/file.h> 20#include <the_Foundation/file.h>
@@ -60,6 +62,7 @@ struct Impl_App {
60 iBool pendingRefresh; 62 iBool pendingRefresh;
61 iGmCerts * certs; 63 iGmCerts * certs;
62 iVisited * visited; 64 iVisited * visited;
65 iBookmarks * bookmarks;
63 int zoomPercent; 66 int zoomPercent;
64 int tabEnum; 67 int tabEnum;
65 /* Preferences: */ 68 /* Preferences: */
@@ -157,6 +160,7 @@ static const char *magicState_App_ = "lgL1";
157static const char *magicTabDocument_App_ = "tabd"; 160static const char *magicTabDocument_App_ = "tabd";
158 161
159static iBool loadState_App_(iApp *d) { 162static iBool loadState_App_(iApp *d) {
163 iUnused(d);
160 iFile *f = iClob(newCStr_File(concatPath_CStr(dataDir_App_, stateFileName_App_))); 164 iFile *f = iClob(newCStr_File(concatPath_CStr(dataDir_App_, stateFileName_App_)));
161 if (open_File(f, readOnly_FileMode)) { 165 if (open_File(f, readOnly_FileMode)) {
162 char magic[4]; 166 char magic[4];
@@ -225,9 +229,11 @@ static void init_App_(iApp *d, int argc, char **argv) {
225 d->zoomPercent = 100; 229 d->zoomPercent = 100;
226 d->certs = new_GmCerts(dataDir_App_); 230 d->certs = new_GmCerts(dataDir_App_);
227 d->visited = new_Visited(); 231 d->visited = new_Visited();
232 d->bookmarks = new_Bookmarks();
228 d->tabEnum = 0; 233 d->tabEnum = 0;
229 loadPrefs_App_(d); 234 loadPrefs_App_(d);
230 load_Visited(d->visited, dataDir_App_); 235 load_Visited(d->visited, dataDir_App_);
236 load_Bookmarks(d->bookmarks, dataDir_App_);
231#if defined (iHaveLoadEmbed) 237#if defined (iHaveLoadEmbed)
232 /* Load the resources from a file. */ { 238 /* Load the resources from a file. */ {
233 if (!load_Embed(concatPath_CStr(cstr_String(execPath_App()), "../resources.bin"))) { 239 if (!load_Embed(concatPath_CStr(cstr_String(execPath_App()), "../resources.bin"))) {
@@ -248,6 +254,8 @@ static void init_App_(iApp *d, int argc, char **argv) {
248static void deinit_App(iApp *d) { 254static void deinit_App(iApp *d) {
249 saveState_App_(d); 255 saveState_App_(d);
250 savePrefs_App_(d); 256 savePrefs_App_(d);
257 save_Bookmarks(d->bookmarks, dataDir_App_);
258 delete_Bookmarks(d->bookmarks);
251 save_Visited(d->visited, dataDir_App_); 259 save_Visited(d->visited, dataDir_App_);
252 delete_Visited(d->visited); 260 delete_Visited(d->visited);
253 delete_GmCerts(d->certs); 261 delete_GmCerts(d->certs);
@@ -407,6 +415,10 @@ iVisited *visited_App(void) {
407 return app_.visited; 415 return app_.visited;
408} 416}
409 417
418iBookmarks *bookmarks_App(void) {
419 return app_.bookmarks;
420}
421
410static iBool handlePrefsCommands_(iWidget *d, const char *cmd) { 422static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
411 if (equal_Command(cmd, "prefs.dismiss") || equal_Command(cmd, "preferences")) { 423 if (equal_Command(cmd, "prefs.dismiss") || equal_Command(cmd, "preferences")) {
412 setUiScale_Window(get_Window(), 424 setUiScale_Window(get_Window(),
@@ -504,7 +516,7 @@ iBool handleCommand_App(const char *cmd) {
504 } 516 }
505 else if (equal_Command(cmd, "tabs.new")) { 517 else if (equal_Command(cmd, "tabs.new")) {
506 const iBool isDuplicate = argLabel_Command(cmd, "duplicate") != 0; 518 const iBool isDuplicate = argLabel_Command(cmd, "duplicate") != 0;
507 iDocumentWidget *newDoc = newTab_App(isDuplicate ? document_App() : NULL); 519 newTab_App(isDuplicate ? document_App() : NULL);
508 if (!isDuplicate) { 520 if (!isDuplicate) {
509 postCommand_App("navigate.home"); 521 postCommand_App("navigate.home");
510 } 522 }
@@ -585,6 +597,15 @@ iBool handleCommand_App(const char *cmd) {
585 refresh_App(); 597 refresh_App();
586 return iTrue; 598 return iTrue;
587 } 599 }
600 else if (equal_Command(cmd, "bookmark.add")) {
601 iDocumentWidget *doc = document_App();
602 add_Bookmarks(d->bookmarks, url_DocumentWidget(doc),
603 bookmarkTitle_DocumentWidget(doc),
604 collectNew_String(),
605 siteIcon_GmDocument(document_DocumentWidget(doc)));
606 postCommand_App("bookmarks.changed");
607 return iTrue;
608 }
588 else { 609 else {
589 return iFalse; 610 return iFalse;
590 } 611 }
diff --git a/src/app.h b/src/app.h
index cf68fb5f..9a6306b9 100644
--- a/src/app.h
+++ b/src/app.h
@@ -5,6 +5,7 @@
5#include <the_Foundation/string.h> 5#include <the_Foundation/string.h>
6#include <the_Foundation/time.h> 6#include <the_Foundation/time.h>
7 7
8iDeclareType(Bookmarks)
8iDeclareType(DocumentWidget) 9iDeclareType(DocumentWidget)
9iDeclareType(GmCerts) 10iDeclareType(GmCerts)
10iDeclareType(Visited) 11iDeclareType(Visited)
@@ -32,6 +33,7 @@ int zoom_App (void);
32 33
33iGmCerts * certs_App (void); 34iGmCerts * certs_App (void);
34iVisited * visited_App (void); 35iVisited * visited_App (void);
36iBookmarks * bookmarks_App (void);
35iDocumentWidget * document_App (void); 37iDocumentWidget * document_App (void);
36iDocumentWidget * document_Command (const char *cmd); 38iDocumentWidget * document_Command (const char *cmd);
37iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf); 39iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf);
diff --git a/src/bookmarks.c b/src/bookmarks.c
index babfc323..b023e90a 100644
--- a/src/bookmarks.c
+++ b/src/bookmarks.c
@@ -55,8 +55,17 @@ void load_Bookmarks(iBookmarks *d, const char *dirPath) {
55 const iRangecc src = range_Block(collect_Block(readAll_File(f))); 55 const iRangecc src = range_Block(collect_Block(readAll_File(f)));
56 iRangecc line = iNullRange; 56 iRangecc line = iNullRange;
57 while (nextSplit_Rangecc(&src, "\n", &line)) { 57 while (nextSplit_Rangecc(&src, "\n", &line)) {
58 /* Skip empty lines. */ {
59 iRangecc ln = line;
60 trim_Rangecc(&ln);
61 if (isEmpty_Range(&ln)) {
62 continue;
63 }
64 }
58 iBookmark bm; 65 iBookmark bm;
59 init_Bookmark(&bm); 66 init_Bookmark(&bm);
67 bm.icon = strtoul(line.start, NULL, 16);
68 line.start += 9;
60 char *endPos; 69 char *endPos;
61 initSeconds_Time(&bm.when, strtod(line.start, &endPos)); 70 initSeconds_Time(&bm.when, strtod(line.start, &endPos));
62 line.start = skipSpace_CStr(endPos); 71 line.start = skipSpace_CStr(endPos);
@@ -77,20 +86,27 @@ void save_Bookmarks(const iBookmarks *d, const char *dirPath) {
77 iString *str = collectNew_String(); 86 iString *str = collectNew_String();
78 iConstForEach(Array, i, &d->bookmarks) { 87 iConstForEach(Array, i, &d->bookmarks) {
79 const iBookmark *bm = i.value; 88 const iBookmark *bm = i.value;
80 format_String(str, "%lf %s\%s\n%s\n", seconds_Time(&bm->when), cstr_String(&bm->url), 89 format_String(str,
81 cstr_String(&bm->title), cstr_String(&bm->tags)); 90 "%08x %lf %s\n%s\n%s\n",
91 bm->icon,
92 seconds_Time(&bm->when),
93 cstr_String(&bm->url),
94 cstr_String(&bm->title),
95 cstr_String(&bm->tags));
82 writeData_File(f, cstr_String(str), size_String(str)); 96 writeData_File(f, cstr_String(str), size_String(str));
83 } 97 }
84 } 98 }
85 iRelease(f); 99 iRelease(f);
86} 100}
87 101
88void add_Bookmarks(iBookmarks *d, const iString *url, const iString *title, const iString *tags) { 102void add_Bookmarks(iBookmarks *d, const iString *url, const iString *title, const iString *tags,
103 iChar icon) {
89 iBookmark bm; 104 iBookmark bm;
90 init_Bookmark(&bm); 105 init_Bookmark(&bm);
91 set_String(&bm.url, url); 106 set_String(&bm.url, url);
92 set_String(&bm.title, title); 107 set_String(&bm.title, title);
93 set_String(&bm.tags, tags); 108 set_String(&bm.tags, tags);
109 bm.icon = icon;
94 initCurrent_Time(&bm.when); 110 initCurrent_Time(&bm.when);
95 pushBack_Array(&d->bookmarks, &bm); 111 pushBack_Array(&d->bookmarks, &bm);
96} 112}
diff --git a/src/bookmarks.h b/src/bookmarks.h
index e32f6bef..2572e3b2 100644
--- a/src/bookmarks.h
+++ b/src/bookmarks.h
@@ -11,6 +11,7 @@ struct Impl_Bookmark {
11 iString url; 11 iString url;
12 iString title; 12 iString title;
13 iString tags; 13 iString tags;
14 iChar icon;
14 iTime when; 15 iTime when;
15}; 16};
16 17
@@ -21,6 +22,8 @@ void clear_Bookmarks (iBookmarks *);
21void load_Bookmarks (iBookmarks *, const char *dirPath); 22void load_Bookmarks (iBookmarks *, const char *dirPath);
22void save_Bookmarks (const iBookmarks *, const char *dirPath); 23void save_Bookmarks (const iBookmarks *, const char *dirPath);
23 24
25void add_Bookmarks (iBookmarks *, const iString *url, const iString *title, const iString *tags, iChar icon);
26
24typedef iBool (*iBookmarksFilterFunc) (const iBookmark *); 27typedef iBool (*iBookmarksFilterFunc) (const iBookmark *);
25typedef int (*iBookmarksCompareFunc)(const iBookmark **, const iBookmark **); 28typedef int (*iBookmarksCompareFunc)(const iBookmark **, const iBookmark **);
26 29
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index ff1c577a..7e4bdc73 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -313,6 +313,27 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
313 } 313 }
314} 314}
315 315
316const iString *bookmarkTitle_DocumentWidget(const iDocumentWidget *d) {
317 iStringArray *title = iClob(new_StringArray());
318 if (!isEmpty_String(title_GmDocument(d->doc))) {
319 pushBack_StringArray(title, title_GmDocument(d->doc));
320 }
321 if (!isEmpty_String(d->titleUser)) {
322 pushBack_StringArray(title, d->titleUser);
323 }
324 else {
325 iUrl parts;
326 init_Url(&parts, d->mod.url);
327 if (!isEmpty_Range(&parts.host)) {
328 pushBackRange_StringArray(title, parts.host);
329 }
330 }
331 if (isEmpty_StringArray(title)) {
332 pushBackCStr_StringArray(title, "Blank Page");
333 }
334 return collect_String(joinCStr_StringArray(title, " \u2014 "));
335}
336
316static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { 337static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) {
317 iLabelWidget *tabButton = tabPageButton_Widget(findWidget_App("doctabs"), d); 338 iLabelWidget *tabButton = tabPageButton_Widget(findWidget_App("doctabs"), d);
318 if (!tabButton) { 339 if (!tabButton) {
diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h
index 05b8b50f..98591901 100644
--- a/src/ui/documentwidget.h
+++ b/src/ui/documentwidget.h
@@ -18,6 +18,7 @@ iHistory * history_DocumentWidget (iDocumentWidget *);
18const iString * url_DocumentWidget (const iDocumentWidget *); 18const iString * url_DocumentWidget (const iDocumentWidget *);
19iBool isRequestOngoing_DocumentWidget (const iDocumentWidget *); 19iBool isRequestOngoing_DocumentWidget (const iDocumentWidget *);
20const iGmDocument * document_DocumentWidget (const iDocumentWidget *); 20const iGmDocument * document_DocumentWidget (const iDocumentWidget *);
21const iString * bookmarkTitle_DocumentWidget (const iDocumentWidget *);
21 22
22void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); 23void setUrl_DocumentWidget (iDocumentWidget *, const iString *url);
23void setUrlFromCache_DocumentWidget (iDocumentWidget *, const iString *url, iBool isFromCache); 24void setUrlFromCache_DocumentWidget (iDocumentWidget *, const iString *url, iBool isFromCache);
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index ca10f0da..8108c797 100644
--- a/src/ui/sidebarwidget.c
+++ b/src/ui/sidebarwidget.c
@@ -2,6 +2,7 @@
2#include "labelwidget.h" 2#include "labelwidget.h"
3#include "scrollwidget.h" 3#include "scrollwidget.h"
4#include "documentwidget.h" 4#include "documentwidget.h"
5#include "bookmarks.h"
5#include "paint.h" 6#include "paint.h"
6#include "util.h" 7#include "util.h"
7#include "command.h" 8#include "command.h"
@@ -111,8 +112,23 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
111 } 112 }
112 break; 113 break;
113 } 114 }
114 case bookmarks_SidebarMode: 115 case bookmarks_SidebarMode: {
116 iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), NULL, NULL)) {
117 const iBookmark *bm = i.ptr;
118 iSidebarItem item;
119 init_SidebarItem(&item);
120 item.icon = bm->icon;
121 set_String(&item.url, &bm->url);
122 set_String(&item.label, &bm->title);
123 iDate date;
124 init_Date(&date, &bm->when);
125 iString *ds = format_Date(&date, "%Y %b %d");
126 set_String(&item.meta, ds);
127 delete_String(ds);
128 pushBack_Array(&d->items, &item);
129 }
115 break; 130 break;
131 }
116 case history_SidebarMode: 132 case history_SidebarMode:
117 break; 133 break;
118 default: 134 default:
@@ -230,6 +246,10 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, size_t index) {
230 postCommandf_App("document.goto loc:%p", head->text.start); 246 postCommandf_App("document.goto loc:%p", head->text.start);
231 break; 247 break;
232 } 248 }
249 case bookmarks_SidebarMode: {
250 postCommandf_App("open url:%s", cstr_String(&item->url));
251 break;
252 }
233 } 253 }
234} 254}
235 255
@@ -336,6 +356,9 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
336 d->scrollY = 0; 356 d->scrollY = 0;
337 updateItems_SidebarWidget_(d); 357 updateItems_SidebarWidget_(d);
338 } 358 }
359 else if (equal_Command(cmd, "bookmarks.changed")) {
360 updateItems_SidebarWidget_(d);
361 }
339 } 362 }
340 if (ev->type == SDL_MOUSEMOTION) { 363 if (ev->type == SDL_MOUSEMOTION) {
341 const iInt2 mouse = init_I2(ev->motion.x, ev->motion.y); 364 const iInt2 mouse = init_I2(ev->motion.x, ev->motion.y);
@@ -407,6 +430,27 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) {
407 mid_Rect(itemRect).y - lineHeight_Text(font) / 2), 430 mid_Rect(itemRect).y - lineHeight_Text(font) / 2),
408 fg, range_String(&item->label)); 431 fg, range_String(&item->label));
409 } 432 }
433 else if (d->mode == bookmarks_SidebarMode) {
434 const int fg =
435 isHover ? (isPressing ? black_ColorId : white_ColorId) : gray75_ColorId;
436 iString str;
437 init_String(&str);
438 appendChar_String(&str, item->icon ? item->icon : 0x1f588);
439 const iRect iconArea = { pos, init_I2(10 * gap_UI, d->itemHeight) };
440 drawCentered_Text(uiBookmarkIcon_FontId,
441 iconArea,
442 iTrue,
443 isHover && isPressing ? black_ColorId : cyan_ColorId,
444 "%s",
445 cstr_String(&str));
446 deinit_String(&str);
447 iInt2 textPos = topRight_Rect(iconArea);
448 drawRange_Text(font, textPos, fg, range_String(&item->label));
449 drawRange_Text(font,
450 addY_I2(textPos, lineHeight_Text(font)),
451 isHover ? (isPressing ? black_ColorId : cyan_ColorId) : teal_ColorId,
452 range_String(&item->meta));
453 }
410 unsetClip_Paint(&p); 454 unsetClip_Paint(&p);
411 pos.y += d->itemHeight; 455 pos.y += d->itemHeight;
412 } 456 }
diff --git a/src/ui/sidebarwidget.h b/src/ui/sidebarwidget.h
index 4d002eee..1645207e 100644
--- a/src/ui/sidebarwidget.h
+++ b/src/ui/sidebarwidget.h
@@ -13,7 +13,7 @@ enum iSidebarMode {
13iDeclareWidgetClass(SidebarWidget) 13iDeclareWidgetClass(SidebarWidget)
14iDeclareObjectConstruction(SidebarWidget) 14iDeclareObjectConstruction(SidebarWidget)
15 15
16void setMode_SidebarWidget (iSidebarWidget *, enum iSidebarMode mode); 16void setMode_SidebarWidget (iSidebarWidget *, enum iSidebarMode mode);
17 17
18enum iSidebarMode mode_SidebarWidget (const iSidebarWidget *); 18enum iSidebarMode mode_SidebarWidget (const iSidebarWidget *);
19int width_SidebarWidget (const iSidebarWidget *); 19int width_SidebarWidget (const iSidebarWidget *);
diff --git a/src/ui/window.c b/src/ui/window.c
index 112b44eb..4f59ef1a 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -72,6 +72,7 @@ static const iMenuItem navMenuItems[] = {
72 { "Open Location...", SDLK_l, KMOD_PRIMARY, "focus.set id:url" }, 72 { "Open Location...", SDLK_l, KMOD_PRIMARY, "focus.set id:url" },
73 { "---", 0, 0, NULL }, 73 { "---", 0, 0, NULL },
74 { "Copy Source Text", SDLK_c, KMOD_PRIMARY, "copy" }, 74 { "Copy Source Text", SDLK_c, KMOD_PRIMARY, "copy" },
75 { "Bookmark This Page", SDLK_d, KMOD_PRIMARY, "bookmark.add" },
75 { "---", 0, 0, NULL }, 76 { "---", 0, 0, NULL },
76 { "Toggle Sidebar", SDLK_s, KMOD_PRIMARY | KMOD_ALT, "sidebar.toggle" }, 77 { "Toggle Sidebar", SDLK_s, KMOD_PRIMARY | KMOD_ALT, "sidebar.toggle" },
77 { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, 78 { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" },
@@ -93,6 +94,8 @@ static const iMenuItem fileMenuItems[] = {
93 94
94static const iMenuItem editMenuItems[] = { 95static const iMenuItem editMenuItems[] = {
95 { "Copy Source Text", SDLK_c, KMOD_PRIMARY, "copy" }, 96 { "Copy Source Text", SDLK_c, KMOD_PRIMARY, "copy" },
97 { "---", 0, 0, NULL },
98 { "Bookmark This Page", SDLK_d, KMOD_PRIMARY, "bookmark.add" },
96}; 99};
97 100
98static const iMenuItem viewMenuItems[] = { 101static const iMenuItem viewMenuItems[] = {