summaryrefslogtreecommitdiff
path: root/src/ui/banner.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/banner.c')
-rw-r--r--src/ui/banner.c262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/ui/banner.c b/src/ui/banner.c
new file mode 100644
index 00000000..5ec3c9f0
--- /dev/null
+++ b/src/ui/banner.c
@@ -0,0 +1,262 @@
1/* Copyright 2021 Jaakko Keränen <jaakko.keranen@iki.fi>
2
3Redistribution and use in source and binary forms, with or without
4modification, are permitted provided that the following conditions are met:
5
61. Redistributions of source code must retain the above copyright notice, this
7 list of conditions and the following disclaimer.
82. Redistributions in binary form must reproduce the above copyright notice,
9 this list of conditions and the following disclaimer in the documentation
10 and/or other materials provided with the distribution.
11
12THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
13ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
16ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22
23#include "banner.h"
24
25#include "command.h"
26#include "documentwidget.h"
27#include "paint.h"
28#include "util.h"
29
30iDeclareType(BannerItem)
31
32struct Impl_BannerItem {
33 enum iBannerType type;
34 enum iGmStatusCode code;
35 iString message;
36 int height;
37};
38
39static void init_BannerItem(iBannerItem *d) {
40 init_String(&d->message);
41 d->height = 0;
42}
43
44static void deinit_BannerItem(iBannerItem *d) {
45 deinit_String(&d->message);
46}
47
48/*----------------------------------------------------------------------------------------------*/
49
50struct Impl_Banner {
51 iDocumentWidget *doc;
52 iRect rect;
53 iString site;
54 iString icon;
55 iArray items;
56};
57
58iDefineTypeConstruction(Banner)
59
60static void updateHeight_Banner_(iBanner *d) {
61 d->rect.size.y = 0;
62 if (!isEmpty_String(&d->site)) { //} || !isEmpty_String(&d->icon)) {
63 d->rect.size.y += lineHeight_Text(banner_FontId) * 2;
64 }
65}
66
67void init_Banner(iBanner *d) {
68 d->doc = NULL;
69 d->rect = zero_Rect();
70 init_String(&d->site);
71 init_String(&d->icon);
72 init_Array(&d->items, sizeof(iBannerItem));
73}
74
75void deinit_Banner(iBanner *d) {
76 clear_Banner(d);
77 deinit_Array(&d->items);
78 deinit_String(&d->icon);
79 deinit_String(&d->site);
80}
81
82void setOwner_Banner(iBanner *d, iDocumentWidget *owner) {
83 d->doc = owner;
84}
85
86void setWidth_Banner(iBanner *d, int width) {
87 d->rect.size.x = width;
88 updateHeight_Banner_(d);
89}
90
91void setPos_Banner(iBanner *d, iInt2 pos) {
92 d->rect.pos = pos;
93}
94
95int height_Banner(const iBanner *d) {
96 return d->rect.size.y;
97}
98
99void clear_Banner(iBanner *d) {
100 iForEach(Array, i, &d->items) {
101 deinit_BannerItem(i.value);
102 }
103 clear_Array(&d->items);
104 clear_String(&d->site);
105 clear_String(&d->icon);
106 d->rect.size.y = 0;
107}
108
109void setSite_Banner(iBanner *d, iRangecc site, iChar icon) {
110 clear_String(&d->site);
111 clear_String(&d->icon);
112 if (icon) {
113 setRange_String(&d->site, site);
114 appendChar_String(&d->icon, icon);
115 }
116 updateHeight_Banner_(d);
117}
118
119void add_Banner(iBanner *d, enum iBannerType type, enum iGmStatusCode code, const iString *message) {
120 iBannerItem item;
121 init_BannerItem(&item);
122 item.type = type;
123 item.code = code;
124 set_String(&item.message, message);
125 pushBack_Array(&d->items, &item);
126 updateHeight_Banner_(d);
127}
128
129void remove_Banner(iBanner *d, enum iGmStatusCode code) {
130 iForEach(Array, i, &d->items) {
131 iBannerItem *item = i.value;
132 if (item->code == code) {
133 deinit_BannerItem(item);
134 remove_ArrayIterator(&i);
135 }
136 }
137 updateHeight_Banner_(d);
138}
139
140iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) {
141 iWidget *w = as_Widget(d->doc);
142 /* on motion: */
143// setCursor_Window(window_Widget(w), SDL_SYSTEM_CURSOR_HAND);
144 return iFalse;
145}
146
147#if 0
148static void drawBannerRun_DrawContext_(iDrawContext *d, const iGmRun *run, iInt2 visPos) {
149 const iGmDocument *doc = d->widget->doc;
150 const iChar icon = siteIcon_GmDocument(doc);
151 iString str;
152 init_String(&str);
153 iInt2 bpos = add_I2(visPos, init_I2(0, lineHeight_Text(banner_FontId) / 2));
154 if (icon) {
155 appendChar_String(&str, icon);
156 const iRect iconRect = visualBounds_Text(run->font, range_String(&str));
157 drawRange_Text(
158 run->font,
159 addY_I2(bpos, -mid_Rect(iconRect).y + lineHeight_Text(run->font) / 2),
160 tmBannerIcon_ColorId,
161 range_String(&str));
162 bpos.x += right_Rect(iconRect) + 3 * gap_Text;
163 }
164 drawRange_Text(run->font,
165 bpos,
166 tmBannerTitle_ColorId,
167 bannerText_DocumentWidget_(d->widget));
168 if (bannerType_GmDocument(doc) == certificateWarning_GmDocumentBanner) {
169 const int domainHeight = lineHeight_Text(banner_FontId) * 2;
170 iRect rect = { add_I2(visPos, init_I2(0, domainHeight)),
171 addY_I2(run->visBounds.size, -domainHeight - lineHeight_Text(uiContent_FontId)) };
172 format_String(&str, "${heading.certwarn}");
173 const int certFlags = d->widget->certFlags;
174 if (certFlags & timeVerified_GmCertFlag && certFlags & domainVerified_GmCertFlag) {
175 iUrl parts;
176 init_Url(&parts, d->widget->mod.url);
177 const iTime oldUntil =
178 domainValidUntil_GmCerts(certs_App(), parts.host, port_Url(&parts));
179 iDate exp;
180 init_Date(&exp, &oldUntil);
181 iTime now;
182 initCurrent_Time(&now);
183 const int days = secondsSince_Time(&oldUntil, &now) / 3600 / 24;
184 appendCStr_String(&str, "\n");
185 if (days <= 30) {
186 appendCStr_String(&str,
187 format_CStr(cstrCount_Lang("dlg.certwarn.mayberenewed.n", days),
188 cstrCollect_String(format_Date(&exp, "%Y-%m-%d")),
189 days));
190 }
191 else {
192 appendCStr_String(&str, cstr_Lang("dlg.certwarn.different"));
193 }
194 }
195 else if (certFlags & domainVerified_GmCertFlag) {
196 appendCStr_String(&str, "\n");
197 appendFormat_String(&str, cstr_Lang("dlg.certwarn.expired"),
198 cstrCollect_String(format_Date(&d->widget->certExpiry, "%Y-%m-%d")));
199 }
200 else if (certFlags & timeVerified_GmCertFlag) {
201 appendCStr_String(&str, "\n");
202 appendFormat_String(&str, cstr_Lang("dlg.certwarn.domain"),
203 cstr_String(d->widget->certSubject));
204 }
205 else {
206 appendCStr_String(&str, "\n");
207 appendCStr_String(&str, cstr_Lang("dlg.certwarn.domain.expired"));
208 }
209 const iInt2 dims = measureWrapRange_Text(
210 uiContent_FontId, width_Rect(rect) - 16 * gap_UI, range_String(&str)).bounds.size;
211 const int warnHeight = run->visBounds.size.y - domainHeight;
212 const int yOff = (lineHeight_Text(uiLabelLarge_FontId) -
213 lineHeight_Text(uiContent_FontId)) / 2;
214 const iRect bgRect =
215 init_Rect(0, visPos.y + domainHeight, d->widgetBounds.size.x, warnHeight);
216 fillRect_Paint(&d->paint, bgRect, orange_ColorId);
217 if (!isDark_ColorTheme(colorTheme_App())) {
218 drawHLine_Paint(&d->paint,
219 topLeft_Rect(bgRect), width_Rect(bgRect), tmBannerTitle_ColorId);
220 drawHLine_Paint(&d->paint,
221 bottomLeft_Rect(bgRect), width_Rect(bgRect), tmBannerTitle_ColorId);
222 }
223 const int fg = black_ColorId;
224 adjustEdges_Rect(&rect, warnHeight / 2 - dims.y / 2 - yOff, 0, 0, 0);
225 bpos = topLeft_Rect(rect);
226 draw_Text(uiLabelLarge_FontId, bpos, fg, "\u26a0");
227 adjustEdges_Rect(&rect, 0, -8 * gap_UI, 0, 8 * gap_UI);
228 translate_Lang(&str);
229 drawWrapRange_Text(uiContent_FontId,
230 addY_I2(topLeft_Rect(rect), yOff),
231 width_Rect(rect),
232 fg,
233 range_String(&str));
234 }
235 deinit_String(&str);
236}
237#endif
238
239void draw_Banner(const iBanner *d) {
240 if (isEmpty_Banner(d)) {
241 return;
242 }
243 iRect bounds = d->rect;
244 iInt2 pos = addY_I2(topLeft_Rect(bounds), lineHeight_Text(banner_FontId) / 2);
245 iPaint p;
246 init_Paint(&p);
247// drawRect_Paint(&p, bounds, red_ColorId);
248 /* Draw the icon. */
249 if (!isEmpty_String(&d->icon)) {
250 const int font = banner_FontId;
251 const iRect iconRect = visualBounds_Text(font, range_String(&d->icon));
252 drawRange_Text(font,
253 addY_I2(pos, -mid_Rect(iconRect).y + lineHeight_Text(font) / 2),
254 tmBannerIcon_ColorId,
255 range_String(&d->icon));
256 pos.x += right_Rect(iconRect) + 3 * gap_Text;
257 }
258 /* Draw the site name. */
259 if (!isEmpty_String(&d->site)) {
260 drawRange_Text(banner_FontId, pos, tmBannerTitle_ColorId, range_String(&d->site));
261 }
262}