summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/color.c12
-rw-r--r--src/ui/color.h1
-rw-r--r--src/ui/sidebarwidget.c196
3 files changed, 173 insertions, 36 deletions
diff --git a/src/ui/color.c b/src/ui/color.c
index 53315a4f..c6ba68bb 100644
--- a/src/ui/color.c
+++ b/src/ui/color.c
@@ -86,7 +86,7 @@ void setThemePalette_Color(enum iColorTheme theme) {
86 copy_(uiInputCursor_ColorId, orange_ColorId); 86 copy_(uiInputCursor_ColorId, orange_ColorId);
87 copy_(uiInputCursorText_ColorId, black_ColorId); 87 copy_(uiInputCursorText_ColorId, black_ColorId);
88 copy_(uiHeading_ColorId, cyan_ColorId); 88 copy_(uiHeading_ColorId, cyan_ColorId);
89 copy_(uiIcon_ColorId, teal_ColorId); 89 copy_(uiIcon_ColorId, cyan_ColorId);
90 copy_(uiIconHover_ColorId, cyan_ColorId); 90 copy_(uiIconHover_ColorId, cyan_ColorId);
91 copy_(uiSeparator_ColorId, gray25_ColorId); 91 copy_(uiSeparator_ColorId, gray25_ColorId);
92 copy_(uiMarked_ColorId, brown_ColorId); 92 copy_(uiMarked_ColorId, brown_ColorId);
@@ -141,7 +141,7 @@ void setThemePalette_Color(enum iColorTheme theme) {
141 copy_(uiBackgroundPressed_ColorId, cyan_ColorId); 141 copy_(uiBackgroundPressed_ColorId, cyan_ColorId);
142 copy_(uiBackgroundFramelessHover_ColorId, orange_ColorId); 142 copy_(uiBackgroundFramelessHover_ColorId, orange_ColorId);
143 copy_(uiText_ColorId, black_ColorId); 143 copy_(uiText_ColorId, black_ColorId);
144 copy_(uiTextStrong_ColorId, brown_ColorId); 144 copy_(uiTextStrong_ColorId, teal_ColorId);
145 copy_(uiTextPressed_ColorId, black_ColorId); 145 copy_(uiTextPressed_ColorId, black_ColorId);
146 copy_(uiTextSelected_ColorId, black_ColorId); 146 copy_(uiTextSelected_ColorId, black_ColorId);
147 copy_(uiTextFramelessHover_ColorId, black_ColorId); 147 copy_(uiTextFramelessHover_ColorId, black_ColorId);
@@ -235,6 +235,14 @@ void set_Color(int color, iColor rgba) {
235 } 235 }
236} 236}
237 237
238iColor mix_Color(iColor c1, iColor c2, float t) {
239 t = iClamp(t, 0.0f, 1.0f);
240 return (iColor){ c1.r * (1 - t) + c2.r * t,
241 c1.g * (1 - t) + c2.g * t,
242 c1.b * (1 - t) + c2.b * t,
243 c1.a * (1 - t) + c2.a * t };
244}
245
238iLocalDef iBool equal_Color_(const iColor *x, const iColor *y) { 246iLocalDef iBool equal_Color_(const iColor *x, const iColor *y) {
239 return memcmp(x, y, sizeof(iColor)) == 0; 247 return memcmp(x, y, sizeof(iColor)) == 0;
240} 248}
diff --git a/src/ui/color.h b/src/ui/color.h
index 596fec7a..e52c7704 100644
--- a/src/ui/color.h
+++ b/src/ui/color.h
@@ -180,6 +180,7 @@ iColor get_Color (int color);
180int darker_Color (int color); 180int darker_Color (int color);
181int lighter_Color (int color); 181int lighter_Color (int color);
182void set_Color (int color, iColor rgba); 182void set_Color (int color, iColor rgba);
183iColor mix_Color (iColor c1, iColor c2, float t);
183 184
184iLocalDef void setHsl_Color(int color, iHSLColor hsl) { 185iLocalDef void setHsl_Color(int color, iHSLColor hsl) {
185 set_Color(color, rgb_HSLColor(hsl)); 186 set_Color(color, rgb_HSLColor(hsl));
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index 04023ebc..f7730394 100644
--- a/src/ui/sidebarwidget.c
+++ b/src/ui/sidebarwidget.c
@@ -1,14 +1,16 @@
1#include "sidebarwidget.h" 1#include "sidebarwidget.h"
2#include "labelwidget.h" 2
3#include "scrollwidget.h" 3#include "../gmdocument.h"
4#include "app.h"
5#include "bookmarks.h"
6#include "command.h"
4#include "documentwidget.h" 7#include "documentwidget.h"
5#include "inputwidget.h" 8#include "inputwidget.h"
6#include "bookmarks.h" 9#include "labelwidget.h"
7#include "paint.h" 10#include "paint.h"
11#include "scrollwidget.h"
8#include "util.h" 12#include "util.h"
9#include "command.h" 13#include "visited.h"
10#include "../gmdocument.h"
11#include "app.h"
12 14
13#include <the_Foundation/array.h> 15#include <the_Foundation/array.h>
14#include <SDL_clipboard.h> 16#include <SDL_clipboard.h>
@@ -23,6 +25,7 @@ struct Impl_SidebarItem {
23 iString label; 25 iString label;
24 iString meta; 26 iString meta;
25 iString url; 27 iString url;
28 iBool isSeparator;
26}; 29};
27 30
28void init_SidebarItem(iSidebarItem *d) { 31void init_SidebarItem(iSidebarItem *d) {
@@ -32,6 +35,7 @@ void init_SidebarItem(iSidebarItem *d) {
32 init_String(&d->label); 35 init_String(&d->label);
33 init_String(&d->meta); 36 init_String(&d->meta);
34 init_String(&d->url); 37 init_String(&d->url);
38 d->isSeparator = iFalse;
35} 39}
36 40
37void deinit_SidebarItem(iSidebarItem *d) { 41void deinit_SidebarItem(iSidebarItem *d) {
@@ -49,6 +53,7 @@ struct Impl_SidebarWidget {
49 enum iSidebarMode mode; 53 enum iSidebarMode mode;
50 iScrollWidget *scroll; 54 iScrollWidget *scroll;
51 int scrollY; 55 int scrollY;
56 int modeScroll[max_SidebarMode];
52 int width; 57 int width;
53 iLabelWidget *modeButtons[max_SidebarMode]; 58 iLabelWidget *modeButtons[max_SidebarMode];
54 int itemHeight; 59 int itemHeight;
@@ -141,12 +146,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
141 item.icon = bm->icon; 146 item.icon = bm->icon;
142 set_String(&item.url, &bm->url); 147 set_String(&item.url, &bm->url);
143 set_String(&item.label, &bm->title); 148 set_String(&item.label, &bm->title);
144// iDate date;
145// init_Date(&date, &bm->when);
146// iString *ds = format_Date(&date, "%Y %b %d");
147// set_String(&item.meta, ds);
148 set_String(&item.meta, &bm->tags); 149 set_String(&item.meta, &bm->tags);
149// delete_String(ds);
150 pushBack_Array(&d->items, &item); 150 pushBack_Array(&d->items, &item);
151 } 151 }
152 d->menu = makeMenu_Widget( 152 d->menu = makeMenu_Widget(
@@ -158,8 +158,42 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
158 4); 158 4);
159 break; 159 break;
160 } 160 }
161 case history_SidebarMode: 161 case history_SidebarMode: {
162 iDate on;
163 initCurrent_Date(&on);
164 const int thisYear = on.year;
165 iConstForEach(PtrArray, i, list_Visited(visited_App(), 200)) {
166 const iVisitedUrl *visit = i.ptr;
167 iSidebarItem item;
168 init_SidebarItem(&item);
169 set_String(&item.url, &visit->url);
170 iDate date;
171 init_Date(&date, &visit->when);
172 if (date.day != on.day || date.month != on.month || date.year != on.year) {
173 /* Date separator. */
174 iSidebarItem sep;
175 init_SidebarItem(&sep);
176 sep.isSeparator = iTrue;
177 set_String(&sep.meta,
178 collect_String(format_Date(
179 &date, date.year != thisYear ? "%b %d %Y" : "%b %d")));
180 pushBack_Array(&d->items, &sep);
181 on = date;
182 }
183 pushBack_Array(&d->items, &item);
184 }
185 d->menu = makeMenu_Widget(
186 as_Widget(d),
187 (iMenuItem[]){
188 { "Copy URL", 0, 0, "history.copy" },
189 { "Add Bookmark", 0, 0, "history.addbookmark" },
190 { "---", 0, 0, NULL },
191 { "Remove URL", 0, 0, "history.delete" },
192 { "---", 0, 0, NULL },
193 { uiTextCaution_ColorEscape "Clear History", 0, 0, "history.clear confirm:1" },
194 }, 6);
162 break; 195 break;
196 }
163 default: 197 default:
164 break; 198 break;
165 } 199 }
@@ -167,15 +201,35 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
167 invalidate_SidebarWidget_(d); 201 invalidate_SidebarWidget_(d);
168} 202}
169 203
204static void scroll_SidebarWidget_(iSidebarWidget *d, int offset) {
205 const int oldScroll = d->scrollY;
206 d->scrollY += offset;
207 if (d->scrollY < 0) {
208 d->scrollY = 0;
209 }
210 const int scrollMax = scrollMax_SidebarWidget_(d);
211 d->scrollY = iMin(d->scrollY, scrollMax);
212 if (oldScroll != d->scrollY) {
213 d->hoverItem = iInvalidPos;
214 updateVisible_SidebarWidget_(d);
215 invalidate_SidebarWidget_(d);
216 }
217}
218
170void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) { 219void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) {
171 if (d->mode == mode) return; 220 if (d->mode == mode) return;
221 if (d->mode >= 0 && d->mode < max_SidebarMode) {
222 d->modeScroll[d->mode] = d->scrollY; /* saved for later */
223 }
172 d->mode = mode; 224 d->mode = mode;
173 for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) { 225 for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) {
174 setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode); 226 setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode);
175 } 227 }
176 const float heights[max_SidebarMode] = { 1.333f, 3, 3, 1.2f }; 228 const float heights[max_SidebarMode] = { 1.333f, 1.333f, 2.5f, 1.2f };
177 d->itemHeight = heights[mode] * lineHeight_Text(uiContent_FontId); 229 d->itemHeight = heights[mode] * lineHeight_Text(uiContent_FontId);
178 invalidate_SidebarWidget_(d); 230 invalidate_SidebarWidget_(d);
231 /* Restore previous scroll position. */
232 d->scrollY = d->modeScroll[mode];
179} 233}
180 234
181enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) { 235enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) {
@@ -210,8 +264,9 @@ void init_SidebarWidget(iSidebarWidget *d) {
210 resizeWidthOfChildren_WidgetFlag | collapse_WidgetFlag, 264 resizeWidthOfChildren_WidgetFlag | collapse_WidgetFlag,
211 iTrue); 265 iTrue);
212 d->scrollY = 0; 266 d->scrollY = 0;
213 d->mode = -1; 267 iZap(d->modeScroll);
214 d->width = 60 * gap_UI; 268 d->mode = -1;
269 d->width = 60 * gap_UI;
215 init_Array(&d->items, sizeof(iSidebarItem)); 270 init_Array(&d->items, sizeof(iSidebarItem));
216 d->hoverItem = iInvalidPos; 271 d->hoverItem = iInvalidPos;
217 init_Click(&d->click, d, SDL_BUTTON_LEFT); 272 init_Click(&d->click, d, SDL_BUTTON_LEFT);
@@ -280,25 +335,18 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, size_t index) {
280 postCommandf_App("document.goto loc:%p", head->text.start); 335 postCommandf_App("document.goto loc:%p", head->text.start);
281 break; 336 break;
282 } 337 }
283 case bookmarks_SidebarMode: { 338 case bookmarks_SidebarMode:
284 postCommandf_App("open url:%s", cstr_String(&item->url)); 339 case history_SidebarMode: {
340 if (!isEmpty_String(&item->url)) {
341 postCommandf_App("open url:%s", cstr_String(&item->url));
342 }
285 break; 343 break;
286 } 344 }
287 } 345 case identities_SidebarMode: {
288} 346 break;
289 347 }
290static void scroll_SidebarWidget_(iSidebarWidget *d, int offset) { 348 default:
291 const int oldScroll = d->scrollY; 349 break;
292 d->scrollY += offset;
293 if (d->scrollY < 0) {
294 d->scrollY = 0;
295 }
296 const int scrollMax = scrollMax_SidebarWidget_(d);
297 d->scrollY = iMin(d->scrollY, scrollMax);
298 if (oldScroll != d->scrollY) {
299 d->hoverItem = iInvalidPos;
300 updateVisible_SidebarWidget_(d);
301 invalidate_SidebarWidget_(d);
302 } 350 }
303} 351}
304 352
@@ -423,7 +471,6 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
423 return iTrue; 471 return iTrue;
424 } 472 }
425 else if (equal_Command(cmd, "tabs.changed") || equal_Command(cmd, "document.changed")) { 473 else if (equal_Command(cmd, "tabs.changed") || equal_Command(cmd, "document.changed")) {
426 d->scrollY = 0;
427 updateItems_SidebarWidget_(d); 474 updateItems_SidebarWidget_(d);
428 } 475 }
429 else if (equal_Command(cmd, "theme.changed")) { 476 else if (equal_Command(cmd, "theme.changed")) {
@@ -460,6 +507,50 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
460 else if (equal_Command(cmd, "bookmarks.changed")) { 507 else if (equal_Command(cmd, "bookmarks.changed")) {
461 updateItems_SidebarWidget_(d); 508 updateItems_SidebarWidget_(d);
462 } 509 }
510 else if (equal_Command(cmd, "history.delete")) {
511 const iSidebarItem *item = hoverItem_SidebarWidget_(d);
512 if (item && !isEmpty_String(&item->url)) {
513 removeUrl_Visited(visited_App(), &item->url);
514 updateItems_SidebarWidget_(d);
515 scroll_SidebarWidget_(d, 0);
516 }
517 return iTrue;
518 }
519 else if (equal_Command(cmd, "history.copy")) {
520 const iSidebarItem *item = hoverItem_SidebarWidget_(d);
521 if (item && !isEmpty_String(&item->url)) {
522 SDL_SetClipboardText(cstr_String(&item->url));
523 }
524 return iTrue;
525 }
526 else if (equal_Command(cmd, "history.addbookmark")) {
527 const iSidebarItem *item = hoverItem_SidebarWidget_(d);
528 if (!isEmpty_String(&item->url)) {
529 /* TODO: Open the bookmark editor dialog. */
530 /*add_Bookmarks(bookmarks_App(),
531 &item->url,
532 urlHost_String(&item->url),
533 collectNew_String(),
534 0x1f310);
535 postCommand_App("bookmarks.changed");*/
536 }
537 }
538 else if (equal_Command(cmd, "history.clear")) {
539 if (argLabel_Command(cmd, "confirm")) {
540 makeQuestion_Widget(
541 uiTextCaution_ColorEscape "CLEAR HISTORY",
542 "Do you really want to erase the history of all visited pages?",
543 (const char *[]){ "Cancel", uiTextCaution_ColorEscape "Clear History" },
544 (const char *[]){ "cancel", "history.clear confirm:0" },
545 2);
546 }
547 else {
548 clear_Visited(visited_App());
549 updateItems_SidebarWidget_(d);
550 scroll_SidebarWidget_(d, 0);
551 }
552 return iTrue;
553 }
463 } 554 }
464 if (ev->type == SDL_MOUSEMOTION && !isVisible_Widget(d->menu)) { 555 if (ev->type == SDL_MOUSEMOTION && !isVisible_Widget(d->menu)) {
465 const iInt2 mouse = init_I2(ev->motion.x, ev->motion.y); 556 const iInt2 mouse = init_I2(ev->motion.x, ev->motion.y);
@@ -549,7 +640,7 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) {
549 const iRect itemRect = { pos, init_I2(width_Rect(bufBounds), d->itemHeight) }; 640 const iRect itemRect = { pos, init_I2(width_Rect(bufBounds), d->itemHeight) };
550 const iBool isHover = (d->hoverItem == i); 641 const iBool isHover = (d->hoverItem == i);
551 setClip_Paint(&p, intersect_Rect(itemRect, bufBounds)); 642 setClip_Paint(&p, intersect_Rect(itemRect, bufBounds));
552 if (isHover) { 643 if (isHover && !item->isSeparator) {
553 fillRect_Paint(&p, 644 fillRect_Paint(&p,
554 itemRect, 645 itemRect,
555 isPressing ? uiBackgroundPressed_ColorId 646 isPressing ? uiBackgroundPressed_ColorId
@@ -587,6 +678,43 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) {
587 (d->itemHeight - lineHeight_Text(font)) / 2); 678 (d->itemHeight - lineHeight_Text(font)) / 2);
588 drawRange_Text(font, textPos, fg, range_String(&item->label)); 679 drawRange_Text(font, textPos, fg, range_String(&item->label));
589 } 680 }
681 else if (d->mode == history_SidebarMode) {
682 iBeginCollect();
683 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId
684 : uiTextFramelessHover_ColorId)
685 : uiText_ColorId;
686 if (!isEmpty_String(&item->meta)) {
687 drawHLine_Paint(
688 &p, topLeft_Rect(itemRect), width_Rect(itemRect), uiIcon_ColorId);
689 drawRange_Text(
690 default_FontId,
691 add_I2(topLeft_Rect(itemRect),
692 init_I2(3 * gap_UI,
693 (d->itemHeight - lineHeight_Text(default_FontId)) / 2)),
694 uiIcon_ColorId,
695 range_String(&item->meta));
696 }
697 else {
698 iUrl parts;
699 init_Url(&parts, &item->url);
700 const iBool isGemini = equalCase_Rangecc(&parts.protocol, "gemini");
701 draw_Text(
702 font,
703 add_I2(topLeft_Rect(itemRect),
704 init_I2(3 * gap_UI, (d->itemHeight - lineHeight_Text(font)) / 2)),
705 fg,
706 "%s%s%s%s%s%s",
707 isGemini ? "" : cstr_Rangecc(parts.protocol),
708 isGemini ? "" : "://",
709 escape_Color(isHover ? (isPressing ? uiTextPressed_ColorId
710 : uiTextFramelessHover_ColorId)
711 : uiTextStrong_ColorId),
712 cstr_Rangecc(parts.host),
713 escape_Color(fg),
714 cstr_Rangecc(parts.path));
715 }
716 iEndCollect();
717 }
590 unsetClip_Paint(&p); 718 unsetClip_Paint(&p);
591 pos.y += d->itemHeight; 719 pos.y += d->itemHeight;
592 } 720 }