diff options
-rw-r--r-- | src/ui/listwidget.c | 11 | ||||
-rw-r--r-- | src/ui/listwidget.h | 1 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 81 |
3 files changed, 72 insertions, 21 deletions
diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c index 39b9bfe5..b27107df 100644 --- a/src/ui/listwidget.c +++ b/src/ui/listwidget.c | |||
@@ -139,6 +139,10 @@ void setItemHeight_ListWidget(iListWidget *d, int itemHeight) { | |||
139 | invalidate_ListWidget(d); | 139 | invalidate_ListWidget(d); |
140 | } | 140 | } |
141 | 141 | ||
142 | int scrollBarWidth_ListWidget(const iListWidget *d) { | ||
143 | return isVisible_Widget(d->scroll) ? width_Widget(d->scroll) : 0; | ||
144 | } | ||
145 | |||
142 | int itemHeight_ListWidget(const iListWidget *d) { | 146 | int itemHeight_ListWidget(const iListWidget *d) { |
143 | return d->itemHeight; | 147 | return d->itemHeight; |
144 | } | 148 | } |
@@ -318,6 +322,7 @@ static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) { | |||
318 | return processEvent_Widget(w, ev); | 322 | return processEvent_Widget(w, ev); |
319 | } | 323 | } |
320 | 324 | ||
325 | #if 0 | ||
321 | static void drawItem_ListWidget_(const iListWidget *d, iPaint *p, size_t index, iInt2 pos) { | 326 | static void drawItem_ListWidget_(const iListWidget *d, iPaint *p, size_t index, iInt2 pos) { |
322 | const iWidget * w = constAs_Widget(d); | 327 | const iWidget * w = constAs_Widget(d); |
323 | const iRect bounds = innerBounds_Widget(w); | 328 | const iRect bounds = innerBounds_Widget(w); |
@@ -325,6 +330,7 @@ static void drawItem_ListWidget_(const iListWidget *d, iPaint *p, size_t index, | |||
325 | const iRect itemRect = { pos, init_I2(width_Rect(bounds), d->itemHeight) }; | 330 | const iRect itemRect = { pos, init_I2(width_Rect(bounds), d->itemHeight) }; |
326 | class_ListItem(item)->draw(item, p, itemRect, d); | 331 | class_ListItem(item)->draw(item, p, itemRect, d); |
327 | } | 332 | } |
333 | #endif | ||
328 | 334 | ||
329 | static const iListItem *item_ListWidget_(const iListWidget *d, size_t pos) { | 335 | static const iListItem *item_ListWidget_(const iListWidget *d, size_t pos) { |
330 | return constAt_PtrArray(&d->items, pos); | 336 | return constAt_PtrArray(&d->items, pos); |
@@ -364,6 +370,9 @@ static void draw_ListWidget_(const iListWidget *d) { | |||
364 | beginTarget_Paint(&p, buf->texture); | 370 | beginTarget_Paint(&p, buf->texture); |
365 | fillRect_Paint(&p, (iRect){ zero_I2(), d->visBuf->texSize }, bg[i]); | 371 | fillRect_Paint(&p, (iRect){ zero_I2(), d->visBuf->texSize }, bg[i]); |
366 | } | 372 | } |
373 | const iRect sbBlankRect = | ||
374 | { init_I2(d->visBuf->texSize.x - scrollBarWidth_ListWidget(d), 0), | ||
375 | init_I2(scrollBarWidth_ListWidget(d), d->itemHeight) }; | ||
367 | iConstForEach(IntSet, v, &d->invalidItems) { | 376 | iConstForEach(IntSet, v, &d->invalidItems) { |
368 | const size_t index = *v.value; | 377 | const size_t index = *v.value; |
369 | if (contains_Range(&drawItems, index)) { | 378 | if (contains_Range(&drawItems, index)) { |
@@ -373,6 +382,7 @@ static void draw_ListWidget_(const iListWidget *d) { | |||
373 | beginTarget_Paint(&p, buf->texture); | 382 | beginTarget_Paint(&p, buf->texture); |
374 | fillRect_Paint(&p, itemRect, bg[i]); | 383 | fillRect_Paint(&p, itemRect, bg[i]); |
375 | class_ListItem(item)->draw(item, &p, itemRect, d); | 384 | class_ListItem(item)->draw(item, &p, itemRect, d); |
385 | fillRect_Paint(&p, moved_Rect(sbBlankRect, init_I2(0, top_Rect(itemRect))), bg[i]); | ||
376 | } | 386 | } |
377 | } | 387 | } |
378 | /* Visible range is not fully covered. Fill in the new items. */ | 388 | /* Visible range is not fully covered. Fill in the new items. */ |
@@ -386,6 +396,7 @@ static void draw_ListWidget_(const iListWidget *d) { | |||
386 | init_I2(d->visBuf->texSize.x, d->itemHeight) }; | 396 | init_I2(d->visBuf->texSize.x, d->itemHeight) }; |
387 | fillRect_Paint(&p, itemRect, bg[i]); | 397 | fillRect_Paint(&p, itemRect, bg[i]); |
388 | class_ListItem(item)->draw(item, &p, itemRect, d); | 398 | class_ListItem(item)->draw(item, &p, itemRect, d); |
399 | fillRect_Paint(&p, moved_Rect(sbBlankRect, init_I2(0, top_Rect(itemRect))), bg[i]); | ||
389 | } | 400 | } |
390 | } | 401 | } |
391 | endTarget_Paint(&p); | 402 | endTarget_Paint(&p); |
diff --git a/src/ui/listwidget.h b/src/ui/listwidget.h index 26c1ac9e..16adf664 100644 --- a/src/ui/listwidget.h +++ b/src/ui/listwidget.h | |||
@@ -55,6 +55,7 @@ void addItem_ListWidget (iListWidget *, iAnyObject *item); | |||
55 | 55 | ||
56 | iScrollWidget * scroll_ListWidget (iListWidget *); | 56 | iScrollWidget * scroll_ListWidget (iListWidget *); |
57 | 57 | ||
58 | int scrollBarWidth_ListWidget (const iListWidget *); /* returns zero if hidden */ | ||
58 | int itemHeight_ListWidget (const iListWidget *); | 59 | int itemHeight_ListWidget (const iListWidget *); |
59 | int scrollPos_ListWidget (const iListWidget *); | 60 | int scrollPos_ListWidget (const iListWidget *); |
60 | 61 | ||
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 12c5e847..7cde5d7b 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
38 | #include "visited.h" | 38 | #include "visited.h" |
39 | 39 | ||
40 | #include <the_Foundation/intset.h> | 40 | #include <the_Foundation/intset.h> |
41 | #include <the_Foundation/regexp.h> | ||
41 | #include <the_Foundation/stringarray.h> | 42 | #include <the_Foundation/stringarray.h> |
42 | #include <SDL_clipboard.h> | 43 | #include <SDL_clipboard.h> |
43 | #include <SDL_mouse.h> | 44 | #include <SDL_mouse.h> |
@@ -113,6 +114,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
113 | d->menu = NULL; | 114 | d->menu = NULL; |
114 | switch (d->mode) { | 115 | switch (d->mode) { |
115 | case feeds_SidebarMode: { | 116 | case feeds_SidebarMode: { |
117 | const iString *docUrl = url_DocumentWidget(document_App()); | ||
116 | iDate on; | 118 | iDate on; |
117 | initCurrent_Date(&on); | 119 | initCurrent_Date(&on); |
118 | const int thisYear = on.year; | 120 | const int thisYear = on.year; |
@@ -135,6 +137,9 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
135 | } | 137 | } |
136 | } | 138 | } |
137 | iSidebarItem *item = new_SidebarItem(); | 139 | iSidebarItem *item = new_SidebarItem(); |
140 | if (equal_String(docUrl, &entry->url)) { | ||
141 | item->listItem.isSelected = iTrue; /* currently being viewed */ | ||
142 | } | ||
138 | item->icon = 0; | 143 | item->icon = 0; |
139 | const iTime visitTime = urlVisitTime_Visited(visited_App(), &entry->url); | 144 | const iTime visitTime = urlVisitTime_Visited(visited_App(), &entry->url); |
140 | if (!isValid_Time(&visitTime)) { | 145 | if (!isValid_Time(&visitTime)) { |
@@ -169,6 +174,8 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
169 | break; | 174 | break; |
170 | } | 175 | } |
171 | case bookmarks_SidebarMode: { | 176 | case bookmarks_SidebarMode: { |
177 | iRegExp *homeTag = iClob(new_RegExp("\\bhomepage\\b", caseSensitive_RegExpOption)); | ||
178 | iRegExp *subTag = iClob(new_RegExp("\\bsubscribed\\b", caseSensitive_RegExpOption)); | ||
172 | iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), cmpTitle_Bookmark_, NULL, NULL)) { | 179 | iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), cmpTitle_Bookmark_, NULL, NULL)) { |
173 | const iBookmark *bm = i.ptr; | 180 | const iBookmark *bm = i.ptr; |
174 | iSidebarItem *item = new_SidebarItem(); | 181 | iSidebarItem *item = new_SidebarItem(); |
@@ -176,7 +183,17 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
176 | item->icon = bm->icon; | 183 | item->icon = bm->icon; |
177 | set_String(&item->url, &bm->url); | 184 | set_String(&item->url, &bm->url); |
178 | set_String(&item->label, &bm->title); | 185 | set_String(&item->label, &bm->title); |
179 | set_String(&item->meta, &bm->tags); | 186 | /* Icons for special tags. */ { |
187 | iRegExpMatch m; | ||
188 | init_RegExpMatch(&m); | ||
189 | if (matchString_RegExp(subTag, &bm->tags, &m)) { | ||
190 | appendChar_String(&item->meta, 0x2605); | ||
191 | } | ||
192 | init_RegExpMatch(&m); | ||
193 | if (matchString_RegExp(homeTag, &bm->tags, &m)) { | ||
194 | appendChar_String(&item->meta, 0x1f3e0); | ||
195 | } | ||
196 | } | ||
180 | addItem_ListWidget(d->list, item); | 197 | addItem_ListWidget(d->list, item); |
181 | iRelease(item); | 198 | iRelease(item); |
182 | } | 199 | } |
@@ -185,8 +202,9 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
185 | (iMenuItem[]){ { "Edit Bookmark...", 0, 0, "bookmark.edit" }, | 202 | (iMenuItem[]){ { "Edit Bookmark...", 0, 0, "bookmark.edit" }, |
186 | { "Copy URL", 0, 0, "bookmark.copy" }, | 203 | { "Copy URL", 0, 0, "bookmark.copy" }, |
187 | { "---", 0, 0, NULL }, | 204 | { "---", 0, 0, NULL }, |
205 | { "---", 0, 0, NULL }, | ||
188 | { uiTextCaution_ColorEscape "Delete Bookmark", 0, 0, "bookmark.delete" } }, | 206 | { uiTextCaution_ColorEscape "Delete Bookmark", 0, 0, "bookmark.delete" } }, |
189 | 4); | 207 | 5); |
190 | break; | 208 | break; |
191 | } | 209 | } |
192 | case history_SidebarMode: { | 210 | case history_SidebarMode: { |
@@ -639,7 +657,8 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
639 | } | 657 | } |
640 | return iTrue; | 658 | return iTrue; |
641 | } | 659 | } |
642 | else if (equal_Command(cmd, "visited.changed") && d->mode == history_SidebarMode) { | 660 | else if (equal_Command(cmd, "visited.changed") && |
661 | (d->mode == history_SidebarMode || d->mode == feeds_SidebarMode)) { | ||
643 | updateItems_SidebarWidget_(d); | 662 | updateItems_SidebarWidget_(d); |
644 | } | 663 | } |
645 | else if (equal_Command(cmd, "bookmarks.changed") && d->mode == bookmarks_SidebarMode) { | 664 | else if (equal_Command(cmd, "bookmarks.changed") && d->mode == bookmarks_SidebarMode) { |
@@ -852,22 +871,31 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) { | |||
852 | 871 | ||
853 | static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, | 872 | static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, |
854 | const iListWidget *list) { | 873 | const iListWidget *list) { |
855 | const int font = uiContent_FontId; | 874 | const iSidebarWidget *sidebar = |
856 | const iSidebarWidget *sidebar = findParentClass_Widget(constAs_Widget(list), | 875 | findParentClass_Widget(constAs_Widget(list), &Class_SidebarWidget); |
857 | &Class_SidebarWidget); | 876 | const iBool isPressing = isMouseDown_ListWidget(list); |
858 | const iBool isPressing = isMouseDown_ListWidget(list); | 877 | const iBool isHover = |
859 | const iBool isHover = | ||
860 | isHover_Widget(constAs_Widget(list)) && constHoverItem_ListWidget(list) == d; | 878 | isHover_Widget(constAs_Widget(list)) && constHoverItem_ListWidget(list) == d; |
861 | const int itemHeight = height_Rect(itemRect); | 879 | const int scrollBarWidth = scrollBarWidth_ListWidget(list); |
880 | const int itemHeight = height_Rect(itemRect); | ||
862 | const int iconColor = | 881 | const int iconColor = |
863 | isHover ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId) : uiIcon_ColorId; | 882 | isHover ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId) : uiIcon_ColorId; |
883 | const int font = uiContent_FontId; | ||
884 | int bg = uiBackground_ColorId; | ||
864 | if (isHover) { | 885 | if (isHover) { |
865 | fillRect_Paint(p, | 886 | bg = isPressing ? uiBackgroundPressed_ColorId |
866 | itemRect, | 887 | : uiBackgroundFramelessHover_ColorId; |
867 | isPressing ? uiBackgroundPressed_ColorId | 888 | fillRect_Paint(p, itemRect, bg); |
868 | : uiBackgroundFramelessHover_ColorId); | ||
869 | } | 889 | } |
870 | iInt2 pos = itemRect.pos; | 890 | iInt2 pos = itemRect.pos; |
891 | /* Selection indicator. */ | ||
892 | if (d->listItem.isSelected && (sidebar->mode == feeds_SidebarMode || | ||
893 | sidebar->mode == identities_SidebarMode)) { | ||
894 | drawRectThickness_Paint(p, | ||
895 | adjusted_Rect(itemRect, zero_I2(), init_I2(-2 - scrollBarWidth, -1)), | ||
896 | gap_UI / 4, | ||
897 | isHover && isPressing ? uiTextPressed_ColorId : uiIcon_ColorId); | ||
898 | } | ||
871 | if (sidebar->mode == documentOutline_SidebarMode) { | 899 | if (sidebar->mode == documentOutline_SidebarMode) { |
872 | const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) | 900 | const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) |
873 | : (tmHeading1_ColorId + d->indent / (4 * gap_UI)); | 901 | : (tmHeading1_ColorId + d->indent / (4 * gap_UI)); |
@@ -949,8 +977,22 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, | |||
949 | const iRect iconArea = { addX_I2(pos, gap_UI), init_I2(7 * gap_UI, itemHeight) }; | 977 | const iRect iconArea = { addX_I2(pos, gap_UI), init_I2(7 * gap_UI, itemHeight) }; |
950 | drawCentered_Text(font, iconArea, iTrue, iconColor, "%s", cstr_String(&str)); | 978 | drawCentered_Text(font, iconArea, iTrue, iconColor, "%s", cstr_String(&str)); |
951 | deinit_String(&str); | 979 | deinit_String(&str); |
952 | iInt2 textPos = addY_I2(topRight_Rect(iconArea), (itemHeight - lineHeight_Text(font)) / 2); | 980 | const iInt2 textPos = addY_I2(topRight_Rect(iconArea), (itemHeight - lineHeight_Text(font)) / 2); |
953 | drawRange_Text(font, textPos, fg, range_String(&d->label)); | 981 | drawRange_Text(font, textPos, fg, range_String(&d->label)); |
982 | const iInt2 metaPos = | ||
983 | init_I2(right_Rect(itemRect) - advanceRange_Text(font, range_String(&d->meta)).x - | ||
984 | 2 * gap_UI - (scrollBarWidth ? scrollBarWidth - gap_UI : 0), | ||
985 | textPos.y); | ||
986 | fillRect_Paint(p, | ||
987 | init_Rect(metaPos.x, | ||
988 | top_Rect(itemRect), | ||
989 | right_Rect(itemRect) - metaPos.x, | ||
990 | height_Rect(itemRect)), | ||
991 | bg); | ||
992 | drawRange_Text(font, | ||
993 | metaPos, | ||
994 | isHover && isPressing ? fg : uiTextCaution_ColorId, | ||
995 | range_String(&d->meta)); | ||
954 | } | 996 | } |
955 | else if (sidebar->mode == history_SidebarMode) { | 997 | else if (sidebar->mode == history_SidebarMode) { |
956 | iBeginCollect(); | 998 | iBeginCollect(); |
@@ -959,7 +1001,10 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, | |||
959 | if (d->listItem.isSeparator) { | 1001 | if (d->listItem.isSeparator) { |
960 | if (!isEmpty_String(&d->meta)) { | 1002 | if (!isEmpty_String(&d->meta)) { |
961 | iInt2 drawPos = addY_I2(topLeft_Rect(itemRect), d->id); | 1003 | iInt2 drawPos = addY_I2(topLeft_Rect(itemRect), d->id); |
962 | drawHLine_Paint(p, addY_I2(drawPos, -gap_UI), width_Rect(itemRect), uiIcon_ColorId); | 1004 | drawHLine_Paint(p, |
1005 | addY_I2(drawPos, -gap_UI), | ||
1006 | width_Rect(itemRect) - scrollBarWidth, | ||
1007 | uiIcon_ColorId); | ||
963 | drawRange_Text( | 1008 | drawRange_Text( |
964 | uiLabelLarge_FontId, | 1009 | uiLabelLarge_FontId, |
965 | add_I2(drawPos, | 1010 | add_I2(drawPos, |
@@ -991,12 +1036,6 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, | |||
991 | else if (sidebar->mode == identities_SidebarMode) { | 1036 | else if (sidebar->mode == identities_SidebarMode) { |
992 | const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) | 1037 | const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) |
993 | : uiTextStrong_ColorId; | 1038 | : uiTextStrong_ColorId; |
994 | if (d->listItem.isSelected) { | ||
995 | drawRectThickness_Paint(p, | ||
996 | adjusted_Rect(itemRect, zero_I2(), init_I2(-2, -1)), | ||
997 | gap_UI / 4, | ||
998 | isHover && isPressing ? uiTextPressed_ColorId : uiIcon_ColorId); | ||
999 | } | ||
1000 | iString icon; | 1039 | iString icon; |
1001 | initUnicodeN_String(&icon, &d->icon, 1); | 1040 | initUnicodeN_String(&icon, &d->icon, 1); |
1002 | iInt2 cPos = topLeft_Rect(itemRect); | 1041 | iInt2 cPos = topLeft_Rect(itemRect); |