summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-12-04 09:04:49 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-12-04 09:04:49 +0200
commitc8089179f84a2cabd84a47a800aaadd9af8bd9b8 (patch)
tree5270a456534b801f1f5fb0c600f9cd34fbbd7a28
parent9fde33bb6f8149cc8dee7ac626b8b56f9f1cd14e (diff)
Added a second sidebar; removed hover outline
A sidebar on the right is a better solution than a kludgy non-interactive special-purpose outline that appears when hoving the mouse on the document scrollbar.
-rw-r--r--src/app.c16
-rw-r--r--src/ui/documentwidget.c4
-rw-r--r--src/ui/sidebarwidget.c182
-rw-r--r--src/ui/sidebarwidget.h7
-rw-r--r--src/ui/util.c4
-rw-r--r--src/ui/widget.c13
-rw-r--r--src/ui/widget.h9
-rw-r--r--src/ui/window.c14
8 files changed, 148 insertions, 101 deletions
diff --git a/src/app.c b/src/app.c
index b799b627..cf8a7119 100644
--- a/src/app.c
+++ b/src/app.c
@@ -139,7 +139,8 @@ const iString *dateStr_(const iDate *date) {
139 139
140static iString *serializePrefs_App_(const iApp *d) { 140static iString *serializePrefs_App_(const iApp *d) {
141 iString *str = new_String(); 141 iString *str = new_String();
142 const iSidebarWidget *sidebar = findWidget_App("sidebar"); 142 const iSidebarWidget *sidebar = findWidget_App("sidebar");
143 const iSidebarWidget *sidebar2 = findWidget_App("sidebar2");
143 appendFormat_String(str, "window.retain arg:%d\n", d->prefs.retainWindowSize); 144 appendFormat_String(str, "window.retain arg:%d\n", d->prefs.retainWindowSize);
144 if (d->prefs.retainWindowSize) { 145 if (d->prefs.retainWindowSize) {
145 const iBool isMaximized = (SDL_GetWindowFlags(d->window->win) & SDL_WINDOW_MAXIMIZED) != 0; 146 const iBool isMaximized = (SDL_GetWindowFlags(d->window->win) & SDL_WINDOW_MAXIMIZED) != 0;
@@ -150,6 +151,7 @@ static iString *serializePrefs_App_(const iApp *d) {
150 h = d->window->lastRect.size.y; 151 h = d->window->lastRect.size.y;
151 appendFormat_String(str, "window.setrect width:%d height:%d coord:%d %d\n", w, h, x, y); 152 appendFormat_String(str, "window.setrect width:%d height:%d coord:%d %d\n", w, h, x, y);
152 appendFormat_String(str, "sidebar.width arg:%d\n", width_SidebarWidget(sidebar)); 153 appendFormat_String(str, "sidebar.width arg:%d\n", width_SidebarWidget(sidebar));
154 appendFormat_String(str, "sidebar2.width arg:%d\n", width_SidebarWidget(sidebar2));
153 /* On macOS, maximization should be applied at creation time or the window will take 155 /* On macOS, maximization should be applied at creation time or the window will take
154 a moment to animate to its maximized size. */ 156 a moment to animate to its maximized size. */
155#if !defined (iPlatformApple) 157#if !defined (iPlatformApple)
@@ -160,10 +162,16 @@ static iString *serializePrefs_App_(const iApp *d) {
160 iUnused(isMaximized); 162 iUnused(isMaximized);
161#endif 163#endif
162 } 164 }
163 if (isVisible_Widget(sidebar)) { 165 /* Sidebars. */ {
164 appendCStr_String(str, "sidebar.toggle\n"); 166 if (isVisible_Widget(sidebar)) {
167 appendCStr_String(str, "sidebar.toggle\n");
168 }
169 appendFormat_String(str, "sidebar.mode arg:%d\n", mode_SidebarWidget(sidebar));
170 if (isVisible_Widget(sidebar2)) {
171 appendCStr_String(str, "sidebar2.toggle\n");
172 }
173 appendFormat_String(str, "sidebar2.mode arg:%d\n", mode_SidebarWidget(sidebar2));
165 } 174 }
166 appendFormat_String(str, "sidebar.mode arg:%d\n", mode_SidebarWidget(sidebar));
167 appendFormat_String(str, "uiscale arg:%f\n", uiScale_Window(d->window)); 175 appendFormat_String(str, "uiscale arg:%f\n", uiScale_Window(d->window));
168 appendFormat_String(str, "prefs.dialogtab arg:%d\n", d->prefs.dialogTab); 176 appendFormat_String(str, "prefs.dialogtab arg:%d\n", d->prefs.dialogTab);
169 appendFormat_String(str, "font.set arg:%d\n", d->prefs.font); 177 appendFormat_String(str, "font.set arg:%d\n", d->prefs.font);
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index a6cc8187..0d931080 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -2909,6 +2909,7 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) {
2909 iMax(0, scrollMax_DocumentWidget_(d) - value_Anim(&d->scrollY)))), 2909 iMax(0, scrollMax_DocumentWidget_(d) - value_Anim(&d->scrollY)))),
2910 tmQuoteIcon_ColorId); 2910 tmQuoteIcon_ColorId);
2911 } 2911 }
2912#if 0
2912 /* Outline on the right side. */ 2913 /* Outline on the right side. */
2913 const float outlineOpacity = value_Anim(&d->outlineOpacity); 2914 const float outlineOpacity = value_Anim(&d->outlineOpacity);
2914 if (prefs_App()->hoverOutline && !isEmpty_Array(&d->outline) && outlineOpacity > 0.0f) { 2915 if (prefs_App()->hoverOutline && !isEmpty_Array(&d->outline) && outlineOpacity > 0.0f) {
@@ -2964,8 +2965,9 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) {
2964 setOpacity_Text(1.0f); 2965 setOpacity_Text(1.0f);
2965 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); 2966 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE);
2966 } 2967 }
2968#endif
2967 unsetClip_Paint(&p); 2969 unsetClip_Paint(&p);
2968 } 2970}
2969 2971
2970static void drawPlayers_DocumentWidget_(const iDocumentWidget *d, iPaint *p) { 2972static void drawPlayers_DocumentWidget_(const iDocumentWidget *d, iPaint *p) {
2971 iConstForEach(PtrArray, i, &d->visiblePlayers) { 2973 iConstForEach(PtrArray, i, &d->visiblePlayers) {
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index 5baa08f7..121e9a7c 100644
--- a/src/ui/sidebarwidget.c
+++ b/src/ui/sidebarwidget.c
@@ -84,7 +84,9 @@ iDefineObjectConstruction(SidebarItem)
84 84
85struct Impl_SidebarWidget { 85struct Impl_SidebarWidget {
86 iWidget widget; 86 iWidget widget;
87 enum iSidebarSide side;
87 enum iSidebarMode mode; 88 enum iSidebarMode mode;
89 iString cmdPrefix;
88 iWidget * blank; 90 iWidget * blank;
89 iListWidget * list; 91 iListWidget * list;
90 int modeScroll[max_SidebarMode]; 92 int modeScroll[max_SidebarMode];
@@ -92,12 +94,11 @@ struct Impl_SidebarWidget {
92 int maxButtonLabelWidth; 94 int maxButtonLabelWidth;
93 int width; 95 int width;
94 iWidget * resizer; 96 iWidget * resizer;
95 SDL_Cursor * resizeCursor;
96 iWidget * menu; 97 iWidget * menu;
97 iSidebarItem * contextItem; /* list item accessed in the context menu */ 98 iSidebarItem * contextItem; /* list item accessed in the context menu */
98}; 99};
99 100
100iDefineObjectConstruction(SidebarWidget) 101iDefineObjectConstructionArgs(SidebarWidget, (enum iSidebarSide side), side)
101 102
102static iBool isResizing_SidebarWidget_(const iSidebarWidget *d) { 103static iBool isResizing_SidebarWidget_(const iSidebarWidget *d) {
103 return (flags_Widget(d->resizer) & pressed_WidgetFlag) != 0; 104 return (flags_Widget(d->resizer) & pressed_WidgetFlag) != 0;
@@ -408,16 +409,19 @@ static const char *tightModeLabels_[max_SidebarMode] = {
408 "\U0001f5b9", 409 "\U0001f5b9",
409}; 410};
410 411
411void init_SidebarWidget(iSidebarWidget *d) { 412void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) {
412 iWidget *w = as_Widget(d); 413 iWidget *w = as_Widget(d);
413 init_Widget(w); 414 init_Widget(w);
414 setId_Widget(w, "sidebar"); 415 setId_Widget(w, side == left_SideBarSide ? "sidebar" : "sidebar2");
416 initCopy_String(&d->cmdPrefix, id_Widget(w));
417 appendChar_String(&d->cmdPrefix, '.');
415 setBackgroundColor_Widget(w, none_ColorId); 418 setBackgroundColor_Widget(w, none_ColorId);
416 setFlags_Widget(w, 419 setFlags_Widget(w,
417 collapse_WidgetFlag | hidden_WidgetFlag | arrangeHorizontal_WidgetFlag | 420 collapse_WidgetFlag | hidden_WidgetFlag | arrangeHorizontal_WidgetFlag |
418 resizeWidthOfChildren_WidgetFlag, 421 resizeWidthOfChildren_WidgetFlag,
419 iTrue); 422 iTrue);
420 iZap(d->modeScroll); 423 iZap(d->modeScroll);
424 d->side = side;
421 d->mode = -1; 425 d->mode = -1;
422 d->width = 60 * gap_UI; 426 d->width = 60 * gap_UI;
423 setFlags_Widget(w, fixedWidth_WidgetFlag, iTrue); 427 setFlags_Widget(w, fixedWidth_WidgetFlag, iTrue);
@@ -428,8 +432,9 @@ void init_SidebarWidget(iSidebarWidget *d) {
428 for (int i = 0; i < max_SidebarMode; i++) { 432 for (int i = 0; i < max_SidebarMode; i++) {
429 d->modeButtons[i] = addChildFlags_Widget( 433 d->modeButtons[i] = addChildFlags_Widget(
430 buttons, 434 buttons,
431 iClob( 435 iClob(new_LabelWidget(
432 new_LabelWidget(tightModeLabels_[i], format_CStr("sidebar.mode arg:%d", i))), 436 tightModeLabels_[i],
437 format_CStr("%s.mode arg:%d", cstr_String(id_Widget(w)), i))),
433 frameless_WidgetFlag); 438 frameless_WidgetFlag);
434 d->maxButtonLabelWidth = 439 d->maxButtonLabelWidth =
435 iMaxi(d->maxButtonLabelWidth, 440 iMaxi(d->maxButtonLabelWidth,
@@ -448,21 +453,22 @@ void init_SidebarWidget(iSidebarWidget *d) {
448 addChildFlags_Widget(content, iClob(d->blank), resizeChildren_WidgetFlag); 453 addChildFlags_Widget(content, iClob(d->blank), resizeChildren_WidgetFlag);
449 addChildFlags_Widget(vdiv, iClob(content), expand_WidgetFlag); 454 addChildFlags_Widget(vdiv, iClob(content), expand_WidgetFlag);
450 setMode_SidebarWidget(d, bookmarks_SidebarMode); 455 setMode_SidebarWidget(d, bookmarks_SidebarMode);
451 d->resizer = addChildFlags_Widget( 456 d->resizer =
452 w, 457 addChildFlags_Widget(w,
453 iClob(new_Widget()), 458 iClob(new_Widget()),
454 hover_WidgetFlag | commandOnClick_WidgetFlag | fixedWidth_WidgetFlag | 459 hover_WidgetFlag | commandOnClick_WidgetFlag | fixedWidth_WidgetFlag |
455 resizeToParentHeight_WidgetFlag | moveToParentRightEdge_WidgetFlag); 460 resizeToParentHeight_WidgetFlag |
456 setId_Widget(d->resizer, "sidebar.grab"); 461 (side == left_SideBarSide ? moveToParentRightEdge_WidgetFlag
462 : moveToParentLeftEdge_WidgetFlag));
463 setId_Widget(d->resizer, side == left_SideBarSide ? "sidebar.grab" : "sidebar2.grab");
457 d->resizer->rect.size.x = gap_UI; 464 d->resizer->rect.size.x = gap_UI;
458 setBackgroundColor_Widget(d->resizer, none_ColorId); 465 setBackgroundColor_Widget(d->resizer, none_ColorId);
459 d->resizeCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
460 d->menu = NULL; 466 d->menu = NULL;
461 addAction_Widget(w, SDLK_r, KMOD_PRIMARY | KMOD_SHIFT, "feeds.refresh"); 467 addAction_Widget(w, SDLK_r, KMOD_PRIMARY | KMOD_SHIFT, "feeds.refresh");
462} 468}
463 469
464void deinit_SidebarWidget(iSidebarWidget *d) { 470void deinit_SidebarWidget(iSidebarWidget *d) {
465 SDL_FreeCursor(d->resizeCursor); 471 deinit_String(&d->cmdPrefix);
466} 472}
467 473
468static const iGmIdentity *constHoverIdentity_SidebarWidget_(const iSidebarWidget *d) { 474static const iGmIdentity *constHoverIdentity_SidebarWidget_(const iSidebarWidget *d) {
@@ -594,6 +600,43 @@ iBool handleBookmarkEditorCommands_SidebarWidget_(iWidget *editor, const char *c
594 return iFalse; 600 return iFalse;
595} 601}
596 602
603static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char *cmd) {
604 iWidget *w = as_Widget(d);
605 if (equal_Command(cmd, "width")) {
606 setWidth_SidebarWidget(d, arg_Command(cmd));
607 return iTrue;
608 }
609 else if (equal_Command(cmd, "mode")) {
610 const iBool wasChanged = setMode_SidebarWidget(d, arg_Command(cmd));
611 updateItems_SidebarWidget_(d);
612 if ((argLabel_Command(cmd, "show") && !isVisible_Widget(w)) ||
613 (argLabel_Command(cmd, "toggle") && (!isVisible_Widget(w) || !wasChanged))) {
614 postCommandf_App("%s.toggle", cstr_String(id_Widget(w)));
615 }
616 scrollOffset_ListWidget(d->list, 0);
617 return iTrue;
618 }
619 else if (equal_Command(cmd, "toggle")) {
620 if (arg_Command(cmd) && isVisible_Widget(w)) {
621 return iTrue;
622 }
623 setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w));
624 if (isVisible_Widget(w)) {
625 w->rect.size.x = d->width;
626 invalidate_ListWidget(d->list);
627 }
628 arrange_Widget(w->parent);
629 updateSize_DocumentWidget(document_App());
630 if (isVisible_Widget(w)) {
631 updateItems_SidebarWidget_(d);
632 scrollOffset_ListWidget(d->list, 0);
633 }
634 refresh_Widget(w->parent);
635 return iTrue;
636 }
637 return iFalse;
638}
639
597static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) { 640static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) {
598 iWidget *w = as_Widget(d); 641 iWidget *w = as_Widget(d);
599 /* Handle commands. */ 642 /* Handle commands. */
@@ -602,7 +645,27 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
602 } 645 }
603 else if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) { 646 else if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) {
604 const char *cmd = command_UserEvent(ev); 647 const char *cmd = command_UserEvent(ev);
605 if (isCommand_Widget(w, ev, "mouse.clicked")) { 648 if (equal_Command(cmd, "tabs.changed") || equal_Command(cmd, "document.changed")) {
649 updateItems_SidebarWidget_(d);
650 scrollOffset_ListWidget(d->list, 0);
651 }
652 else if (equal_Command(cmd, "visited.changed") &&
653 (d->mode == history_SidebarMode || d->mode == feeds_SidebarMode)) {
654 updateItems_SidebarWidget_(d);
655 }
656 else if (equal_Command(cmd, "bookmarks.changed") && (d->mode == bookmarks_SidebarMode ||
657 d->mode == feeds_SidebarMode)) {
658 updateItems_SidebarWidget_(d);
659 }
660 else if (equal_Command(cmd, "idents.changed") && d->mode == identities_SidebarMode) {
661 updateItems_SidebarWidget_(d);
662 }
663 else if (startsWith_CStr(cmd, cstr_String(&d->cmdPrefix))) {
664 if (handleSidebarCommand_SidebarWidget_(d, cmd + size_String(&d->cmdPrefix))) {
665 return iTrue;
666 }
667 }
668 else if (isCommand_Widget(w, ev, "mouse.clicked")) {
606 if (argLabel_Command(cmd, "button") == SDL_BUTTON_LEFT) { 669 if (argLabel_Command(cmd, "button") == SDL_BUTTON_LEFT) {
607 if (arg_Command(cmd)) { 670 if (arg_Command(cmd)) {
608 setFlags_Widget(d->resizer, pressed_WidgetFlag, iTrue); 671 setFlags_Widget(d->resizer, pressed_WidgetFlag, iTrue);
@@ -624,7 +687,13 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
624 else if (isCommand_Widget(w, ev, "mouse.moved")) { 687 else if (isCommand_Widget(w, ev, "mouse.moved")) {
625 if (isResizing_SidebarWidget_(d)) { 688 if (isResizing_SidebarWidget_(d)) {
626 const iInt2 local = localCoord_Widget(w, coord_Command(cmd)); 689 const iInt2 local = localCoord_Widget(w, coord_Command(cmd));
627 setWidth_SidebarWidget(d, local.x + d->resizer->rect.size.x / 2); 690 const int resMid = d->resizer->rect.size.x / 2;
691 setWidth_SidebarWidget(
692 d,
693 (d->side == left_SideBarSide
694 ? local.x
695 : (rootSize_Window(get_Window()).x - coord_Command(cmd).x)) +
696 resMid);
628 } 697 }
629 return iTrue; 698 return iTrue;
630 } 699 }
@@ -638,50 +707,14 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
638 else if (isCommand_Widget(w, ev, "menu.closed")) { 707 else if (isCommand_Widget(w, ev, "menu.closed")) {
639 setFlags_Widget(as_Widget(d->list), disabled_WidgetFlag, iFalse); 708 setFlags_Widget(as_Widget(d->list), disabled_WidgetFlag, iFalse);
640 } 709 }
641 else if (equal_Command(cmd, "sidebar.width")) { 710 else if (isCommand_Widget(w, ev, "bookmark.copy")) {
642 setWidth_SidebarWidget(d, arg_Command(cmd));
643 return iTrue;
644 }
645 else if (equal_Command(cmd, "sidebar.mode")) {
646 const iBool wasChanged = setMode_SidebarWidget(d, arg_Command(cmd));
647 updateItems_SidebarWidget_(d);
648 if ((argLabel_Command(cmd, "show") && !isVisible_Widget(w)) ||
649 (argLabel_Command(cmd, "toggle") && (!isVisible_Widget(w) || !wasChanged))) {
650 postCommand_App("sidebar.toggle");
651 }
652 scrollOffset_ListWidget(d->list, 0);
653 return iTrue;
654 }
655 else if (equal_Command(cmd, "sidebar.toggle")) {
656 if (arg_Command(cmd) && isVisible_Widget(w)) {
657 return iTrue;
658 }
659 setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w));
660 if (isVisible_Widget(w)) {
661 w->rect.size.x = d->width;
662 invalidate_ListWidget(d->list);
663 }
664 arrange_Widget(w->parent);
665 updateSize_DocumentWidget(document_App());
666 if (isVisible_Widget(w)) {
667 updateItems_SidebarWidget_(d);
668 scrollOffset_ListWidget(d->list, 0);
669 }
670 refresh_Widget(w->parent);
671 return iTrue;
672 }
673 else if (equal_Command(cmd, "tabs.changed") || equal_Command(cmd, "document.changed")) {
674 updateItems_SidebarWidget_(d);
675 scrollOffset_ListWidget(d->list, 0);
676 }
677 else if (equal_Command(cmd, "bookmark.copy")) {
678 const iSidebarItem *item = d->contextItem; 711 const iSidebarItem *item = d->contextItem;
679 if (d->mode == bookmarks_SidebarMode && item) { 712 if (d->mode == bookmarks_SidebarMode && item) {
680 SDL_SetClipboardText(cstr_String(&item->url)); 713 SDL_SetClipboardText(cstr_String(&item->url));
681 } 714 }
682 return iTrue; 715 return iTrue;
683 } 716 }
684 else if (equal_Command(cmd, "bookmark.edit")) { 717 else if (isCommand_Widget(w, ev, "bookmark.edit")) {
685 const iSidebarItem *item = d->contextItem; 718 const iSidebarItem *item = d->contextItem;
686 if (d->mode == bookmarks_SidebarMode && item) { 719 if (d->mode == bookmarks_SidebarMode && item) {
687 setFlags_Widget(w, disabled_WidgetFlag, iTrue); 720 setFlags_Widget(w, disabled_WidgetFlag, iTrue);
@@ -695,7 +728,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
695 } 728 }
696 return iTrue; 729 return iTrue;
697 } 730 }
698 else if (equal_Command(cmd, "bookmark.tag")) { 731 else if (isCommand_Widget(w, ev, "bookmark.tag")) {
699 const iSidebarItem *item = d->contextItem; 732 const iSidebarItem *item = d->contextItem;
700 if (d->mode == bookmarks_SidebarMode && item) { 733 if (d->mode == bookmarks_SidebarMode && item) {
701 const char *tag = cstr_String(string_Command(cmd, "tag")); 734 const char *tag = cstr_String(string_Command(cmd, "tag"));
@@ -713,7 +746,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
713 } 746 }
714 return iTrue; 747 return iTrue;
715 } 748 }
716 else if (equal_Command(cmd, "bookmark.delete")) { 749 else if (isCommand_Widget(w, ev, "bookmark.delete")) {
717 const iSidebarItem *item = d->contextItem; 750 const iSidebarItem *item = d->contextItem;
718 if (d->mode == bookmarks_SidebarMode && item && remove_Bookmarks(bookmarks_App(), item->id)) { 751 if (d->mode == bookmarks_SidebarMode && item && remove_Bookmarks(bookmarks_App(), item->id)) {
719 removeEntries_Feeds(item->id); 752 removeEntries_Feeds(item->id);
@@ -721,10 +754,6 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
721 } 754 }
722 return iTrue; 755 return iTrue;
723 } 756 }
724 else if (equal_Command(cmd, "visited.changed") &&
725 (d->mode == history_SidebarMode || d->mode == feeds_SidebarMode)) {
726 updateItems_SidebarWidget_(d);
727 }
728 else if (equal_Command(cmd, "feeds.update.finished") && d->mode == feeds_SidebarMode) { 757 else if (equal_Command(cmd, "feeds.update.finished") && d->mode == feeds_SidebarMode) {
729 updateItems_SidebarWidget_(d); 758 updateItems_SidebarWidget_(d);
730 } 759 }
@@ -742,11 +771,11 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
742 else if (startsWith_CStr(cmd, "feed.entry.") && d->mode == feeds_SidebarMode) { 771 else if (startsWith_CStr(cmd, "feed.entry.") && d->mode == feeds_SidebarMode) {
743 const iSidebarItem *item = d->contextItem; 772 const iSidebarItem *item = d->contextItem;
744 if (item) { 773 if (item) {
745 if (equal_Command(cmd, "feed.entry.opentab")) { 774 if (isCommand_Widget(w, ev, "feed.entry.opentab")) {
746 postCommandf_App("open newtab:1 url:%s", cstr_String(&item->url)); 775 postCommandf_App("open newtab:1 url:%s", cstr_String(&item->url));
747 return iTrue; 776 return iTrue;
748 } 777 }
749 if (equal_Command(cmd, "feed.entry.toggleread")) { 778 if (isCommand_Widget(w, ev, "feed.entry.toggleread")) {
750 iVisited *vis = visited_App(); 779 iVisited *vis = visited_App();
751 if (containsUrl_Visited(vis, &item->url)) { 780 if (containsUrl_Visited(vis, &item->url)) {
752 removeUrl_Visited(vis, &item->url); 781 removeUrl_Visited(vis, &item->url);
@@ -757,18 +786,18 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
757 postCommand_App("visited.changed"); 786 postCommand_App("visited.changed");
758 return iTrue; 787 return iTrue;
759 } 788 }
760 if (equal_Command(cmd, "feed.entry.bookmark")) { 789 if (isCommand_Widget(w, ev, "feed.entry.bookmark")) {
761 makeBookmarkCreation_Widget(&item->url, &item->label, item->icon); 790 makeBookmarkCreation_Widget(&item->url, &item->label, item->icon);
762 postCommand_App("focus.set id:bmed.title"); 791 postCommand_App("focus.set id:bmed.title");
763 return iTrue; 792 return iTrue;
764 } 793 }
765 iBookmark *feedBookmark = get_Bookmarks(bookmarks_App(), item->id); 794 iBookmark *feedBookmark = get_Bookmarks(bookmarks_App(), item->id);
766 if (feedBookmark) { 795 if (feedBookmark) {
767 if (equal_Command(cmd, "feed.entry.openfeed")) { 796 if (isCommand_Widget(w, ev, "feed.entry.openfeed")) {
768 postCommandf_App("open url:%s", cstr_String(&feedBookmark->url)); 797 postCommandf_App("open url:%s", cstr_String(&feedBookmark->url));
769 return iTrue; 798 return iTrue;
770 } 799 }
771 if (equal_Command(cmd, "feed.entry.edit")) { 800 if (isCommand_Widget(w, ev, "feed.entry.edit")) {
772 setFlags_Widget(w, disabled_WidgetFlag, iTrue); 801 setFlags_Widget(w, disabled_WidgetFlag, iTrue);
773 iWidget *dlg = makeBookmarkEditor_Widget(); 802 iWidget *dlg = makeBookmarkEditor_Widget();
774 setText_InputWidget(findChild_Widget(dlg, "bmed.title"), &feedBookmark->title); 803 setText_InputWidget(findChild_Widget(dlg, "bmed.title"), &feedBookmark->title);
@@ -778,7 +807,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
778 setFocus_Widget(findChild_Widget(dlg, "bmed.title")); 807 setFocus_Widget(findChild_Widget(dlg, "bmed.title"));
779 return iTrue; 808 return iTrue;
780 } 809 }
781 if (equal_Command(cmd, "feed.entry.unsubscribe")) { 810 if (isCommand_Widget(w, ev, "feed.entry.unsubscribe")) {
782 if (arg_Command(cmd)) { 811 if (arg_Command(cmd)) {
783 removeTag_Bookmark(feedBookmark, "subscribed"); 812 removeTag_Bookmark(feedBookmark, "subscribed");
784 removeEntries_Feeds(id_Bookmark(feedBookmark)); 813 removeEntries_Feeds(id_Bookmark(feedBookmark));
@@ -791,7 +820,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
791 cstr_String(&feedBookmark->title)), 820 cstr_String(&feedBookmark->title)),
792 (const char *[]){ "Cancel", 821 (const char *[]){ "Cancel",
793 uiTextCaution_ColorEscape "Unsubscribe" }, 822 uiTextCaution_ColorEscape "Unsubscribe" },
794 (const char *[]){ "cancel", "feed.entry.unsubscribe arg:1" }, 823 (const char *[]){ "cancel", "feed.entry.unsubscribe arg:1" }, /* FIXME: which sidebar */
795 2); 824 2);
796 } 825 }
797 return iTrue; 826 return iTrue;
@@ -799,13 +828,6 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
799 } 828 }
800 } 829 }
801 } 830 }
802 else if (equal_Command(cmd, "bookmarks.changed") && (d->mode == bookmarks_SidebarMode ||
803 d->mode == feeds_SidebarMode)) {
804 updateItems_SidebarWidget_(d);
805 }
806 else if (equal_Command(cmd, "idents.changed") && d->mode == identities_SidebarMode) {
807 updateItems_SidebarWidget_(d);
808 }
809 else if (isCommand_Widget(w, ev, "ident.use")) { 831 else if (isCommand_Widget(w, ev, "ident.use")) {
810 iGmIdentity * ident = menuIdentity_SidebarWidget_(d); 832 iGmIdentity * ident = menuIdentity_SidebarWidget_(d);
811 const iString *tabUrl = url_DocumentWidget(document_App()); 833 const iString *tabUrl = url_DocumentWidget(document_App());
@@ -843,7 +865,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
843 } 865 }
844 return iTrue; 866 return iTrue;
845 } 867 }
846 else if (equal_Command(cmd, "ident.setnotes")) { 868 else if (isCommand_Widget(w, ev, "ident.setnotes")) {
847 iGmIdentity *ident = pointerLabel_Command(cmd, "ident"); 869 iGmIdentity *ident = pointerLabel_Command(cmd, "ident");
848 if (ident) { 870 if (ident) {
849 setCStr_String(&ident->notes, suffixPtr_Command(cmd, "value")); 871 setCStr_String(&ident->notes, suffixPtr_Command(cmd, "value"));
@@ -864,7 +886,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
864 } 886 }
865 return iTrue; 887 return iTrue;
866 } 888 }
867 else if (equal_Command(cmd, "ident.delete")) { 889 else if (isCommand_Widget(w, ev, "ident.delete")) {
868 iSidebarItem *item = d->contextItem; 890 iSidebarItem *item = d->contextItem;
869 if (argLabel_Command(cmd, "confirm")) { 891 if (argLabel_Command(cmd, "confirm")) {
870 makeQuestion_Widget(uiTextCaution_ColorEscape "DELETE IDENTITY", 892 makeQuestion_Widget(uiTextCaution_ColorEscape "DELETE IDENTITY",
@@ -876,7 +898,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
876 (const char *[]){ "Cancel", 898 (const char *[]){ "Cancel",
877 uiTextCaution_ColorEscape 899 uiTextCaution_ColorEscape
878 "Delete Identity and Files" }, 900 "Delete Identity and Files" },
879 (const char *[]){ "cancel", "ident.delete confirm:0" }, 901 (const char *[]){ "cancel", "ident.delete confirm:0" }, /* FIXME: which sidebar */
880 2); 902 2);
881 return iTrue; 903 return iTrue;
882 } 904 }
@@ -884,7 +906,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
884 updateItems_SidebarWidget_(d); 906 updateItems_SidebarWidget_(d);
885 return iTrue; 907 return iTrue;
886 } 908 }
887 else if (equal_Command(cmd, "history.delete")) { 909 else if (isCommand_Widget(w, ev, "history.delete")) {
888 if (d->contextItem && !isEmpty_String(&d->contextItem->url)) { 910 if (d->contextItem && !isEmpty_String(&d->contextItem->url)) {
889 removeUrl_Visited(visited_App(), &d->contextItem->url); 911 removeUrl_Visited(visited_App(), &d->contextItem->url);
890 updateItems_SidebarWidget_(d); 912 updateItems_SidebarWidget_(d);
@@ -892,14 +914,14 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
892 } 914 }
893 return iTrue; 915 return iTrue;
894 } 916 }
895 else if (equal_Command(cmd, "history.copy")) { 917 else if (isCommand_Widget(w, ev, "history.copy")) {
896 const iSidebarItem *item = d->contextItem; 918 const iSidebarItem *item = d->contextItem;
897 if (item && !isEmpty_String(&item->url)) { 919 if (item && !isEmpty_String(&item->url)) {
898 SDL_SetClipboardText(cstr_String(&item->url)); 920 SDL_SetClipboardText(cstr_String(&item->url));
899 } 921 }
900 return iTrue; 922 return iTrue;
901 } 923 }
902 else if (equal_Command(cmd, "history.addbookmark")) { 924 else if (isCommand_Widget(w, ev, "history.addbookmark")) {
903 const iSidebarItem *item = d->contextItem; 925 const iSidebarItem *item = d->contextItem;
904 if (!isEmpty_String(&item->url)) { 926 if (!isEmpty_String(&item->url)) {
905 makeBookmarkCreation_Widget( 927 makeBookmarkCreation_Widget(
diff --git a/src/ui/sidebarwidget.h b/src/ui/sidebarwidget.h
index 0d4ed9c8..fa74e049 100644
--- a/src/ui/sidebarwidget.h
+++ b/src/ui/sidebarwidget.h
@@ -33,8 +33,13 @@ enum iSidebarMode {
33 max_SidebarMode 33 max_SidebarMode
34}; 34};
35 35
36enum iSidebarSide {
37 left_SideBarSide,
38 right_SideBarSide,
39};
40
36iDeclareWidgetClass(SidebarWidget) 41iDeclareWidgetClass(SidebarWidget)
37iDeclareObjectConstruction(SidebarWidget) 42iDeclareObjectConstructionArgs(SidebarWidget, enum iSidebarSide side)
38 43
39iBool setMode_SidebarWidget (iSidebarWidget *, enum iSidebarMode mode); 44iBool setMode_SidebarWidget (iSidebarWidget *, enum iSidebarMode mode);
40 45
diff --git a/src/ui/util.c b/src/ui/util.c
index d9997004..ef69b5f1 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -1031,8 +1031,8 @@ iWidget *makePreferences_Widget(void) {
1031 appendTwoColumnPage_(tabs, "General", '1', &headings, &values); 1031 appendTwoColumnPage_(tabs, "General", '1', &headings, &values);
1032 addChild_Widget(headings, iClob(makeHeading_Widget("Downloads folder:"))); 1032 addChild_Widget(headings, iClob(makeHeading_Widget("Downloads folder:")));
1033 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.downloads"); 1033 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.downloads");
1034 addChild_Widget(headings, iClob(makeHeading_Widget("Outline on scrollbar:"))); 1034 /*addChild_Widget(headings, iClob(makeHeading_Widget("Outline on scrollbar:")));
1035 addChild_Widget(values, iClob(makeToggle_Widget("prefs.hoveroutline"))); 1035 addChild_Widget(values, iClob(makeToggle_Widget("prefs.hoveroutline")));*/
1036 addChild_Widget(headings, iClob(makeHeading_Widget("Smooth scrolling:"))); 1036 addChild_Widget(headings, iClob(makeHeading_Widget("Smooth scrolling:")));
1037 addChild_Widget(values, iClob(makeToggle_Widget("prefs.smoothscroll"))); 1037 addChild_Widget(values, iClob(makeToggle_Widget("prefs.smoothscroll")));
1038 addChild_Widget(headings, iClob(makeHeading_Widget("Load image on scroll:"))); 1038 addChild_Widget(headings, iClob(makeHeading_Widget("Load image on scroll:")));
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 4d50da38..f3e73ee7 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -263,10 +263,13 @@ void arrange_Widget(iWidget *d) {
263 setFlags_Widget(d, wasCollapsed_WidgetFlag, iTrue); 263 setFlags_Widget(d, wasCollapsed_WidgetFlag, iTrue);
264 return; 264 return;
265 } 265 }
266 if (d->flags & moveToParentRightEdge_WidgetFlag) { 266 if (d->flags & moveToParentLeftEdge_WidgetFlag) {
267 d->rect.pos.x = d->padding[0];
268 }
269 else if (d->flags & moveToParentRightEdge_WidgetFlag) {
267 d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); 270 d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect);
268 } 271 }
269 if (d->flags & centerHorizontal_WidgetFlag) { 272 else if (d->flags & centerHorizontal_WidgetFlag) {
270 centerHorizontal_Widget_(d); 273 centerHorizontal_Widget_(d);
271 } 274 }
272 if (d->flags & resizeToParentWidth_WidgetFlag) { 275 if (d->flags & resizeToParentWidth_WidgetFlag) {
@@ -388,7 +391,8 @@ void arrange_Widget(iWidget *d) {
388 continue; 391 continue;
389 } 392 }
390 if (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag)) { 393 if (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag)) {
391 if (child->flags & moveToParentRightEdge_WidgetFlag) { 394 if (child->flags &
395 (moveToParentLeftEdge_WidgetFlag | moveToParentRightEdge_WidgetFlag)) {
392 continue; /* Not part of the sequential arrangement .*/ 396 continue; /* Not part of the sequential arrangement .*/
393 } 397 }
394 child->rect.pos = pos; 398 child->rect.pos = pos;
@@ -422,7 +426,8 @@ void arrange_Widget(iWidget *d) {
422 iForEach(ObjectList, j, d->children) { 426 iForEach(ObjectList, j, d->children) {
423 iWidget *child = as_Widget(j.object); 427 iWidget *child = as_Widget(j.object);
424 if (child->flags & 428 if (child->flags &
425 (resizeToParentWidth_WidgetFlag | moveToParentRightEdge_WidgetFlag)) { 429 (resizeToParentWidth_WidgetFlag | moveToParentLeftEdge_WidgetFlag |
430 moveToParentRightEdge_WidgetFlag)) {
426 arrange_Widget(child); 431 arrange_Widget(child);
427 } 432 }
428 } 433 }
diff --git a/src/ui/widget.h b/src/ui/widget.h
index 278ae081..f06a6607 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -85,10 +85,11 @@ enum iWidgetFlag {
85/* 64-bit extended flags */ 85/* 64-bit extended flags */
86#define wasCollapsed_WidgetFlag iBit64(32) 86#define wasCollapsed_WidgetFlag iBit64(32)
87#define centerHorizontal_WidgetFlag iBit64(33) 87#define centerHorizontal_WidgetFlag iBit64(33)
88#define moveToParentRightEdge_WidgetFlag iBit64(34) 88#define moveToParentLeftEdge_WidgetFlag iBit64(34)
89#define wrapText_WidgetFlag iBit64(35) 89#define moveToParentRightEdge_WidgetFlag iBit64(35)
90#define borderTop_WidgetFlag iBit64(36) 90#define wrapText_WidgetFlag iBit64(36)
91#define overflowScrollable_WidgetFlag iBit64(37) 91#define borderTop_WidgetFlag iBit64(37)
92#define overflowScrollable_WidgetFlag iBit64(38)
92 93
93enum iWidgetAddPos { 94enum iWidgetAddPos {
94 back_WidgetAddPos, 95 back_WidgetAddPos,
diff --git a/src/ui/window.c b/src/ui/window.c
index 199e35a7..53300d24 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -109,7 +109,8 @@ static const iMenuItem navMenuItems_[] = {
109 { "---", 0, 0, NULL }, 109 { "---", 0, 0, NULL },
110 { "Show Feed Entries", 0, 0, "!open url:about:feeds" }, 110 { "Show Feed Entries", 0, 0, "!open url:about:feeds" },
111 { "---", 0, 0, NULL }, 111 { "---", 0, 0, NULL },
112 { "Toggle Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, 112 { "Toggle Left Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },
113 { "Toggle Right Sidebar", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },
113 { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, 114 { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" },
114 { "Zoom Out", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" }, 115 { "Zoom Out", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" },
115 { "Reset Zoom", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" }, 116 { "Reset Zoom", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" },
@@ -144,7 +145,8 @@ static const iMenuItem viewMenuItems_[] = {
144 { "Show History", '3', KMOD_PRIMARY, "sidebar.mode arg:2 toggle:1" }, 145 { "Show History", '3', KMOD_PRIMARY, "sidebar.mode arg:2 toggle:1" },
145 { "Show Identities", '4', KMOD_PRIMARY, "sidebar.mode arg:3 toggle:1" }, 146 { "Show Identities", '4', KMOD_PRIMARY, "sidebar.mode arg:3 toggle:1" },
146 { "Show Page Outline", '5', KMOD_PRIMARY, "sidebar.mode arg:4 toggle:1" }, 147 { "Show Page Outline", '5', KMOD_PRIMARY, "sidebar.mode arg:4 toggle:1" },
147 { "Toggle Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, 148 { "Toggle Left Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },
149 { "Toggle Right Sidebar", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },
148 { "---", 0, 0, NULL }, 150 { "---", 0, 0, NULL },
149 { "Go Back", SDLK_LEFTBRACKET, KMOD_PRIMARY, "navigate.back" }, 151 { "Go Back", SDLK_LEFTBRACKET, KMOD_PRIMARY, "navigate.back" },
150 { "Go Forward", SDLK_RIGHTBRACKET, KMOD_PRIMARY, "navigate.forward" }, 152 { "Go Forward", SDLK_RIGHTBRACKET, KMOD_PRIMARY, "navigate.forward" },
@@ -459,10 +461,12 @@ static void setupUserInterface_Window(iWindow *d) {
459 addChild_Widget(buttons, iClob(newIcon_LabelWidget("\u2795", 0, 0, "tabs.new"))), 461 addChild_Widget(buttons, iClob(newIcon_LabelWidget("\u2795", 0, 0, "tabs.new"))),
460 "newtab"); 462 "newtab");
461 } 463 }
462 /* Side bar. */ { 464 /* Side bars. */ {
463 iWidget *content = findChild_Widget(d->root, "tabs.content"); 465 iWidget *content = findChild_Widget(d->root, "tabs.content");
464 iSidebarWidget *sidebar = new_SidebarWidget(); 466 iSidebarWidget *sidebar1 = new_SidebarWidget(left_SideBarSide);
465 addChildPos_Widget(content, iClob(sidebar), front_WidgetAddPos); 467 addChildPos_Widget(content, iClob(sidebar1), front_WidgetAddPos);
468 iSidebarWidget *sidebar2 = new_SidebarWidget(right_SideBarSide);
469 addChildPos_Widget(content, iClob(sidebar2), back_WidgetAddPos);
466 } 470 }
467 /* Lookup results. */ { 471 /* Lookup results. */ {
468 iLookupWidget *lookup = new_LookupWidget(); 472 iLookupWidget *lookup = new_LookupWidget();