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.c200
1 files changed, 150 insertions, 50 deletions
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index 86410d11..27646b22 100644
--- a/src/ui/sidebarwidget.c
+++ b/src/ui/sidebarwidget.c
@@ -148,6 +148,65 @@ static iLabelWidget *addActionButton_SidebarWidget_(iSidebarWidget *d, const cha
148 return btn; 148 return btn;
149} 149}
150 150
151static iGmIdentity *menuIdentity_SidebarWidget_(const iSidebarWidget *d) {
152 if (d->mode == identities_SidebarMode) {
153 if (d->contextItem) {
154 return identity_GmCerts(certs_App(), d->contextItem->id);
155 }
156 }
157 return NULL;
158}
159
160static void updateContextMenu_SidebarWidget_(iSidebarWidget *d) {
161 if (d->mode != identities_SidebarMode) {
162 return;
163 }
164 iArray *items = collectNew_Array(sizeof(iMenuItem));
165 pushBackN_Array(items, (iMenuItem[]){
166 { person_Icon " ${ident.use}", 0, 0, "ident.use arg:1" },
167 { close_Icon " ${ident.stopuse}", 0, 0, "ident.use arg:0" },
168 { close_Icon " ${ident.stopuse.all}", 0, 0, "ident.use arg:0 clear:1" },
169 { "---", 0, 0, NULL },
170 { edit_Icon " ${menu.edit.notes}", 0, 0, "ident.edit" },
171 { "${ident.fingerprint}", 0, 0, "ident.fingerprint" },
172 { export_Icon " ${ident.export}", 0, 0, "ident.export" },
173 { "---", 0, 0, NULL },
174 { delete_Icon " " uiTextCaution_ColorEscape "${ident.delete}", 0, 0, "ident.delete confirm:1" },
175 }, 9);
176 /* Used URLs. */
177 const iGmIdentity *ident = menuIdentity_SidebarWidget_(d);
178 if (ident) {
179 size_t insertPos = 3;
180 if (!isEmpty_StringSet(ident->useUrls)) {
181 insert_Array(items, insertPos++, &(iMenuItem){ "---", 0, 0, NULL });
182 }
183 const iString *docUrl = url_DocumentWidget(document_App());
184 iBool usedOnCurrentPage = iFalse;
185 iConstForEach(StringSet, i, ident->useUrls) {
186 const iString *url = i.value;
187 usedOnCurrentPage |= equalCase_String(docUrl, url);
188 iRangecc urlStr = range_String(url);
189 if (startsWith_Rangecc(urlStr, "gemini://")) {
190 urlStr.start += 9; /* omit the default scheme */
191 }
192 if (endsWith_Rangecc(urlStr, "/")) {
193 urlStr.end--; /* looks cleaner */
194 }
195 insert_Array(items,
196 insertPos++,
197 &(iMenuItem){ format_CStr(globe_Icon " %s", cstr_Rangecc(urlStr)),
198 0,
199 0,
200 format_CStr("!open url:%s", cstr_String(url)) });
201 }
202 if (!usedOnCurrentPage) {
203 remove_Array(items, 1);
204 }
205 }
206 destroy_Widget(d->menu);
207 d->menu = makeMenu_Widget(as_Widget(d), data_Array(items), size_Array(items));
208}
209
151static void updateItems_SidebarWidget_(iSidebarWidget *d) { 210static void updateItems_SidebarWidget_(iSidebarWidget *d) {
152 clear_ListWidget(d->list); 211 clear_ListWidget(d->list);
153 releaseChildren_Widget(d->blank); 212 releaseChildren_Widget(d->blank);
@@ -375,13 +434,14 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
375 } 434 }
376 case identities_SidebarMode: { 435 case identities_SidebarMode: {
377 const iString *tabUrl = url_DocumentWidget(document_App()); 436 const iString *tabUrl = url_DocumentWidget(document_App());
437 const iRangecc tabHost = urlHost_String(tabUrl);
378 isEmpty = iTrue; 438 isEmpty = iTrue;
379 iConstForEach(PtrArray, i, identities_GmCerts(certs_App())) { 439 iConstForEach(PtrArray, i, identities_GmCerts(certs_App())) {
380 const iGmIdentity *ident = i.ptr; 440 const iGmIdentity *ident = i.ptr;
381 iSidebarItem *item = new_SidebarItem(); 441 iSidebarItem *item = new_SidebarItem();
382 item->id = (uint32_t) index_PtrArrayConstIterator(&i); 442 item->id = (uint32_t) index_PtrArrayConstIterator(&i);
383 item->icon = ident->icon; 443 item->icon = 0x1f464; /* person */
384 set_String(&item->label, collect_String(subject_TlsCertificate(ident->cert))); 444 set_String(&item->label, name_GmIdentity(ident));
385 iDate until; 445 iDate until;
386 validUntil_TlsCertificate(ident->cert, &until); 446 validUntil_TlsCertificate(ident->cert, &until);
387 const iBool isActive = isUsedOn_GmIdentity(ident, tabUrl); 447 const iBool isActive = isUsedOn_GmIdentity(ident, tabUrl);
@@ -406,6 +466,9 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
406 cstr_String(&ident->notes)); 466 cstr_String(&ident->notes));
407 } 467 }
408 item->listItem.isSelected = isActive; 468 item->listItem.isSelected = isActive;
469 if (isUsedOnDomain_GmIdentity(ident, tabHost)) {
470 item->indent = 1; /* will be highlighted */
471 }
409 addItem_ListWidget(d->list, item); 472 addItem_ListWidget(d->list, item);
410 iRelease(item); 473 iRelease(item);
411 isEmpty = iFalse; 474 isEmpty = iFalse;
@@ -415,11 +478,11 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
415 addActionButton_SidebarWidget_(d, add_Icon " ${sidebar.action.ident.new}", "ident.new", 0); 478 addActionButton_SidebarWidget_(d, add_Icon " ${sidebar.action.ident.new}", "ident.new", 0);
416 addActionButton_SidebarWidget_(d, "${sidebar.action.ident.import}", "ident.import", 0); 479 addActionButton_SidebarWidget_(d, "${sidebar.action.ident.import}", "ident.import", 0);
417 } 480 }
481 /*
418 const iMenuItem menuItems[] = { 482 const iMenuItem menuItems[] = {
419 { person_Icon " ${ident.use}", 0, 0, "ident.use arg:1" }, 483 { person_Icon " ${ident.use}", 0, 0, "ident.use arg:1" },
420 { close_Icon " ${ident.stopuse}", 0, 0, "ident.use arg:0" }, 484 { close_Icon " ${ident.stopuse}", 0, 0, "ident.use arg:0" },
421 { close_Icon " ${ident.stopuse.all}", 0, 0, "ident.use arg:0 clear:1" }, 485 { close_Icon " ${ident.stopuse.all}", 0, 0, "ident.use arg:0 clear:1" },
422 { "${ident.showuse}", 0, 0, "ident.showuse" },
423 { "---", 0, 0, NULL }, 486 { "---", 0, 0, NULL },
424 { edit_Icon " ${menu.edit.notes}", 0, 0, "ident.edit" }, 487 { edit_Icon " ${menu.edit.notes}", 0, 0, "ident.edit" },
425 { "${ident.fingerprint}", 0, 0, "ident.fingerprint" }, 488 { "${ident.fingerprint}", 0, 0, "ident.fingerprint" },
@@ -429,6 +492,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
429 { delete_Icon " " uiTextCaution_ColorEscape "${ident.delete}", 0, 0, "ident.delete confirm:1" }, 492 { delete_Icon " " uiTextCaution_ColorEscape "${ident.delete}", 0, 0, "ident.delete confirm:1" },
430 }; 493 };
431 d->menu = makeMenu_Widget(as_Widget(d), menuItems, iElemCount(menuItems)); 494 d->menu = makeMenu_Widget(as_Widget(d), menuItems, iElemCount(menuItems));
495 */
432 break; 496 break;
433 } 497 }
434 default: 498 default:
@@ -697,20 +761,11 @@ static const iGmIdentity *constHoverIdentity_SidebarWidget_(const iSidebarWidget
697 return NULL; 761 return NULL;
698} 762}
699 763
700static iGmIdentity *menuIdentity_SidebarWidget_(const iSidebarWidget *d) {
701 if (d->mode == identities_SidebarMode) {
702 if (d->contextItem) {
703 return identity_GmCerts(certs_App(), d->contextItem->id);
704 }
705 }
706 return NULL;
707}
708
709static iGmIdentity *hoverIdentity_SidebarWidget_(const iSidebarWidget *d) { 764static iGmIdentity *hoverIdentity_SidebarWidget_(const iSidebarWidget *d) {
710 return iConstCast(iGmIdentity *, constHoverIdentity_SidebarWidget_(d)); 765 return iConstCast(iGmIdentity *, constHoverIdentity_SidebarWidget_(d));
711} 766}
712 767
713static void itemClicked_SidebarWidget_(iSidebarWidget *d, const iSidebarItem *item) { 768static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, size_t itemIndex) {
714 setFocus_Widget(NULL); 769 setFocus_Widget(NULL);
715 switch (d->mode) { 770 switch (d->mode) {
716 case documentOutline_SidebarMode: { 771 case documentOutline_SidebarMode: {
@@ -735,17 +790,19 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, const iSidebarItem *it
735 break; 790 break;
736 } 791 }
737 case identities_SidebarMode: { 792 case identities_SidebarMode: {
738 iGmIdentity *ident = hoverIdentity_SidebarWidget_(d); 793 d->contextItem = item;
739 if (ident) { 794 if (d->contextIndex != iInvalidPos) {
740 const iString *tabUrl = url_DocumentWidget(document_App()); 795 invalidateItem_ListWidget(d->list, d->contextIndex);
741 if (isUsedOn_GmIdentity(ident, tabUrl)) { 796 }
742 signOut_GmCerts(certs_App(), tabUrl); 797 d->contextIndex = itemIndex;
743 } 798 if (itemIndex < numItems_ListWidget(d->list)) {
744 else { 799 updateContextMenu_SidebarWidget_(d);
745 signIn_GmCerts(certs_App(), ident, tabUrl); 800 arrange_Widget(d->menu);
746 } 801 openMenu_Widget(d->menu,
747 updateItems_SidebarWidget_(d); 802 d->side == left_SideBarSide
748 updateMouseHover_ListWidget(d->list); 803 ? topRight_Rect(itemRect_ListWidget(d->list, itemIndex))
804 : addX_I2(topLeft_Rect(itemRect_ListWidget(d->list, itemIndex)),
805 -width_Widget(d->menu)));
749 } 806 }
750 break; 807 break;
751 } 808 }
@@ -848,6 +905,7 @@ iBool handleBookmarkEditorCommands_SidebarWidget_(iWidget *editor, const char *c
848 isSelected_Widget(findChild_Widget(editor, "bmed.tag.linksplit"))); 905 isSelected_Widget(findChild_Widget(editor, "bmed.tag.linksplit")));
849 postCommand_App("bookmarks.changed"); 906 postCommand_App("bookmarks.changed");
850 } 907 }
908 setupSheetTransition_Mobile(editor, iFalse);
851 destroy_Widget(editor); 909 destroy_Widget(editor);
852 return iTrue; 910 return iTrue;
853 } 911 }
@@ -878,7 +936,8 @@ static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char *
878 if (arg_Command(cmd) && isVisible_Widget(w)) { 936 if (arg_Command(cmd) && isVisible_Widget(w)) {
879 return iTrue; 937 return iTrue;
880 } 938 }
881 const iBool isAnimated = argLabel_Command(cmd, "noanim") == 0 && 939 const iBool isAnimated = prefs_App()->uiAnimations &&
940 argLabel_Command(cmd, "noanim") == 0 &&
882 (deviceType_App() != phone_AppDeviceType); 941 (deviceType_App() != phone_AppDeviceType);
883 int visX = 0; 942 int visX = 0;
884 if (isVisible_Widget(w)) { 943 if (isVisible_Widget(w)) {
@@ -1008,7 +1067,8 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
1008 return iTrue; 1067 return iTrue;
1009 } 1068 }
1010 else if (isCommand_Widget(w, ev, "list.clicked")) { 1069 else if (isCommand_Widget(w, ev, "list.clicked")) {
1011 itemClicked_SidebarWidget_(d, pointerLabel_Command(cmd, "item")); 1070 itemClicked_SidebarWidget_(
1071 d, pointerLabel_Command(cmd, "item"), argU32Label_Command(cmd, "arg"));
1012 return iTrue; 1072 return iTrue;
1013 } 1073 }
1014 else if (isCommand_Widget(w, ev, "menu.closed")) { 1074 else if (isCommand_Widget(w, ev, "menu.closed")) {
@@ -1190,23 +1250,17 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
1190 } 1250 }
1191 else if (arg_Command(cmd)) { 1251 else if (arg_Command(cmd)) {
1192 signIn_GmCerts(certs_App(), ident, tabUrl); 1252 signIn_GmCerts(certs_App(), ident, tabUrl);
1253 postCommand_App("navigate.reload");
1193 } 1254 }
1194 else { 1255 else {
1195 signOut_GmCerts(certs_App(), tabUrl); 1256 signOut_GmCerts(certs_App(), tabUrl);
1257 postCommand_App("navigate.reload");
1196 } 1258 }
1197 saveIdentities_GmCerts(certs_App()); 1259 saveIdentities_GmCerts(certs_App());
1198 updateItems_SidebarWidget_(d); 1260 updateItems_SidebarWidget_(d);
1199 } 1261 }
1200 return iTrue; 1262 return iTrue;
1201 } 1263 }
1202 else if (isCommand_Widget(w, ev, "ident.showuse")) {
1203 const iGmIdentity *ident = menuIdentity_SidebarWidget_(d);
1204 if (ident) {
1205 makeSimpleMessage_Widget(uiHeading_ColorEscape "${heading.ident.use}",
1206 cstrCollect_String(joinCStr_StringSet(ident->useUrls, "\n")));
1207 }
1208 return iTrue;
1209 }
1210 else if (isCommand_Widget(w, ev, "ident.edit")) { 1264 else if (isCommand_Widget(w, ev, "ident.edit")) {
1211 const iGmIdentity *ident = menuIdentity_SidebarWidget_(d); 1265 const iGmIdentity *ident = menuIdentity_SidebarWidget_(d);
1212 if (ident) { 1266 if (ident) {
@@ -1228,6 +1282,20 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
1228 } 1282 }
1229 return iTrue; 1283 return iTrue;
1230 } 1284 }
1285 else if (isCommand_Widget(w, ev, "ident.export")) {
1286 const iGmIdentity *ident = menuIdentity_SidebarWidget_(d);
1287 if (ident) {
1288 iString *pem = collect_String(pem_TlsCertificate(ident->cert));
1289 append_String(pem, collect_String(privateKeyPem_TlsCertificate(ident->cert)));
1290 iDocumentWidget *expTab = newTab_App(NULL, iTrue);
1291 setUrlAndSource_DocumentWidget(
1292 expTab,
1293 collectNewFormat_String("file:%s.pem", cstr_String(name_GmIdentity(ident))),
1294 collectNewCStr_String("text/plain"),
1295 utf8_String(pem));
1296 }
1297 return iTrue;
1298 }
1231 else if (isCommand_Widget(w, ev, "ident.setnotes")) { 1299 else if (isCommand_Widget(w, ev, "ident.setnotes")) {
1232 iGmIdentity *ident = pointerLabel_Command(cmd, "ident"); 1300 iGmIdentity *ident = pointerLabel_Command(cmd, "ident");
1233 if (ident) { 1301 if (ident) {
@@ -1336,20 +1404,21 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
1336 d->contextIndex = iInvalidPos; 1404 d->contextIndex = iInvalidPos;
1337 } 1405 }
1338 } 1406 }
1339 if (d->menu && ev->type == SDL_MOUSEBUTTONDOWN) { 1407 if ((d->menu || d->mode == identities_SidebarMode )&& ev->type == SDL_MOUSEBUTTONDOWN) {
1340 if (ev->button.button == SDL_BUTTON_RIGHT) { 1408 if (ev->button.button == SDL_BUTTON_RIGHT) {
1341 d->contextItem = NULL; 1409 d->contextItem = NULL;
1342 if (!isVisible_Widget(d->menu)) { 1410 if (!isVisible_Widget(d->menu)) {
1343 updateMouseHover_ListWidget(d->list); 1411 updateMouseHover_ListWidget(d->list);
1344 } 1412 }
1345 if (constHoverItem_ListWidget(d->list) || isVisible_Widget(d->menu)) { 1413 if (constHoverItem_ListWidget(d->list) || isVisible_Widget(d->menu)) {
1346 d->contextItem = hoverItem_ListWidget(d->list); 1414 d->contextItem = hoverItem_ListWidget(d->list);
1347 /* Context is drawn in hover state. */ 1415 /* Context is drawn in hover state. */
1348 if (d->contextIndex != iInvalidPos) { 1416 if (d->contextIndex != iInvalidPos) {
1349 invalidateItem_ListWidget(d->list, d->contextIndex); 1417 invalidateItem_ListWidget(d->list, d->contextIndex);
1350 } 1418 }
1351 d->contextIndex = hoverItemIndex_ListWidget(d->list); 1419 d->contextIndex = hoverItemIndex_ListWidget(d->list);
1352 /* Update menu items. */ 1420 /* Update menu items. */
1421 updateContextMenu_SidebarWidget_(d);
1353 /* TODO: Some callback-based mechanism would be nice for updating menus right 1422 /* TODO: Some callback-based mechanism would be nice for updating menus right
1354 before they open? */ 1423 before they open? */
1355 if (d->mode == bookmarks_SidebarMode && d->contextItem) { 1424 if (d->mode == bookmarks_SidebarMode && d->contextItem) {
@@ -1407,11 +1476,13 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
1407 (!cmdClear && cmdUse && isUsedOn_GmIdentity(ident, docUrl)) || 1476 (!cmdClear && cmdUse && isUsedOn_GmIdentity(ident, docUrl)) ||
1408 (!cmdClear && !cmdUse && !isUsedOn_GmIdentity(ident, docUrl))); 1477 (!cmdClear && !cmdUse && !isUsedOn_GmIdentity(ident, docUrl)));
1409 } 1478 }
1479 /*
1410 else if (equal_Command(cmdItem, "ident.showuse")) { 1480 else if (equal_Command(cmdItem, "ident.showuse")) {
1411 setFlags_Widget(as_Widget(menuItem), 1481 setFlags_Widget(as_Widget(menuItem),
1412 disabled_WidgetFlag, 1482 disabled_WidgetFlag,
1413 !isUsed_GmIdentity(ident)); 1483 !isUsed_GmIdentity(ident));
1414 } 1484 }
1485 */
1415 } 1486 }
1416 } 1487 }
1417 } 1488 }
@@ -1423,10 +1494,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
1423 const int kmods = keyMods_Sym(ev->key.keysym.mod); 1494 const int kmods = keyMods_Sym(ev->key.keysym.mod);
1424 /* Hide the sidebar when Escape is pressed. */ 1495 /* Hide the sidebar when Escape is pressed. */
1425 if (kmods == 0 && key == SDLK_ESCAPE && isVisible_Widget(d)) { 1496 if (kmods == 0 && key == SDLK_ESCAPE && isVisible_Widget(d)) {
1426 setFlags_Widget(w, hidden_WidgetFlag, iTrue); 1497 postCommand_Widget(d, "%s.toggle", cstr_String(id_Widget(w)));
1427 arrange_Widget(w->parent);
1428 updateSize_DocumentWidget(document_App());
1429 refresh_Widget(w->parent);
1430 return iTrue; 1498 return iTrue;
1431 } 1499 }
1432 } 1500 }
@@ -1460,7 +1528,8 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) {
1460 const iRect bounds = bounds_Widget(w); 1528 const iRect bounds = bounds_Widget(w);
1461 iPaint p; 1529 iPaint p;
1462 init_Paint(&p); 1530 init_Paint(&p);
1463 if (flags_Widget(w) & visualOffset_WidgetFlag && isVisible_Widget(w)) { 1531 if (flags_Widget(w) & visualOffset_WidgetFlag &&
1532 flags_Widget(w) & horizontalOffset_WidgetFlag && isVisible_Widget(w)) {
1464 fillRect_Paint(&p, boundsWithoutVisualOffset_Widget(w), tmBackground_ColorId); 1533 fillRect_Paint(&p, boundsWithoutVisualOffset_Widget(w), tmBackground_ColorId);
1465 } 1534 }
1466 draw_Widget(w); 1535 draw_Widget(w);
@@ -1493,6 +1562,7 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,
1493 const int itemHeight = height_Rect(itemRect); 1562 const int itemHeight = height_Rect(itemRect);
1494 const int iconColor = isHover ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId) 1563 const int iconColor = isHover ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId)
1495 : uiIcon_ColorId; 1564 : uiIcon_ColorId;
1565 const int altIconColor = isPressing ? uiTextPressed_ColorId : uiTextCaution_ColorId;
1496 const int font = sidebar->itemFonts[d->isBold ? 1 : 0]; 1566 const int font = sidebar->itemFonts[d->isBold ? 1 : 0];
1497 int bg = uiBackgroundSidebar_ColorId; 1567 int bg = uiBackgroundSidebar_ColorId;
1498 if (isHover) { 1568 if (isHover) {
@@ -1611,7 +1681,7 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,
1611 : uiText_ColorId; 1681 : uiText_ColorId;
1612 iString str; 1682 iString str;
1613 init_String(&str); 1683 init_String(&str);
1614 appendChar_String(&str, d->icon ? d->icon : 0x1f588); 1684 appendChar_String(&str, d->icon ? d->icon : 0x1f588);
1615 const iRect iconArea = { addX_I2(pos, gap_UI), 1685 const iRect iconArea = { addX_I2(pos, gap_UI),
1616 init_I2(1.75f * lineHeight_Text(font), itemHeight) }; 1686 init_I2(1.75f * lineHeight_Text(font), itemHeight) };
1617 drawCentered_Text(font, 1687 drawCentered_Text(font,
@@ -1625,9 +1695,13 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,
1625 deinit_String(&str); 1695 deinit_String(&str);
1626 const iInt2 textPos = addY_I2(topRight_Rect(iconArea), (itemHeight - lineHeight_Text(font)) / 2); 1696 const iInt2 textPos = addY_I2(topRight_Rect(iconArea), (itemHeight - lineHeight_Text(font)) / 2);
1627 drawRange_Text(font, textPos, fg, range_String(&d->label)); 1697 drawRange_Text(font, textPos, fg, range_String(&d->label));
1698 const int metaFont = default_FontId;
1699 const int metaIconWidth = 4.5f * gap_UI;
1628 const iInt2 metaPos = 1700 const iInt2 metaPos =
1629 init_I2(right_Rect(itemRect) - advanceRange_Text(font, range_String(&d->meta)).x - 1701 init_I2(right_Rect(itemRect) -
1630 2 * gap_UI - (scrollBarWidth ? scrollBarWidth - gap_UI : 0), 1702 length_String(&d->meta) *
1703 metaIconWidth
1704 - 2 * gap_UI - (blankWidth ? blankWidth - 1.5f * gap_UI : (gap_UI / 2)),
1631 textPos.y); 1705 textPos.y);
1632 fillRect_Paint(p, 1706 fillRect_Paint(p,
1633 init_Rect(metaPos.x, 1707 init_Rect(metaPos.x,
@@ -1635,10 +1709,22 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,
1635 right_Rect(itemRect) - metaPos.x, 1709 right_Rect(itemRect) - metaPos.x,
1636 height_Rect(itemRect)), 1710 height_Rect(itemRect)),
1637 bg); 1711 bg);
1638 drawRange_Text(font, 1712 iInt2 mpos = metaPos;
1639 metaPos, 1713 iStringConstIterator iter;
1640 isHover && isPressing ? fg : uiTextCaution_ColorId, 1714 init_StringConstIterator(&iter, &d->meta);
1641 range_String(&d->meta)); 1715 iRangecc range = { cstr_String(&d->meta), iter.pos };
1716 while (iter.value) {
1717 next_StringConstIterator(&iter);
1718 range.end = iter.pos;
1719 iRect iconArea = { mpos, init_I2(metaIconWidth, lineHeight_Text(metaFont)) };
1720 iRect visBounds = visualBounds_Text(metaFont, range);
1721 drawRange_Text(metaFont,
1722 sub_I2(mid_Rect(iconArea), mid_Rect(visBounds)),
1723 isHover && isPressing ? fg : uiTextCaution_ColorId,
1724 range);
1725 mpos.x += metaIconWidth;
1726 range.start = range.end;
1727 }
1642 } 1728 }
1643 else if (sidebar->mode == history_SidebarMode) { 1729 else if (sidebar->mode == history_SidebarMode) {
1644 iBeginCollect(); 1730 iBeginCollect();
@@ -1683,6 +1769,7 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,
1683 else if (sidebar->mode == identities_SidebarMode) { 1769 else if (sidebar->mode == identities_SidebarMode) {
1684 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) 1770 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId)
1685 : uiTextStrong_ColorId; 1771 : uiTextStrong_ColorId;
1772 const iBool isUsedOnDomain = (d->indent != 0);
1686 iString icon; 1773 iString icon;
1687 initUnicodeN_String(&icon, &d->icon, 1); 1774 initUnicodeN_String(&icon, &d->icon, 1);
1688 iInt2 cPos = topLeft_Rect(itemRect); 1775 iInt2 cPos = topLeft_Rect(itemRect);
@@ -1694,8 +1781,21 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,
1694 const int metaFg = isHover ? permanent_ColorId | (isPressing ? uiTextPressed_ColorId 1781 const int metaFg = isHover ? permanent_ColorId | (isPressing ? uiTextPressed_ColorId
1695 : uiTextFramelessHover_ColorId) 1782 : uiTextFramelessHover_ColorId)
1696 : uiTextDim_ColorId; 1783 : uiTextDim_ColorId;
1697 drawRange_Text( 1784 if (!d->listItem.isSelected && !isUsedOnDomain) {
1698 font, cPos, d->listItem.isSelected ? iconColor : metaFg, range_String(&icon)); 1785 /* Draw an outline of the icon. */
1786 for (int off = 0; off < 4; ++off) {
1787 drawRange_Text(font,
1788 add_I2(cPos, init_I2(off % 2 == 0 ? -1 : 1, off / 2 == 0 ? -1 : 1)),
1789 metaFg,
1790 range_String(&icon));
1791 }
1792 }
1793 drawRange_Text(font,
1794 cPos,
1795 d->listItem.isSelected ? iconColor
1796 : isUsedOnDomain ? altIconColor
1797 : uiBackgroundSidebar_ColorId,
1798 range_String(&icon));
1699 deinit_String(&icon); 1799 deinit_String(&icon);
1700 drawRange_Text(d->listItem.isSelected ? sidebar->itemFonts[1] : font, 1800 drawRange_Text(d->listItem.isSelected ? sidebar->itemFonts[1] : font,
1701 add_I2(cPos, init_I2(indent, 0)), 1801 add_I2(cPos, init_I2(indent, 0)),