summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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