summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-07-24 21:05:02 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-07-24 21:05:02 +0300
commite32fd4e7796d6e7c5a4803e45bc230378ec4dd0b (patch)
tree5232331654a977cf4ad1bf06eedc2f8752db6c32 /src
parent0f0b4250ca460d58edb61cc0dd509ba1980c3272 (diff)
Font update; ANSI color escapes; fixed URL update
Newer version of the Fira fonts, and added a separate UI font (Source Sans Pro). The text renderer checks for the 4-bit ANSI color escapes for the setting the foreground color. InputWidget supports paste from clipboard. The navbar updates the current URL when the page has been loaded.
Diffstat (limited to 'src')
-rw-r--r--src/gmdocument.c10
-rw-r--r--src/gmrequest.c8
-rw-r--r--src/gmrequest.h1
-rw-r--r--src/ui/color.c64
-rw-r--r--src/ui/color.h3
-rw-r--r--src/ui/documentwidget.c1
-rw-r--r--src/ui/inputwidget.c62
-rw-r--r--src/ui/metrics.c2
-rw-r--r--src/ui/text.c21
-rw-r--r--src/ui/text.h8
10 files changed, 152 insertions, 28 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c
index 8355a0eb..6fde864a 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -151,7 +151,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
151 header1_FontId, 151 header1_FontId,
152 header2_FontId, 152 header2_FontId,
153 header3_FontId, 153 header3_FontId,
154 default_FontId, 154 regular_FontId,
155 }; 155 };
156 static const int colors[max_GmLineType] = { 156 static const int colors[max_GmLineType] = {
157 gray75_ColorId, 157 gray75_ColorId,
@@ -267,7 +267,13 @@ static void doLayout_GmDocument_(iGmDocument *d) {
267 const char *contPos; 267 const char *contPos;
268 run.bounds.size = tryAdvanceRange_Text( 268 run.bounds.size = tryAdvanceRange_Text(
269 run.font, runLine, isPreformat ? 0 : (d->size.x - run.bounds.pos.x), &contPos); 269 run.font, runLine, isPreformat ? 0 : (d->size.x - run.bounds.pos.x), &contPos);
270 run.text = (iRangecc){ runLine.start, contPos }; 270 if (contPos > runLine.start) {
271 run.text = (iRangecc){ runLine.start, contPos };
272 }
273 else {
274 run.text = runLine;
275 contPos = runLine.end;
276 }
271 pushBack_Array(&d->layout, &run); 277 pushBack_Array(&d->layout, &run);
272 runLine.start = contPos; 278 runLine.start = contPos;
273 trimStart_Rangecc(&runLine); 279 trimStart_Rangecc(&runLine);
diff --git a/src/gmrequest.c b/src/gmrequest.c
index 2bda65e9..ce53abee 100644
--- a/src/gmrequest.c
+++ b/src/gmrequest.c
@@ -58,9 +58,9 @@ void deinit_GmRequest(iGmRequest *d) {
58 iDisconnectObject(TlsRequest, d->req, finished, d); 58 iDisconnectObject(TlsRequest, d->req, finished, d);
59 cancel_TlsRequest(d->req); 59 cancel_TlsRequest(d->req);
60 d->state = finished_GmRequestState; 60 d->state = finished_GmRequestState;
61 iRelease(d->req);
62 d->req = NULL;
63 } 61 }
62 iRelease(d->req);
63 d->req = NULL;
64 } 64 }
65 unlock_Mutex(&d->mutex); 65 unlock_Mutex(&d->mutex);
66 delete_Audience(d->finished); 66 delete_Audience(d->finished);
@@ -237,4 +237,8 @@ const iBlock *body_GmRequest(const iGmRequest *d) {
237 return body; 237 return body;
238} 238}
239 239
240const iString *url_GmRequest(const iGmRequest *d) {
241 return &d->url;
242}
243
240iDefineClass(GmRequest) 244iDefineClass(GmRequest)
diff --git a/src/gmrequest.h b/src/gmrequest.h
index e7d5916b..b2cd339b 100644
--- a/src/gmrequest.h
+++ b/src/gmrequest.h
@@ -21,3 +21,4 @@ const char * error_GmRequest (const iGmRequest *); /* NULL if suc
21enum iGmStatusCode status_GmRequest (const iGmRequest *); 21enum iGmStatusCode status_GmRequest (const iGmRequest *);
22const iString * meta_GmRequest (const iGmRequest *); 22const iString * meta_GmRequest (const iGmRequest *);
23const iBlock * body_GmRequest (const iGmRequest *); 23const iBlock * body_GmRequest (const iGmRequest *);
24const iString * url_GmRequest (const iGmRequest *);
diff --git a/src/ui/color.c b/src/ui/color.c
index d6a995c7..179006c1 100644
--- a/src/ui/color.c
+++ b/src/ui/color.c
@@ -1,5 +1,7 @@
1#include "color.h" 1#include "color.h"
2 2
3#include <the_Foundation/string.h>
4
3static const iColor transparent_; 5static const iColor transparent_;
4 6
5iColor get_Color(int color) { 7iColor get_Color(int color) {
@@ -26,3 +28,65 @@ iColor get_Color(int color) {
26 } 28 }
27 return *clr; 29 return *clr;
28} 30}
31
32iColor ansi_Color(iRangecc escapeSequence, int fallback) {
33 iColor clr = get_Color(fallback);
34 for (const char *ch = escapeSequence.start; ch < escapeSequence.end; ch++) {
35 char *endPtr;
36 unsigned long arg = strtoul(ch, &endPtr, 10);
37 ch = endPtr;
38 switch (arg) {
39 default:
40 break;
41 case 30:
42 clr = (iColor){ 0, 0, 0, 255 };
43 break;
44 case 31:
45 clr = (iColor){ 170, 0, 0, 255 };
46 break;
47 case 32:
48 clr = (iColor){ 0, 170, 0, 255 };
49 break;
50 case 33:
51 clr = (iColor){ 170, 85, 0, 255 };
52 break;
53 case 34:
54 clr = (iColor){ 0, 0, 170, 255 };
55 break;
56 case 35:
57 clr = (iColor){ 170, 0, 170, 255 };
58 break;
59 case 36:
60 clr = (iColor){ 0, 170, 170, 255 };
61 break;
62 case 37:
63 clr = (iColor){ 170, 170, 170, 255 };
64 break;
65 case 90:
66 clr = (iColor){ 85, 85, 85, 255 };
67 break;
68 case 91:
69 clr = (iColor){ 255, 85, 85, 255 };
70 break;
71 case 92:
72 clr = (iColor){ 85, 255, 85, 255 };
73 break;
74 case 93:
75 clr = (iColor){ 255, 255, 85, 255 };
76 break;
77 case 94:
78 clr = (iColor){ 85, 85, 255, 255 };
79 break;
80 case 95:
81 clr = (iColor){ 255, 85, 255, 255 };
82 break;
83 case 96:
84 clr = (iColor){ 85, 255, 255, 255 };
85 break;
86 case 97:
87 clr = (iColor){ 255, 255, 255, 255 };
88 break;
89 }
90 }
91 return clr;
92}
diff --git a/src/ui/color.h b/src/ui/color.h
index aeb57375..7587e213 100644
--- a/src/ui/color.h
+++ b/src/ui/color.h
@@ -1,6 +1,6 @@
1#pragma once 1#pragma once
2 2
3#include <the_Foundation/defs.h> 3#include <the_Foundation/range.h>
4 4
5enum iColorId { 5enum iColorId {
6 none_ColorId = -1, 6 none_ColorId = -1,
@@ -48,3 +48,4 @@ struct Impl_Color {
48}; 48};
49 49
50iColor get_Color (int color); 50iColor get_Color (int color);
51iColor ansi_Color (iRangecc escapeSequence, int fallback);
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 121ca7cf..2466675e 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -368,6 +368,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
368 checkResponseCode_DocumentWidget_(d); 368 checkResponseCode_DocumentWidget_(d);
369 d->state = ready_DocumentState; 369 d->state = ready_DocumentState;
370 iReleasePtr(&d->request); 370 iReleasePtr(&d->request);
371 postCommandf_App("document.changed url:%s", cstr_String(d->url));
371 return iTrue; 372 return iTrue;
372 } 373 }
373 else if (isCommand_Widget(w, ev, "scroll.moved")) { 374 else if (isCommand_Widget(w, ev, "scroll.moved")) {
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index b73fac9e..22b30616 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -3,6 +3,7 @@
3#include "util.h" 3#include "util.h"
4 4
5#include <the_Foundation/array.h> 5#include <the_Foundation/array.h>
6#include <SDL_clipboard.h>
6#include <SDL_timer.h> 7#include <SDL_timer.h>
7 8
8static const int REFRESH_INTERVAL = 256; 9static const int REFRESH_INTERVAL = 256;
@@ -132,6 +133,23 @@ void end_InputWidget(iInputWidget *d, iBool accept) {
132 postCommand_Widget(w, "input.ended id:%s arg:%d", id, accept ? 1 : 0); 133 postCommand_Widget(w, "input.ended id:%s arg:%d", id, accept ? 1 : 0);
133} 134}
134 135
136static void insertChar_InputWidget_(iInputWidget *d, iChar chr) {
137 if (d->mode == insert_InputMode) {
138 insert_Array(&d->text, d->cursor, &chr);
139 d->cursor++;
140 }
141 else if (d->maxLen == 0 || d->cursor < d->maxLen) {
142 if (d->cursor >= size_Array(&d->text)) {
143 resize_Array(&d->text, d->cursor + 1);
144 }
145 set_Array(&d->text, d->cursor++, &chr);
146 if (d->maxLen && d->cursor == d->maxLen) {
147 setFocus_Widget(NULL);
148 }
149 }
150 refresh_Widget(as_Widget(d));
151}
152
135static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { 153static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
136 iWidget *w = as_Widget(d); 154 iWidget *w = as_Widget(d);
137 if (isCommand_Widget(w, ev, "focus.gained")) { 155 if (isCommand_Widget(w, ev, "focus.gained")) {
@@ -161,6 +179,20 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
161 if (ev->type == SDL_KEYDOWN && isFocused_Widget(w)) { 179 if (ev->type == SDL_KEYDOWN && isFocused_Widget(w)) {
162 const int key = ev->key.keysym.sym; 180 const int key = ev->key.keysym.sym;
163 const int mods = keyMods_Sym(ev->key.keysym.mod); 181 const int mods = keyMods_Sym(ev->key.keysym.mod);
182 if (mods == KMOD_PRIMARY) {
183 switch (key) {
184 case 'v':
185 if (SDL_HasClipboardText()) {
186 char *text = SDL_GetClipboardText();
187 iString *paste = collect_String(newCStr_String(text));
188 SDL_free(text);
189 iConstForEach(String, i, paste) {
190 insertChar_InputWidget_(d, i.value);
191 }
192 }
193 return iTrue;
194 }
195 }
164 switch (key) { 196 switch (key) {
165 case SDLK_RETURN: 197 case SDLK_RETURN:
166 case SDLK_KP_ENTER: 198 case SDLK_KP_ENTER:
@@ -237,21 +269,9 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
237 } 269 }
238 else if (ev->type == SDL_TEXTINPUT && isFocused_Widget(w)) { 270 else if (ev->type == SDL_TEXTINPUT && isFocused_Widget(w)) {
239 const iString *uni = collectNewCStr_String(ev->text.text); 271 const iString *uni = collectNewCStr_String(ev->text.text);
240 const iChar chr = first_String(uni); 272 iConstForEach(String, i, uni) {
241 if (d->mode == insert_InputMode) { 273 insertChar_InputWidget_(d, i.value);
242 insert_Array(&d->text, d->cursor, &chr);
243 d->cursor++;
244 }
245 else {
246 if (d->cursor >= size_Array(&d->text)) {
247 resize_Array(&d->text, d->cursor + 1);
248 }
249 set_Array(&d->text, d->cursor++, &chr);
250 if (d->maxLen && d->cursor == d->maxLen) {
251 setFocus_Widget(NULL);
252 }
253 } 274 }
254 refresh_Widget(w);
255 return iTrue; 275 return iTrue;
256 } 276 }
257 return processEvent_Widget(w, ev); 277 return processEvent_Widget(w, ev);
@@ -259,7 +279,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
259 279
260static void draw_InputWidget_(const iInputWidget *d) { 280static void draw_InputWidget_(const iInputWidget *d) {
261 const uint32_t time = frameTime_Window(get_Window()); 281 const uint32_t time = frameTime_Window(get_Window());
262 const iInt2 padding = init_I2(3 * gap_UI, gap_UI); 282 const iInt2 padding = init_I2(3 * gap_UI, gap_UI / 2);
263 iRect bounds = adjusted_Rect(bounds_Widget(constAs_Widget(d)), padding, neg_I2(padding)); 283 iRect bounds = adjusted_Rect(bounds_Widget(constAs_Widget(d)), padding, neg_I2(padding));
264 const iBool isFocused = isFocused_Widget(constAs_Widget(d)); 284 const iBool isFocused = isFocused_Widget(constAs_Widget(d));
265 const iBool isHover = isHover_Widget(constAs_Widget(d)) && 285 const iBool isHover = isHover_Widget(constAs_Widget(d)) &&
@@ -286,13 +306,19 @@ static void draw_InputWidget_(const iInputWidget *d) {
286 } 306 }
287 xOff = iMin(xOff, 0); 307 xOff = iMin(xOff, 0);
288 } 308 }
289 draw_Text(d->font, addX_I2(topLeft_Rect(bounds), xOff), white_ColorId, cstr_String(&text)); 309 const int yOff = (height_Rect(bounds) - lineHeight_Text(d->font)) / 2;
310 draw_Text(d->font,
311 add_I2(topLeft_Rect(bounds),
312 init_I2(xOff, yOff)),
313 white_ColorId,
314 cstr_String(&text));
290 clearClip_Paint(&p); 315 clearClip_Paint(&p);
291 /* Cursor blinking. */ 316 /* Cursor blinking. */
292 if (isFocused && (time & 256)) { 317 if (isFocused && (time & 256)) {
293 const iInt2 prefixSize = advanceN_Text(d->font, cstr_String(&text), d->cursor); 318 const iInt2 prefixSize = advanceN_Text(d->font, cstr_String(&text), d->cursor);
294 const iInt2 curPos = init_I2(xOff + left_Rect(bounds) + prefixSize.x, top_Rect(bounds)); 319 const iInt2 curPos = init_I2(xOff + left_Rect(bounds) + prefixSize.x,
295 const iRect curRect = { curPos, addX_I2(emSize, 1) }; 320 yOff + top_Rect(bounds));
321 const iRect curRect = { curPos, addX_I2(emSize, 1) };
296 iString cur; 322 iString cur;
297 if (d->cursor < size_Array(&d->text)) { 323 if (d->cursor < size_Array(&d->text)) {
298 initUnicodeN_String(&cur, constAt_Array(&d->text, d->cursor), 1); 324 initUnicodeN_String(&cur, constAt_Array(&d->text, d->cursor), 1);
diff --git a/src/ui/metrics.c b/src/ui/metrics.c
index 949daaff..3c4bfd75 100644
--- a/src/ui/metrics.c
+++ b/src/ui/metrics.c
@@ -2,7 +2,7 @@
2 2
3#include <the_Foundation/math.h> 3#include <the_Foundation/math.h>
4 4
5#define defaultFontSize_Metrics 20 5#define defaultFontSize_Metrics 18
6#define defaultGap_Metrics 4 6#define defaultGap_Metrics 4
7 7
8int gap_UI = defaultGap_Metrics; 8int gap_UI = defaultGap_Metrics;
diff --git a/src/ui/text.c b/src/ui/text.c
index 27c41396..f1c2c947 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -11,6 +11,7 @@
11#include <the_Foundation/file.h> 11#include <the_Foundation/file.h>
12#include <the_Foundation/hash.h> 12#include <the_Foundation/hash.h>
13#include <the_Foundation/math.h> 13#include <the_Foundation/math.h>
14#include <the_Foundation/regexp.h>
14#include <the_Foundation/path.h> 15#include <the_Foundation/path.h>
15#include <the_Foundation/vec2.h> 16#include <the_Foundation/vec2.h>
16 17
@@ -89,12 +90,14 @@ struct Impl_Text {
89 iInt2 cachePos; 90 iInt2 cachePos;
90 int cacheRowHeight; 91 int cacheRowHeight;
91 SDL_Palette * grayscale; 92 SDL_Palette * grayscale;
93 iRegExp * ansiEscape;
92}; 94};
93 95
94static iText text_; 96static iText text_;
95 97
96void init_Text(SDL_Renderer *render) { 98void init_Text(SDL_Renderer *render) {
97 iText *d = &text_; 99 iText *d = &text_;
100 d->ansiEscape = new_RegExp("\\[([0-9;]+)m", 0);
98 d->render = render; 101 d->render = render;
99 /* A grayscale palette for rasterized glyphs. */ { 102 /* A grayscale palette for rasterized glyphs. */ {
100 SDL_Color colors[256]; 103 SDL_Color colors[256];
@@ -117,6 +120,7 @@ void init_Text(SDL_Renderer *render) {
117 } 120 }
118 /* Load the fonts. */ { 121 /* Load the fonts. */ {
119 const struct { const iBlock *ttf; int size; } fontData[max_FontId] = { 122 const struct { const iBlock *ttf; int size; } fontData[max_FontId] = {
123 { &fontSourceSansProRegular_Embedded, fontSize_UI },
120 { &fontFiraSansRegular_Embedded, fontSize_UI }, 124 { &fontFiraSansRegular_Embedded, fontSize_UI },
121 { &fontFiraMonoRegular_Embedded, fontSize_UI * 0.866f }, 125 { &fontFiraMonoRegular_Embedded, fontSize_UI * 0.866f },
122 { &fontFiraMonoRegular_Embedded, fontSize_UI * 0.666f }, 126 { &fontFiraMonoRegular_Embedded, fontSize_UI * 0.666f },
@@ -141,6 +145,7 @@ void deinit_Text(void) {
141 } 145 }
142 SDL_DestroyTexture(d->cache); 146 SDL_DestroyTexture(d->cache);
143 d->render = NULL; 147 d->render = NULL;
148 iRelease(d->ansiEscape);
144} 149}
145 150
146static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, iChar ch, float xShift) { 151static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, iChar ch, float xShift) {
@@ -414,6 +419,20 @@ static iInt2 run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
414 iChar prevCh = 0; 419 iChar prevCh = 0;
415 for (const char *chPos = text.start; chPos != text.end; ) { 420 for (const char *chPos = text.start; chPos != text.end; ) {
416 iAssert(chPos < text.end); 421 iAssert(chPos < text.end);
422 if (*chPos == 0x1b) {
423 /* ANSI escape. */
424 chPos++;
425 iRegExpMatch m;
426 if (match_RegExp(text_.ansiEscape, chPos, text.end - chPos, &m)) {
427 if (mode == draw_RunMode) {
428 /* Change the color. */
429 const iColor clr = ansi_Color(capturedRange_RegExpMatch(&m, 1), gray75_ColorId);
430 SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b);
431 }
432 chPos = end_RegExpMatch(&m);
433 continue;
434 }
435 }
417 iChar ch = nextChar_(&chPos, text.end); 436 iChar ch = nextChar_(&chPos, text.end);
418 /* Special instructions. */ { 437 /* Special instructions. */ {
419 if (ch == '\n') { 438 if (ch == '\n') {
@@ -424,8 +443,8 @@ static iInt2 run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
424 } 443 }
425 if (ch == '\r') { 444 if (ch == '\r') {
426 const iChar esc = nextChar_(&chPos, text.end); 445 const iChar esc = nextChar_(&chPos, text.end);
427 const iColor clr = get_Color(esc - '0');
428 if (mode == draw_RunMode) { 446 if (mode == draw_RunMode) {
447 const iColor clr = get_Color(esc - '0');
429 SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b); 448 SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b);
430 } 449 }
431 prevCh = 0; 450 prevCh = 0;
diff --git a/src/ui/text.h b/src/ui/text.h
index 2181fa34..be95e948 100644
--- a/src/ui/text.h
+++ b/src/ui/text.h
@@ -7,6 +7,7 @@
7 7
8enum iFontId { 8enum iFontId {
9 default_FontId, 9 default_FontId,
10 regular_FontId,
10 monospace_FontId, 11 monospace_FontId,
11 monospaceSmall_FontId, 12 monospaceSmall_FontId,
12 medium_FontId, 13 medium_FontId,
@@ -17,9 +18,11 @@ enum iFontId {
17 hugeBold_FontId, 18 hugeBold_FontId,
18 max_FontId, 19 max_FontId,
19 /* UI fonts: */ 20 /* UI fonts: */
20 uiInput_FontId = monospace_FontId, 21 uiLabel_FontId = default_FontId,
22 uiShortcuts_FontId = default_FontId,
23 uiInput_FontId = monospace_FontId,
21 /* Document fonts: */ 24 /* Document fonts: */
22 paragraph_FontId = default_FontId, 25 paragraph_FontId = regular_FontId,
23 firstParagraph_FontId = medium_FontId, 26 firstParagraph_FontId = medium_FontId,
24 preformatted_FontId = monospace_FontId, 27 preformatted_FontId = monospace_FontId,
25 preformattedSmall_FontId = monospaceSmall_FontId, 28 preformattedSmall_FontId = monospaceSmall_FontId,
@@ -27,7 +30,6 @@ enum iFontId {
27 header1_FontId = hugeBold_FontId, 30 header1_FontId = hugeBold_FontId,
28 header2_FontId = largeBold_FontId, 31 header2_FontId = largeBold_FontId,
29 header3_FontId = medium_FontId, 32 header3_FontId = medium_FontId,
30 uiShortcuts_FontId = default_FontId,
31}; 33};
32 34
33#define specialSymbol_Text 0x10 35#define specialSymbol_Text 0x10