diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-15 19:03:33 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-15 19:03:41 +0200 |
commit | 42bd372f1b0c93df06000f55df779696e4cb3aa3 (patch) | |
tree | eef1fbd17b47650653186318ed343e71cd7584ba /src | |
parent | ee2d10692f702ec650aed084825a49a531769077 (diff) |
Translation: Handling cancellation/errors
Diffstat (limited to 'src')
-rw-r--r-- | src/defs.h | 1 | ||||
-rw-r--r-- | src/ui/translation.c | 57 | ||||
-rw-r--r-- | src/ui/util.c | 1 | ||||
-rw-r--r-- | src/ui/widget.c | 25 |
4 files changed, 72 insertions, 12 deletions
@@ -79,3 +79,4 @@ enum iFileVersion { | |||
79 | #define scissor_Icon "\u2700" | 79 | #define scissor_Icon "\u2700" |
80 | #define clipCopy_Icon "\u2398" | 80 | #define clipCopy_Icon "\u2398" |
81 | #define clipboard_Icon "\U0001f4cb" | 81 | #define clipboard_Icon "\U0001f4cb" |
82 | #define unhappy_Icon "\U0001f641" | ||
diff --git a/src/ui/translation.c b/src/ui/translation.c index c2f332be..63d64d1b 100644 --- a/src/ui/translation.c +++ b/src/ui/translation.c | |||
@@ -23,6 +23,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
23 | #include "translation.h" | 23 | #include "translation.h" |
24 | 24 | ||
25 | #include "app.h" | 25 | #include "app.h" |
26 | #include "defs.h" | ||
26 | #include "gmdocument.h" | 27 | #include "gmdocument.h" |
27 | #include "ui/command.h" | 28 | #include "ui/command.h" |
28 | #include "ui/documentwidget.h" | 29 | #include "ui/documentwidget.h" |
@@ -54,6 +55,7 @@ struct Impl_TranslationProgressWidget { | |||
54 | uint32_t startTime; | 55 | uint32_t startTime; |
55 | int font; | 56 | int font; |
56 | iArray sprites; | 57 | iArray sprites; |
58 | iString message; | ||
57 | }; | 59 | }; |
58 | 60 | ||
59 | void init_TranslationProgressWidget(iTranslationProgressWidget *d) { | 61 | void init_TranslationProgressWidget(iTranslationProgressWidget *d) { |
@@ -62,6 +64,7 @@ void init_TranslationProgressWidget(iTranslationProgressWidget *d) { | |||
62 | setId_Widget(w, "xlt.progress"); | 64 | setId_Widget(w, "xlt.progress"); |
63 | init_Array(&d->sprites, sizeof(iSprite)); | 65 | init_Array(&d->sprites, sizeof(iSprite)); |
64 | d->startTime = SDL_GetTicks(); | 66 | d->startTime = SDL_GetTicks(); |
67 | init_String(&d->message); | ||
65 | /* Set up some letters to animate. */ | 68 | /* Set up some letters to animate. */ |
66 | const char *chars = "ARGOS"; | 69 | const char *chars = "ARGOS"; |
67 | const size_t n = strlen(chars); | 70 | const size_t n = strlen(chars); |
@@ -84,6 +87,7 @@ void init_TranslationProgressWidget(iTranslationProgressWidget *d) { | |||
84 | } | 87 | } |
85 | 88 | ||
86 | void deinit_TranslationProgressWidget(iTranslationProgressWidget *d) { | 89 | void deinit_TranslationProgressWidget(iTranslationProgressWidget *d) { |
90 | deinit_String(&d->message); | ||
87 | iForEach(Array, i, &d->sprites) { | 91 | iForEach(Array, i, &d->sprites) { |
88 | iSprite *spr = i.value; | 92 | iSprite *spr = i.value; |
89 | deinit_String(&spr->text); | 93 | deinit_String(&spr->text); |
@@ -97,6 +101,11 @@ static void draw_TranslationProgressWidget_(const iTranslationProgressWidget *d) | |||
97 | const iWidget *w = &d->widget; | 101 | const iWidget *w = &d->widget; |
98 | const float t = (float) (SDL_GetTicks() - d->startTime) / 1000.0f; | 102 | const float t = (float) (SDL_GetTicks() - d->startTime) / 1000.0f; |
99 | const iRect bounds = bounds_Widget(w); | 103 | const iRect bounds = bounds_Widget(w); |
104 | if (!isEmpty_String(&d->message)) { | ||
105 | drawCentered_Text( | ||
106 | uiLabel_FontId, bounds, iFalse, uiText_ColorId, "%s", cstr_String(&d->message)); | ||
107 | return; | ||
108 | } | ||
100 | iPaint p; | 109 | iPaint p; |
101 | init_Paint(&p); | 110 | init_Paint(&p); |
102 | const iInt2 mid = mid_Rect(bounds); | 111 | const iInt2 mid = mid_Rect(bounds); |
@@ -109,7 +118,8 @@ static void draw_TranslationProgressWidget_(const iTranslationProgressWidget *d) | |||
109 | int bg = uiBackgroundSelected_ColorId; | 118 | int bg = uiBackgroundSelected_ColorId; |
110 | int fg = uiTextSelected_ColorId; | 119 | int fg = uiTextSelected_ColorId; |
111 | iInt2 pos = add_I2(mid, spr->pos); | 120 | iInt2 pos = add_I2(mid, spr->pos); |
112 | pos.y += sin(angle + t) * spr->size.y * iClamp(t * 0.25f - 0.3f, 0.0f, 1.0f); | 121 | float t2 = sin(0.2f * t); |
122 | pos.y += sin(angle + t) * spr->size.y * t2 * t2 * iClamp(t * 0.25f - 0.3f, 0.0f, 1.0f); | ||
113 | if (bg >= 0) { | 123 | if (bg >= 0) { |
114 | p.alpha = opacity * 255; | 124 | p.alpha = opacity * 255; |
115 | fillRect_Paint(&p, (iRect){ pos, spr->size }, bg); | 125 | fillRect_Paint(&p, (iRect){ pos, spr->size }, bg); |
@@ -146,6 +156,7 @@ static const char *tripleBacktickSymbol = "\u20e3"; | |||
146 | static const char *h1Symbol = "\u20e4"; | 156 | static const char *h1Symbol = "\u20e4"; |
147 | static const char *h2Symbol = "\u20e5"; | 157 | static const char *h2Symbol = "\u20e5"; |
148 | static const char *h3Symbol = "\u20e6"; | 158 | static const char *h3Symbol = "\u20e6"; |
159 | static const char *bulletSymbol = "\n\u20e7"; | ||
149 | 160 | ||
150 | static iString *quote_String_(const iString *d) { | 161 | static iString *quote_String_(const iString *d) { |
151 | iString *quot = new_String(); | 162 | iString *quot = new_String(); |
@@ -265,6 +276,7 @@ void submit_Translation(iTranslation *d) { | |||
265 | replace_String(docSrc, "###", h3Symbol); | 276 | replace_String(docSrc, "###", h3Symbol); |
266 | replace_String(docSrc, "##", h2Symbol); | 277 | replace_String(docSrc, "##", h2Symbol); |
267 | replace_String(docSrc, "#", h1Symbol); | 278 | replace_String(docSrc, "#", h1Symbol); |
279 | replace_String(docSrc, "\n*", bulletSymbol); | ||
268 | printf_Block(json, | 280 | printf_Block(json, |
269 | "{\"q\":\"%s\",\"source\":\"%s\",\"target\":\"%s\"}", | 281 | "{\"q\":\"%s\",\"source\":\"%s\",\"target\":\"%s\"}", |
270 | cstrCollect_String(quote_String_(docSrc)), | 282 | cstrCollect_String(quote_String_(docSrc)), |
@@ -283,11 +295,19 @@ void submit_Translation(iTranslation *d) { | |||
283 | d->timer = SDL_AddTimer(1000 / 30, animate_Translation_, d); | 295 | d->timer = SDL_AddTimer(1000 / 30, animate_Translation_, d); |
284 | } | 296 | } |
285 | 297 | ||
286 | static void processResult_Translation_(iTranslation *d) { | 298 | static void setFailed_Translation_(iTranslation *d, const char *msg) { |
299 | iTranslationProgressWidget *prog = findChild_Widget(d->dlg, "xlt.progress"); | ||
300 | if (prog && isEmpty_String(&prog->message)) { | ||
301 | setCStr_String(&prog->message, msg); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | static iBool processResult_Translation_(iTranslation *d) { | ||
287 | SDL_RemoveTimer(d->timer); | 306 | SDL_RemoveTimer(d->timer); |
288 | d->timer = 0; | 307 | d->timer = 0; |
289 | if (status_TlsRequest(d->request) == error_TlsRequestStatus) { | 308 | if (status_TlsRequest(d->request) == error_TlsRequestStatus) { |
290 | return; | 309 | setFailed_Translation_(d, explosion_Icon " Request Failed"); |
310 | return iFalse; | ||
291 | } | 311 | } |
292 | iBlock *resultData = collect_Block(readAll_TlsRequest(d->request)); | 312 | iBlock *resultData = collect_Block(readAll_TlsRequest(d->request)); |
293 | // printf("result(%zu):\n%s\n", size_Block(resultData), cstr_Block(resultData)); | 313 | // printf("result(%zu):\n%s\n", size_Block(resultData), cstr_Block(resultData)); |
@@ -299,16 +319,19 @@ static void processResult_Translation_(iTranslation *d) { | |||
299 | iString *translation = unquote_String_(collect_String(captured_RegExpMatch(&m, 1))); | 319 | iString *translation = unquote_String_(collect_String(captured_RegExpMatch(&m, 1))); |
300 | replace_String(translation, tripleBacktickSymbol, "```"); | 320 | replace_String(translation, tripleBacktickSymbol, "```"); |
301 | replace_String(translation, doubleArrowSymbol, "=>"); | 321 | replace_String(translation, doubleArrowSymbol, "=>"); |
302 | replace_String(translation, h3Symbol, "###"); | 322 | replace_String(translation, h3Symbol, "### "); |
303 | replace_String(translation, h2Symbol, "##"); | 323 | replace_String(translation, h2Symbol, "## "); |
304 | replace_String(translation, h1Symbol, "#"); | 324 | replace_String(translation, h1Symbol, "# "); |
325 | replace_String(translation, bulletSymbol, "\n* "); | ||
305 | setSource_DocumentWidget(d->doc, translation); | 326 | setSource_DocumentWidget(d->doc, translation); |
306 | postCommand_App("sidebar.update"); | 327 | postCommand_App("sidebar.update"); |
307 | delete_String(translation); | 328 | delete_String(translation); |
308 | } | 329 | } |
309 | else { | 330 | else { |
310 | /* TODO: Report failure! */ | 331 | setFailed_Translation_(d, unhappy_Icon " Service Unavailable"); |
332 | return iFalse; | ||
311 | } | 333 | } |
334 | return iTrue; | ||
312 | } | 335 | } |
313 | 336 | ||
314 | static iLabelWidget *acceptButton_Translation_(const iTranslation *d) { | 337 | static iLabelWidget *acceptButton_Translation_(const iTranslation *d) { |
@@ -342,14 +365,26 @@ iBool handleCommand_Translation(iTranslation *d, const char *cmd) { | |||
342 | } | 365 | } |
343 | if (equalWidget_Command(cmd, w, "translation.finished")) { | 366 | if (equalWidget_Command(cmd, w, "translation.finished")) { |
344 | if (!isFinished_Translation(d)) { | 367 | if (!isFinished_Translation(d)) { |
345 | processResult_Translation_(d); | 368 | if (processResult_Translation_(d)) { |
346 | destroy_Widget(d->dlg); | 369 | destroy_Widget(d->dlg); |
347 | d->dlg = NULL; | 370 | d->dlg = NULL; |
371 | } | ||
348 | } | 372 | } |
349 | return iTrue; | 373 | return iTrue; |
350 | } | 374 | } |
351 | if (equalWidget_Command(cmd, d->dlg, "translation.cancel")) { | 375 | if (equalWidget_Command(cmd, d->dlg, "translation.cancel")) { |
352 | cancel_TlsRequest(d->request); | 376 | if (status_TlsRequest(d->request) == submitted_TlsRequestStatus) { |
377 | setFailed_Translation_(d, "Cancelled"); | ||
378 | updateTextCStr_LabelWidget( | ||
379 | findMenuItem_Widget(findChild_Widget(d->dlg, "dialogbuttons"), | ||
380 | "translation.cancel"), | ||
381 | "Dismiss"); | ||
382 | cancel_TlsRequest(d->request); | ||
383 | } | ||
384 | else { | ||
385 | destroy_Widget(d->dlg); | ||
386 | d->dlg = NULL; | ||
387 | } | ||
353 | return iTrue; | 388 | return iTrue; |
354 | } | 389 | } |
355 | return iFalse; | 390 | return iFalse; |
diff --git a/src/ui/util.c b/src/ui/util.c index 61ecf948..9d75129e 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -2222,6 +2222,7 @@ const char *languageId_String(const iString *menuItemLabel) { | |||
2222 | 2222 | ||
2223 | iWidget *makeTranslation_Widget(iWidget *parent) { | 2223 | iWidget *makeTranslation_Widget(iWidget *parent) { |
2224 | iWidget *dlg = makeSheet_Widget("xlt"); | 2224 | iWidget *dlg = makeSheet_Widget("xlt"); |
2225 | setFlags_Widget(dlg, keepOnTop_WidgetFlag, iFalse); | ||
2225 | setCommandHandler_Widget(dlg, translationHandler_); | 2226 | setCommandHandler_Widget(dlg, translationHandler_); |
2226 | addChildFlags_Widget(dlg, | 2227 | addChildFlags_Widget(dlg, |
2227 | iClob(new_LabelWidget(uiHeading_ColorEscape "TRANSLATE PAGE", NULL)), | 2228 | iClob(new_LabelWidget(uiHeading_ColorEscape "TRANSLATE PAGE", NULL)), |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 19546235..6a6480e5 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -619,15 +619,30 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
619 | iReverseForEach(PtrArray, i, rootData_.onTop) { | 619 | iReverseForEach(PtrArray, i, rootData_.onTop) { |
620 | iWidget *widget = *i.value; | 620 | iWidget *widget = *i.value; |
621 | if (isVisible_Widget(widget) && dispatchEvent_Widget(widget, ev)) { | 621 | if (isVisible_Widget(widget) && dispatchEvent_Widget(widget, ev)) { |
622 | #if 0 | ||
623 | if (ev->type == SDL_MOUSEMOTION) { | ||
624 | printf("[%p] %s:'%s' (on top) ate the motion\n", | ||
625 | widget, class_Widget(widget)->name, | ||
626 | cstr_String(id_Widget(widget))); | ||
627 | fflush(stdout); | ||
628 | } | ||
629 | #endif | ||
622 | return iTrue; | 630 | return iTrue; |
623 | } | 631 | } |
624 | } | 632 | } |
625 | } | 633 | } |
626 | else if (ev->type == SDL_MOUSEMOTION && !rootData_.hover && | 634 | else if (ev->type == SDL_MOUSEMOTION && |
635 | (!rootData_.hover || hasParent_Widget(d, rootData_.hover)) && | ||
627 | flags_Widget(d) & hover_WidgetFlag && ~flags_Widget(d) & hidden_WidgetFlag && | 636 | flags_Widget(d) & hover_WidgetFlag && ~flags_Widget(d) & hidden_WidgetFlag && |
628 | ~flags_Widget(d) & disabled_WidgetFlag) { | 637 | ~flags_Widget(d) & disabled_WidgetFlag) { |
629 | if (contains_Widget(d, init_I2(ev->motion.x, ev->motion.y))) { | 638 | if (contains_Widget(d, init_I2(ev->motion.x, ev->motion.y))) { |
630 | setHover_Widget(d); | 639 | setHover_Widget(d); |
640 | #if 0 | ||
641 | printf("set hover to [%p] %s:'%s'\n", | ||
642 | d, class_Widget(d)->name, | ||
643 | cstr_String(id_Widget(d))); | ||
644 | fflush(stdout); | ||
645 | #endif | ||
631 | } | 646 | } |
632 | } | 647 | } |
633 | if (filterEvent_Widget_(d, ev)) { | 648 | if (filterEvent_Widget_(d, ev)) { |
@@ -644,6 +659,14 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
644 | } | 659 | } |
645 | if (dispatchEvent_Widget(child, ev)) { | 660 | if (dispatchEvent_Widget(child, ev)) { |
646 | #if 0 | 661 | #if 0 |
662 | if (ev->type == SDL_MOUSEMOTION) { | ||
663 | printf("[%p] %s:'%s' (on top) ate the motion\n", | ||
664 | child, class_Widget(child)->name, | ||
665 | cstr_String(id_Widget(child))); | ||
666 | fflush(stdout); | ||
667 | } | ||
668 | #endif | ||
669 | #if 0 | ||
647 | if (ev->type == SDL_MOUSEBUTTONDOWN) { | 670 | if (ev->type == SDL_MOUSEBUTTONDOWN) { |
648 | printf("[%p] %s:'%s' ate the button %d\n", | 671 | printf("[%p] %s:'%s' ate the button %d\n", |
649 | child, class_Widget(child)->name, | 672 | child, class_Widget(child)->name, |