summaryrefslogtreecommitdiff
path: root/src/ui/sidebarwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/sidebarwidget.c')
-rw-r--r--src/ui/sidebarwidget.c607
1 files changed, 352 insertions, 255 deletions
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index a919fca6..8dada9eb 100644
--- a/src/ui/sidebarwidget.c
+++ b/src/ui/sidebarwidget.c
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
30#include "gmdocument.h" 30#include "gmdocument.h"
31#include "inputwidget.h" 31#include "inputwidget.h"
32#include "labelwidget.h" 32#include "labelwidget.h"
33#include "listwidget.h"
33#include "paint.h" 34#include "paint.h"
34#include "scrollwidget.h" 35#include "scrollwidget.h"
35#include "util.h" 36#include "util.h"
@@ -41,27 +42,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
41#include <SDL_mouse.h> 42#include <SDL_mouse.h>
42 43
43iDeclareType(SidebarItem) 44iDeclareType(SidebarItem)
45typedef iListItemClass iSidebarItemClass;
44 46
45struct Impl_SidebarItem { 47struct Impl_SidebarItem {
46 uint32_t id; 48 iListItem listItem;
47 int indent; 49 uint32_t id;
48 iChar icon; 50 int indent;
49 iString label; 51 iChar icon;
50 iString meta; 52 iString label;
51 iString url; 53 iString meta;
52 iBool isSeparator; 54 iString url;
53 iBool isSelected;
54}; 55};
55 56
56void init_SidebarItem(iSidebarItem *d) { 57void init_SidebarItem(iSidebarItem *d) {
58 init_ListItem(&d->listItem);
57 d->id = 0; 59 d->id = 0;
58 d->indent = 0; 60 d->indent = 0;
59 d->icon = 0; 61 d->icon = 0;
60 init_String(&d->label); 62 init_String(&d->label);
61 init_String(&d->meta); 63 init_String(&d->meta);
62 init_String(&d->url); 64 init_String(&d->url);
63 d->isSeparator = iFalse;
64 d->isSelected = iFalse;
65} 65}
66 66
67void deinit_SidebarItem(iSidebarItem *d) { 67void deinit_SidebarItem(iSidebarItem *d) {
@@ -70,53 +70,60 @@ void deinit_SidebarItem(iSidebarItem *d) {
70 deinit_String(&d->label); 70 deinit_String(&d->label);
71} 71}
72 72
73iDefineTypeConstruction(SidebarItem) 73static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, const iListWidget *list);
74
75iBeginDefineSubclass(SidebarItem, ListItem)
76 .draw = (iAny *) draw_SidebarItem_,
77iEndDefineSubclass(SidebarItem)
78
79iDefineObjectConstruction(SidebarItem)
74 80
75/*----------------------------------------------------------------------------------------------*/ 81/*----------------------------------------------------------------------------------------------*/
76 82
77struct Impl_SidebarWidget { 83struct Impl_SidebarWidget {
78 iWidget widget; 84 iWidget widget;
79 enum iSidebarMode mode; 85 enum iSidebarMode mode;
80 iScrollWidget *scroll; 86 iListWidget *list;
81 int scrollY; 87// iScrollWidget *scroll;
88// int scrollY;
82 int modeScroll[max_SidebarMode]; 89 int modeScroll[max_SidebarMode];
83 int width; 90 int width;
84 iLabelWidget *modeButtons[max_SidebarMode]; 91 iLabelWidget *modeButtons[max_SidebarMode];
85 int itemHeight; 92 int itemHeight;
86 int maxButtonLabelWidth; 93 int maxButtonLabelWidth;
87 iArray items; 94// iArray items;
88 size_t hoverItem; 95// size_t hoverItem;
89 iClick click; 96// iClick click;
90 iWidget *resizer; 97 iWidget *resizer;
91 SDL_Cursor *resizeCursor; 98 SDL_Cursor *resizeCursor;
92 iWidget *menu; 99 iWidget *menu;
93 iIntSet invalidItems; 100// iIntSet invalidItems;
94 SDL_Texture *visBuffer; 101// SDL_Texture *visBuffer;
95 iBool visBufferValid; 102// iBool visBufferValid;
96}; 103};
97 104
98iDefineObjectConstruction(SidebarWidget) 105iDefineObjectConstruction(SidebarWidget)
99 106
100static void invalidate_SidebarWidget_(iSidebarWidget *d) { 107//static void invalidate_SidebarWidget_(iSidebarWidget *d) {
101 d->visBufferValid = iFalse; 108// d->visBufferValid = iFalse;
102 refresh_Widget(as_Widget(d)); 109// refresh_Widget(as_Widget(d));
103 clear_IntSet(&d->invalidItems); /* all will be drawn */ 110// clear_IntSet(&d->invalidItems); /* all will be drawn */
104} 111//}
105 112
106static iBool isResizing_SidebarWidget_(const iSidebarWidget *d) { 113static iBool isResizing_SidebarWidget_(const iSidebarWidget *d) {
107 return (flags_Widget(d->resizer) & pressed_WidgetFlag) != 0; 114 return (flags_Widget(d->resizer) & pressed_WidgetFlag) != 0;
108} 115}
109 116
110static void clearItems_SidebarWidget_(iSidebarWidget *d) { 117//static void clearItems_SidebarWidget_(iSidebarWidget *d) {
111 iForEach(Array, i, &d->items) { 118// iForEach(Array, i, &d->items) {
112 deinit_SidebarItem(i.value); 119// deinit_SidebarItem(i.value);
113 } 120// }
114 clear_Array(&d->items); 121// clear_Array(&d->items);
115} 122//}
116 123
117static iRect contentBounds_SidebarWidget_(const iSidebarWidget *d) { 124static iRect contentBounds_SidebarWidget_(const iSidebarWidget *d) {
118 iRect bounds = bounds_Widget(constAs_Widget(d)); 125 iRect bounds = bounds_Widget(constAs_Widget(d));
119 const iWidget *scroll = constAs_Widget(d->scroll); 126 const iWidget *scroll = constAs_Widget(scroll_ListWidget(d->list));
120 adjustEdges_Rect(&bounds, 127 adjustEdges_Rect(&bounds,
121 as_Widget(d->modeButtons[0])->rect.size.y + gap_UI, 128 as_Widget(d->modeButtons[0])->rect.size.y + gap_UI,
122 isVisible_Widget(scroll) ? -scroll->rect.size.x : 0, 129 isVisible_Widget(scroll) ? -scroll->rect.size.x : 0,
@@ -125,57 +132,60 @@ static iRect contentBounds_SidebarWidget_(const iSidebarWidget *d) {
125 return bounds; 132 return bounds;
126} 133}
127 134
128static int scrollMax_SidebarWidget_(const iSidebarWidget *d) { 135//static int scrollMax_SidebarWidget_(const iSidebarWidget *d) {
129 return iMax(0, 136// return iMax(0,
130 (int) size_Array(&d->items) * d->itemHeight - 137// (int) numItems_ListWidget(d->list) * d->itemHeight -
131 height_Rect(contentBounds_SidebarWidget_(d))); 138// height_Rect(contentBounds_SidebarWidget_(d)));
132} 139//}
133 140
134static void updateVisible_SidebarWidget_(iSidebarWidget *d) { 141//static void updateVisible_SidebarWidget_(iSidebarWidget *d) {
135 const int contentSize = size_Array(&d->items) * d->itemHeight; 142// const int contentSize = size_Array(&d->items) * d->itemHeight;
136 const iRect bounds = contentBounds_SidebarWidget_(d); 143// const iRect bounds = contentBounds_SidebarWidget_(d);
137 setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_SidebarWidget_(d) }); 144// setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_SidebarWidget_(d) });
138 setThumb_ScrollWidget(d->scroll, 145// setThumb_ScrollWidget(d->scroll,
139 d->scrollY, 146// d->scrollY,
140 contentSize > 0 ? height_Rect(bounds_Widget(as_Widget(d->scroll))) * 147// contentSize > 0 ? height_Rect(bounds_Widget(as_Widget(d->scroll))) *
141 height_Rect(bounds) / contentSize 148// height_Rect(bounds) / contentSize
142 : 0); 149// : 0);
143} 150//}
144 151
145static int cmpTitle_Bookmark_(const iBookmark **a, const iBookmark **b) { 152static int cmpTitle_Bookmark_(const iBookmark **a, const iBookmark **b) {
146 return cmpStringCase_String(&(*a)->title, &(*b)->title); 153 return cmpStringCase_String(&(*a)->title, &(*b)->title);
147} 154}
148 155
149static void updateItems_SidebarWidget_(iSidebarWidget *d) { 156static void updateItems_SidebarWidget_(iSidebarWidget *d) {
150 clearItems_SidebarWidget_(d); 157// clearItems_SidebarWidget_(d);
158 clear_ListWidget(d->list);
151 destroy_Widget(d->menu); 159 destroy_Widget(d->menu);
152 d->menu = NULL; 160 d->menu = NULL;
153 d->hoverItem = iInvalidPos; 161// d->hoverItem = iInvalidPos;
154 switch (d->mode) { 162 switch (d->mode) {
155 case documentOutline_SidebarMode: { 163 case documentOutline_SidebarMode: {
156 const iGmDocument *doc = document_DocumentWidget(document_App()); 164 const iGmDocument *doc = document_DocumentWidget(document_App());
157 iConstForEach(Array, i, headings_GmDocument(doc)) { 165 iConstForEach(Array, i, headings_GmDocument(doc)) {
158 const iGmHeading *head = i.value; 166 const iGmHeading *head = i.value;
159 iSidebarItem item; 167 iSidebarItem *item = new_SidebarItem();
160 init_SidebarItem(&item); 168// init_SidebarItem(&item);
161 item.id = index_ArrayConstIterator(&i); 169 item->id = index_ArrayConstIterator(&i);
162 setRange_String(&item.label, head->text); 170 setRange_String(&item->label, head->text);
163 item.indent = head->level * 4 * gap_UI; 171 item->indent = head->level * 4 * gap_UI;
164 pushBack_Array(&d->items, &item); 172 addItem_ListWidget(d->list, item);
173 iRelease(item);
165 } 174 }
166 break; 175 break;
167 } 176 }
168 case bookmarks_SidebarMode: { 177 case bookmarks_SidebarMode: {
169 iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), NULL, cmpTitle_Bookmark_)) { 178 iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), NULL, cmpTitle_Bookmark_)) {
170 const iBookmark *bm = i.ptr; 179 const iBookmark *bm = i.ptr;
171 iSidebarItem item; 180 iSidebarItem *item = new_SidebarItem();
172 init_SidebarItem(&item); 181// init_SidebarItem(&item);
173 item.id = id_Bookmark(bm); 182 item->id = id_Bookmark(bm);
174 item.icon = bm->icon; 183 item->icon = bm->icon;
175 set_String(&item.url, &bm->url); 184 set_String(&item->url, &bm->url);
176 set_String(&item.label, &bm->title); 185 set_String(&item->label, &bm->title);
177 set_String(&item.meta, &bm->tags); 186 set_String(&item->meta, &bm->tags);
178 pushBack_Array(&d->items, &item); 187 addItem_ListWidget(d->list, item);
188 iRelease(item);
179 } 189 }
180 d->menu = makeMenu_Widget( 190 d->menu = makeMenu_Widget(
181 as_Widget(d), 191 as_Widget(d),
@@ -192,27 +202,32 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
192 const int thisYear = on.year; 202 const int thisYear = on.year;
193 iConstForEach(PtrArray, i, list_Visited(visited_App(), 200)) { 203 iConstForEach(PtrArray, i, list_Visited(visited_App(), 200)) {
194 const iVisitedUrl *visit = i.ptr; 204 const iVisitedUrl *visit = i.ptr;
195 iSidebarItem item; 205 iSidebarItem *item = new_SidebarItem();
196 init_SidebarItem(&item); 206// init_SidebarItem(&item);
197 set_String(&item.url, &visit->url); 207 set_String(&item->url, &visit->url);
198 iDate date; 208 iDate date;
199 init_Date(&date, &visit->when); 209 init_Date(&date, &visit->when);
200 if (date.day != on.day || date.month != on.month || date.year != on.year) { 210 if (date.day != on.day || date.month != on.month || date.year != on.year) {
201 on = date; 211 on = date;
202 /* Date separator. */ 212 /* Date separator. */
203 iSidebarItem sep; 213 iSidebarItem *sep = new_SidebarItem();
204 init_SidebarItem(&sep); 214// init_SidebarItem(&sep);
205 sep.isSeparator = iTrue; 215 sep->listItem.isSeparator = iTrue;
206 set_String(&sep.meta, 216 set_String(&sep->meta,
207 collect_String(format_Date( 217 collect_String(format_Date(
208 &date, date.year != thisYear ? "%b %d %Y" : "%b %d"))); 218 &date, date.year != thisYear ? "%b %d %Y" : "%b %d")));
209 pushBack_Array(&d->items, &sep); 219// pushBack_Array(&d->items, &sep);
220 addItem_ListWidget(d->list, sep);
221 iRelease(sep);
210 /* Date separators are two items tall. */ 222 /* Date separators are two items tall. */
211 init_SidebarItem(&sep); 223 sep = new_SidebarItem();
212 sep.isSeparator = iTrue; 224 sep->listItem.isSeparator = iTrue;
213 pushBack_Array(&d->items, &sep); 225 addItem_ListWidget(d->list, sep);
226 iRelease(sep);
214 } 227 }
215 pushBack_Array(&d->items, &item); 228// pushBack_Array(&d->items, &item);
229 addItem_ListWidget(d->list, item);
230 iRelease(item);
216 } 231 }
217 d->menu = makeMenu_Widget( 232 d->menu = makeMenu_Widget(
218 as_Widget(d), 233 as_Widget(d),
@@ -230,16 +245,16 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
230 const iString *tabUrl = url_DocumentWidget(document_App()); 245 const iString *tabUrl = url_DocumentWidget(document_App());
231 iConstForEach(PtrArray, i, identities_GmCerts(certs_App())) { 246 iConstForEach(PtrArray, i, identities_GmCerts(certs_App())) {
232 const iGmIdentity *ident = i.ptr; 247 const iGmIdentity *ident = i.ptr;
233 iSidebarItem item; 248 iSidebarItem *item = new_SidebarItem();
234 init_SidebarItem(&item); 249// init_SidebarItem(&item);
235 item.id = index_PtrArrayConstIterator(&i); 250 item->id = index_PtrArrayConstIterator(&i);
236 item.icon = ident->icon; 251 item->icon = ident->icon;
237 set_String(&item.label, collect_String(subject_TlsCertificate(ident->cert))); 252 set_String(&item->label, collect_String(subject_TlsCertificate(ident->cert)));
238 iDate until; 253 iDate until;
239 validUntil_TlsCertificate(ident->cert, &until); 254 validUntil_TlsCertificate(ident->cert, &until);
240 const iBool isActive = isUsedOn_GmIdentity(ident, tabUrl); 255 const iBool isActive = isUsedOn_GmIdentity(ident, tabUrl);
241 format_String( 256 format_String(
242 &item.meta, 257 &item->meta,
243 "%s", 258 "%s",
244 isActive ? "Using" 259 isActive ? "Using"
245 : isUsed_GmIdentity(ident) 260 : isUsed_GmIdentity(ident)
@@ -250,17 +265,19 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
250 ? "Temporary" 265 ? "Temporary"
251 : cstrCollect_String(format_Date(&until, "Expires %b %d, %Y")); 266 : cstrCollect_String(format_Date(&until, "Expires %b %d, %Y"));
252 if (isEmpty_String(&ident->notes)) { 267 if (isEmpty_String(&ident->notes)) {
253 appendFormat_String(&item.meta, "\n%s", expiry); 268 appendFormat_String(&item->meta, "\n%s", expiry);
254 } 269 }
255 else { 270 else {
256 appendFormat_String(&item.meta, 271 appendFormat_String(&item->meta,
257 " \u2014 %s\n%s%s", 272 " \u2014 %s\n%s%s",
258 expiry, 273 expiry,
259 escape_Color(uiHeading_ColorId), 274 escape_Color(uiHeading_ColorId),
260 cstr_String(&ident->notes)); 275 cstr_String(&ident->notes));
261 } 276 }
262 item.isSelected = isActive; 277 item->listItem.isSelected = isActive;
263 pushBack_Array(&d->items, &item); 278 //pushBack_Array(&d->items, &item);
279 addItem_ListWidget(d->list, item);
280 iRelease(item);
264 } 281 }
265 const iMenuItem menuItems[] = { 282 const iMenuItem menuItems[] = {
266 { "Use on This Page", 0, 0, "ident.use arg:1" }, 283 { "Use on This Page", 0, 0, "ident.use arg:1" },
@@ -280,39 +297,38 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
280 default: 297 default:
281 break; 298 break;
282 } 299 }
283 updateVisible_SidebarWidget_(d); 300 updateVisible_ListWidget(d->list);
284 invalidate_SidebarWidget_(d); 301 invalidate_ListWidget(d->list);
285} 302}
286 303
287static void scroll_SidebarWidget_(iSidebarWidget *d, int offset) { 304//static void scroll_SidebarWidget_(iSidebarWidget *d, int offset) {
288 const int oldScroll = d->scrollY; 305// const int oldScroll = d->scrollY;
289 d->scrollY += offset; 306// d->scrollY += offset;
290 if (d->scrollY < 0) { 307// if (d->scrollY < 0) {
291 d->scrollY = 0; 308// d->scrollY = 0;
292 } 309// }
293 const int scrollMax = scrollMax_SidebarWidget_(d); 310// const int scrollMax = scrollMax_SidebarWidget_(d);
294 d->scrollY = iMin(d->scrollY, scrollMax); 311// d->scrollY = iMin(d->scrollY, scrollMax);
295 if (oldScroll != d->scrollY) { 312// if (oldScroll != d->scrollY) {
296 d->hoverItem = iInvalidPos; 313// d->hoverItem = iInvalidPos;
297 updateVisible_SidebarWidget_(d); 314// updateVisible_SidebarWidget_(d);
298 invalidate_SidebarWidget_(d); 315// invalidate_SidebarWidget_(d);
299 } 316// }
300} 317//}
301 318
302void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) { 319void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) {
303 if (d->mode == mode) return; 320 if (d->mode == mode) return;
304 if (d->mode >= 0 && d->mode < max_SidebarMode) { 321 if (d->mode >= 0 && d->mode < max_SidebarMode) {
305 d->modeScroll[d->mode] = d->scrollY; /* saved for later */ 322 d->modeScroll[d->mode] = scrollPos_ListWidget(d->list); /* saved for later */
306 } 323 }
307 d->mode = mode; 324 d->mode = mode;
308 for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) { 325 for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) {
309 setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode); 326 setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode);
310 } 327 }
311 const float heights[max_SidebarMode] = { 1.333f, 1.333f, 3.5f, 1.2f }; 328 const float heights[max_SidebarMode] = { 1.333f, 1.333f, 3.5f, 1.2f };
312 d->itemHeight = heights[mode] * lineHeight_Text(uiContent_FontId); 329 setItemHeight_ListWidget(d->list, heights[mode] * lineHeight_Text(uiContent_FontId));
313 invalidate_SidebarWidget_(d);
314 /* Restore previous scroll position. */ 330 /* Restore previous scroll position. */
315 d->scrollY = d->modeScroll[mode]; 331 setScrollPos_ListWidget(d->list, d->modeScroll[mode]);
316} 332}
317 333
318enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) { 334enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) {
@@ -343,18 +359,15 @@ void init_SidebarWidget(iSidebarWidget *d) {
343 setId_Widget(w, "sidebar"); 359 setId_Widget(w, "sidebar");
344 setBackgroundColor_Widget(w, none_ColorId); 360 setBackgroundColor_Widget(w, none_ColorId);
345 setFlags_Widget(w, 361 setFlags_Widget(w,
346 hidden_WidgetFlag | hover_WidgetFlag | arrangeHorizontal_WidgetFlag | 362 hidden_WidgetFlag | arrangeVertical_WidgetFlag |
347 resizeWidthOfChildren_WidgetFlag | collapse_WidgetFlag, 363 resizeChildren_WidgetFlag | collapse_WidgetFlag,
348 iTrue); 364 iTrue);
349 d->scrollY = 0;
350 iZap(d->modeScroll); 365 iZap(d->modeScroll);
351 d->mode = -1; 366 d->mode = -1;
352 d->width = 60 * gap_UI; 367 d->width = 60 * gap_UI;
353 init_Array(&d->items, sizeof(iSidebarItem));
354 d->hoverItem = iInvalidPos;
355 init_Click(&d->click, d, SDL_BUTTON_LEFT);
356 setFlags_Widget(w, fixedWidth_WidgetFlag, iTrue); 368 setFlags_Widget(w, fixedWidth_WidgetFlag, iTrue);
357 d->maxButtonLabelWidth = 0; 369 d->maxButtonLabelWidth = 0;
370 /* TODO: Add a parent h-div for the mode buttons. */
358 for (int i = 0; i < max_SidebarMode; i++) { 371 for (int i = 0; i < max_SidebarMode; i++) {
359 d->modeButtons[i] = addChildFlags_Widget( 372 d->modeButtons[i] = addChildFlags_Widget(
360 w, 373 w,
@@ -365,8 +378,7 @@ void init_SidebarWidget(iSidebarWidget *d) {
365 iMaxi(d->maxButtonLabelWidth, 378 iMaxi(d->maxButtonLabelWidth,
366 3 * gap_UI + measure_Text(uiLabel_FontId, normalModeLabels_[i]).x); 379 3 * gap_UI + measure_Text(uiLabel_FontId, normalModeLabels_[i]).x);
367 } 380 }
368 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); 381 addChildFlags_Widget(w, iClob(d->list = new_ListWidget()), expand_WidgetFlag);
369 setThumb_ScrollWidget(d->scroll, 0, 0);
370 setMode_SidebarWidget(d, documentOutline_SidebarMode); 382 setMode_SidebarWidget(d, documentOutline_SidebarMode);
371 d->resizer = addChildFlags_Widget( 383 d->resizer = addChildFlags_Widget(
372 w, 384 w,
@@ -378,55 +390,51 @@ void init_SidebarWidget(iSidebarWidget *d) {
378 setBackgroundColor_Widget(d->resizer, none_ColorId); 390 setBackgroundColor_Widget(d->resizer, none_ColorId);
379 d->resizeCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); 391 d->resizeCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
380 d->menu = NULL; 392 d->menu = NULL;
381 init_IntSet(&d->invalidItems);
382 d->visBuffer = NULL;
383 d->visBufferValid = iFalse;
384} 393}
385 394
386void deinit_SidebarWidget(iSidebarWidget *d) { 395void deinit_SidebarWidget(iSidebarWidget *d) {
387 SDL_FreeCursor(d->resizeCursor); 396 SDL_FreeCursor(d->resizeCursor);
388 clearItems_SidebarWidget_(d); 397 //clearItems_SidebarWidget_(d);
389 deinit_Array(&d->items); 398// deinit_Array(&d->items);
390 SDL_DestroyTexture(d->visBuffer);
391} 399}
392 400
393static int visCount_SidebarWidget_(const iSidebarWidget *d) { 401//static int visCount_SidebarWidget_(const iSidebarWidget *d) {
394 return iMin(height_Rect(bounds_Widget(constAs_Widget(d))) / d->itemHeight, 402// return iMin(height_Rect(bounds_Widget(constAs_Widget(d))) / d->itemHeight,
395 (int) size_Array(&d->items)); 403// (int) size_Array(&d->items));
396} 404//}
397 405
398static iRanges visRange_SidebarWidget_(const iSidebarWidget *d) { 406//static iRanges visRange_SidebarWidget_(const iSidebarWidget *d) {
399 iRanges vis = { d->scrollY / d->itemHeight, 0 }; 407// iRanges vis = { d->scrollY / d->itemHeight, 0 };
400 vis.end = iMin(size_Array(&d->items), vis.start + visCount_SidebarWidget_(d)); 408// vis.end = iMin(size_Array(&d->items), vis.start + visCount_SidebarWidget_(d));
401 return vis; 409// return vis;
402} 410//}
403 411
404static size_t itemIndex_SidebarWidget_(const iSidebarWidget *d, iInt2 pos) { 412//static size_t itemIndex_SidebarWidget_(const iSidebarWidget *d, iInt2 pos) {
405 const iRect bounds = contentBounds_SidebarWidget_(d); 413// const iRect bounds = contentBounds_SidebarWidget_(d);
406 pos.y -= top_Rect(bounds) - d->scrollY; 414// pos.y -= top_Rect(bounds) - d->scrollY;
407 if (pos.y < 0) return iInvalidPos; 415// if (pos.y < 0) return iInvalidPos;
408 size_t index = pos.y / d->itemHeight; 416// size_t index = pos.y / d->itemHeight;
409 if (index >= size_Array(&d->items)) return iInvalidPos; 417// if (index >= size_Array(&d->items)) return iInvalidPos;
410 return index; 418// return index;
411} 419//}
412 420
413static const iSidebarItem *constHoverItem_SidebarWidget_(const iSidebarWidget *d) { 421//static const iSidebarItem *constHoverItem_SidebarWidget_(const iSidebarWidget *d) {
414 if (d->hoverItem < size_Array(&d->items)) { 422// if (d->hoverItem < size_Array(&d->items)) {
415 return constAt_Array(&d->items, d->hoverItem); 423// return constAt_Array(&d->items, d->hoverItem);
416 } 424// }
417 return NULL; 425// return NULL;
418} 426//}
419 427
420static iSidebarItem *hoverItem_SidebarWidget_(iSidebarWidget *d) { 428//static iSidebarItem *hoverItem_SidebarWidget_(iSidebarWidget *d) {
421 if (d->hoverItem < size_Array(&d->items)) { 429// if (d->hoverItem < size_Array(&d->items)) {
422 return at_Array(&d->items, d->hoverItem); 430// return at_Array(&d->items, d->hoverItem);
423 } 431// }
424 return NULL; 432// return NULL;
425} 433//}
426 434
427static const iGmIdentity *constHoverIdentity_SidebarWidget_(const iSidebarWidget *d) { 435static const iGmIdentity *constHoverIdentity_SidebarWidget_(const iSidebarWidget *d) {
428 if (d->mode == identities_SidebarMode) { 436 if (d->mode == identities_SidebarMode) {
429 const iSidebarItem *hoverItem = constHoverItem_SidebarWidget_(d); 437 const iSidebarItem *hoverItem = constHoverItem_ListWidget(d->list);
430 if (hoverItem) { 438 if (hoverItem) {
431 return identity_GmCerts(certs_App(), hoverItem->id); 439 return identity_GmCerts(certs_App(), hoverItem->id);
432 } 440 }
@@ -438,28 +446,28 @@ static iGmIdentity *hoverIdentity_SidebarWidget_(const iSidebarWidget *d) {
438 return iConstCast(iGmIdentity *, constHoverIdentity_SidebarWidget_(d)); 446 return iConstCast(iGmIdentity *, constHoverIdentity_SidebarWidget_(d));
439} 447}
440 448
441static void setHoverItem_SidebarWidget_(iSidebarWidget *d, size_t index) { 449//static void setHoverItem_SidebarWidget_(iSidebarWidget *d, size_t index) {
442 if (index < size_Array(&d->items)) { 450// if (index < size_Array(&d->items)) {
443 if (constValue_Array(&d->items, index, iSidebarItem).isSeparator) { 451// if (constValue_Array(&d->items, index, iSidebarItem).isSeparator) {
444 index = iInvalidPos; 452// index = iInvalidPos;
445 } 453// }
446 } 454// }
447 if (d->hoverItem != index) { 455// if (d->hoverItem != index) {
448 insert_IntSet(&d->invalidItems, d->hoverItem); 456// insert_IntSet(&d->invalidItems, d->hoverItem);
449 insert_IntSet(&d->invalidItems, index); 457// insert_IntSet(&d->invalidItems, index);
450 d->hoverItem = index; 458// d->hoverItem = index;
451 refresh_Widget(as_Widget(d)); 459// refresh_Widget(as_Widget(d));
452 } 460// }
453} 461//}
454 462
455static void updateMouseHover_SidebarWidget_(iSidebarWidget *d) { 463//static void updateMouseHover_SidebarWidget_(iSidebarWidget *d) {
456 const iInt2 mouse = mouseCoord_Window(get_Window()); 464// const iInt2 mouse = mouseCoord_Window(get_Window());
457 setHoverItem_SidebarWidget_(d, itemIndex_SidebarWidget_(d, mouse)); 465// setHoverItem_SidebarWidget_(d, itemIndex_SidebarWidget_(d, mouse));
458} 466//}
459 467
460static void itemClicked_SidebarWidget_(iSidebarWidget *d, size_t index) { 468static void itemClicked_SidebarWidget_(iSidebarWidget *d, const iSidebarItem *item) {
461 setFocus_Widget(NULL); 469 setFocus_Widget(NULL);
462 const iSidebarItem *item = constAt_Array(&d->items, index); 470// const iSidebarItem *item = constAt_Array(&d->items, index);
463 switch (d->mode) { 471 switch (d->mode) {
464 case documentOutline_SidebarMode: { 472 case documentOutline_SidebarMode: {
465 const iGmDocument *doc = document_DocumentWidget(document_App()); 473 const iGmDocument *doc = document_DocumentWidget(document_App());
@@ -485,7 +493,7 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, size_t index) {
485 signIn_GmCerts(certs_App(), ident, tabUrl); 493 signIn_GmCerts(certs_App(), ident, tabUrl);
486 } 494 }
487 updateItems_SidebarWidget_(d); 495 updateItems_SidebarWidget_(d);
488 updateMouseHover_SidebarWidget_(d); 496 updateMouseHover_ListWidget(d->list);
489 } 497 }
490 break; 498 break;
491 } 499 }
@@ -520,7 +528,7 @@ void setWidth_SidebarWidget(iSidebarWidget *d, int width) {
520 checkModeButtonLayout_SidebarWidget_(d); 528 checkModeButtonLayout_SidebarWidget_(d);
521 if (!isRefreshPending_App()) { 529 if (!isRefreshPending_App()) {
522 updateSize_DocumentWidget(document_App()); 530 updateSize_DocumentWidget(document_App());
523 invalidate_SidebarWidget_(d); 531 invalidate_ListWidget(d->list);
524 } 532 }
525} 533}
526 534
@@ -531,7 +539,7 @@ iBool handleBookmarkEditorCommands_SidebarWidget_(iWidget *editor, const char *c
531 const iString *title = text_InputWidget(findChild_Widget(editor, "bmed.title")); 539 const iString *title = text_InputWidget(findChild_Widget(editor, "bmed.title"));
532 const iString *url = text_InputWidget(findChild_Widget(editor, "bmed.url")); 540 const iString *url = text_InputWidget(findChild_Widget(editor, "bmed.url"));
533 const iString *tags = text_InputWidget(findChild_Widget(editor, "bmed.tags")); 541 const iString *tags = text_InputWidget(findChild_Widget(editor, "bmed.tags"));
534 const iSidebarItem *item = hoverItem_SidebarWidget_(d); 542 const iSidebarItem *item = hoverItem_ListWidget(d->list);
535 iAssert(item); /* hover item cannot have been changed */ 543 iAssert(item); /* hover item cannot have been changed */
536 iBookmark *bm = get_Bookmarks(bookmarks_App(), item->id); 544 iBookmark *bm = get_Bookmarks(bookmarks_App(), item->id);
537 set_String(&bm->title, title); 545 set_String(&bm->title, title);
@@ -550,9 +558,9 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
550 iWidget *w = as_Widget(d); 558 iWidget *w = as_Widget(d);
551 /* Handle commands. */ 559 /* Handle commands. */
552 if (isResize_UserEvent(ev)) { 560 if (isResize_UserEvent(ev)) {
553 updateVisible_SidebarWidget_(d); 561 updateVisible_ListWidget(d->list);
554 checkModeButtonLayout_SidebarWidget_(d); 562 checkModeButtonLayout_SidebarWidget_(d);
555 invalidate_SidebarWidget_(d); 563 invalidate_ListWidget(d->list);
556 } 564 }
557 else if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) { 565 else if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) {
558 const char *cmd = command_UserEvent(ev); 566 const char *cmd = command_UserEvent(ev);
@@ -580,6 +588,10 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
580 } 588 }
581 return iTrue; 589 return iTrue;
582 } 590 }
591 else if (isCommand_Widget(w, ev, "list.clicked")) {
592 itemClicked_SidebarWidget_(d, pointerLabel_Command(cmd, "item"));
593 return iTrue;
594 }
583 else if (equal_Command(cmd, "sidebar.width")) { 595 else if (equal_Command(cmd, "sidebar.width")) {
584 setWidth_SidebarWidget(d, arg_Command(cmd)); 596 setWidth_SidebarWidget(d, arg_Command(cmd));
585 return iTrue; 597 return iTrue;
@@ -590,7 +602,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
590 if (argLabel_Command(cmd, "show") && !isVisible_Widget(w)) { 602 if (argLabel_Command(cmd, "show") && !isVisible_Widget(w)) {
591 postCommand_App("sidebar.toggle arg:1"); 603 postCommand_App("sidebar.toggle arg:1");
592 } 604 }
593 scroll_SidebarWidget_(d, 0); 605 scrollOffset_ListWidget(d->list, 0);
594 return iTrue; 606 return iTrue;
595 } 607 }
596 else if (equal_Command(cmd, "sidebar.toggle")) { 608 else if (equal_Command(cmd, "sidebar.toggle")) {
@@ -600,34 +612,25 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
600 setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w)); 612 setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w));
601 if (isVisible_Widget(w)) { 613 if (isVisible_Widget(w)) {
602 w->rect.size.x = d->width; 614 w->rect.size.x = d->width;
603 invalidate_SidebarWidget_(d); 615 invalidate_ListWidget(d->list);
604 } 616 }
605 arrange_Widget(w->parent); 617 arrange_Widget(w->parent);
606 updateSize_DocumentWidget(document_App()); 618 updateSize_DocumentWidget(document_App());
607 refresh_Widget(w->parent); 619 refresh_Widget(w->parent);
608 return iTrue; 620 return iTrue;
609 } 621 }
610 else if (equal_Command(cmd, "scroll.moved")) {
611 d->scrollY = arg_Command(command_UserEvent(ev));
612 d->hoverItem = iInvalidPos;
613 invalidate_SidebarWidget_(d);
614 return iTrue;
615 }
616 else if (equal_Command(cmd, "tabs.changed") || equal_Command(cmd, "document.changed")) { 622 else if (equal_Command(cmd, "tabs.changed") || equal_Command(cmd, "document.changed")) {
617 updateItems_SidebarWidget_(d); 623 updateItems_SidebarWidget_(d);
618 } 624 }
619 else if (equal_Command(cmd, "theme.changed")) {
620 invalidate_SidebarWidget_(d);
621 }
622 else if (equal_Command(cmd, "bookmark.copy")) { 625 else if (equal_Command(cmd, "bookmark.copy")) {
623 const iSidebarItem *item = hoverItem_SidebarWidget_(d); 626 const iSidebarItem *item = hoverItem_ListWidget(d->list);
624 if (d->mode == bookmarks_SidebarMode && item) { 627 if (d->mode == bookmarks_SidebarMode && item) {
625 SDL_SetClipboardText(cstr_String(&item->url)); 628 SDL_SetClipboardText(cstr_String(&item->url));
626 } 629 }
627 return iTrue; 630 return iTrue;
628 } 631 }
629 else if (equal_Command(cmd, "bookmark.edit")) { 632 else if (equal_Command(cmd, "bookmark.edit")) {
630 const iSidebarItem *item = hoverItem_SidebarWidget_(d); 633 const iSidebarItem *item = hoverItem_ListWidget(d->list);
631 if (d->mode == bookmarks_SidebarMode && item) { 634 if (d->mode == bookmarks_SidebarMode && item) {
632 setFlags_Widget(w, disabled_WidgetFlag, iTrue); 635 setFlags_Widget(w, disabled_WidgetFlag, iTrue);
633 iWidget *dlg = makeBookmarkEditor_Widget(); 636 iWidget *dlg = makeBookmarkEditor_Widget();
@@ -641,7 +644,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
641 return iTrue; 644 return iTrue;
642 } 645 }
643 else if (equal_Command(cmd, "bookmark.delete")) { 646 else if (equal_Command(cmd, "bookmark.delete")) {
644 const iSidebarItem *item = hoverItem_SidebarWidget_(d); 647 const iSidebarItem *item = hoverItem_ListWidget(d->list);
645 if (d->mode == bookmarks_SidebarMode && item && remove_Bookmarks(bookmarks_App(), item->id)) { 648 if (d->mode == bookmarks_SidebarMode && item && remove_Bookmarks(bookmarks_App(), item->id)) {
646 postCommand_App("bookmarks.changed"); 649 postCommand_App("bookmarks.changed");
647 } 650 }
@@ -712,7 +715,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
712 return iTrue; 715 return iTrue;
713 } 716 }
714 else if (equal_Command(cmd, "ident.delete")) { 717 else if (equal_Command(cmd, "ident.delete")) {
715 iSidebarItem *item = hoverItem_SidebarWidget_(d); 718 iSidebarItem *item = hoverItem_ListWidget(d->list);
716 if (argLabel_Command(cmd, "confirm")) { 719 if (argLabel_Command(cmd, "confirm")) {
717 makeQuestion_Widget(uiTextCaution_ColorEscape "DELETE IDENTITY", 720 makeQuestion_Widget(uiTextCaution_ColorEscape "DELETE IDENTITY",
718 format_CStr("Do you really want to delete the identity\n" 721 format_CStr("Do you really want to delete the identity\n"
@@ -732,23 +735,23 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
732 return iTrue; 735 return iTrue;
733 } 736 }
734 else if (equal_Command(cmd, "history.delete")) { 737 else if (equal_Command(cmd, "history.delete")) {
735 const iSidebarItem *item = hoverItem_SidebarWidget_(d); 738 const iSidebarItem *item = hoverItem_ListWidget(d->list);
736 if (item && !isEmpty_String(&item->url)) { 739 if (item && !isEmpty_String(&item->url)) {
737 removeUrl_Visited(visited_App(), &item->url); 740 removeUrl_Visited(visited_App(), &item->url);
738 updateItems_SidebarWidget_(d); 741 updateItems_SidebarWidget_(d);
739 scroll_SidebarWidget_(d, 0); 742 scrollOffset_ListWidget(d->list, 0);
740 } 743 }
741 return iTrue; 744 return iTrue;
742 } 745 }
743 else if (equal_Command(cmd, "history.copy")) { 746 else if (equal_Command(cmd, "history.copy")) {
744 const iSidebarItem *item = hoverItem_SidebarWidget_(d); 747 const iSidebarItem *item = hoverItem_ListWidget(d->list);
745 if (item && !isEmpty_String(&item->url)) { 748 if (item && !isEmpty_String(&item->url)) {
746 SDL_SetClipboardText(cstr_String(&item->url)); 749 SDL_SetClipboardText(cstr_String(&item->url));
747 } 750 }
748 return iTrue; 751 return iTrue;
749 } 752 }
750 else if (equal_Command(cmd, "history.addbookmark")) { 753 else if (equal_Command(cmd, "history.addbookmark")) {
751 const iSidebarItem *item = hoverItem_SidebarWidget_(d); 754 const iSidebarItem *item = hoverItem_ListWidget(d->list);
752 if (!isEmpty_String(&item->url)) { 755 if (!isEmpty_String(&item->url)) {
753 makeBookmarkCreation_Widget( 756 makeBookmarkCreation_Widget(
754 &item->url, 757 &item->url,
@@ -768,53 +771,55 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
768 else { 771 else {
769 clear_Visited(visited_App()); 772 clear_Visited(visited_App());
770 updateItems_SidebarWidget_(d); 773 updateItems_SidebarWidget_(d);
771 scroll_SidebarWidget_(d, 0); 774 scrollOffset_ListWidget(d->list, 0);
772 } 775 }
773 return iTrue; 776 return iTrue;
774 } 777 }
775 } 778 }
776 if (ev->type == SDL_MOUSEMOTION && !isVisible_Widget(d->menu)) { 779 if (ev->type == SDL_MOUSEMOTION && !isVisible_Widget(d->menu)) {
777 const iInt2 mouse = init_I2(ev->motion.x, ev->motion.y); 780 const iInt2 mouse = init_I2(ev->motion.x, ev->motion.y);
778 size_t hover = iInvalidPos; 781// size_t hover = iInvalidPos;
779 if (contains_Widget(d->resizer, mouse)) { 782 if (contains_Widget(d->resizer, mouse)) {
780 setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_SIZEWE); 783 setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_SIZEWE);
781 } 784 }
782 else if (contains_Widget(constAs_Widget(d->scroll), mouse)) { 785// else if (contains_Widget(constAs_Widget(d->scroll), mouse)) {
783 setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW); 786// setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW);
784 } 787// }
785 else if (contains_Widget(w, mouse)) { 788// else if (contains_Widget(w, mouse)) {
786 hover = itemIndex_SidebarWidget_(d, mouse); 789// hover = itemIndex_SidebarWidget_(d, mouse);
787 } 790// }
788 setHoverItem_SidebarWidget_(d, hover); 791// setHoverItem_SidebarWidget_(d, hover);
789 /* Update cursor. */ 792 /* Update cursor. */
790 if (contains_Widget(w, mouse) && !contains_Widget(d->resizer, mouse) && 793 else if (contains_Widget(w, mouse)) /* && !contains_Widget(d->resizer, mouse) &&
791 !contains_Widget(constAs_Widget(d->scroll), mouse)) { 794 !contains_Widget(constAs_Widget(d->scroll), mouse))*/ {
792 const iSidebarItem *item = constHoverItem_SidebarWidget_(d); 795 const iSidebarItem *item = constHoverItem_ListWidget(d->list);
793 if (item && d->mode != identities_SidebarMode) { 796 if (item && d->mode != identities_SidebarMode) {
794 setCursor_Window(get_Window(), item->isSeparator ? SDL_SYSTEM_CURSOR_ARROW 797 setCursor_Window(get_Window(),
795 : SDL_SYSTEM_CURSOR_HAND); 798 item->listItem.isSeparator ? SDL_SYSTEM_CURSOR_ARROW
799 : SDL_SYSTEM_CURSOR_HAND);
796 } 800 }
797 else { 801 else {
798 setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW); 802 setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW);
799 } 803 }
800 } 804 }
801 } 805 }
802 if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { 806// if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) {
803#if defined (iPlatformApple) 807//#if defined (iPlatformApple)
804 /* Momentum scrolling. */ 808// /* Momentum scrolling. */
805 scroll_SidebarWidget_(d, -ev->wheel.y * get_Window()->pixelRatio); 809// scroll_SidebarWidget_(d, -ev->wheel.y * get_Window()->pixelRatio);
806#else 810//#else
807 scroll_SidebarWidget_(d, -ev->wheel.y * 3 * d->itemHeight); 811// scroll_SidebarWidget_(d, -ev->wheel.y * 3 * d->itemHeight);
808#endif 812//#endif
809 return iTrue; 813// return iTrue;
810 } 814// }
811 if (d->menu && ev->type == SDL_MOUSEBUTTONDOWN) { 815 if (d->menu && ev->type == SDL_MOUSEBUTTONDOWN) {
812 if (ev->button.button == SDL_BUTTON_RIGHT) { 816 if (ev->button.button == SDL_BUTTON_RIGHT) {
813 if (!isVisible_Widget(d->menu)) { 817 if (!isVisible_Widget(d->menu)) {
814 setHoverItem_SidebarWidget_( 818 updateMouseHover_ListWidget(d->list);
815 d, itemIndex_SidebarWidget_(d, init_I2(ev->button.x, ev->button.y))); 819// setHoverItem_ListWidget(
820// d->list, itemIndex_ListWidget(d->list, init_I2(ev->button.x, ev->button.y)));
816 } 821 }
817 if (d->hoverItem != iInvalidPos || isVisible_Widget(d->menu)) { 822 if (constHoverItem_ListWidget(d->list) || isVisible_Widget(d->menu)) {
818 /* Update menu items. */ 823 /* Update menu items. */
819 if (d->mode == identities_SidebarMode) { 824 if (d->mode == identities_SidebarMode) {
820 const iGmIdentity *ident = constHoverIdentity_SidebarWidget_(d); 825 const iGmIdentity *ident = constHoverIdentity_SidebarWidget_(d);
@@ -845,41 +850,27 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
845 } 850 }
846 } 851 }
847 processContextMenuEvent_Widget(d->menu, ev, {}); 852 processContextMenuEvent_Widget(d->menu, ev, {});
848 switch (processEvent_Click(&d->click, ev)) { 853// switch (processEvent_Click(&d->click, ev)) {
849 case started_ClickResult: 854// case started_ClickResult:
850 //invalidate_SidebarWidget_(d); 855// //invalidate_SidebarWidget_(d);
851 break; 856// break;
852 case finished_ClickResult: 857// case finished_ClickResult:
853 if (contains_Rect(contentBounds_SidebarWidget_(d), pos_Click(&d->click)) && 858// if (contains_Rect(contentBounds_SidebarWidget_(d), pos_Click(&d->click)) &&
854 d->hoverItem != iInvalidSize) { 859// d->hoverItem != iInvalidSize) {
855 itemClicked_SidebarWidget_(d, d->hoverItem); 860// itemClicked_SidebarWidget_(d, d->hoverItem);
856 } 861// }
857// invalidate_SidebarWidget_(d); 862// // invalidate_SidebarWidget_(d);
858 break; 863// break;
859 default: 864// default:
860 break; 865// break;
861 } 866// }
862 return processEvent_Widget(w, ev); 867 return processEvent_Widget(w, ev);
863} 868}
864 869
865static void allocVisBuffer_SidebarWidget_(iSidebarWidget *d) {
866 const iInt2 size = contentBounds_SidebarWidget_(d).size;
867 if (!d->visBuffer || !isEqual_I2(size_SDLTexture(d->visBuffer), size)) {
868 if (d->visBuffer) {
869 SDL_DestroyTexture(d->visBuffer);
870 }
871 d->visBuffer = SDL_CreateTexture(renderer_Window(get_Window()),
872 SDL_PIXELFORMAT_RGBA8888,
873 SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET,
874 size.x,
875 size.y);
876 SDL_SetTextureBlendMode(d->visBuffer, SDL_BLENDMODE_NONE);
877 d->visBufferValid = iFalse;
878 }
879}
880
881static void draw_SidebarWidget_(const iSidebarWidget *d) { 870static void draw_SidebarWidget_(const iSidebarWidget *d) {
882 const iWidget *w = constAs_Widget(d); 871 const iWidget *w = constAs_Widget(d);
872 const iRect bounds = bounds_Widget(w);
873#if 0
883 const iRect bounds = contentBounds_SidebarWidget_(d); 874 const iRect bounds = contentBounds_SidebarWidget_(d);
884 const iBool isPressing = d->click.isActive && contains_Rect(bounds, pos_Click(&d->click)); 875 const iBool isPressing = d->click.isActive && contains_Rect(bounds, pos_Click(&d->click));
885 iPaint p; 876 iPaint p;
@@ -1033,18 +1024,124 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) {
1033 } 1024 }
1034 endTarget_Paint(&p); 1025 endTarget_Paint(&p);
1035 /* Update state. */ { 1026 /* Update state. */ {
1036 iSidebarWidget *m = iConstCast(iSidebarWidget *, d); 1027// iSidebarWidget *m = iConstCast(iSidebarWidget *, d);
1037 m->visBufferValid = iTrue; 1028// m->visBufferValid = iTrue;
1038 clear_IntSet(&m->invalidItems); 1029// clear_IntSet(&m->invalidItems);
1039 } 1030 }
1040 } 1031 }
1041 SDL_RenderCopy( 1032 SDL_RenderCopy(
1042 renderer_Window(get_Window()), d->visBuffer, NULL, (const SDL_Rect *) &bounds); 1033 renderer_Window(get_Window()), d->visBuffer, NULL, (const SDL_Rect *) &bounds);
1034#endif
1035 iPaint p;
1036 init_Paint(&p);
1043 draw_Widget(w); 1037 draw_Widget(w);
1044 drawVLine_Paint(&p, 1038 drawVLine_Paint(
1045 addX_I2(topRight_Rect(bounds_Widget(w)), -1), 1039 &p, addX_I2(topRight_Rect(bounds), -1), height_Rect(bounds), uiSeparator_ColorId);
1046 height_Rect(bounds_Widget(w)), 1040}
1047 uiSeparator_ColorId); 1041
1042static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,
1043 const iListWidget *list) {
1044 const iSidebarWidget *sidebar = (const iSidebarWidget *) constAs_Widget(list)->parent;
1045 const iBool isPressing = isMouseDown_ListWidget(list);
1046 const int font = uiContent_FontId;
1047 const iBool isHover =
1048 isHover_Widget(constAs_Widget(list)) && constHoverItem_ListWidget(list) == d;
1049 const int itemHeight = height_Rect(itemRect);
1050 const int iconColor =
1051 isHover ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId) : uiIcon_ColorId;
1052 if (isHover && !d->listItem.isSeparator) {
1053 fillRect_Paint(p,
1054 itemRect,
1055 isPressing ? uiBackgroundPressed_ColorId
1056 : uiBackgroundFramelessHover_ColorId);
1057 }
1058 iInt2 pos = itemRect.pos;
1059 if (sidebar->mode == documentOutline_SidebarMode) {
1060 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId)
1061 : (tmHeading1_ColorId + d->indent / (4 * gap_UI));
1062 drawRange_Text(font,
1063 init_I2(pos.x + 3 * gap_UI + d->indent,
1064 mid_Rect(itemRect).y - lineHeight_Text(font) / 2),
1065 fg,
1066 range_String(&d->label));
1067 }
1068 else if (sidebar->mode == bookmarks_SidebarMode) {
1069 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId)
1070 : uiText_ColorId;
1071 iString str;
1072 init_String(&str);
1073 appendChar_String(&str, d->icon ? d->icon : 0x1f588);
1074 const iRect iconArea = { addX_I2(pos, gap_UI), init_I2(7 * gap_UI, itemHeight) };
1075 drawCentered_Text(font, iconArea, iTrue, iconColor, "%s", cstr_String(&str));
1076 deinit_String(&str);
1077 iInt2 textPos = addY_I2(topRight_Rect(iconArea), (itemHeight - lineHeight_Text(font)) / 2);
1078 drawRange_Text(font, textPos, fg, range_String(&d->label));
1079 }
1080 else if (sidebar->mode == history_SidebarMode) {
1081 iBeginCollect();
1082 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId)
1083 : uiText_ColorId;
1084 if (d->listItem.isSeparator) {
1085 if (!isEmpty_String(&d->meta)) {
1086 unsetClip_Paint(p);
1087 iInt2 drawPos = addY_I2(topLeft_Rect(itemRect), itemHeight * 0.666f);
1088 drawHLine_Paint(p, drawPos, width_Rect(itemRect), uiIcon_ColorId);
1089 drawRange_Text(
1090 default_FontId,
1091 add_I2(drawPos,
1092 init_I2(3 * gap_UI, (itemHeight - lineHeight_Text(default_FontId)) / 2)),
1093 uiIcon_ColorId,
1094 range_String(&d->meta));
1095 }
1096 }
1097 else {
1098 iUrl parts;
1099 init_Url(&parts, &d->url);
1100 const iBool isGemini = equalCase_Rangecc(parts.scheme, "gemini");
1101 draw_Text(font,
1102 add_I2(topLeft_Rect(itemRect),
1103 init_I2(3 * gap_UI, (itemHeight - lineHeight_Text(font)) / 2)),
1104 fg,
1105 "%s%s%s%s%s%s",
1106 isGemini ? "" : cstr_Rangecc(parts.scheme),
1107 isGemini ? "" : "://",
1108 escape_Color(isHover ? (isPressing ? uiTextPressed_ColorId
1109 : uiTextFramelessHover_ColorId)
1110 : uiTextStrong_ColorId),
1111 cstr_Rangecc(parts.host),
1112 escape_Color(fg),
1113 cstr_Rangecc(parts.path));
1114 }
1115 iEndCollect();
1116 }
1117 else if (sidebar->mode == identities_SidebarMode) {
1118 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId)
1119 : uiTextStrong_ColorId;
1120 if (d->listItem.isSelected) {
1121 drawRectThickness_Paint(p,
1122 adjusted_Rect(itemRect, zero_I2(), init_I2(-2, -1)),
1123 gap_UI / 4,
1124 isHover && isPressing ? uiTextPressed_ColorId : uiIcon_ColorId);
1125 }
1126 iString icon;
1127 initUnicodeN_String(&icon, &d->icon, 1);
1128 iInt2 cPos = topLeft_Rect(itemRect);
1129 addv_I2(&cPos,
1130 init_I2(3 * gap_UI,
1131 (itemHeight - lineHeight_Text(default_FontId) * 2 - lineHeight_Text(font)) /
1132 2));
1133 const int metaFg = isHover ? permanent_ColorId | (isPressing ? uiTextPressed_ColorId
1134 : uiTextFramelessHover_ColorId)
1135 : uiText_ColorId;
1136 drawRange_Text(
1137 font, cPos, d->listItem.isSelected ? iconColor : metaFg, range_String(&icon));
1138 deinit_String(&icon);
1139 drawRange_Text(font, add_I2(cPos, init_I2(6 * gap_UI, 0)), fg, range_String(&d->label));
1140 drawRange_Text(default_FontId,
1141 add_I2(cPos, init_I2(6 * gap_UI, lineHeight_Text(font))),
1142 metaFg,
1143 range_String(&d->meta));
1144 }
1048} 1145}
1049 1146
1050iBeginDefineSubclass(SidebarWidget, Widget) 1147iBeginDefineSubclass(SidebarWidget, Widget)