diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-10-26 08:46:55 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-10-26 08:46:55 +0300 |
commit | c2f3c6569c0dd6bddd26e3c63196b0afb236def0 (patch) | |
tree | 0a50798689b5c3664722989b48f7d805a8608ffa /src | |
parent | 4d878508c816e9d42215db3c72240a13a9f96f8c (diff) |
Dismissing document warnings; Banner hover
The warning about terminal emulation can be dismissed on site-specific basis.
Banner items show a hover frame (like buttons) to indicate they can be clicked.
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/banner.c | 55 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 19 |
2 files changed, 58 insertions, 16 deletions
diff --git a/src/ui/banner.c b/src/ui/banner.c index e817f1bb..cb30d8c5 100644 --- a/src/ui/banner.c +++ b/src/ui/banner.c | |||
@@ -56,6 +56,8 @@ struct Impl_Banner { | |||
56 | iString icon; | 56 | iString icon; |
57 | int siteHeight; | 57 | int siteHeight; |
58 | iArray items; | 58 | iArray items; |
59 | iBool isHover; | ||
60 | size_t hoverIndex; | ||
59 | iBool isClick; | 61 | iBool isClick; |
60 | }; | 62 | }; |
61 | 63 | ||
@@ -91,6 +93,8 @@ void init_Banner(iBanner *d) { | |||
91 | init_String(&d->icon); | 93 | init_String(&d->icon); |
92 | init_Array(&d->items, sizeof(iBannerItem)); | 94 | init_Array(&d->items, sizeof(iBannerItem)); |
93 | d->isClick = iFalse; | 95 | d->isClick = iFalse; |
96 | d->isHover = iFalse; | ||
97 | d->hoverIndex = iInvalidPos; | ||
94 | } | 98 | } |
95 | 99 | ||
96 | void deinit_Banner(iBanner *d) { | 100 | void deinit_Banner(iBanner *d) { |
@@ -222,7 +226,12 @@ void draw_Banner(const iBanner *d) { | |||
222 | const iBannerItem *item = i.value; | 226 | const iBannerItem *item = i.value; |
223 | const iRect itemRect = { pos, init_I2(d->rect.size.x, item->height) }; | 227 | const iRect itemRect = { pos, init_I2(d->rect.size.x, item->height) }; |
224 | fillRect_Paint(&p, itemRect, tmBannerItemBackground_ColorId); | 228 | fillRect_Paint(&p, itemRect, tmBannerItemBackground_ColorId); |
225 | drawRect_Paint(&p, itemRect, tmBannerItemFrame_ColorId); | 229 | drawRect_Paint(&p, |
230 | itemRect, | ||
231 | item->type == warning_BannerType && d->isHover && | ||
232 | d->hoverIndex == index_ArrayConstIterator(&i) | ||
233 | ? tmBannerItemText_ColorId | ||
234 | : tmBannerItemFrame_ColorId); | ||
226 | setBaseAttributes_Text(uiContent_FontId, tmBannerItemText_ColorId); | 235 | setBaseAttributes_Text(uiContent_FontId, tmBannerItemText_ColorId); |
227 | iWrapText wt = { | 236 | iWrapText wt = { |
228 | .text = range_String(&item->text), | 237 | .text = range_String(&item->text), |
@@ -251,11 +260,22 @@ static size_t itemAtCoord_Banner_(const iBanner *d, iInt2 coord) { | |||
251 | iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) { | 260 | iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) { |
252 | iWidget *w = as_Widget(d->doc); | 261 | iWidget *w = as_Widget(d->doc); |
253 | switch (ev->type) { | 262 | switch (ev->type) { |
254 | case SDL_MOUSEMOTION: | 263 | case SDL_MOUSEMOTION: { |
255 | if (contains_Rect(d->rect, init_I2(ev->motion.x, ev->motion.y))) { | 264 | const iInt2 coord = init_I2(ev->motion.x, ev->motion.y); |
265 | const iBool isInside = contains_Rect(d->rect, coord); | ||
266 | if (isInside) { | ||
256 | setCursor_Window(window_Widget(w), SDL_SYSTEM_CURSOR_HAND); | 267 | setCursor_Window(window_Widget(w), SDL_SYSTEM_CURSOR_HAND); |
257 | } | 268 | } |
269 | if (isInside ^ d->isHover) { | ||
270 | d->isHover = isInside; | ||
271 | } | ||
272 | const size_t at = d->isHover ? itemAtCoord_Banner_(d, coord) : iInvalidPos; | ||
273 | if (at != d->hoverIndex) { | ||
274 | d->hoverIndex = at; | ||
275 | refresh_Widget(w); | ||
276 | } | ||
258 | break; | 277 | break; |
278 | } | ||
259 | case SDL_MOUSEBUTTONDOWN: | 279 | case SDL_MOUSEBUTTONDOWN: |
260 | case SDL_MOUSEBUTTONUP: | 280 | case SDL_MOUSEBUTTONUP: |
261 | /* Clicking on the top/side banner navigates to site root. */ | 281 | /* Clicking on the top/side banner navigates to site root. */ |
@@ -276,6 +296,7 @@ iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) { | |||
276 | } | 296 | } |
277 | else { | 297 | else { |
278 | const iBannerItem *item = constAt_Array(&d->items, index); | 298 | const iBannerItem *item = constAt_Array(&d->items, index); |
299 | d->isHover = iFalse; | ||
279 | if (item->type == error_BannerType) { | 300 | if (item->type == error_BannerType) { |
280 | postCommand_Widget(d->doc, "document.info"); | 301 | postCommand_Widget(d->doc, "document.info"); |
281 | } | 302 | } |
@@ -285,17 +306,23 @@ iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) { | |||
285 | postCommandf_App("open newtab:1 url:about:fonts"); | 306 | postCommandf_App("open newtab:1 url:about:fonts"); |
286 | break; | 307 | break; |
287 | case ansiEscapes_GmStatusCode: | 308 | case ansiEscapes_GmStatusCode: |
288 | makeQuestion_Widget(uiHeading_ColorEscape "${heading.dismiss.warning}", | 309 | makeQuestion_Widget( |
289 | format_Lang("${dlg.dismiss.ansi}", | 310 | uiHeading_ColorEscape "${heading.dismiss.warning}", |
290 | format_CStr(uiTextStrong_ColorEscape "%s" | 311 | format_Lang( |
291 | restore_ColorEscape, cstr_Rangecc(urlHost_String(url_DocumentWidget(d->doc))))), | 312 | "${dlg.dismiss.ansi}", |
292 | (iMenuItem[]){ { "${cancel}" }, | 313 | format_CStr(uiTextStrong_ColorEscape |
293 | { uiTextAction_ColorEscape "${dlg.dismiss.warning}", | 314 | "%s" restore_ColorEscape, |
294 | SDLK_RETURN, 0, | 315 | cstr_Rangecc(urlHost_String( |
295 | format_CStr("document.dismiss warning:%d", | 316 | url_DocumentWidget(d->doc))))), |
296 | ansiEscapes_GmDocumentWarning) | 317 | (iMenuItem[]){ |
297 | } | 318 | { "${cancel}" }, |
298 | }, 2); | 319 | { uiTextAction_ColorEscape "${dlg.dismiss.warning}", |
320 | SDLK_RETURN, | ||
321 | 0, | ||
322 | format_CStr("!document.dismiss warning:%d ptr:%p", | ||
323 | ansiEscapes_GmDocumentWarning, | ||
324 | d->doc) } }, | ||
325 | 2); | ||
299 | break; | 326 | break; |
300 | default: | 327 | default: |
301 | postCommand_Widget(d->doc, "document.info"); | 328 | postCommand_Widget(d->doc, "document.info"); |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 755cec6a..7e7a2983 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
47 | #include "root.h" | 47 | #include "root.h" |
48 | #include "mediaui.h" | 48 | #include "mediaui.h" |
49 | #include "scrollwidget.h" | 49 | #include "scrollwidget.h" |
50 | #include "sitespec.h" | ||
50 | #include "touch.h" | 51 | #include "touch.h" |
51 | #include "translation.h" | 52 | #include "translation.h" |
52 | #include "uploadwidget.h" | 53 | #include "uploadwidget.h" |
@@ -1798,11 +1799,14 @@ static void cacheDocumentGlyphs_DocumentWidget_(const iDocumentWidget *d) { | |||
1798 | } | 1799 | } |
1799 | 1800 | ||
1800 | static void addBannerWarnings_DocumentWidget_(iDocumentWidget *d) { | 1801 | static void addBannerWarnings_DocumentWidget_(iDocumentWidget *d) { |
1801 | if (warnings_GmDocument(d->doc) & missingGlyphs_GmDocumentWarning) { | 1802 | const int dismissed = value_SiteSpec(collectNewRange_String(urlRoot_String(d->mod.url)), |
1803 | dismissWarnings_SiteSpecKey); | ||
1804 | const int warnings = warnings_GmDocument(d->doc) & ~dismissed; | ||
1805 | if (warnings & missingGlyphs_GmDocumentWarning) { | ||
1802 | add_Banner(d->banner, warning_BannerType, missingGlyphs_GmStatusCode, NULL); | 1806 | add_Banner(d->banner, warning_BannerType, missingGlyphs_GmStatusCode, NULL); |
1803 | /* TODO: List one or more of the missing characters and/or their Unicode blocks? */ | 1807 | /* TODO: List one or more of the missing characters and/or their Unicode blocks? */ |
1804 | } | 1808 | } |
1805 | if (warnings_GmDocument(d->doc) & ansiEscapes_GmDocumentWarning) { | 1809 | if (warnings & ansiEscapes_GmDocumentWarning) { |
1806 | add_Banner(d->banner, warning_BannerType, ansiEscapes_GmStatusCode, NULL); | 1810 | add_Banner(d->banner, warning_BannerType, ansiEscapes_GmStatusCode, NULL); |
1807 | } | 1811 | } |
1808 | } | 1812 | } |
@@ -3383,6 +3387,17 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
3383 | else if (equal_Command(cmd, "document.autoreload.set") && document_App() == d) { | 3387 | else if (equal_Command(cmd, "document.autoreload.set") && document_App() == d) { |
3384 | d->mod.reloadInterval = arg_Command(cmd); | 3388 | d->mod.reloadInterval = arg_Command(cmd); |
3385 | } | 3389 | } |
3390 | else if (equalWidget_Command(cmd, w, "document.dismiss")) { | ||
3391 | const iString *site = collectNewRange_String(urlRoot_String(d->mod.url)); | ||
3392 | const int dismissed = value_SiteSpec(site, dismissWarnings_SiteSpecKey); | ||
3393 | const int arg = argLabel_Command(cmd, "warning"); | ||
3394 | setValue_SiteSpec(site, dismissWarnings_SiteSpecKey, dismissed | arg); | ||
3395 | if (arg == ansiEscapes_GmDocumentWarning) { | ||
3396 | remove_Banner(d->banner, ansiEscapes_GmStatusCode); | ||
3397 | refresh_Widget(w); | ||
3398 | } | ||
3399 | return iTrue; | ||
3400 | } | ||
3386 | else if (startsWith_CStr(cmd, "pinch.") && document_Command(cmd) == d) { | 3401 | else if (startsWith_CStr(cmd, "pinch.") && document_Command(cmd) == d) { |
3387 | return handlePinch_DocumentWidget_(d, cmd); | 3402 | return handlePinch_DocumentWidget_(d, cmd); |
3388 | } | 3403 | } |