diff options
-rw-r--r-- | src/ui/color.c | 12 | ||||
-rw-r--r-- | src/ui/color.h | 1 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 196 | ||||
-rw-r--r-- | src/visited.c | 33 | ||||
-rw-r--r-- | src/visited.h | 5 |
5 files changed, 210 insertions, 37 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 | ||
238 | iColor 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 | |||
238 | iLocalDef iBool equal_Color_(const iColor *x, const iColor *y) { | 246 | iLocalDef 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); | |||
180 | int darker_Color (int color); | 180 | int darker_Color (int color); |
181 | int lighter_Color (int color); | 181 | int lighter_Color (int color); |
182 | void set_Color (int color, iColor rgba); | 182 | void set_Color (int color, iColor rgba); |
183 | iColor mix_Color (iColor c1, iColor c2, float t); | ||
183 | 184 | ||
184 | iLocalDef void setHsl_Color(int color, iHSLColor hsl) { | 185 | iLocalDef 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 | ||
28 | void init_SidebarItem(iSidebarItem *d) { | 31 | void 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 | ||
37 | void deinit_SidebarItem(iSidebarItem *d) { | 41 | void 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 | ||
204 | static 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 | |||
170 | void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) { | 219 | void 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 | ||
181 | enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) { | 235 | enum 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 | } | |
290 | static 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 | } |
diff --git a/src/visited.c b/src/visited.c index af976be5..ea9a73c9 100644 --- a/src/visited.c +++ b/src/visited.c | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <the_Foundation/file.h> | 4 | #include <the_Foundation/file.h> |
5 | #include <the_Foundation/path.h> | 5 | #include <the_Foundation/path.h> |
6 | #include <the_Foundation/ptrarray.h> | ||
6 | #include <the_Foundation/sortedarray.h> | 7 | #include <the_Foundation/sortedarray.h> |
7 | 8 | ||
8 | static const size_t maxAgeVisited_Visited_ = 3600 * 24 * 30; /* one month */ | 9 | static const size_t maxAgeVisited_Visited_ = 3600 * 24 * 30; /* one month */ |
@@ -99,6 +100,16 @@ void clear_Visited(iVisited *d) { | |||
99 | clear_SortedArray(&d->visited); | 100 | clear_SortedArray(&d->visited); |
100 | } | 101 | } |
101 | 102 | ||
103 | static size_t find_Visited_(const iVisited *d, const iString *url) { | ||
104 | iVisitedUrl visit; | ||
105 | init_VisitedUrl(&visit); | ||
106 | set_String(&visit.url, url); | ||
107 | size_t pos = iInvalidPos; | ||
108 | locate_SortedArray(&d->visited, &visit, &pos); | ||
109 | deinit_VisitedUrl(&visit); | ||
110 | return pos; | ||
111 | } | ||
112 | |||
102 | void visitUrl_Visited(iVisited *d, const iString *url) { | 113 | void visitUrl_Visited(iVisited *d, const iString *url) { |
103 | iVisitedUrl visit; | 114 | iVisitedUrl visit; |
104 | init_VisitedUrl(&visit); | 115 | init_VisitedUrl(&visit); |
@@ -115,6 +126,14 @@ void visitUrl_Visited(iVisited *d, const iString *url) { | |||
115 | insert_SortedArray(&d->visited, &visit); | 126 | insert_SortedArray(&d->visited, &visit); |
116 | } | 127 | } |
117 | 128 | ||
129 | void removeUrl_Visited(iVisited *d, const iString *url) { | ||
130 | size_t pos = find_Visited_(d, url); | ||
131 | if (pos != iInvalidPos) { | ||
132 | deinit_VisitedUrl(at_SortedArray(&d->visited, pos)); | ||
133 | remove_Array(&d->visited.values, pos); | ||
134 | } | ||
135 | } | ||
136 | |||
118 | iTime urlVisitTime_Visited(const iVisited *d, const iString *url) { | 137 | iTime urlVisitTime_Visited(const iVisited *d, const iString *url) { |
119 | iVisitedUrl item; | 138 | iVisitedUrl item; |
120 | size_t pos; | 139 | size_t pos; |
@@ -126,3 +145,17 @@ iTime urlVisitTime_Visited(const iVisited *d, const iString *url) { | |||
126 | deinit_String(&item.url); | 145 | deinit_String(&item.url); |
127 | return item.when; | 146 | return item.when; |
128 | } | 147 | } |
148 | |||
149 | static int cmpWhenDescending_VisitedUrlPtr_(const void *a, const void *b) { | ||
150 | const iVisitedUrl *s = *(const void **) a, *t = *(const void **) b; | ||
151 | return -cmp_Time(&s->when, &t->when); | ||
152 | } | ||
153 | |||
154 | const iArray *list_Visited(const iVisited *d, size_t count) { | ||
155 | iPtrArray *urls = collectNew_PtrArray(); | ||
156 | iConstForEach(Array, i, &d->visited.values) { | ||
157 | pushBack_PtrArray(urls, i.value); | ||
158 | } | ||
159 | sort_Array(urls, cmpWhenDescending_VisitedUrlPtr_); | ||
160 | return urls; | ||
161 | } | ||
diff --git a/src/visited.h b/src/visited.h index 2f8382c7..25047383 100644 --- a/src/visited.h +++ b/src/visited.h | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | #include "gmrequest.h" | 3 | #include "gmrequest.h" |
4 | 4 | ||
5 | #include <the_Foundation/array.h> | 5 | #include <the_Foundation/ptrarray.h> |
6 | #include <the_Foundation/string.h> | 6 | #include <the_Foundation/string.h> |
7 | #include <the_Foundation/time.h> | 7 | #include <the_Foundation/time.h> |
8 | 8 | ||
@@ -23,3 +23,6 @@ void save_Visited (const iVisited *, const char *dirPath); | |||
23 | 23 | ||
24 | iTime urlVisitTime_Visited (const iVisited *, const iString *url); | 24 | iTime urlVisitTime_Visited (const iVisited *, const iString *url); |
25 | void visitUrl_Visited (iVisited *, const iString *url); /* adds URL to the visited URLs set */ | 25 | void visitUrl_Visited (iVisited *, const iString *url); /* adds URL to the visited URLs set */ |
26 | void removeUrl_Visited (iVisited *, const iString *url); | ||
27 | |||
28 | const iPtrArray * list_Visited (const iVisited *, size_t count); /* returns collected */ | ||