diff options
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/certimportwidget.c | 8 | ||||
-rw-r--r-- | src/ui/color.c | 86 | ||||
-rw-r--r-- | src/ui/color.h | 42 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 374 | ||||
-rw-r--r-- | src/ui/documentwidget.h | 8 | ||||
-rw-r--r-- | src/ui/indicatorwidget.c | 2 | ||||
-rw-r--r-- | src/ui/inputwidget.c | 41 | ||||
-rw-r--r-- | src/ui/inputwidget.h | 27 | ||||
-rw-r--r-- | src/ui/labelwidget.c | 57 | ||||
-rw-r--r-- | src/ui/labelwidget.h | 6 | ||||
-rw-r--r-- | src/ui/mediaui.c | 2 | ||||
-rw-r--r-- | src/ui/mobile.c | 20 | ||||
-rw-r--r-- | src/ui/root.c | 141 | ||||
-rw-r--r-- | src/ui/root.h | 3 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 91 | ||||
-rw-r--r-- | src/ui/sidebarwidget.h | 4 | ||||
-rw-r--r-- | src/ui/text.c | 79 | ||||
-rw-r--r-- | src/ui/text.h | 6 | ||||
-rw-r--r-- | src/ui/touch.c | 98 | ||||
-rw-r--r-- | src/ui/util.c | 104 | ||||
-rw-r--r-- | src/ui/widget.c | 110 | ||||
-rw-r--r-- | src/ui/widget.h | 17 | ||||
-rw-r--r-- | src/ui/window.c | 8 |
23 files changed, 985 insertions, 349 deletions
diff --git a/src/ui/certimportwidget.c b/src/ui/certimportwidget.c index e121b4d0..6e818137 100644 --- a/src/ui/certimportwidget.c +++ b/src/ui/certimportwidget.c | |||
@@ -215,6 +215,14 @@ static iBool processEvent_CertImportWidget_(iCertImportWidget *d, const SDL_Even | |||
215 | return iTrue; | 215 | return iTrue; |
216 | } | 216 | } |
217 | } | 217 | } |
218 | if (isCommand_UserEvent(ev, "input.paste")) { | ||
219 | if (!tryImportFromClipboard_CertImportWidget_(d)) { | ||
220 | makeSimpleMessage_Widget(uiTextCaution_ColorEscape "${heading.certimport.pasted}", | ||
221 | "${dlg.certimport.notfound}"); | ||
222 | } | ||
223 | postRefresh_App(); | ||
224 | return iTrue; | ||
225 | } | ||
218 | if (isCommand_UserEvent(ev, "certimport.paste")) { | 226 | if (isCommand_UserEvent(ev, "certimport.paste")) { |
219 | tryImportFromClipboard_CertImportWidget_(d); | 227 | tryImportFromClipboard_CertImportWidget_(d); |
220 | return iTrue; | 228 | return iTrue; |
diff --git a/src/ui/color.c b/src/ui/color.c index a6ba18e4..05ec1f6f 100644 --- a/src/ui/color.c +++ b/src/ui/color.c | |||
@@ -24,11 +24,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
24 | #include "root.h" | 24 | #include "root.h" |
25 | #include "app.h" | 25 | #include "app.h" |
26 | 26 | ||
27 | #include <the_Foundation/file.h> | ||
28 | #include <the_Foundation/path.h> | ||
27 | #include <the_Foundation/string.h> | 29 | #include <the_Foundation/string.h> |
28 | 30 | ||
29 | static const iColor transparent_; | 31 | static const iColor transparent_; |
30 | 32 | ||
31 | static const iColor darkPalette_[] = { | 33 | static iColor darkPalette_[] = { |
32 | { 0, 0, 0, 255 }, | 34 | { 0, 0, 0, 255 }, |
33 | { 40, 40, 40, 255 }, | 35 | { 40, 40, 40, 255 }, |
34 | { 80, 80, 80, 255 }, | 36 | { 80, 80, 80, 255 }, |
@@ -47,7 +49,7 @@ static const iColor darkPalette_[] = { | |||
47 | { 0, 200, 0, 255 }, | 49 | { 0, 200, 0, 255 }, |
48 | }; | 50 | }; |
49 | 51 | ||
50 | static const iColor lightPalette_[] = { | 52 | static iColor lightPalette_[] = { |
51 | { 0, 0, 0, 255 }, | 53 | { 0, 0, 0, 255 }, |
52 | { 75, 75, 75, 255 }, | 54 | { 75, 75, 75, 255 }, |
53 | { 150, 150, 150, 255 }, | 55 | { 150, 150, 150, 255 }, |
@@ -468,12 +470,12 @@ const char *escape_Color(int color) { | |||
468 | return esc[color]; | 470 | return esc[color]; |
469 | } | 471 | } |
470 | /* TODO: Conflict with format strings! "%" (37) may be used as the color value. */ | 472 | /* TODO: Conflict with format strings! "%" (37) may be used as the color value. */ |
471 | /* Double-\r is used for range extension. */ | 473 | /* Double-\v is used for range extension. */ |
472 | if (color + asciiBase_ColorEscape > 127) { | 474 | if (color + asciiBase_ColorEscape > 127) { |
473 | iAssert(color - asciiExtended_ColorEscape + asciiBase_ColorEscape <= 127); | 475 | iAssert(color - asciiExtended_ColorEscape + asciiBase_ColorEscape <= 127); |
474 | return format_CStr("\r\r%c", color - asciiExtended_ColorEscape + asciiBase_ColorEscape); | 476 | return format_CStr("\v\v%c", color - asciiExtended_ColorEscape + asciiBase_ColorEscape); |
475 | } | 477 | } |
476 | return format_CStr("\r%c", color + asciiBase_ColorEscape); | 478 | return format_CStr("\v%c", color + asciiBase_ColorEscape); |
477 | } | 479 | } |
478 | 480 | ||
479 | iHSLColor setSat_HSLColor(iHSLColor d, float sat) { | 481 | iHSLColor setSat_HSLColor(iHSLColor d, float sat) { |
@@ -804,3 +806,77 @@ iColor ansiForeground_Color(iRangecc escapeSequence, int fallback) { | |||
804 | } | 806 | } |
805 | return clr; | 807 | return clr; |
806 | } | 808 | } |
809 | |||
810 | iBool loadPalette_Color(const char *path) { | ||
811 | iBool wasLoaded = iFalse; | ||
812 | iFile *f = newCStr_File(concatPath_CStr(path, "palette.txt")); | ||
813 | if (open_File(f, text_FileMode | readOnly_FileMode)) { | ||
814 | iColor *dstPal = darkPalette_; | ||
815 | iRangecc srcLine = iNullRange; | ||
816 | const iBlock *src = collect_Block(readAll_File(f)); | ||
817 | while (nextSplit_Rangecc(range_Block(src), "\n", &srcLine)) { | ||
818 | iRangecc line = srcLine; | ||
819 | trim_Rangecc(&line); | ||
820 | if (isEmpty_Range(&line)) { | ||
821 | continue; | ||
822 | } | ||
823 | if (*line.start == '#') { | ||
824 | /* Control directive. */ | ||
825 | line.start++; | ||
826 | trim_Rangecc(&line); | ||
827 | if (equalCase_Rangecc(line, "dark")) { | ||
828 | dstPal = darkPalette_; | ||
829 | } | ||
830 | else if (equalCase_Rangecc(line, "light")) { | ||
831 | dstPal = lightPalette_; | ||
832 | } | ||
833 | continue; | ||
834 | } | ||
835 | static const struct { | ||
836 | const char *label; | ||
837 | int paletteIndex; | ||
838 | } colors_[] = { | ||
839 | { "black:", 0 }, { "gray25:", 1 }, { "gray50:", 2 }, { "gray75:", 3 }, | ||
840 | { "white:", 4 }, { "brown:", 5 }, { "orange:", 6 }, { "teal:", 7 }, | ||
841 | { "cyan:", 8 }, { "yellow:", 9 }, { "red:", 10 }, { "magenta:", 11 }, | ||
842 | { "blue:", 12 }, { "green:", 13 }, | ||
843 | }; | ||
844 | iForIndices(i, colors_) { | ||
845 | if (startsWithCase_Rangecc(line, colors_[i].label)) { | ||
846 | iColor *dst = &dstPal[colors_[i].paletteIndex]; | ||
847 | line.start += strlen(colors_[i].label); | ||
848 | trim_Rangecc(&line); | ||
849 | if (!isEmpty_Range(&line)) { | ||
850 | if (*line.start == '#') { | ||
851 | /* Hexadecimal color. */ | ||
852 | line.start++; | ||
853 | if (size_Range(&line) == 6) { | ||
854 | iBlock *vals = hexDecode_Rangecc(line); | ||
855 | iAssert(size_Block(vals) == 3); | ||
856 | const uint8_t *rgb = constData_Block(vals); | ||
857 | *dst = (iColor){ rgb[0], rgb[1], rgb[2], 255 }; | ||
858 | delete_Block(vals); | ||
859 | } | ||
860 | else { | ||
861 | fprintf(stderr, "[Color] invalid custom color: %s\n", | ||
862 | cstr_Rangecc(line)); | ||
863 | } | ||
864 | } | ||
865 | else { | ||
866 | unsigned int red = 0, green = 0, blue = 0; | ||
867 | sscanf(line.start, "%u %u %u", &red, &green, &blue); | ||
868 | if (red > 255 || green > 255 || blue > 255) { | ||
869 | fprintf(stderr, "[Color] RGB value(s) out of range: %s\n", | ||
870 | cstr_Rangecc(line)); | ||
871 | } | ||
872 | *dst = (iColor){ red, green, blue, 255 }; | ||
873 | } | ||
874 | } | ||
875 | } | ||
876 | } | ||
877 | } | ||
878 | wasLoaded = iTrue; | ||
879 | } | ||
880 | iRelease(f); | ||
881 | return wasLoaded; | ||
882 | } | ||
diff --git a/src/ui/color.h b/src/ui/color.h index d2fa3c00..37ec49eb 100644 --- a/src/ui/color.h +++ b/src/ui/color.h | |||
@@ -187,26 +187,26 @@ iLocalDef iBool isRegularText_ColorId(enum iColorId d) { | |||
187 | #define asciiBase_ColorEscape 33 | 187 | #define asciiBase_ColorEscape 33 |
188 | #define asciiExtended_ColorEscape (128 - asciiBase_ColorEscape) | 188 | #define asciiExtended_ColorEscape (128 - asciiBase_ColorEscape) |
189 | 189 | ||
190 | #define restore_ColorEscape "\r\x24" /* ASCII Cancel */ | 190 | #define restore_ColorEscape "\v\x24" /* ASCII Cancel */ |
191 | #define black_ColorEscape "\r!" | 191 | #define black_ColorEscape "\v!" |
192 | #define gray25_ColorEscape "\r\"" | 192 | #define gray25_ColorEscape "\v\"" |
193 | #define gray50_ColorEscape "\r#" | 193 | #define gray50_ColorEscape "\v#" |
194 | #define gray75_ColorEscape "\r$" | 194 | #define gray75_ColorEscape "\v$" |
195 | #define white_ColorEscape "\r%" | 195 | #define white_ColorEscape "\v%" |
196 | #define brown_ColorEscape "\r&" | 196 | #define brown_ColorEscape "\v&" |
197 | #define orange_ColorEscape "\r'" | 197 | #define orange_ColorEscape "\v'" |
198 | #define teal_ColorEscape "\r(" | 198 | #define teal_ColorEscape "\v(" |
199 | #define cyan_ColorEscape "\r)" | 199 | #define cyan_ColorEscape "\v)" |
200 | #define yellow_ColorEscape "\r*" | 200 | #define yellow_ColorEscape "\v*" |
201 | #define red_ColorEscape "\r+" | 201 | #define red_ColorEscape "\v+" |
202 | #define magenta_ColorEscape "\r," | 202 | #define magenta_ColorEscape "\v," |
203 | #define blue_ColorEscape "\r-" | 203 | #define blue_ColorEscape "\v-" |
204 | #define green_ColorEscape "\r." | 204 | #define green_ColorEscape "\v." |
205 | #define uiText_ColorEscape "\r4" | 205 | #define uiText_ColorEscape "\v4" |
206 | #define uiTextAction_ColorEscape "\r<" | 206 | #define uiTextAction_ColorEscape "\v<" |
207 | #define uiTextCaution_ColorEscape "\r=" | 207 | #define uiTextCaution_ColorEscape "\v=" |
208 | #define uiTextStrong_ColorEscape "\r:" | 208 | #define uiTextStrong_ColorEscape "\v:" |
209 | #define uiHeading_ColorEscape "\rR" | 209 | #define uiHeading_ColorEscape "\vR" |
210 | 210 | ||
211 | iDeclareType(Color) | 211 | iDeclareType(Color) |
212 | iDeclareType(HSLColor) | 212 | iDeclareType(HSLColor) |
@@ -244,7 +244,9 @@ iLocalDef void setHsl_Color(int color, iHSLColor hsl) { | |||
244 | set_Color(color, rgb_HSLColor(hsl)); | 244 | set_Color(color, rgb_HSLColor(hsl)); |
245 | } | 245 | } |
246 | 246 | ||
247 | iBool loadPalette_Color (const char *path); | ||
247 | void setThemePalette_Color (enum iColorTheme theme); | 248 | void setThemePalette_Color (enum iColorTheme theme); |
248 | 249 | ||
249 | iColor ansiForeground_Color (iRangecc escapeSequence, int fallback); | 250 | iColor ansiForeground_Color (iRangecc escapeSequence, int fallback); |
250 | const char * escape_Color (int color); | 251 | const char * escape_Color (int color); |
252 | |||
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 6184a75a..cb1fde28 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -130,7 +130,8 @@ void deinit_PersistentDocumentState(iPersistentDocumentState *d) { | |||
130 | 130 | ||
131 | void serialize_PersistentDocumentState(const iPersistentDocumentState *d, iStream *outs) { | 131 | void serialize_PersistentDocumentState(const iPersistentDocumentState *d, iStream *outs) { |
132 | serialize_String(d->url, outs); | 132 | serialize_String(d->url, outs); |
133 | writeU16_Stream(outs, d->reloadInterval & 7); | 133 | uint16_t params = d->reloadInterval & 7; |
134 | writeU16_Stream(outs, params); | ||
134 | serialize_History(d->history, outs); | 135 | serialize_History(d->history, outs); |
135 | } | 136 | } |
136 | 137 | ||
@@ -223,6 +224,7 @@ enum iDocumentWidgetFlag { | |||
223 | movingSelectMarkEnd_DocumentWidgetFlag = iBit(11), | 224 | movingSelectMarkEnd_DocumentWidgetFlag = iBit(11), |
224 | otherRootByDefault_DocumentWidgetFlag = iBit(12), /* links open to other root by default */ | 225 | otherRootByDefault_DocumentWidgetFlag = iBit(12), /* links open to other root by default */ |
225 | urlChanged_DocumentWidgetFlag = iBit(13), | 226 | urlChanged_DocumentWidgetFlag = iBit(13), |
227 | openedFromSidebar_DocumentWidgetFlag = iBit(14), | ||
226 | }; | 228 | }; |
227 | 229 | ||
228 | enum iDocumentLinkOrdinalMode { | 230 | enum iDocumentLinkOrdinalMode { |
@@ -315,6 +317,10 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
315 | init_Widget(w); | 317 | init_Widget(w); |
316 | setId_Widget(w, format_CStr("document%03d", ++docEnum_)); | 318 | setId_Widget(w, format_CStr("document%03d", ++docEnum_)); |
317 | setFlags_Widget(w, hover_WidgetFlag | noBackground_WidgetFlag, iTrue); | 319 | setFlags_Widget(w, hover_WidgetFlag | noBackground_WidgetFlag, iTrue); |
320 | if (deviceType_App() != desktop_AppDeviceType) { | ||
321 | setFlags_Widget(w, leftEdgeDraggable_WidgetFlag | rightEdgeDraggable_WidgetFlag | | ||
322 | horizontalOffset_WidgetFlag, iTrue); | ||
323 | } | ||
318 | init_PersistentDocumentState(&d->mod); | 324 | init_PersistentDocumentState(&d->mod); |
319 | d->flags = 0; | 325 | d->flags = 0; |
320 | d->phoneToolbar = NULL; | 326 | d->phoneToolbar = NULL; |
@@ -392,6 +398,7 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
392 | } | 398 | } |
393 | 399 | ||
394 | void deinit_DocumentWidget(iDocumentWidget *d) { | 400 | void deinit_DocumentWidget(iDocumentWidget *d) { |
401 | pauseAllPlayers_Media(media_GmDocument(d->doc), iTrue); | ||
395 | removeTicker_App(animate_DocumentWidget_, d); | 402 | removeTicker_App(animate_DocumentWidget_, d); |
396 | removeTicker_App(prerender_DocumentWidget_, d); | 403 | removeTicker_App(prerender_DocumentWidget_, d); |
397 | remove_Periodic(periodic_App(), d); | 404 | remove_Periodic(periodic_App(), d); |
@@ -976,6 +983,9 @@ static void updateTimestampBuf_DocumentWidget_(const iDocumentWidget *d) { | |||
976 | } | 983 | } |
977 | 984 | ||
978 | static void invalidate_DocumentWidget_(iDocumentWidget *d) { | 985 | static void invalidate_DocumentWidget_(iDocumentWidget *d) { |
986 | if (flags_Widget(as_Widget(d)) & destroyPending_WidgetFlag) { | ||
987 | return; | ||
988 | } | ||
979 | invalidate_VisBuf(d->visBuf); | 989 | invalidate_VisBuf(d->visBuf); |
980 | clear_PtrSet(d->invalidRuns); | 990 | clear_PtrSet(d->invalidRuns); |
981 | } | 991 | } |
@@ -1016,9 +1026,7 @@ static void showOrHidePinningIndicator_DocumentWidget_(iDocumentWidget *d) { | |||
1016 | isPinned_DocumentWidget_(d)); | 1026 | isPinned_DocumentWidget_(d)); |
1017 | } | 1027 | } |
1018 | 1028 | ||
1019 | void setSource_DocumentWidget(iDocumentWidget *d, const iString *source) { | 1029 | static void documentWasChanged_DocumentWidget_(iDocumentWidget *d) { |
1020 | setUrl_GmDocument(d->doc, d->mod.url); | ||
1021 | setSource_GmDocument(d->doc, source, documentWidth_DocumentWidget_(d)); | ||
1022 | documentRunsInvalidated_DocumentWidget_(d); | 1030 | documentRunsInvalidated_DocumentWidget_(d); |
1023 | updateWindowTitle_DocumentWidget_(d); | 1031 | updateWindowTitle_DocumentWidget_(d); |
1024 | updateVisible_DocumentWidget_(d); | 1032 | updateVisible_DocumentWidget_(d); |
@@ -1035,6 +1043,26 @@ void setSource_DocumentWidget(iDocumentWidget *d, const iString *source) { | |||
1035 | } | 1043 | } |
1036 | } | 1044 | } |
1037 | showOrHidePinningIndicator_DocumentWidget_(d); | 1045 | showOrHidePinningIndicator_DocumentWidget_(d); |
1046 | setCachedDocument_History(d->mod.history, | ||
1047 | d->doc, /* keeps a ref */ | ||
1048 | (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0); | ||
1049 | } | ||
1050 | |||
1051 | void setSource_DocumentWidget(iDocumentWidget *d, const iString *source) { | ||
1052 | setUrl_GmDocument(d->doc, d->mod.url); | ||
1053 | setSource_GmDocument(d->doc, | ||
1054 | source, | ||
1055 | documentWidth_DocumentWidget_(d), | ||
1056 | isFinished_GmRequest(d->request) ? final_GmDocumentUpdate | ||
1057 | : partial_GmDocumentUpdate); | ||
1058 | documentWasChanged_DocumentWidget_(d); | ||
1059 | } | ||
1060 | |||
1061 | static void replaceDocument_DocumentWidget_(iDocumentWidget *d, iGmDocument *newDoc) { | ||
1062 | pauseAllPlayers_Media(media_GmDocument(d->doc), iTrue); | ||
1063 | iRelease(d->doc); | ||
1064 | d->doc = ref_Object(newDoc); | ||
1065 | documentWasChanged_DocumentWidget_(d); | ||
1038 | } | 1066 | } |
1039 | 1067 | ||
1040 | static void updateTheme_DocumentWidget_(iDocumentWidget *d) { | 1068 | static void updateTheme_DocumentWidget_(iDocumentWidget *d) { |
@@ -1143,16 +1171,22 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode | |||
1143 | { person_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" } }, | 1171 | { person_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" } }, |
1144 | 2); | 1172 | 2); |
1145 | } | 1173 | } |
1146 | setBanner_GmDocument(d->doc, useBanner ? bannerType_DocumentWidget_(d) : none_GmDocumentBanner); | 1174 | /* Make a new document for the error page.*/ { |
1147 | setFormat_GmDocument(d->doc, gemini_GmDocumentFormat); | 1175 | iGmDocument *errorDoc = new_GmDocument(); |
1176 | setUrl_GmDocument(errorDoc, d->mod.url); | ||
1177 | setBanner_GmDocument(errorDoc, useBanner ? bannerType_DocumentWidget_(d) : none_GmDocumentBanner); | ||
1178 | setFormat_GmDocument(errorDoc, gemini_SourceFormat); | ||
1179 | replaceDocument_DocumentWidget_(d, errorDoc); | ||
1180 | iRelease(errorDoc); | ||
1181 | } | ||
1148 | translate_Lang(src); | 1182 | translate_Lang(src); |
1183 | d->state = ready_RequestState; | ||
1149 | setSource_DocumentWidget(d, src); | 1184 | setSource_DocumentWidget(d, src); |
1150 | updateTheme_DocumentWidget_(d); | 1185 | updateTheme_DocumentWidget_(d); |
1151 | reset_SmoothScroll(&d->scrollY); | 1186 | reset_SmoothScroll(&d->scrollY); |
1152 | init_Anim(&d->sideOpacity, 0); | 1187 | init_Anim(&d->sideOpacity, 0); |
1153 | init_Anim(&d->altTextOpacity, 0); | 1188 | init_Anim(&d->altTextOpacity, 0); |
1154 | resetWideRuns_DocumentWidget_(d); | 1189 | resetWideRuns_DocumentWidget_(d); |
1155 | d->state = ready_RequestState; | ||
1156 | } | 1190 | } |
1157 | 1191 | ||
1158 | static void updateFetchProgress_DocumentWidget_(iDocumentWidget *d) { | 1192 | static void updateFetchProgress_DocumentWidget_(iDocumentWidget *d) { |
@@ -1264,9 +1298,9 @@ static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool | |||
1264 | 2); | 1298 | 2); |
1265 | } | 1299 | } |
1266 | if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { | 1300 | if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { |
1267 | redoLayout_GmDocument(d->doc); | 1301 | redoLayout_GmDocument(d->doc); |
1268 | updateVisible_DocumentWidget_(d); | 1302 | updateVisible_DocumentWidget_(d); |
1269 | invalidate_DocumentWidget_(d); | 1303 | invalidate_DocumentWidget_(d); |
1270 | } | 1304 | } |
1271 | } | 1305 | } |
1272 | else if (equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { | 1306 | else if (equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { |
@@ -1348,7 +1382,9 @@ static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool | |||
1348 | } | 1382 | } |
1349 | } | 1383 | } |
1350 | 1384 | ||
1351 | static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse *response, | 1385 | static void updateDocument_DocumentWidget_(iDocumentWidget *d, |
1386 | const iGmResponse *response, | ||
1387 | iGmDocument *cachedDoc, | ||
1352 | const iBool isInitialUpdate) { | 1388 | const iBool isInitialUpdate) { |
1353 | if (d->state == ready_RequestState) { | 1389 | if (d->state == ready_RequestState) { |
1354 | return; | 1390 | return; |
@@ -1371,7 +1407,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse | |||
1371 | if (isSuccess_GmStatusCode(statusCode)) { | 1407 | if (isSuccess_GmStatusCode(statusCode)) { |
1372 | /* Check the MIME type. */ | 1408 | /* Check the MIME type. */ |
1373 | iRangecc charset = range_CStr("utf-8"); | 1409 | iRangecc charset = range_CStr("utf-8"); |
1374 | enum iGmDocumentFormat docFormat = undefined_GmDocumentFormat; | 1410 | enum iSourceFormat docFormat = undefined_SourceFormat; |
1375 | const iString *mimeStr = collect_String(lower_String(&response->meta)); /* for convenience */ | 1411 | const iString *mimeStr = collect_String(lower_String(&response->meta)); /* for convenience */ |
1376 | set_String(&d->sourceMime, mimeStr); | 1412 | set_String(&d->sourceMime, mimeStr); |
1377 | iRangecc mime = range_String(mimeStr); | 1413 | iRangecc mime = range_String(mimeStr); |
@@ -1380,20 +1416,20 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse | |||
1380 | iRangecc param = seg; | 1416 | iRangecc param = seg; |
1381 | trim_Rangecc(¶m); | 1417 | trim_Rangecc(¶m); |
1382 | if (equal_Rangecc(param, "text/gemini")) { | 1418 | if (equal_Rangecc(param, "text/gemini")) { |
1383 | docFormat = gemini_GmDocumentFormat; | 1419 | docFormat = gemini_SourceFormat; |
1384 | setRange_String(&d->sourceMime, param); | 1420 | setRange_String(&d->sourceMime, param); |
1385 | } | 1421 | } |
1386 | else if (startsWith_Rangecc(param, "text/") || | 1422 | else if (startsWith_Rangecc(param, "text/") || |
1387 | equal_Rangecc(param, "application/json") || | 1423 | equal_Rangecc(param, "application/json") || |
1388 | equal_Rangecc(param, "application/x-pem-file") || | 1424 | equal_Rangecc(param, "application/x-pem-file") || |
1389 | equal_Rangecc(param, "application/pem-certificate-chain")) { | 1425 | equal_Rangecc(param, "application/pem-certificate-chain")) { |
1390 | docFormat = plainText_GmDocumentFormat; | 1426 | docFormat = plainText_SourceFormat; |
1391 | setRange_String(&d->sourceMime, param); | 1427 | setRange_String(&d->sourceMime, param); |
1392 | } | 1428 | } |
1393 | else if (equal_Rangecc(param, "application/zip") || | 1429 | else if (equal_Rangecc(param, "application/zip") || |
1394 | (startsWith_Rangecc(param, "application/") && | 1430 | (startsWith_Rangecc(param, "application/") && |
1395 | endsWithCase_Rangecc(param, "+zip"))) { | 1431 | endsWithCase_Rangecc(param, "+zip"))) { |
1396 | docFormat = gemini_GmDocumentFormat; | 1432 | docFormat = gemini_SourceFormat; |
1397 | setRange_String(&d->sourceMime, param); | 1433 | setRange_String(&d->sourceMime, param); |
1398 | iString *key = collectNew_String(); | 1434 | iString *key = collectNew_String(); |
1399 | toString_Sym(SDLK_s, KMOD_PRIMARY, key); | 1435 | toString_Sym(SDLK_s, KMOD_PRIMARY, key); |
@@ -1420,9 +1456,10 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse | |||
1420 | startsWith_Rangecc(param, "audio/")) { | 1456 | startsWith_Rangecc(param, "audio/")) { |
1421 | const iBool isAudio = startsWith_Rangecc(param, "audio/"); | 1457 | const iBool isAudio = startsWith_Rangecc(param, "audio/"); |
1422 | /* Make a simple document with an image or audio player. */ | 1458 | /* Make a simple document with an image or audio player. */ |
1423 | docFormat = gemini_GmDocumentFormat; | 1459 | docFormat = gemini_SourceFormat; |
1424 | setRange_String(&d->sourceMime, param); | 1460 | setRange_String(&d->sourceMime, param); |
1425 | const iGmLinkId imgLinkId = 1; /* there's only the one link */ | 1461 | const iGmLinkId imgLinkId = 1; /* there's only the one link */ |
1462 | /* TODO: Do the image loading in `postProcessRequestContent_DocumentWidget_()` */ | ||
1426 | if ((isAudio && isInitialUpdate) || (!isAudio && isRequestFinished)) { | 1463 | if ((isAudio && isInitialUpdate) || (!isAudio && isRequestFinished)) { |
1427 | const char *linkTitle = | 1464 | const char *linkTitle = |
1428 | startsWith_String(mimeStr, "image/") ? "Image" : "Audio"; | 1465 | startsWith_String(mimeStr, "image/") ? "Image" : "Audio"; |
@@ -1432,7 +1469,9 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse | |||
1432 | linkTitle = | 1469 | linkTitle = |
1433 | baseName_Path(collect_String(newRange_String(parts.path))).start; | 1470 | baseName_Path(collect_String(newRange_String(parts.path))).start; |
1434 | } | 1471 | } |
1435 | format_String(&str, "=> %s %s\n", cstr_String(d->mod.url), linkTitle); | 1472 | format_String(&str, "=> %s %s\n", |
1473 | cstr_String(withSpacesEncoded_String(d->mod.url)), | ||
1474 | linkTitle); | ||
1436 | setData_Media(media_GmDocument(d->doc), | 1475 | setData_Media(media_GmDocument(d->doc), |
1437 | imgLinkId, | 1476 | imgLinkId, |
1438 | mimeStr, | 1477 | mimeStr, |
@@ -1464,7 +1503,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse | |||
1464 | } | 1503 | } |
1465 | } | 1504 | } |
1466 | } | 1505 | } |
1467 | if (docFormat == undefined_GmDocumentFormat) { | 1506 | if (docFormat == undefined_SourceFormat) { |
1468 | showErrorPage_DocumentWidget_(d, unsupportedMimeType_GmStatusCode, &response->meta); | 1507 | showErrorPage_DocumentWidget_(d, unsupportedMimeType_GmStatusCode, &response->meta); |
1469 | deinit_String(&str); | 1508 | deinit_String(&str); |
1470 | return; | 1509 | return; |
@@ -1476,7 +1515,10 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse | |||
1476 | collect_String(decode_Block(&str.chars, cstr_Rangecc(charset)))); | 1515 | collect_String(decode_Block(&str.chars, cstr_Rangecc(charset)))); |
1477 | } | 1516 | } |
1478 | } | 1517 | } |
1479 | if (setSource) { | 1518 | if (cachedDoc) { |
1519 | replaceDocument_DocumentWidget_(d, cachedDoc); | ||
1520 | } | ||
1521 | else if (setSource) { | ||
1480 | setSource_DocumentWidget(d, &str); | 1522 | setSource_DocumentWidget(d, &str); |
1481 | } | 1523 | } |
1482 | deinit_String(&str); | 1524 | deinit_String(&str); |
@@ -1556,14 +1598,16 @@ static void cacheDocumentGlyphs_DocumentWidget_(const iDocumentWidget *d) { | |||
1556 | } | 1598 | } |
1557 | 1599 | ||
1558 | static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float normScrollY, | 1600 | static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float normScrollY, |
1559 | const iGmResponse *resp) { | 1601 | const iGmResponse *resp, iGmDocument *cachedDoc) { |
1560 | setLinkNumberMode_DocumentWidget_(d, iFalse); | 1602 | setLinkNumberMode_DocumentWidget_(d, iFalse); |
1561 | clear_ObjectList(d->media); | 1603 | clear_ObjectList(d->media); |
1562 | delete_Gempub(d->sourceGempub); | 1604 | delete_Gempub(d->sourceGempub); |
1563 | d->sourceGempub = NULL; | 1605 | d->sourceGempub = NULL; |
1564 | reset_GmDocument(d->doc); | 1606 | pauseAllPlayers_Media(media_GmDocument(d->doc), iTrue); |
1607 | iRelease(d->doc); | ||
1565 | destroy_Widget(d->footerButtons); | 1608 | destroy_Widget(d->footerButtons); |
1566 | d->footerButtons = NULL; | 1609 | d->footerButtons = NULL; |
1610 | d->doc = new_GmDocument(); | ||
1567 | resetWideRuns_DocumentWidget_(d); | 1611 | resetWideRuns_DocumentWidget_(d); |
1568 | d->state = fetching_RequestState; | 1612 | d->state = fetching_RequestState; |
1569 | /* Do the fetch. */ { | 1613 | /* Do the fetch. */ { |
@@ -1574,10 +1618,12 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n | |||
1574 | d->sourceStatus = success_GmStatusCode; | 1618 | d->sourceStatus = success_GmStatusCode; |
1575 | format_String(&d->sourceHeader, cstr_Lang("pageinfo.header.cached")); | 1619 | format_String(&d->sourceHeader, cstr_Lang("pageinfo.header.cached")); |
1576 | set_Block(&d->sourceContent, &resp->body); | 1620 | set_Block(&d->sourceContent, &resp->body); |
1577 | updateDocument_DocumentWidget_(d, resp, iTrue); | 1621 | updateDocument_DocumentWidget_(d, resp, cachedDoc, iTrue); |
1578 | postProcessRequestContent_DocumentWidget_(d, iTrue); | 1622 | // setCachedDocument_History(d->mod.history, d->doc, |
1623 | // (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0); | ||
1579 | } | 1624 | } |
1580 | d->state = ready_RequestState; | 1625 | d->state = ready_RequestState; |
1626 | postProcessRequestContent_DocumentWidget_(d, iTrue); | ||
1581 | init_Anim(&d->altTextOpacity, 0); | 1627 | init_Anim(&d->altTextOpacity, 0); |
1582 | reset_SmoothScroll(&d->scrollY); | 1628 | reset_SmoothScroll(&d->scrollY); |
1583 | init_Anim(&d->scrollY.pos, d->initNormScrollY * size_GmDocument(d->doc).y); | 1629 | init_Anim(&d->scrollY.pos, d->initNormScrollY * size_GmDocument(d->doc).y); |
@@ -1587,13 +1633,18 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n | |||
1587 | cacheDocumentGlyphs_DocumentWidget_(d); | 1633 | cacheDocumentGlyphs_DocumentWidget_(d); |
1588 | d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag; | 1634 | d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag; |
1589 | d->flags &= ~urlChanged_DocumentWidgetFlag; | 1635 | d->flags &= ~urlChanged_DocumentWidgetFlag; |
1590 | postCommandf_Root(as_Widget(d)->root, "document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); | 1636 | postCommandf_Root( |
1637 | as_Widget(d)->root, "document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); | ||
1591 | } | 1638 | } |
1592 | 1639 | ||
1593 | static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { | 1640 | static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { |
1594 | const iRecentUrl *recent = findUrl_History(d->mod.history, withSpacesEncoded_String(d->mod.url)); | 1641 | const iRecentUrl *recent = findUrl_History(d->mod.history, withSpacesEncoded_String(d->mod.url)); |
1595 | if (recent && recent->cachedResponse) { | 1642 | if (recent && recent->cachedResponse) { |
1596 | updateFromCachedResponse_DocumentWidget_(d, recent->normScrollY, recent->cachedResponse); | 1643 | iChangeFlags(d->flags, |
1644 | openedFromSidebar_DocumentWidgetFlag, | ||
1645 | recent->flags.openedFromSidebar); | ||
1646 | updateFromCachedResponse_DocumentWidget_( | ||
1647 | d, recent->normScrollY, recent->cachedResponse, recent->cachedDoc); | ||
1597 | return iTrue; | 1648 | return iTrue; |
1598 | } | 1649 | } |
1599 | else if (!isEmpty_String(d->mod.url)) { | 1650 | else if (!isEmpty_String(d->mod.url)) { |
@@ -1634,7 +1685,7 @@ static void scrollBegan_DocumentWidget_(iAnyObject *any, int offset, uint32_t du | |||
1634 | if (deviceType_App() == phone_AppDeviceType) { | 1685 | if (deviceType_App() == phone_AppDeviceType) { |
1635 | const float normPos = normScrollPos_DocumentWidget_(d); | 1686 | const float normPos = normScrollPos_DocumentWidget_(d); |
1636 | if (prefs_App()->hideToolbarOnScroll && iAbs(offset) > 5 && normPos >= 0) { | 1687 | if (prefs_App()->hideToolbarOnScroll && iAbs(offset) > 5 && normPos >= 0) { |
1637 | showToolbars_Root(as_Widget(d)->root, offset < 0); | 1688 | showToolbar_Root(as_Widget(d)->root, offset < 0); |
1638 | } | 1689 | } |
1639 | } | 1690 | } |
1640 | updateVisible_DocumentWidget_(d); | 1691 | updateVisible_DocumentWidget_(d); |
@@ -1843,13 +1894,15 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { | |||
1843 | /* Keep scroll position when reloading the same page. */ | 1894 | /* Keep scroll position when reloading the same page. */ |
1844 | reset_SmoothScroll(&d->scrollY); | 1895 | reset_SmoothScroll(&d->scrollY); |
1845 | } | 1896 | } |
1846 | reset_GmDocument(d->doc); /* new content incoming */ | 1897 | pauseAllPlayers_Media(media_GmDocument(d->doc), iTrue); |
1898 | iRelease(d->doc); /* new content incoming */ | ||
1899 | d->doc = new_GmDocument(); | ||
1847 | delete_Gempub(d->sourceGempub); | 1900 | delete_Gempub(d->sourceGempub); |
1848 | d->sourceGempub = NULL; | 1901 | d->sourceGempub = NULL; |
1849 | destroy_Widget(d->footerButtons); | 1902 | destroy_Widget(d->footerButtons); |
1850 | d->footerButtons = NULL; | 1903 | d->footerButtons = NULL; |
1851 | resetWideRuns_DocumentWidget_(d); | 1904 | resetWideRuns_DocumentWidget_(d); |
1852 | updateDocument_DocumentWidget_(d, resp, iTrue); | 1905 | updateDocument_DocumentWidget_(d, resp, NULL, iTrue); |
1853 | break; | 1906 | break; |
1854 | case categoryRedirect_GmStatusCode: | 1907 | case categoryRedirect_GmStatusCode: |
1855 | if (isEmpty_String(&resp->meta)) { | 1908 | if (isEmpty_String(&resp->meta)) { |
@@ -1900,7 +1953,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { | |||
1900 | switch (category_GmStatusCode(statusCode)) { | 1953 | switch (category_GmStatusCode(statusCode)) { |
1901 | case categorySuccess_GmStatusCode: | 1954 | case categorySuccess_GmStatusCode: |
1902 | /* More content available. */ | 1955 | /* More content available. */ |
1903 | updateDocument_DocumentWidget_(d, resp, iFalse); | 1956 | updateDocument_DocumentWidget_(d, resp, NULL, iFalse); |
1904 | break; | 1957 | break; |
1905 | default: | 1958 | default: |
1906 | break; | 1959 | break; |
@@ -2085,16 +2138,16 @@ static const iString *saveToDownloads_(const iString *url, const iString *mime, | |||
2085 | exportDownloadedFile_iOS(savePath); | 2138 | exportDownloadedFile_iOS(savePath); |
2086 | #else | 2139 | #else |
2087 | if (showDialog) { | 2140 | if (showDialog) { |
2088 | const iMenuItem items[2] = { | 2141 | const iMenuItem items[2] = { |
2089 | { "${dlg.save.opendownload}", 0, 0, | 2142 | { "${dlg.save.opendownload}", 0, 0, |
2090 | format_CStr("!open url:%s", cstrCollect_String(makeFileUrl_String(savePath))) }, | 2143 | format_CStr("!open url:%s", cstrCollect_String(makeFileUrl_String(savePath))) }, |
2091 | { "${dlg.message.ok}", 0, 0, "message.ok" }, | 2144 | { "${dlg.message.ok}", 0, 0, "message.ok" }, |
2092 | }; | 2145 | }; |
2093 | makeMessage_Widget(uiHeading_ColorEscape "${heading.save}", | 2146 | makeMessage_Widget(uiHeading_ColorEscape "${heading.save}", |
2094 | format_CStr("%s\n${dlg.save.size} %.3f %s", | 2147 | format_CStr("%s\n${dlg.save.size} %.3f %s", |
2095 | cstr_String(path_File(f)), | 2148 | cstr_String(path_File(f)), |
2096 | isMega ? size / 1.0e6f : (size / 1.0e3f), | 2149 | isMega ? size / 1.0e6f : (size / 1.0e3f), |
2097 | isMega ? "${mb}" : "${kb}"), | 2150 | isMega ? "${mb}" : "${kb}"), |
2098 | items, | 2151 | items, |
2099 | iElemCount(items)); | 2152 | iElemCount(items)); |
2100 | } | 2153 | } |
@@ -2208,6 +2261,147 @@ static iBool handlePinch_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | |||
2208 | return iTrue; | 2261 | return iTrue; |
2209 | } | 2262 | } |
2210 | 2263 | ||
2264 | static void swap_DocumentWidget_(iDocumentWidget *d, iGmDocument *doc, | ||
2265 | iDocumentWidget *swapBuffersWith) { | ||
2266 | if (doc) { | ||
2267 | iAssert(isInstance_Object(doc, &Class_GmDocument)); | ||
2268 | iGmDocument *copy = ref_Object(doc); | ||
2269 | iRelease(d->doc); | ||
2270 | d->doc = copy; | ||
2271 | d->scrollY = swapBuffersWith->scrollY; | ||
2272 | updateVisible_DocumentWidget_(d); | ||
2273 | iSwap(iVisBuf *, d->visBuf, swapBuffersWith->visBuf); | ||
2274 | iSwap(iVisBufMeta *, d->visBufMeta, swapBuffersWith->visBufMeta); | ||
2275 | iSwap(iDrawBufs *, d->drawBufs, swapBuffersWith->drawBufs); | ||
2276 | invalidate_DocumentWidget_(swapBuffersWith); | ||
2277 | } | ||
2278 | } | ||
2279 | |||
2280 | static iWidget *swipeParent_DocumentWidget_(iDocumentWidget *d) { | ||
2281 | return findChild_Widget(as_Widget(d)->root->widget, "doctabs"); | ||
2282 | } | ||
2283 | |||
2284 | static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | ||
2285 | iWidget *w = as_Widget(d); | ||
2286 | /* Swipe animations are rather complex and utilize both cached GmDocument content | ||
2287 | and temporary DocumentWidgets. Depending on the swipe direction, this DocumentWidget | ||
2288 | may wait until the finger is released to actually perform the navigation action. */ | ||
2289 | if (equal_Command(cmd, "edgeswipe.moved")) { | ||
2290 | //printf("[%p] responds to edgeswipe.moved\n", d); | ||
2291 | as_Widget(d)->offsetRef = NULL; | ||
2292 | const int side = argLabel_Command(cmd, "side"); | ||
2293 | const int offset = arg_Command(cmd); | ||
2294 | if (side == 1) { /* left edge */ | ||
2295 | if (atOldest_History(d->mod.history)) { | ||
2296 | return iTrue; | ||
2297 | } | ||
2298 | iWidget *swipeParent = swipeParent_DocumentWidget_(d); | ||
2299 | /* The temporary "swipeIn" will display the previous page until the finger is lifted. */ | ||
2300 | iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); | ||
2301 | if (!swipeIn) { | ||
2302 | const iBool sidebarSwipe = (isPortraitPhone_App() && | ||
2303 | d->flags & openedFromSidebar_DocumentWidgetFlag && | ||
2304 | !isVisible_Widget(findWidget_App("sidebar"))); | ||
2305 | swipeIn = new_DocumentWidget(); | ||
2306 | setId_Widget(as_Widget(swipeIn), "swipein"); | ||
2307 | setFlags_Widget(as_Widget(swipeIn), | ||
2308 | disabled_WidgetFlag | refChildrenOffset_WidgetFlag | | ||
2309 | fixedPosition_WidgetFlag | fixedSize_WidgetFlag, iTrue); | ||
2310 | swipeIn->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos)); | ||
2311 | swipeIn->widget.rect.size = d->widget.rect.size; | ||
2312 | swipeIn->widget.offsetRef = parent_Widget(w); | ||
2313 | if (!sidebarSwipe) { | ||
2314 | iRecentUrl *recent = new_RecentUrl(); | ||
2315 | preceding_History(d->mod.history, recent); | ||
2316 | if (recent->cachedDoc) { | ||
2317 | iChangeRef(swipeIn->doc, recent->cachedDoc); | ||
2318 | updateScrollMax_DocumentWidget_(d); | ||
2319 | setValue_Anim(&swipeIn->scrollY.pos, size_GmDocument(swipeIn->doc).y * recent->normScrollY, 0); | ||
2320 | updateVisible_DocumentWidget_(swipeIn); | ||
2321 | swipeIn->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag; | ||
2322 | } | ||
2323 | delete_RecentUrl(recent); | ||
2324 | } | ||
2325 | addChildPos_Widget(swipeParent, iClob(swipeIn), front_WidgetAddPos); | ||
2326 | } | ||
2327 | } | ||
2328 | if (side == 2) { /* right edge */ | ||
2329 | if (offset < -get_Window()->pixelRatio * 10) { | ||
2330 | int animSpan = 10; | ||
2331 | if (!atLatest_History(d->mod.history) && | ||
2332 | ~flags_Widget(w) & dragged_WidgetFlag) { | ||
2333 | animSpan = 0; | ||
2334 | postCommand_Widget(d, "navigate.forward"); | ||
2335 | setFlags_Widget(w, dragged_WidgetFlag, iTrue); | ||
2336 | /* Set up the swipe dummy. */ | ||
2337 | iWidget *swipeParent = swipeParent_DocumentWidget_(d); | ||
2338 | iDocumentWidget *target = new_DocumentWidget(); | ||
2339 | setId_Widget(as_Widget(target), "swipeout"); | ||
2340 | /* The target takes the old document and jumps on top. */ | ||
2341 | target->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos)); | ||
2342 | target->widget.rect.size = d->widget.rect.size; | ||
2343 | setFlags_Widget(as_Widget(target), fixedPosition_WidgetFlag | fixedSize_WidgetFlag, iTrue); | ||
2344 | swap_DocumentWidget_(target, d->doc, d); | ||
2345 | addChildPos_Widget(swipeParent, iClob(target), front_WidgetAddPos); | ||
2346 | setFlags_Widget(as_Widget(target), refChildrenOffset_WidgetFlag, iTrue); | ||
2347 | as_Widget(target)->offsetRef = parent_Widget(w); | ||
2348 | destroy_Widget(as_Widget(target)); /* will be actually deleted after animation finishes */ | ||
2349 | } | ||
2350 | if (flags_Widget(w) & dragged_WidgetFlag) { | ||
2351 | setVisualOffset_Widget(w, width_Widget(w) + | ||
2352 | width_Widget(d) * offset / size_Root(w->root).x, | ||
2353 | animSpan, 0); | ||
2354 | } | ||
2355 | else { | ||
2356 | setVisualOffset_Widget(w, offset / 4, animSpan, 0); | ||
2357 | } | ||
2358 | } | ||
2359 | return iTrue; | ||
2360 | } | ||
2361 | } | ||
2362 | if (equal_Command(cmd, "edgeswipe.ended") && argLabel_Command(cmd, "side") == 2) { | ||
2363 | if (argLabel_Command(cmd, "abort") && flags_Widget(w) & dragged_WidgetFlag) { | ||
2364 | postCommand_Widget(d, "navigate.back"); | ||
2365 | } | ||
2366 | setFlags_Widget(w, dragged_WidgetFlag, iFalse); | ||
2367 | setVisualOffset_Widget(w, 0, 100, 0); | ||
2368 | return iTrue; | ||
2369 | } | ||
2370 | if (equal_Command(cmd, "edgeswipe.ended") && argLabel_Command(cmd, "side") == 1) { | ||
2371 | iWidget *swipeParent = swipeParent_DocumentWidget_(d); | ||
2372 | iWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); | ||
2373 | if (swipeIn) { | ||
2374 | swipeIn->offsetRef = NULL; | ||
2375 | destroy_Widget(swipeIn); | ||
2376 | } | ||
2377 | } | ||
2378 | if (equal_Command(cmd, "swipe.back")) { | ||
2379 | if (atOldest_History(d->mod.history)) { | ||
2380 | setVisualOffset_Widget(w, 0, 100, 0); | ||
2381 | return iTrue; | ||
2382 | } | ||
2383 | iWidget *swipeParent = swipeParent_DocumentWidget_(d); | ||
2384 | iDocumentWidget *target = new_DocumentWidget(); | ||
2385 | setId_Widget(as_Widget(target), "swipeout"); | ||
2386 | /* The target takes the old document and jumps on top. */ | ||
2387 | target->widget.rect.pos = windowToInner_Widget(swipeParent, innerToWindow_Widget(w, zero_I2())); | ||
2388 | /* Note: `innerToWindow_Widget` does not apply visual offset. */ | ||
2389 | target->widget.rect.size = w->rect.size; | ||
2390 | setFlags_Widget(as_Widget(target), fixedPosition_WidgetFlag | fixedSize_WidgetFlag, iTrue); | ||
2391 | swap_DocumentWidget_(target, d->doc, d); | ||
2392 | addChildPos_Widget(swipeParent, iClob(target), back_WidgetAddPos); | ||
2393 | setFlags_Widget(as_Widget(d), refChildrenOffset_WidgetFlag, iTrue); | ||
2394 | as_Widget(d)->offsetRef = swipeParent; | ||
2395 | setVisualOffset_Widget(as_Widget(target), value_Anim(&w->visualOffset), 0, 0); | ||
2396 | setVisualOffset_Widget(as_Widget(target), width_Widget(target), 150, 0); | ||
2397 | destroy_Widget(as_Widget(target)); /* will be actually deleted after animation finishes */ | ||
2398 | setVisualOffset_Widget(w, 0, 0, 0); | ||
2399 | postCommand_Widget(d, "navigate.back"); | ||
2400 | return iTrue; | ||
2401 | } | ||
2402 | return iFalse; | ||
2403 | } | ||
2404 | |||
2211 | static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | 2405 | static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { |
2212 | iWidget *w = as_Widget(d); | 2406 | iWidget *w = as_Widget(d); |
2213 | if (equal_Command(cmd, "document.openurls.changed")) { | 2407 | if (equal_Command(cmd, "document.openurls.changed")) { |
@@ -2256,6 +2450,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2256 | return iFalse; | 2450 | return iFalse; |
2257 | } | 2451 | } |
2258 | else if (equal_Command(cmd, "theme.changed") && document_App() == d) { | 2452 | else if (equal_Command(cmd, "theme.changed") && document_App() == d) { |
2453 | // invalidateTheme_History(d->mod.history); /* cached colors */ | ||
2259 | updateTheme_DocumentWidget_(d); | 2454 | updateTheme_DocumentWidget_(d); |
2260 | updateVisible_DocumentWidget_(d); | 2455 | updateVisible_DocumentWidget_(d); |
2261 | updateTrust_DocumentWidget_(d, NULL); | 2456 | updateTrust_DocumentWidget_(d, NULL); |
@@ -2345,6 +2540,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2345 | msg, "%s\n", formatCStrs_Lang("num.bytes.n", size_Block(&d->sourceContent))); | 2540 | msg, "%s\n", formatCStrs_Lang("num.bytes.n", size_Block(&d->sourceContent))); |
2346 | } | 2541 | } |
2347 | } | 2542 | } |
2543 | /* TODO: On mobile, omit the CA status. */ | ||
2348 | appendFormat_String( | 2544 | appendFormat_String( |
2349 | msg, | 2545 | msg, |
2350 | "\n%s${pageinfo.cert.status}\n" | 2546 | "\n%s${pageinfo.cert.status}\n" |
@@ -2649,6 +2845,18 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2649 | return iTrue; | 2845 | return iTrue; |
2650 | } | 2846 | } |
2651 | else if (equal_Command(cmd, "navigate.back") && document_App() == d) { | 2847 | else if (equal_Command(cmd, "navigate.back") && document_App() == d) { |
2848 | if (isPortraitPhone_App()) { | ||
2849 | if (d->flags & openedFromSidebar_DocumentWidgetFlag && | ||
2850 | !isVisible_Widget(findWidget_App("sidebar"))) { | ||
2851 | postCommand_App("sidebar.toggle"); | ||
2852 | showToolbar_Root(get_Root(), iTrue); | ||
2853 | #if defined (iPlatformAppleMobile) | ||
2854 | playHapticEffect_iOS(gentleTap_HapticEffect); | ||
2855 | #endif | ||
2856 | return iTrue; | ||
2857 | } | ||
2858 | d->flags &= ~openedFromSidebar_DocumentWidgetFlag; | ||
2859 | } | ||
2652 | if (d->request) { | 2860 | if (d->request) { |
2653 | postCommandf_Root(w->root, | 2861 | postCommandf_Root(w->root, |
2654 | "document.request.cancelled doc:%p url:%s", d, cstr_String(d->mod.url)); | 2862 | "document.request.cancelled doc:%p url:%s", d, cstr_String(d->mod.url)); |
@@ -2811,7 +3019,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2811 | uiHeading_ColorEscape "${heading.import.bookmarks}", | 3019 | uiHeading_ColorEscape "${heading.import.bookmarks}", |
2812 | formatCStrs_Lang("dlg.import.found.n", count), | 3020 | formatCStrs_Lang("dlg.import.found.n", count), |
2813 | (iMenuItem[]){ { "${cancel}", 0, 0, NULL }, | 3021 | (iMenuItem[]){ { "${cancel}", 0, 0, NULL }, |
2814 | { format_CStr(cstrCount_Lang("dlg.import.add.n", count), | 3022 | { format_CStr(cstrCount_Lang("dlg.import.add.n", (int) count), |
2815 | uiTextAction_ColorEscape, | 3023 | uiTextAction_ColorEscape, |
2816 | count), | 3024 | count), |
2817 | 0, | 3025 | 0, |
@@ -2870,6 +3078,10 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2870 | else if (startsWith_CStr(cmd, "pinch.") && document_Command(cmd) == d) { | 3078 | else if (startsWith_CStr(cmd, "pinch.") && document_Command(cmd) == d) { |
2871 | return handlePinch_DocumentWidget_(d, cmd); | 3079 | return handlePinch_DocumentWidget_(d, cmd); |
2872 | } | 3080 | } |
3081 | else if ((startsWith_CStr(cmd, "edgeswipe.") || startsWith_CStr(cmd, "swipe.")) && | ||
3082 | document_App() == d) { | ||
3083 | return handleSwipe_DocumentWidget_(d, cmd); | ||
3084 | } | ||
2873 | return iFalse; | 3085 | return iFalse; |
2874 | } | 3086 | } |
2875 | 3087 | ||
@@ -3318,6 +3530,18 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3318 | d->contextLink->linkId) }); | 3530 | d->contextLink->linkId) }); |
3319 | } | 3531 | } |
3320 | } | 3532 | } |
3533 | if (equalCase_Rangecc(scheme, "file")) { | ||
3534 | /* Local files may be deleted. */ | ||
3535 | pushBack_Array( | ||
3536 | &items, | ||
3537 | &(iMenuItem){ delete_Icon " " uiTextCaution_ColorEscape | ||
3538 | "${link.file.delete}", | ||
3539 | 0, | ||
3540 | 0, | ||
3541 | format_CStr("!file.delete confirm:1 path:%s", | ||
3542 | cstrCollect_String( | ||
3543 | localFilePathFromUrl_String(linkUrl))) }); | ||
3544 | } | ||
3321 | } | 3545 | } |
3322 | else if (deviceType_App() == desktop_AppDeviceType) { | 3546 | else if (deviceType_App() == desktop_AppDeviceType) { |
3323 | if (!isEmpty_Range(&d->selectMark)) { | 3547 | if (!isEmpty_Range(&d->selectMark)) { |
@@ -3870,14 +4094,14 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
3870 | } | 4094 | } |
3871 | #endif | 4095 | #endif |
3872 | /* Fill the background. */ { | 4096 | /* Fill the background. */ { |
3873 | if (run->linkId && linkFlags & isOpen_GmLinkFlag) { | 4097 | if (run->linkId && linkFlags & isOpen_GmLinkFlag && ~linkFlags & content_GmLinkFlag) { |
3874 | /* Open links get a highlighted background. */ | 4098 | /* Open links get a highlighted background. */ |
3875 | int bg = tmBackgroundOpenLink_ColorId; | 4099 | int bg = tmBackgroundOpenLink_ColorId; |
3876 | const int frame = tmFrameOpenLink_ColorId; | 4100 | const int frame = tmFrameOpenLink_ColorId; |
3877 | iRect wideRect = { init_I2(left_Rect(d->widgetBounds), visPos.y), | 4101 | iRect wideRect = { init_I2(left_Rect(d->widgetBounds), visPos.y), |
3878 | init_I2(width_Rect(d->widgetBounds) + | 4102 | init_I2(width_Rect(d->widgetBounds) + |
3879 | width_Widget(d->widget->scroll), | 4103 | width_Widget(d->widget->scroll), |
3880 | height_Rect(run->visBounds)) }; | 4104 | height_Rect(run->visBounds)) }; |
3881 | /* The first line is composed of two runs that may be drawn in either order, so | 4105 | /* The first line is composed of two runs that may be drawn in either order, so |
3882 | only draw half of the background. */ | 4106 | only draw half of the background. */ |
3883 | if (run->flags & decoration_GmRunFlag) { | 4107 | if (run->flags & decoration_GmRunFlag) { |
@@ -3931,16 +4155,17 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
3931 | linkOrdinalChar_DocumentWidget_(d->widget, ord - d->widget->ordinalBase); | 4155 | linkOrdinalChar_DocumentWidget_(d->widget, ord - d->widget->ordinalBase); |
3932 | if (ordChar) { | 4156 | if (ordChar) { |
3933 | const char *circle = "\u25ef"; /* Large Circle */ | 4157 | const char *circle = "\u25ef"; /* Large Circle */ |
4158 | const int circleFont = defaultContentRegular_FontId; | ||
3934 | iRect nbArea = { init_I2(d->viewPos.x - gap_UI / 3, visPos.y), | 4159 | iRect nbArea = { init_I2(d->viewPos.x - gap_UI / 3, visPos.y), |
3935 | init_I2(3.95f * gap_Text, 1.0f * lineHeight_Text(run->font)) }; | 4160 | init_I2(3.95f * gap_Text, 1.0f * lineHeight_Text(circleFont)) }; |
3936 | drawRange_Text( | 4161 | drawRange_Text( |
3937 | run->font, topLeft_Rect(nbArea), tmQuote_ColorId, range_CStr(circle)); | 4162 | circleFont, topLeft_Rect(nbArea), tmQuote_ColorId, range_CStr(circle)); |
3938 | iRect circleArea = visualBounds_Text(run->font, range_CStr(circle)); | 4163 | iRect circleArea = visualBounds_Text(circleFont, range_CStr(circle)); |
3939 | addv_I2(&circleArea.pos, topLeft_Rect(nbArea)); | 4164 | addv_I2(&circleArea.pos, topLeft_Rect(nbArea)); |
3940 | drawCentered_Text(defaultContentSmall_FontId, | 4165 | drawCentered_Text(defaultContentSmall_FontId, |
3941 | circleArea, | 4166 | circleArea, |
3942 | iTrue, | 4167 | iTrue, |
3943 | tmQuote_ColorId, | 4168 | tmQuote_ColorId, |
3944 | "%lc", | 4169 | "%lc", |
3945 | (int) ordChar); | 4170 | (int) ordChar); |
3946 | goto runDrawn; | 4171 | goto runDrawn; |
@@ -4178,7 +4403,7 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | |||
4178 | iDrawBufs * dbuf = d->drawBufs; | 4403 | iDrawBufs * dbuf = d->drawBufs; |
4179 | iPaint p; | 4404 | iPaint p; |
4180 | init_Paint(&p); | 4405 | init_Paint(&p); |
4181 | setClip_Paint(&p, bounds); | 4406 | setClip_Paint(&p, boundsWithoutVisualOffset_Widget(w)); |
4182 | /* Side icon and current heading. */ | 4407 | /* Side icon and current heading. */ |
4183 | if (prefs_App()->sideIcon && opacity > 0 && dbuf->sideIconBuf) { | 4408 | if (prefs_App()->sideIcon && opacity > 0 && dbuf->sideIconBuf) { |
4184 | const iInt2 texSize = size_SDLTexture(dbuf->sideIconBuf); | 4409 | const iInt2 texSize = size_SDLTexture(dbuf->sideIconBuf); |
@@ -4263,7 +4488,8 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, | |||
4263 | /* Swap buffers around to have room available both before and after the visible region. */ | 4488 | /* Swap buffers around to have room available both before and after the visible region. */ |
4264 | allocVisBuffer_DocumentWidget_(d); | 4489 | allocVisBuffer_DocumentWidget_(d); |
4265 | reposition_VisBuf(visBuf, vis); | 4490 | reposition_VisBuf(visBuf, vis); |
4266 | /* Redraw the invalid ranges. */ { | 4491 | /* Redraw the invalid ranges. */ |
4492 | if (~flags_Widget(constAs_Widget(d)) & destroyPending_WidgetFlag) { | ||
4267 | iPaint *p = &ctx->paint; | 4493 | iPaint *p = &ctx->paint; |
4268 | init_Paint(p); | 4494 | init_Paint(p); |
4269 | iForIndices(i, visBuf->buffers) { | 4495 | iForIndices(i, visBuf->buffers) { |
@@ -4427,12 +4653,17 @@ static void prerender_DocumentWidget_(iAny *context) { | |||
4427 | } | 4653 | } |
4428 | 4654 | ||
4429 | static void draw_DocumentWidget_(const iDocumentWidget *d) { | 4655 | static void draw_DocumentWidget_(const iDocumentWidget *d) { |
4430 | const iWidget *w = constAs_Widget(d); | 4656 | const iWidget *w = constAs_Widget(d); |
4431 | const iRect bounds = bounds_Widget(w); | 4657 | const iRect bounds = bounds_Widget(w); |
4658 | const iRect boundsWithoutVisOff = boundsWithoutVisualOffset_Widget(w); | ||
4659 | const iRect clipBounds = intersect_Rect(bounds, boundsWithoutVisOff); | ||
4432 | if (width_Rect(bounds) <= 0) { | 4660 | if (width_Rect(bounds) <= 0) { |
4433 | return; | 4661 | return; |
4434 | } | 4662 | } |
4435 | // draw_Widget(w); | 4663 | /* TODO: Come up with a better palette caching system. |
4664 | It should be able to recompute cached colors in `History` when the theme has changed. | ||
4665 | Cache the theme seed in `GmDocument`? */ | ||
4666 | // makePaletteGlobal_GmDocument(d->doc); | ||
4436 | if (d->drawBufs->flags & updateTimestampBuf_DrawBufsFlag) { | 4667 | if (d->drawBufs->flags & updateTimestampBuf_DrawBufsFlag) { |
4437 | updateTimestampBuf_DocumentWidget_(d); | 4668 | updateTimestampBuf_DocumentWidget_(d); |
4438 | } | 4669 | } |
@@ -4447,14 +4678,15 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
4447 | .vis = vis, | 4678 | .vis = vis, |
4448 | .showLinkNumbers = (d->flags & showLinkNumbers_DocumentWidgetFlag) != 0, | 4679 | .showLinkNumbers = (d->flags & showLinkNumbers_DocumentWidgetFlag) != 0, |
4449 | }; | 4680 | }; |
4681 | init_Paint(&ctx.paint); | ||
4450 | render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */); | 4682 | render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */); |
4451 | setClip_Paint(&ctx.paint, bounds); | 4683 | setClip_Paint(&ctx.paint, clipBounds); |
4452 | int yTop = docBounds.pos.y - pos_SmoothScroll(&d->scrollY); | 4684 | int yTop = docBounds.pos.y - pos_SmoothScroll(&d->scrollY); |
4453 | draw_VisBuf(d->visBuf, init_I2(bounds.pos.x, yTop), ySpan_Rect(bounds)); | 4685 | draw_VisBuf(d->visBuf, init_I2(bounds.pos.x, yTop), ySpan_Rect(bounds)); |
4454 | /* Text markers. */ | 4686 | /* Text markers. */ |
4455 | const iBool isTouchSelecting = (flags_Widget(w) & touchDrag_WidgetFlag) != 0; | 4687 | const iBool isTouchSelecting = (flags_Widget(w) & touchDrag_WidgetFlag) != 0; |
4456 | if (!isEmpty_Range(&d->foundMark) || !isEmpty_Range(&d->selectMark)) { | 4688 | if (!isEmpty_Range(&d->foundMark) || !isEmpty_Range(&d->selectMark)) { |
4457 | SDL_Renderer *render = renderer_Window(get_Window()); | 4689 | SDL_Renderer *render = renderer_Window(get_Window()); |
4458 | ctx.firstMarkRect = zero_Rect(); | 4690 | ctx.firstMarkRect = zero_Rect(); |
4459 | ctx.lastMarkRect = zero_Rect(); | 4691 | ctx.lastMarkRect = zero_Rect(); |
4460 | SDL_SetRenderDrawBlendMode(render, | 4692 | SDL_SetRenderDrawBlendMode(render, |
@@ -4483,7 +4715,6 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
4483 | } | 4715 | } |
4484 | } | 4716 | } |
4485 | drawMedia_DocumentWidget_(d, &ctx.paint); | 4717 | drawMedia_DocumentWidget_(d, &ctx.paint); |
4486 | unsetClip_Paint(&ctx.paint); | ||
4487 | /* Fill the top and bottom, in case the document is short. */ | 4718 | /* Fill the top and bottom, in case the document is short. */ |
4488 | if (yTop > top_Rect(bounds)) { | 4719 | if (yTop > top_Rect(bounds)) { |
4489 | fillRect_Paint(&ctx.paint, | 4720 | fillRect_Paint(&ctx.paint, |
@@ -4497,6 +4728,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
4497 | init_Rect(bounds.pos.x, yBottom, bounds.size.x, bottom_Rect(bounds) - yBottom), | 4728 | init_Rect(bounds.pos.x, yBottom, bounds.size.x, bottom_Rect(bounds) - yBottom), |
4498 | tmBackground_ColorId); | 4729 | tmBackground_ColorId); |
4499 | } | 4730 | } |
4731 | unsetClip_Paint(&ctx.paint); | ||
4500 | drawSideElements_DocumentWidget_(d); | 4732 | drawSideElements_DocumentWidget_(d); |
4501 | if (prefs_App()->hoverLink && d->hoverLink) { | 4733 | if (prefs_App()->hoverLink && d->hoverLink) { |
4502 | const int font = uiLabel_FontId; | 4734 | const int font = uiLabel_FontId; |
@@ -4558,6 +4790,23 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
4558 | drawCentered_Text(uiLabelBold_FontId, rect, iFalse, uiBackground_ColorId, "%zu bytes selected", | 4790 | drawCentered_Text(uiLabelBold_FontId, rect, iFalse, uiBackground_ColorId, "%zu bytes selected", |
4559 | size_Range(&mark)); | 4791 | size_Range(&mark)); |
4560 | } | 4792 | } |
4793 | if (w->offsetRef) { | ||
4794 | const int offX = visualOffsetByReference_Widget(w); | ||
4795 | if (offX) { | ||
4796 | setClip_Paint(&ctx.paint, clipBounds); | ||
4797 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); | ||
4798 | ctx.paint.alpha = iAbs(offX) / (float) get_Window()->size.x * 300; | ||
4799 | fillRect_Paint(&ctx.paint, bounds, backgroundFadeColor_Widget()); | ||
4800 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); | ||
4801 | unsetClip_Paint(&ctx.paint); | ||
4802 | } | ||
4803 | else { | ||
4804 | /* TODO: Should have a better place to do this; drawing is supposed to be immutable. */ | ||
4805 | iWidget *mut = iConstCast(iWidget *, w); | ||
4806 | mut->offsetRef = NULL; | ||
4807 | mut->flags &= ~refChildrenOffset_WidgetFlag; | ||
4808 | } | ||
4809 | } | ||
4561 | } | 4810 | } |
4562 | 4811 | ||
4563 | /*----------------------------------------------------------------------------------------------*/ | 4812 | /*----------------------------------------------------------------------------------------------*/ |
@@ -4625,9 +4874,12 @@ static void setUrl_DocumentWidget_(iDocumentWidget *d, const iString *url) { | |||
4625 | d->flags |= urlChanged_DocumentWidgetFlag; | 4874 | d->flags |= urlChanged_DocumentWidgetFlag; |
4626 | set_String(d->mod.url, url); | 4875 | set_String(d->mod.url, url); |
4627 | } | 4876 | } |
4628 | } | 4877 | } |
4629 | 4878 | ||
4630 | void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBool isFromCache) { | 4879 | void setUrlFlags_DocumentWidget(iDocumentWidget *d, const iString *url, int setUrlFlags) { |
4880 | iChangeFlags(d->flags, openedFromSidebar_DocumentWidgetFlag, | ||
4881 | (setUrlFlags & openedFromSidebar_DocumentWidgetSetUrlFlag) != 0); | ||
4882 | const iBool isFromCache = (setUrlFlags & useCachedContentIfAvailable_DocumentWidgetSetUrlFlag) != 0; | ||
4631 | setLinkNumberMode_DocumentWidget_(d, iFalse); | 4883 | setLinkNumberMode_DocumentWidget_(d, iFalse); |
4632 | setUrl_DocumentWidget_(d, urlFragmentStripped_String(url)); | 4884 | setUrl_DocumentWidget_(d, urlFragmentStripped_String(url)); |
4633 | /* See if there a username in the URL. */ | 4885 | /* See if there a username in the URL. */ |
@@ -4639,6 +4891,7 @@ void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBoo | |||
4639 | 4891 | ||
4640 | void setUrlAndSource_DocumentWidget(iDocumentWidget *d, const iString *url, const iString *mime, | 4892 | void setUrlAndSource_DocumentWidget(iDocumentWidget *d, const iString *url, const iString *mime, |
4641 | const iBlock *source) { | 4893 | const iBlock *source) { |
4894 | d->flags &= ~openedFromSidebar_DocumentWidgetFlag; | ||
4642 | setLinkNumberMode_DocumentWidget_(d, iFalse); | 4895 | setLinkNumberMode_DocumentWidget_(d, iFalse); |
4643 | setUrl_DocumentWidget_(d, url); | 4896 | setUrl_DocumentWidget_(d, url); |
4644 | parseUser_DocumentWidget_(d); | 4897 | parseUser_DocumentWidget_(d); |
@@ -4647,7 +4900,7 @@ void setUrlAndSource_DocumentWidget(iDocumentWidget *d, const iString *url, cons | |||
4647 | initCurrent_Time(&resp->when); | 4900 | initCurrent_Time(&resp->when); |
4648 | set_String(&resp->meta, mime); | 4901 | set_String(&resp->meta, mime); |
4649 | set_Block(&resp->body, source); | 4902 | set_Block(&resp->body, source); |
4650 | updateFromCachedResponse_DocumentWidget_(d, 0, resp); | 4903 | updateFromCachedResponse_DocumentWidget_(d, 0, resp, NULL); |
4651 | delete_GmResponse(resp); | 4904 | delete_GmResponse(resp); |
4652 | } | 4905 | } |
4653 | 4906 | ||
@@ -4656,12 +4909,12 @@ iDocumentWidget *duplicate_DocumentWidget(const iDocumentWidget *orig) { | |||
4656 | delete_History(d->mod.history); | 4909 | delete_History(d->mod.history); |
4657 | d->initNormScrollY = normScrollPos_DocumentWidget_(d); | 4910 | d->initNormScrollY = normScrollPos_DocumentWidget_(d); |
4658 | d->mod.history = copy_History(orig->mod.history); | 4911 | d->mod.history = copy_History(orig->mod.history); |
4659 | setUrlFromCache_DocumentWidget(d, orig->mod.url, iTrue); | 4912 | setUrlFlags_DocumentWidget(d, orig->mod.url, useCachedContentIfAvailable_DocumentWidgetSetUrlFlag); |
4660 | return d; | 4913 | return d; |
4661 | } | 4914 | } |
4662 | 4915 | ||
4663 | void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) { | 4916 | void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) { |
4664 | setUrlFromCache_DocumentWidget(d, url, iFalse); | 4917 | setUrlFlags_DocumentWidget(d, url, 0); |
4665 | } | 4918 | } |
4666 | 4919 | ||
4667 | void setInitialScroll_DocumentWidget(iDocumentWidget *d, float normScrollY) { | 4920 | void setInitialScroll_DocumentWidget(iDocumentWidget *d, float normScrollY) { |
@@ -4672,6 +4925,11 @@ void setRedirectCount_DocumentWidget(iDocumentWidget *d, int count) { | |||
4672 | d->redirectCount = count; | 4925 | d->redirectCount = count; |
4673 | } | 4926 | } |
4674 | 4927 | ||
4928 | void setOpenedFromSidebar_DocumentWidget(iDocumentWidget *d, iBool fromSidebar) { | ||
4929 | iChangeFlags(d->flags, openedFromSidebar_DocumentWidgetFlag, fromSidebar); | ||
4930 | // setCachedDocument_History(d->mod.history, d->doc, fromSidebar); | ||
4931 | } | ||
4932 | |||
4675 | iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) { | 4933 | iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) { |
4676 | return d->request != NULL; | 4934 | return d->request != NULL; |
4677 | } | 4935 | } |
diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h index c038f981..1921b25a 100644 --- a/src/ui/documentwidget.h +++ b/src/ui/documentwidget.h | |||
@@ -45,11 +45,17 @@ const iString * bookmarkTitle_DocumentWidget (const iDocumentWidget *); | |||
45 | const iString * feedTitle_DocumentWidget (const iDocumentWidget *); | 45 | const iString * feedTitle_DocumentWidget (const iDocumentWidget *); |
46 | int documentWidth_DocumentWidget (const iDocumentWidget *); | 46 | int documentWidth_DocumentWidget (const iDocumentWidget *); |
47 | 47 | ||
48 | enum iDocumentWidgetSetUrlFlags { | ||
49 | useCachedContentIfAvailable_DocumentWidgetSetUrlFlag = iBit(1), | ||
50 | openedFromSidebar_DocumentWidgetSetUrlFlag = iBit(2), | ||
51 | }; | ||
52 | |||
48 | void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); | 53 | void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); |
49 | void setUrlFromCache_DocumentWidget (iDocumentWidget *, const iString *url, iBool isFromCache); | 54 | void setUrlFlags_DocumentWidget (iDocumentWidget *, const iString *url, int setUrlFlags); |
50 | void setUrlAndSource_DocumentWidget (iDocumentWidget *, const iString *url, const iString *mime, const iBlock *source); | 55 | void setUrlAndSource_DocumentWidget (iDocumentWidget *, const iString *url, const iString *mime, const iBlock *source); |
51 | void setInitialScroll_DocumentWidget (iDocumentWidget *, float normScrollY); /* set after content received */ | 56 | void setInitialScroll_DocumentWidget (iDocumentWidget *, float normScrollY); /* set after content received */ |
52 | void setRedirectCount_DocumentWidget (iDocumentWidget *, int count); | 57 | void setRedirectCount_DocumentWidget (iDocumentWidget *, int count); |
53 | void setSource_DocumentWidget (iDocumentWidget *, const iString *sourceText); | 58 | void setSource_DocumentWidget (iDocumentWidget *, const iString *sourceText); |
59 | void setOpenedFromSidebar_DocumentWidget(iDocumentWidget *, iBool fromSidebar); | ||
54 | 60 | ||
55 | void updateSize_DocumentWidget (iDocumentWidget *); | 61 | void updateSize_DocumentWidget (iDocumentWidget *); |
diff --git a/src/ui/indicatorwidget.c b/src/ui/indicatorwidget.c index 4a829ae3..bc0bd0fa 100644 --- a/src/ui/indicatorwidget.c +++ b/src/ui/indicatorwidget.c | |||
@@ -109,7 +109,7 @@ void draw_IndicatorWidget_(const iIndicatorWidget *d) { | |||
109 | colors[0] = black_ColorId; | 109 | colors[0] = black_ColorId; |
110 | } | 110 | } |
111 | fillRect_Paint(&p, | 111 | fillRect_Paint(&p, |
112 | (iRect){ topLeft_Rect(rect), init_I2(pos * width_Rect(rect), gap_UI / 4)}, | 112 | (iRect){ topLeft_Rect(rect), init_I2(pos * width_Rect(rect), gap_UI / 3)}, |
113 | colors[isCompleted_IndicatorWidget_(d) ? 1 : 0]); | 113 | colors[isCompleted_IndicatorWidget_(d) ? 1 : 0]); |
114 | } | 114 | } |
115 | } | 115 | } |
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index 32fb5ccb..b108ee17 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -80,6 +80,7 @@ enum iInputWidgetFlag { | |||
80 | markWords_InputWidgetFlag = iBit(8), | 80 | markWords_InputWidgetFlag = iBit(8), |
81 | needUpdateBuffer_InputWidgetFlag = iBit(9), | 81 | needUpdateBuffer_InputWidgetFlag = iBit(9), |
82 | enterKeyEnabled_InputWidgetFlag = iBit(10), | 82 | enterKeyEnabled_InputWidgetFlag = iBit(10), |
83 | enterKeyInsertsLineFeed_InputWidgetFlag = iBit(11), | ||
83 | }; | 84 | }; |
84 | 85 | ||
85 | /*----------------------------------------------------------------------------------------------*/ | 86 | /*----------------------------------------------------------------------------------------------*/ |
@@ -347,8 +348,11 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) { | |||
347 | d->lastCursor = 0; | 348 | d->lastCursor = 0; |
348 | d->cursorLine = 0; | 349 | d->cursorLine = 0; |
349 | d->lastUpdateWidth = 0; | 350 | d->lastUpdateWidth = 0; |
350 | d->verticalMoveX = -1; /* TODO: Use this. */ | 351 | d->verticalMoveX = -1; /* TODO: Use this. */ |
351 | d->inFlags = eatEscape_InputWidgetFlag | enterKeyEnabled_InputWidgetFlag; | 352 | d->inFlags = eatEscape_InputWidgetFlag | enterKeyEnabled_InputWidgetFlag; |
353 | if (deviceType_App() != desktop_AppDeviceType) { | ||
354 | d->inFlags |= enterKeyInsertsLineFeed_InputWidgetFlag; | ||
355 | } | ||
352 | iZap(d->mark); | 356 | iZap(d->mark); |
353 | setMaxLen_InputWidget(d, maxLen); | 357 | setMaxLen_InputWidget(d, maxLen); |
354 | d->maxLayoutLines = iInvalidSize; | 358 | d->maxLayoutLines = iInvalidSize; |
@@ -464,6 +468,10 @@ void setValidator_InputWidget(iInputWidget *d, iInputWidgetValidatorFunc validat | |||
464 | d->validatorContext = context; | 468 | d->validatorContext = context; |
465 | } | 469 | } |
466 | 470 | ||
471 | void setEnterInsertsLF_InputWidget(iInputWidget *d, iBool enterInsertsLF) { | ||
472 | iChangeFlags(d->inFlags, enterKeyInsertsLineFeed_InputWidgetFlag, enterInsertsLF); | ||
473 | } | ||
474 | |||
467 | void setEnterKeyEnabled_InputWidget(iInputWidget *d, iBool enterKeyEnabled) { | 475 | void setEnterKeyEnabled_InputWidget(iInputWidget *d, iBool enterKeyEnabled) { |
468 | iChangeFlags(d->inFlags, enterKeyEnabled_InputWidgetFlag, enterKeyEnabled); | 476 | iChangeFlags(d->inFlags, enterKeyEnabled_InputWidgetFlag, enterKeyEnabled); |
469 | } | 477 | } |
@@ -714,12 +722,12 @@ iLocalDef iBool isLastLine_InputWidget_(const iInputWidget *d, const iInputLine | |||
714 | } | 722 | } |
715 | 723 | ||
716 | static size_t indexForRelativeX_InputWidget_(const iInputWidget *d, int x, const iInputLine *line) { | 724 | static size_t indexForRelativeX_InputWidget_(const iInputWidget *d, int x, const iInputLine *line) { |
725 | size_t index = line->offset; | ||
717 | if (x <= 0) { | 726 | if (x <= 0) { |
718 | return line->offset; | 727 | return index; |
719 | } | 728 | } |
720 | const char *endPos; | 729 | const char *endPos; |
721 | tryAdvanceNoWrap_Text(d->font, range_String(&line->text), x, &endPos); | 730 | tryAdvanceNoWrap_Text(d->font, range_String(&line->text), x, &endPos); |
722 | size_t index = line->offset; | ||
723 | if (endPos == constEnd_String(&line->text)) { | 731 | if (endPos == constEnd_String(&line->text)) { |
724 | index += line->len; | 732 | index += line->len; |
725 | } | 733 | } |
@@ -1166,7 +1174,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
1166 | case SDLK_KP_ENTER: | 1174 | case SDLK_KP_ENTER: |
1167 | if (mods == KMOD_SHIFT || (d->maxLen == 0 && | 1175 | if (mods == KMOD_SHIFT || (d->maxLen == 0 && |
1168 | ~d->inFlags & isUrl_InputWidgetFlag && | 1176 | ~d->inFlags & isUrl_InputWidgetFlag && |
1169 | deviceType_App() != desktop_AppDeviceType)) { | 1177 | d->inFlags & enterKeyInsertsLineFeed_InputWidgetFlag)) { |
1170 | pushUndo_InputWidget_(d); | 1178 | pushUndo_InputWidget_(d); |
1171 | deleteMarked_InputWidget_(d); | 1179 | deleteMarked_InputWidget_(d); |
1172 | insertChar_InputWidget_(d, '\n'); | 1180 | insertChar_InputWidget_(d, '\n'); |
@@ -1357,13 +1365,7 @@ static void draw_InputWidget_(const iInputWidget *d) { | |||
1357 | } | 1365 | } |
1358 | iPaint p; | 1366 | iPaint p; |
1359 | init_Paint(&p); | 1367 | init_Paint(&p); |
1360 | /* `lines` is already up to date and ready for drawing. */ | 1368 | /* `lines` is already up to date and ready for drawing. */ |
1361 | /* TODO: If empty, draw the hint. */ | ||
1362 | // iString *text = visText_InputWidget_(d); | ||
1363 | // if (isWhite_(text) && !isEmpty_String(&d->hint)) { | ||
1364 | // set_String(text, &d->hint); | ||
1365 | // isHint = iTrue; | ||
1366 | // } | ||
1367 | fillRect_Paint( | 1369 | fillRect_Paint( |
1368 | &p, bounds, isFocused ? uiInputBackgroundFocused_ColorId : uiInputBackground_ColorId); | 1370 | &p, bounds, isFocused ? uiInputBackgroundFocused_ColorId : uiInputBackground_ColorId); |
1369 | drawRectThickness_Paint(&p, | 1371 | drawRectThickness_Paint(&p, |
@@ -1374,7 +1376,6 @@ static void draw_InputWidget_(const iInputWidget *d) { | |||
1374 | setClip_Paint(&p, adjusted_Rect(bounds, init_I2(d->leftPadding, 0), | 1376 | setClip_Paint(&p, adjusted_Rect(bounds, init_I2(d->leftPadding, 0), |
1375 | init_I2(-d->rightPadding, w->flags & extraPadding_WidgetFlag ? -gap_UI / 2 : 0))); | 1377 | init_I2(-d->rightPadding, w->flags & extraPadding_WidgetFlag ? -gap_UI / 2 : 0))); |
1376 | const iRect contentBounds = contentBounds_InputWidget_(d); | 1378 | const iRect contentBounds = contentBounds_InputWidget_(d); |
1377 | // const iInt2 textOrigin = textOrigin_InputWidget_(d); //, cstr_String(text)); | ||
1378 | iInt2 drawPos = topLeft_Rect(contentBounds); | 1379 | iInt2 drawPos = topLeft_Rect(contentBounds); |
1379 | const int fg = isHint ? uiAnnotation_ColorId | 1380 | const int fg = isHint ? uiAnnotation_ColorId |
1380 | : isFocused && !isEmpty_Array(&d->text) ? uiInputTextFocused_ColorId | 1381 | : isFocused && !isEmpty_Array(&d->text) ? uiInputTextFocused_ColorId |
@@ -1418,19 +1419,6 @@ static void draw_InputWidget_(const iInputWidget *d) { | |||
1418 | drawPos.y += lineHeight_Text(d->font); | 1419 | drawPos.y += lineHeight_Text(d->font); |
1419 | } | 1420 | } |
1420 | } | 1421 | } |
1421 | // if (d->buffered && !isFocused && !isHint) { | ||
1422 | // /* Most input widgets will use this, since only one is focused at a time. */ | ||
1423 | // draw_TextBuf(d->buffered, textOrigin, white_ColorId); | ||
1424 | // } | ||
1425 | // else { | ||
1426 | // draw_Text(d->font, | ||
1427 | // textOrigin, | ||
1428 | // isHint ? uiAnnotation_ColorId | ||
1429 | // : isFocused && !isEmpty_Array(&d->text) ? uiInputTextFocused_ColorId | ||
1430 | // : uiInputText_ColorId, | ||
1431 | // "%s", | ||
1432 | // cstr_String(text)); | ||
1433 | // } | ||
1434 | unsetClip_Paint(&p); | 1422 | unsetClip_Paint(&p); |
1435 | /* Cursor blinking. */ | 1423 | /* Cursor blinking. */ |
1436 | if (isFocused && d->cursorVis) { | 1424 | if (isFocused && d->cursorVis) { |
@@ -1474,7 +1462,6 @@ static void draw_InputWidget_(const iInputWidget *d) { | |||
1474 | deinit_String(&cur); | 1462 | deinit_String(&cur); |
1475 | } | 1463 | } |
1476 | } | 1464 | } |
1477 | // delete_String(text); | ||
1478 | drawChildren_Widget(w); | 1465 | drawChildren_Widget(w); |
1479 | } | 1466 | } |
1480 | 1467 | ||
diff --git a/src/ui/inputwidget.h b/src/ui/inputwidget.h index 5c39aae0..c70d9ad6 100644 --- a/src/ui/inputwidget.h +++ b/src/ui/inputwidget.h | |||
@@ -41,20 +41,21 @@ struct Impl_InputWidgetContentPadding { | |||
41 | 41 | ||
42 | typedef void (*iInputWidgetValidatorFunc)(iInputWidget *, void *context); | 42 | typedef void (*iInputWidgetValidatorFunc)(iInputWidget *, void *context); |
43 | 43 | ||
44 | void setHint_InputWidget (iInputWidget *, const char *hintText); | 44 | void setHint_InputWidget (iInputWidget *, const char *hintText); |
45 | void setMode_InputWidget (iInputWidget *, enum iInputMode mode); | 45 | void setMode_InputWidget (iInputWidget *, enum iInputMode mode); |
46 | void setMaxLen_InputWidget (iInputWidget *, size_t maxLen); | 46 | void setMaxLen_InputWidget (iInputWidget *, size_t maxLen); |
47 | void setText_InputWidget (iInputWidget *, const iString *text); | 47 | void setText_InputWidget (iInputWidget *, const iString *text); |
48 | void setTextCStr_InputWidget (iInputWidget *, const char *cstr); | 48 | void setTextCStr_InputWidget (iInputWidget *, const char *cstr); |
49 | void setFont_InputWidget (iInputWidget *, int fontId); | 49 | void setFont_InputWidget (iInputWidget *, int fontId); |
50 | void setCursor_InputWidget (iInputWidget *, size_t pos); | 50 | void setCursor_InputWidget (iInputWidget *, size_t pos); |
51 | void setContentPadding_InputWidget (iInputWidget *, int left, int right); /* only affects the text entry */ | 51 | void setContentPadding_InputWidget (iInputWidget *, int left, int right); /* only affects the text entry */ |
52 | void setMaxLayoutLines_InputWidget (iInputWidget *, size_t maxLayoutLines); | 52 | void setMaxLayoutLines_InputWidget (iInputWidget *, size_t maxLayoutLines); |
53 | void setValidator_InputWidget (iInputWidget *, iInputWidgetValidatorFunc validator, void *context); | 53 | void setValidator_InputWidget (iInputWidget *, iInputWidgetValidatorFunc validator, void *context); |
54 | void setEnterInsertsLF_InputWidget (iInputWidget *, iBool enterInsertsLF); | ||
54 | void setEnterKeyEnabled_InputWidget (iInputWidget *, iBool enterKeyEnabled); | 55 | void setEnterKeyEnabled_InputWidget (iInputWidget *, iBool enterKeyEnabled); |
55 | void begin_InputWidget (iInputWidget *); | 56 | void begin_InputWidget (iInputWidget *); |
56 | void end_InputWidget (iInputWidget *, iBool accept); | 57 | void end_InputWidget (iInputWidget *, iBool accept); |
57 | void selectAll_InputWidget (iInputWidget *); | 58 | void selectAll_InputWidget (iInputWidget *); |
58 | 59 | ||
59 | void setSelectAllOnFocus_InputWidget (iInputWidget *, iBool selectAllOnFocus); | 60 | void setSelectAllOnFocus_InputWidget (iInputWidget *, iBool selectAllOnFocus); |
60 | void setSensitiveContent_InputWidget (iInputWidget *, iBool isSensitive); | 61 | void setSensitiveContent_InputWidget (iInputWidget *, iBool isSensitive); |
@@ -62,15 +63,13 @@ void setUrlContent_InputWidget (iInputWidget *, iBool isUrl); | |||
62 | void setNotifyEdits_InputWidget (iInputWidget *, iBool notifyEdits); | 63 | void setNotifyEdits_InputWidget (iInputWidget *, iBool notifyEdits); |
63 | void setEatEscape_InputWidget (iInputWidget *, iBool eatEscape); | 64 | void setEatEscape_InputWidget (iInputWidget *, iBool eatEscape); |
64 | 65 | ||
65 | const iString * text_InputWidget (const iInputWidget *); | 66 | iInputWidgetContentPadding contentPadding_InputWidget (const iInputWidget *); |
67 | const iString * text_InputWidget (const iInputWidget *); | ||
66 | 68 | ||
67 | iLocalDef const char *cstrText_InputWidget(const iInputWidget *d) { | 69 | iLocalDef const char *cstrText_InputWidget(const iInputWidget *d) { |
68 | return cstr_String(text_InputWidget(d)); | 70 | return cstr_String(text_InputWidget(d)); |
69 | } | 71 | } |
70 | 72 | ||
71 | iInputWidgetContentPadding | ||
72 | contentPadding_InputWidget (const iInputWidget *); | ||
73 | |||
74 | iLocalDef iInputWidget *newHint_InputWidget(size_t maxLen, const char *hint) { | 73 | iLocalDef iInputWidget *newHint_InputWidget(size_t maxLen, const char *hint) { |
75 | iInputWidget *d = new_InputWidget(maxLen); | 74 | iInputWidget *d = new_InputWidget(maxLen); |
76 | setHint_InputWidget(d, hint); | 75 | setHint_InputWidget(d, hint); |
diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c index 95f281be..b68ab793 100644 --- a/src/ui/labelwidget.c +++ b/src/ui/labelwidget.c | |||
@@ -44,6 +44,9 @@ struct Impl_LabelWidget { | |||
44 | struct { | 44 | struct { |
45 | uint8_t alignVisual : 1; /* align according to visible bounds, not font metrics */ | 45 | uint8_t alignVisual : 1; /* align according to visible bounds, not font metrics */ |
46 | uint8_t noAutoMinHeight : 1; /* minimum height is not set automatically */ | 46 | uint8_t noAutoMinHeight : 1; /* minimum height is not set automatically */ |
47 | uint8_t drawAsOutline : 1; /* draw as outline, filled with background color */ | ||
48 | uint8_t noTopFrame : 1; | ||
49 | uint8_t wrap : 1; | ||
47 | } flags; | 50 | } flags; |
48 | }; | 51 | }; |
49 | 52 | ||
@@ -206,7 +209,7 @@ static void getColors_LabelWidget_(const iLabelWidget *d, int *bg, int *fg, int | |||
206 | } | 209 | } |
207 | } | 210 | } |
208 | int colorEscape = none_ColorId; | 211 | int colorEscape = none_ColorId; |
209 | if (startsWith_String(&d->label, "\r")) { | 212 | if (startsWith_String(&d->label, "\v")) { |
210 | colorEscape = cstr_String(&d->label)[1] - asciiBase_ColorEscape; /* TODO: can be two bytes long */ | 213 | colorEscape = cstr_String(&d->label)[1] - asciiBase_ColorEscape; /* TODO: can be two bytes long */ |
211 | } | 214 | } |
212 | if (isHover_LabelWidget_(d)) { | 215 | if (isHover_LabelWidget_(d)) { |
@@ -289,7 +292,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { | |||
289 | }; | 292 | }; |
290 | drawLines_Paint(&p, points + 2, 3, frame2); | 293 | drawLines_Paint(&p, points + 2, 3, frame2); |
291 | drawLines_Paint( | 294 | drawLines_Paint( |
292 | &p, points, !isHover && flags & noTopFrame_WidgetFlag ? 2 : 3, frame); | 295 | &p, points, !isHover && flags & d->flags.noTopFrame ? 2 : 3, frame); |
293 | } | 296 | } |
294 | } | 297 | } |
295 | setClip_Paint(&p, rect); | 298 | setClip_Paint(&p, rect); |
@@ -315,7 +318,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { | |||
315 | cstr_String(&str)); | 318 | cstr_String(&str)); |
316 | deinit_String(&str); | 319 | deinit_String(&str); |
317 | } | 320 | } |
318 | if (flags & wrapText_WidgetFlag) { | 321 | if (d->flags.wrap) { |
319 | const iRect inner = adjusted_Rect(innerBounds_Widget(w), init_I2(iconPad, 0), zero_I2()); | 322 | const iRect inner = adjusted_Rect(innerBounds_Widget(w), init_I2(iconPad, 0), zero_I2()); |
320 | const int wrap = inner.size.x; | 323 | const int wrap = inner.size.x; |
321 | drawWrapRange_Text(d->font, topLeft_Rect(inner), wrap, fg, range_String(&d->label)); | 324 | drawWrapRange_Text(d->font, topLeft_Rect(inner), wrap, fg, range_String(&d->label)); |
@@ -348,14 +351,14 @@ static void draw_LabelWidget_(const iLabelWidget *d) { | |||
348 | cstr_String(&d->label)); | 351 | cstr_String(&d->label)); |
349 | } | 352 | } |
350 | else { | 353 | else { |
351 | drawCentered_Text(d->font, | 354 | drawCenteredOutline_Text( |
352 | adjusted_Rect(bounds, | 355 | d->font, |
353 | add_I2(zero_I2(), init_I2(iconPad, 0)), | 356 | adjusted_Rect(bounds, add_I2(zero_I2(), init_I2(iconPad, 0)), neg_I2(zero_I2())), |
354 | neg_I2(zero_I2())), | 357 | d->flags.alignVisual, |
355 | d->flags.alignVisual, | 358 | d->flags.drawAsOutline ? fg : none_ColorId, |
356 | fg, | 359 | d->flags.drawAsOutline ? d->widget.bgColor : fg, |
357 | "%s", | 360 | "%s", |
358 | cstr_String(&d->label)); | 361 | cstr_String(&d->label)); |
359 | } | 362 | } |
360 | if (flags & chevron_WidgetFlag) { | 363 | if (flags & chevron_WidgetFlag) { |
361 | const iRect chRect = rect; | 364 | const iRect chRect = rect; |
@@ -370,7 +373,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { | |||
370 | 373 | ||
371 | static void sizeChanged_LabelWidget_(iLabelWidget *d) { | 374 | static void sizeChanged_LabelWidget_(iLabelWidget *d) { |
372 | iWidget *w = as_Widget(d); | 375 | iWidget *w = as_Widget(d); |
373 | if (flags_Widget(w) & wrapText_WidgetFlag) { | 376 | if (d->flags.wrap) { |
374 | if (flags_Widget(w) & fixedHeight_WidgetFlag) { | 377 | if (flags_Widget(w) & fixedHeight_WidgetFlag) { |
375 | /* Calculate a new height based on the wrapping. */ | 378 | /* Calculate a new height based on the wrapping. */ |
376 | w->rect.size.y = advanceWrapRange_Text( | 379 | w->rect.size.y = advanceWrapRange_Text( |
@@ -408,7 +411,7 @@ void updateSize_LabelWidget(iLabelWidget *d) { | |||
408 | w->minSize.y = size.y; /* vertically text must remain visible */ | 411 | w->minSize.y = size.y; /* vertically text must remain visible */ |
409 | } | 412 | } |
410 | /* Wrapped text implies that width must be defined by arrangement. */ | 413 | /* Wrapped text implies that width must be defined by arrangement. */ |
411 | if (!(flags & (fixedWidth_WidgetFlag | wrapText_WidgetFlag))) { | 414 | if (~flags & fixedWidth_WidgetFlag && !d->flags.wrap) { |
412 | w->rect.size.x = size.x; | 415 | w->rect.size.x = size.x; |
413 | } | 416 | } |
414 | if (~flags & fixedHeight_WidgetFlag) { | 417 | if (~flags & fixedHeight_WidgetFlag) { |
@@ -440,8 +443,11 @@ void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { | |||
440 | d->kmods = 0; | 443 | d->kmods = 0; |
441 | init_Click(&d->click, d, !isEmpty_String(&d->command) ? SDL_BUTTON_LEFT : 0); | 444 | init_Click(&d->click, d, !isEmpty_String(&d->command) ? SDL_BUTTON_LEFT : 0); |
442 | setFlags_Widget(w, hover_WidgetFlag, d->click.button != 0); | 445 | setFlags_Widget(w, hover_WidgetFlag, d->click.button != 0); |
443 | d->flags.alignVisual = iFalse; | 446 | d->flags.alignVisual = iFalse; |
444 | d->flags.noAutoMinHeight = iFalse; | 447 | d->flags.noAutoMinHeight = iFalse; |
448 | d->flags.drawAsOutline = iFalse; | ||
449 | d->flags.noTopFrame = iFalse; | ||
450 | d->flags.wrap = iFalse; | ||
445 | updateSize_LabelWidget(d); | 451 | updateSize_LabelWidget(d); |
446 | updateKey_LabelWidget_(d); /* could be bound to another key */ | 452 | updateKey_LabelWidget_(d); /* could be bound to another key */ |
447 | } | 453 | } |
@@ -481,6 +487,20 @@ void setNoAutoMinHeight_LabelWidget(iLabelWidget *d, iBool noAutoMinHeight) { | |||
481 | } | 487 | } |
482 | } | 488 | } |
483 | 489 | ||
490 | void setNoTopFrame_LabelWidget(iLabelWidget *d, iBool noTopFrame) { | ||
491 | d->flags.noTopFrame = noTopFrame; | ||
492 | } | ||
493 | |||
494 | void setWrap_LabelWidget(iLabelWidget *d, iBool wrap) { | ||
495 | d->flags.wrap = wrap; | ||
496 | } | ||
497 | |||
498 | void setOutline_LabelWidget(iLabelWidget *d, iBool drawAsOutline) { | ||
499 | if (d) { | ||
500 | d->flags.drawAsOutline = drawAsOutline; | ||
501 | } | ||
502 | } | ||
503 | |||
484 | void updateText_LabelWidget(iLabelWidget *d, const iString *text) { | 504 | void updateText_LabelWidget(iLabelWidget *d, const iString *text) { |
485 | set_String(&d->label, text); | 505 | set_String(&d->label, text); |
486 | set_String(&d->srcLabel, text); | 506 | set_String(&d->srcLabel, text); |
@@ -495,6 +515,11 @@ void updateTextCStr_LabelWidget(iLabelWidget *d, const char *text) { | |||
495 | refresh_Widget(&d->widget); | 515 | refresh_Widget(&d->widget); |
496 | } | 516 | } |
497 | 517 | ||
518 | void updateTextAndResizeWidthCStr_LabelWidget(iLabelWidget *d, const char *text) { | ||
519 | updateTextCStr_LabelWidget(d, text); | ||
520 | d->widget.rect.size.x = defaultSize_LabelWidget(d).x; | ||
521 | } | ||
522 | |||
498 | void setTextCStr_LabelWidget(iLabelWidget *d, const char *text) { | 523 | void setTextCStr_LabelWidget(iLabelWidget *d, const char *text) { |
499 | setCStr_String(&d->label, text); | 524 | setCStr_String(&d->label, text); |
500 | set_String(&d->srcLabel, &d->label); | 525 | set_String(&d->srcLabel, &d->label); |
@@ -537,6 +562,10 @@ iChar icon_LabelWidget(const iLabelWidget *d) { | |||
537 | return d->icon; | 562 | return d->icon; |
538 | } | 563 | } |
539 | 564 | ||
565 | iBool isWrapped_LabelWidget(const iLabelWidget *d) { | ||
566 | return d->flags.wrap; | ||
567 | } | ||
568 | |||
540 | const iString *text_LabelWidget(const iLabelWidget *d) { | 569 | const iString *text_LabelWidget(const iLabelWidget *d) { |
541 | if (!d) return collectNew_String(); | 570 | if (!d) return collectNew_String(); |
542 | return &d->label; | 571 | return &d->label; |
diff --git a/src/ui/labelwidget.h b/src/ui/labelwidget.h index e38a1dc8..b8b6fd87 100644 --- a/src/ui/labelwidget.h +++ b/src/ui/labelwidget.h | |||
@@ -31,6 +31,9 @@ iDeclareObjectConstructionArgs(LabelWidget, const char *label, const char *comma | |||
31 | 31 | ||
32 | void setAlignVisually_LabelWidget(iLabelWidget *, iBool alignVisual); | 32 | void setAlignVisually_LabelWidget(iLabelWidget *, iBool alignVisual); |
33 | void setNoAutoMinHeight_LabelWidget(iLabelWidget *, iBool noAutoMinHeight); | 33 | void setNoAutoMinHeight_LabelWidget(iLabelWidget *, iBool noAutoMinHeight); |
34 | void setNoTopFrame_LabelWidget (iLabelWidget *, iBool noTopFrame); | ||
35 | void setWrap_LabelWidget (iLabelWidget *, iBool wrap); | ||
36 | void setOutline_LabelWidget (iLabelWidget *, iBool drawAsOutline); | ||
34 | void setFont_LabelWidget (iLabelWidget *, int fontId); | 37 | void setFont_LabelWidget (iLabelWidget *, int fontId); |
35 | void setTextColor_LabelWidget (iLabelWidget *, int color); | 38 | void setTextColor_LabelWidget (iLabelWidget *, int color); |
36 | void setText_LabelWidget (iLabelWidget *, const iString *text); /* resizes widget */ | 39 | void setText_LabelWidget (iLabelWidget *, const iString *text); /* resizes widget */ |
@@ -43,12 +46,15 @@ void updateSize_LabelWidget (iLabelWidget *); | |||
43 | void updateText_LabelWidget (iLabelWidget *, const iString *text); /* not resized */ | 46 | void updateText_LabelWidget (iLabelWidget *, const iString *text); /* not resized */ |
44 | void updateTextCStr_LabelWidget (iLabelWidget *, const char *text); /* not resized */ | 47 | void updateTextCStr_LabelWidget (iLabelWidget *, const char *text); /* not resized */ |
45 | 48 | ||
49 | void updateTextAndResizeWidthCStr_LabelWidget (iLabelWidget *, const char *text); | ||
50 | |||
46 | iInt2 defaultSize_LabelWidget (const iLabelWidget *); | 51 | iInt2 defaultSize_LabelWidget (const iLabelWidget *); |
47 | int font_LabelWidget (const iLabelWidget *); | 52 | int font_LabelWidget (const iLabelWidget *); |
48 | const iString * text_LabelWidget (const iLabelWidget *); | 53 | const iString * text_LabelWidget (const iLabelWidget *); |
49 | const iString * sourceText_LabelWidget (const iLabelWidget *); /* untranslated */ | 54 | const iString * sourceText_LabelWidget (const iLabelWidget *); /* untranslated */ |
50 | const iString * command_LabelWidget (const iLabelWidget *); | 55 | const iString * command_LabelWidget (const iLabelWidget *); |
51 | iChar icon_LabelWidget (const iLabelWidget *); | 56 | iChar icon_LabelWidget (const iLabelWidget *); |
57 | iBool isWrapped_LabelWidget (const iLabelWidget *); | ||
52 | 58 | ||
53 | iLabelWidget *newKeyMods_LabelWidget(const char *label, int key, int kmods, const char *command); | 59 | iLabelWidget *newKeyMods_LabelWidget(const char *label, int key, int kmods, const char *command); |
54 | iLabelWidget *newColor_LabelWidget (const char *text, int color); | 60 | iLabelWidget *newColor_LabelWidget (const char *text, int color); |
diff --git a/src/ui/mediaui.c b/src/ui/mediaui.c index bc417fc3..fa09b214 100644 --- a/src/ui/mediaui.c +++ b/src/ui/mediaui.c | |||
@@ -118,7 +118,7 @@ void draw_PlayerUI(iPlayerUI *d, iPaint *p) { | |||
118 | isPaused_Player(d->player) ? "\U0001f782" : "\u23f8", | 118 | isPaused_Player(d->player) ? "\U0001f782" : "\u23f8", |
119 | uiContent_FontId); | 119 | uiContent_FontId); |
120 | drawPlayerButton_(p, d->rewindRect, "\u23ee", uiContent_FontId); | 120 | drawPlayerButton_(p, d->rewindRect, "\u23ee", uiContent_FontId); |
121 | drawPlayerButton_(p, d->menuRect, "\U0001d362", uiContent_FontId); | 121 | drawPlayerButton_(p, d->menuRect, menu_Icon, uiContent_FontId); |
122 | if (!isAdjusting) { | 122 | if (!isAdjusting) { |
123 | drawPlayerButton_( | 123 | drawPlayerButton_( |
124 | p, d->volumeRect, volumeChar_(volume_Player(d->player)), uiContentSymbols_FontId); | 124 | p, d->volumeRect, volumeChar_(volume_Player(d->player)), uiContentSymbols_FontId); |
diff --git a/src/ui/mobile.c b/src/ui/mobile.c index 263fc141..0ff3fe85 100644 --- a/src/ui/mobile.c +++ b/src/ui/mobile.c | |||
@@ -120,7 +120,7 @@ static iBool mainDetailSplitHandler_(iWidget *mainDetailSplit, const char *cmd) | |||
120 | } | 120 | } |
121 | iForEach(ObjectList, i, children_Widget(detailStack)) { | 121 | iForEach(ObjectList, i, children_Widget(detailStack)) { |
122 | iWidget *panel = i.object; | 122 | iWidget *panel = i.object; |
123 | setFlags_Widget(panel, edgeDraggable_WidgetFlag, !isSideBySide); | 123 | setFlags_Widget(panel, leftEdgeDraggable_WidgetFlag, !isSideBySide); |
124 | if (isSideBySide) { | 124 | if (isSideBySide) { |
125 | setVisualOffset_Widget(panel, 0, 0, 0); | 125 | setVisualOffset_Widget(panel, 0, 0, 0); |
126 | } | 126 | } |
@@ -150,8 +150,7 @@ static iBool topPanelHandler_(iWidget *topPanel, const char *cmd) { | |||
150 | setFlags_Widget(button, selected_WidgetFlag, iTrue); | 150 | setFlags_Widget(button, selected_WidgetFlag, iTrue); |
151 | return iTrue; | 151 | return iTrue; |
152 | } | 152 | } |
153 | if (equal_Command(cmd, "mouse.clicked") && arg_Command(cmd) && | 153 | if (equal_Command(cmd, "swipe.back")) { |
154 | argLabel_Command(cmd, "button") == SDL_BUTTON_X1) { | ||
155 | postCommand_App("panel.close"); | 154 | postCommand_App("panel.close"); |
156 | return iTrue; | 155 | return iTrue; |
157 | } | 156 | } |
@@ -201,6 +200,8 @@ static iBool isTwoColumnPage_(iWidget *d) { | |||
201 | 200 | ||
202 | static iBool isOmittedPref_(const iString *id) { | 201 | static iBool isOmittedPref_(const iString *id) { |
203 | static const char *omittedPrefs[] = { | 202 | static const char *omittedPrefs[] = { |
203 | "prefs.userfont", | ||
204 | "prefs.animate", | ||
204 | "prefs.smoothscroll", | 205 | "prefs.smoothscroll", |
205 | "prefs.imageloadscroll", | 206 | "prefs.imageloadscroll", |
206 | "prefs.pinsplit", | 207 | "prefs.pinsplit", |
@@ -413,7 +414,7 @@ void finalizeSheet_Mobile(iWidget *sheet) { | |||
413 | setFlags_Widget(sheet, | 414 | setFlags_Widget(sheet, |
414 | frameless_WidgetFlag | | 415 | frameless_WidgetFlag | |
415 | //resizeWidthOfChildren_WidgetFlag | | 416 | //resizeWidthOfChildren_WidgetFlag | |
416 | edgeDraggable_WidgetFlag | | 417 | leftEdgeDraggable_WidgetFlag | |
417 | commandOnClick_WidgetFlag, | 418 | commandOnClick_WidgetFlag, |
418 | iTrue); | 419 | iTrue); |
419 | iPtrArray * contents = collect_PtrArray(new_PtrArray()); /* two-column pages */ | 420 | iPtrArray * contents = collect_PtrArray(new_PtrArray()); /* two-column pages */ |
@@ -446,7 +447,7 @@ void finalizeSheet_Mobile(iWidget *sheet) { | |||
446 | } | 447 | } |
447 | addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); | 448 | addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); |
448 | /* Slide top panel with detail panels. */ { | 449 | /* Slide top panel with detail panels. */ { |
449 | setFlags_Widget(topPanel, refChildrenOffset_WidgetFlag, iTrue); | 450 | setFlags_Widget(topPanel, refChildrenOffset_WidgetFlag, iTrue); |
450 | topPanel->offsetRef = detailStack; | 451 | topPanel->offsetRef = detailStack; |
451 | } | 452 | } |
452 | if (prefsTabs) { | 453 | if (prefsTabs) { |
@@ -472,7 +473,8 @@ void finalizeSheet_Mobile(iWidget *sheet) { | |||
472 | 0x02699, /* gear */ | 473 | 0x02699, /* gear */ |
473 | 0x1f4f1, /* mobile phone */ | 474 | 0x1f4f1, /* mobile phone */ |
474 | 0x1f3a8, /* palette */ | 475 | 0x1f3a8, /* palette */ |
475 | 0x1f523, | 476 | 0x1f5da, /* aA */ |
477 | 0x1f660, /* pointing bud */ | ||
476 | 0x1f5a7, /* computer network */ | 478 | 0x1f5a7, /* computer network */ |
477 | }; | 479 | }; |
478 | setIcon_LabelWidget(panelButton, icons[i]); | 480 | setIcon_LabelWidget(panelButton, icons[i]); |
@@ -621,6 +623,12 @@ void finalizeSheet_Mobile(iWidget *sheet) { | |||
621 | /* Additional elements for preferences. */ | 623 | /* Additional elements for preferences. */ |
622 | if (isPrefs) { | 624 | if (isPrefs) { |
623 | addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); | 625 | addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); |
626 | /* Management. */ { | ||
627 | iLabelWidget *idManButton = addChildFlags_Widget(topPanel, | ||
628 | iClob(makePanelButton_(person_Icon " ${sidebar.identities}", "panel.open")), | ||
629 | chevron_WidgetFlag | borderTop_WidgetFlag); | ||
630 | } | ||
631 | addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); | ||
624 | iLabelWidget *aboutButton = addChildFlags_Widget(topPanel, | 632 | iLabelWidget *aboutButton = addChildFlags_Widget(topPanel, |
625 | iClob(makePanelButton_(planet_Icon " ${menu.about}", "panel.open")), | 633 | iClob(makePanelButton_(planet_Icon " ${menu.about}", "panel.open")), |
626 | chevron_WidgetFlag | borderTop_WidgetFlag); | 634 | chevron_WidgetFlag | borderTop_WidgetFlag); |
diff --git a/src/ui/root.c b/src/ui/root.c index 15548e74..5266978b 100644 --- a/src/ui/root.c +++ b/src/ui/root.c | |||
@@ -52,10 +52,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
52 | 52 | ||
53 | #include <SDL_timer.h> | 53 | #include <SDL_timer.h> |
54 | 54 | ||
55 | #if defined (iPlatformAppleDesktop) | ||
56 | # define iHaveNativeMenus | ||
57 | #endif | ||
58 | |||
59 | #if defined (iPlatformPcDesktop) | 55 | #if defined (iPlatformPcDesktop) |
60 | /* TODO: Submenus wouldn't hurt here. */ | 56 | /* TODO: Submenus wouldn't hurt here. */ |
61 | static const iMenuItem navMenuItems_[] = { | 57 | static const iMenuItem navMenuItems_[] = { |
@@ -90,6 +86,7 @@ static const iMenuItem navMenuItems_[] = { | |||
90 | #if defined (iPlatformAppleMobile) | 86 | #if defined (iPlatformAppleMobile) |
91 | /* Tablet menu. */ | 87 | /* Tablet menu. */ |
92 | static const iMenuItem tabletNavMenuItems_[] = { | 88 | static const iMenuItem tabletNavMenuItems_[] = { |
89 | { folder_Icon " ${menu.openfile}", SDLK_o, KMOD_PRIMARY, "file.open" }, | ||
93 | { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" }, | 90 | { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" }, |
94 | { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" }, | 91 | { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" }, |
95 | { "---", 0, 0, NULL }, | 92 | { "---", 0, 0, NULL }, |
@@ -110,6 +107,7 @@ static const iMenuItem tabletNavMenuItems_[] = { | |||
110 | 107 | ||
111 | /* Phone menu. */ | 108 | /* Phone menu. */ |
112 | static const iMenuItem phoneNavMenuItems_[] = { | 109 | static const iMenuItem phoneNavMenuItems_[] = { |
110 | { folder_Icon " ${menu.openfile}", SDLK_o, KMOD_PRIMARY, "file.open" }, | ||
113 | { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" }, | 111 | { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" }, |
114 | { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" }, | 112 | { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" }, |
115 | { "---", 0, 0, NULL }, | 113 | { "---", 0, 0, NULL }, |
@@ -273,7 +271,8 @@ void destroyPending_Root(iRoot *d) { | |||
273 | setCurrent_Root(d); | 271 | setCurrent_Root(d); |
274 | iForEach(PtrSet, i, d->pendingDestruction) { | 272 | iForEach(PtrSet, i, d->pendingDestruction) { |
275 | iWidget *widget = *i.value; | 273 | iWidget *widget = *i.value; |
276 | if (!isFinished_Anim(&widget->visualOffset)) { | 274 | if (!isFinished_Anim(&widget->visualOffset) || |
275 | isBeingVisuallyOffsetByReference_Widget(widget)) { | ||
277 | continue; | 276 | continue; |
278 | } | 277 | } |
279 | if (widget->flags & keepOnTop_WidgetFlag) { | 278 | if (widget->flags & keepOnTop_WidgetFlag) { |
@@ -282,7 +281,7 @@ void destroyPending_Root(iRoot *d) { | |||
282 | if (widget->parent) { | 281 | if (widget->parent) { |
283 | removeChild_Widget(widget->parent, widget); | 282 | removeChild_Widget(widget->parent, widget); |
284 | } | 283 | } |
285 | iAssert(widget->parent == NULL); | 284 | iAssert(widget->parent == NULL); |
286 | iRelease(widget); | 285 | iRelease(widget); |
287 | remove_PtrSetIterator(&i); | 286 | remove_PtrSetIterator(&i); |
288 | } | 287 | } |
@@ -433,9 +432,9 @@ static void updateNavBarIdentity_(iWidget *navBar) { | |||
433 | const iGmIdentity *ident = | 432 | const iGmIdentity *ident = |
434 | identityForUrl_GmCerts(certs_App(), url_DocumentWidget(document_App())); | 433 | identityForUrl_GmCerts(certs_App(), url_DocumentWidget(document_App())); |
435 | iWidget *button = findChild_Widget(navBar, "navbar.ident"); | 434 | iWidget *button = findChild_Widget(navBar, "navbar.ident"); |
436 | iWidget *tool = findWidget_App("toolbar.ident"); | 435 | iLabelWidget *toolButton = findWidget_App("toolbar.ident"); |
437 | setFlags_Widget(button, selected_WidgetFlag, ident != NULL); | 436 | setFlags_Widget(button, selected_WidgetFlag, ident != NULL); |
438 | setFlags_Widget(tool, selected_WidgetFlag, ident != NULL); | 437 | setOutline_LabelWidget(toolButton, ident == NULL); |
439 | /* Update menu. */ | 438 | /* Update menu. */ |
440 | iLabelWidget *idItem = child_Widget(findChild_Widget(button, "menu"), 0); | 439 | iLabelWidget *idItem = child_Widget(findChild_Widget(button, "menu"), 0); |
441 | const iString *subjectName = ident ? name_GmIdentity(ident) : NULL; | 440 | const iString *subjectName = ident ? name_GmIdentity(ident) : NULL; |
@@ -444,6 +443,12 @@ static void updateNavBarIdentity_(iWidget *navBar) { | |||
444 | subjectName ? format_CStr(uiTextAction_ColorEscape "%s", cstr_String(subjectName)) | 443 | subjectName ? format_CStr(uiTextAction_ColorEscape "%s", cstr_String(subjectName)) |
445 | : "${menu.identity.notactive}"); | 444 | : "${menu.identity.notactive}"); |
446 | setFlags_Widget(as_Widget(idItem), disabled_WidgetFlag, !ident); | 445 | setFlags_Widget(as_Widget(idItem), disabled_WidgetFlag, !ident); |
446 | iLabelWidget *toolName = findWidget_App("toolbar.name"); | ||
447 | if (toolName) { | ||
448 | updateTextCStr_LabelWidget(toolName, subjectName ? cstr_String(subjectName) : ""); | ||
449 | setFont_LabelWidget(toolButton, subjectName ? defaultMedium_FontId : uiLabelLarge_FontId); | ||
450 | arrange_Widget(parent_Widget(toolButton)); | ||
451 | } | ||
447 | } | 452 | } |
448 | 453 | ||
449 | static void updateNavDirButtons_(iWidget *navBar) { | 454 | static void updateNavDirButtons_(iWidget *navBar) { |
@@ -515,6 +520,26 @@ void updatePadding_Root(iRoot *d) { | |||
515 | #endif | 520 | #endif |
516 | } | 521 | } |
517 | 522 | ||
523 | void updateToolbarColors_Root(iRoot *d) { | ||
524 | #if defined (iPlatformMobile) | ||
525 | iWidget *toolBar = findChild_Widget(d->widget, "toolbar"); | ||
526 | if (toolBar) { | ||
527 | const iBool isSidebarVisible = isVisible_Widget(findChild_Widget(d->widget, "sidebar")); | ||
528 | const int bg = isSidebarVisible ? uiBackgroundSidebar_ColorId : | ||
529 | tmBannerBackground_ColorId; | ||
530 | setBackgroundColor_Widget(toolBar, bg); | ||
531 | iForEach(ObjectList, i, children_Widget(toolBar)) { | ||
532 | iLabelWidget *btn = i.object; | ||
533 | setTextColor_LabelWidget(i.object, isSidebarVisible ? uiTextDim_ColorId : | ||
534 | tmBannerIcon_ColorId); | ||
535 | setBackgroundColor_Widget(i.object, bg); /* using noBackground, but ident has outline */ | ||
536 | } | ||
537 | } | ||
538 | #else | ||
539 | iUnused(d); | ||
540 | #endif | ||
541 | } | ||
542 | |||
518 | void dismissPortraitPhoneSidebars_Root(iRoot *d) { | 543 | void dismissPortraitPhoneSidebars_Root(iRoot *d) { |
519 | if (deviceType_App() == phone_AppDeviceType && isPortrait_App()) { | 544 | if (deviceType_App() == phone_AppDeviceType && isPortrait_App()) { |
520 | iWidget *sidebar = findChild_Widget(d->widget, "sidebar"); | 545 | iWidget *sidebar = findChild_Widget(d->widget, "sidebar"); |
@@ -551,9 +576,16 @@ static void updateUrlInputContentPadding_(iWidget *navBar) { | |||
551 | } | 576 | } |
552 | 577 | ||
553 | static void showSearchQueryIndicator_(iBool show) { | 578 | static void showSearchQueryIndicator_(iBool show) { |
579 | iWidget *navBar = findWidget_Root("navbar"); | ||
554 | iWidget *indicator = findWidget_App("input.indicator.search"); | 580 | iWidget *indicator = findWidget_App("input.indicator.search"); |
581 | updateTextCStr_LabelWidget((iLabelWidget *) indicator, | ||
582 | (deviceType_App() == phone_AppDeviceType || | ||
583 | flags_Widget(navBar) & tight_WidgetFlag) | ||
584 | ? "${status.query.tight} " return_Icon | ||
585 | : "${status.query} " return_Icon); | ||
586 | indicator->rect.size.x = defaultSize_LabelWidget((iLabelWidget *) indicator).x; /* don't touch height */ | ||
555 | showCollapsed_Widget(indicator, show); | 587 | showCollapsed_Widget(indicator, show); |
556 | updateUrlInputContentPadding_(findWidget_Root("navbar")); | 588 | updateUrlInputContentPadding_(navBar); |
557 | } | 589 | } |
558 | 590 | ||
559 | static int navBarAvailableSpace_(iWidget *navBar) { | 591 | static int navBarAvailableSpace_(iWidget *navBar) { |
@@ -692,6 +724,7 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) { | |||
692 | iInputWidget *url = findWidget_Root("url"); | 724 | iInputWidget *url = findWidget_Root("url"); |
693 | const iString *urlStr = collect_String(suffix_Command(cmd, "url")); | 725 | const iString *urlStr = collect_String(suffix_Command(cmd, "url")); |
694 | trimCache_App(); | 726 | trimCache_App(); |
727 | trimMemory_App(); | ||
695 | visitUrl_Visited(visited_App(), withSpacesEncoded_String(urlStr), 0); /* TODO: internal URI normalization */ | 728 | visitUrl_Visited(visited_App(), withSpacesEncoded_String(urlStr), 0); /* TODO: internal URI normalization */ |
696 | postCommand_App("visited.changed"); /* sidebar will update */ | 729 | postCommand_App("visited.changed"); /* sidebar will update */ |
697 | setText_InputWidget(url, urlStr); | 730 | setText_InputWidget(url, urlStr); |
@@ -827,20 +860,20 @@ static iBool handleToolBarCommands_(iWidget *toolBar, const char *cmd) { | |||
827 | const int viewHeight = size_Root(get_Root()).y; | 860 | const int viewHeight = size_Root(get_Root()).y; |
828 | if (arg_Command(cmd) >= 0) { | 861 | if (arg_Command(cmd) >= 0) { |
829 | postCommandf_App("sidebar.mode arg:%d show:1", arg_Command(cmd)); | 862 | postCommandf_App("sidebar.mode arg:%d show:1", arg_Command(cmd)); |
830 | if (!isVisible) { | 863 | // if (!isVisible) { |
831 | setVisualOffset_Widget(sidebar, viewHeight, 0, 0); | 864 | // setVisualOffset_Widget(sidebar, viewHeight, 0, 0); |
832 | setVisualOffset_Widget(sidebar, 0, 400, easeOut_AnimFlag | softer_AnimFlag); | 865 | // setVisualOffset_Widget(sidebar, 0, 400, easeOut_AnimFlag | softer_AnimFlag); |
833 | } | 866 | // } |
834 | } | 867 | } |
835 | else { | 868 | else { |
836 | postCommandf_App("sidebar.toggle"); | 869 | postCommandf_App("sidebar.toggle"); |
837 | if (isVisible) { | 870 | // if (isVisible) { |
838 | setVisualOffset_Widget(sidebar, height_Widget(sidebar), 250, easeIn_AnimFlag); | 871 | // setVisualOffset_Widget(sidebar, height_Widget(sidebar), 250, easeIn_AnimFlag); |
839 | } | 872 | // } |
840 | else { | 873 | // else { |
841 | setVisualOffset_Widget(sidebar, viewHeight, 0, 0); | 874 | // setVisualOffset_Widget(sidebar, viewHeight, 0, 0); |
842 | setVisualOffset_Widget(sidebar, 0, 400, easeOut_AnimFlag | softer_AnimFlag); | 875 | // setVisualOffset_Widget(sidebar, 0, 400, easeOut_AnimFlag | softer_AnimFlag); |
843 | } | 876 | // } |
844 | } | 877 | } |
845 | return iTrue; | 878 | return iTrue; |
846 | } | 879 | } |
@@ -848,7 +881,10 @@ static iBool handleToolBarCommands_(iWidget *toolBar, const char *cmd) { | |||
848 | /* TODO: Clean this up. */ | 881 | /* TODO: Clean this up. */ |
849 | iWidget *sidebar = findWidget_App("sidebar"); | 882 | iWidget *sidebar = findWidget_App("sidebar"); |
850 | iWidget *sidebar2 = findWidget_App("sidebar2"); | 883 | iWidget *sidebar2 = findWidget_App("sidebar2"); |
851 | dismissSidebar_(sidebar, "toolbar.view"); | 884 | //dismissSidebar_(sidebar, "toolbar.view"); |
885 | if (isVisible_Widget(sidebar)) { | ||
886 | postCommandf_App("sidebar.toggle"); | ||
887 | } | ||
852 | const iBool isVisible = isVisible_Widget(sidebar2); | 888 | const iBool isVisible = isVisible_Widget(sidebar2); |
853 | // setFlags_Widget(findChild_Widget(toolBar, "toolbar.ident"), noBackground_WidgetFlag, | 889 | // setFlags_Widget(findChild_Widget(toolBar, "toolbar.ident"), noBackground_WidgetFlag, |
854 | // isVisible); | 890 | // isVisible); |
@@ -921,6 +957,23 @@ void updateMetrics_Root(iRoot *d) { | |||
921 | updatePadding_Root(d); | 957 | updatePadding_Root(d); |
922 | arrange_Widget(d->widget); | 958 | arrange_Widget(d->widget); |
923 | updateUrlInputContentPadding_(navBar); | 959 | updateUrlInputContentPadding_(navBar); |
960 | /* Position the toolbar identity name label manually. */ { | ||
961 | iLabelWidget *idName = findChild_Widget(d->widget, "toolbar.name"); | ||
962 | if (idName) { | ||
963 | const iWidget *toolBar = findChild_Widget(d->widget, "toolbar"); | ||
964 | const iWidget *viewButton = findChild_Widget(d->widget, "toolbar.view"); | ||
965 | const iWidget *idButton = findChild_Widget(toolBar, "toolbar.ident"); | ||
966 | const int font = defaultSmall_FontId; | ||
967 | setFont_LabelWidget(idName, font); | ||
968 | setPos_Widget(as_Widget(idName), | ||
969 | windowToLocal_Widget(as_Widget(idName), | ||
970 | init_I2(left_Rect(bounds_Widget(idButton)), | ||
971 | bottom_Rect(bounds_Widget(viewButton)) - | ||
972 | lineHeight_Text(font) - gap_UI / 2))); | ||
973 | setFixedSize_Widget(as_Widget(idName), init_I2(width_Widget(idButton), | ||
974 | lineHeight_Text(font))); | ||
975 | } | ||
976 | } | ||
924 | postRefresh_App(); | 977 | postRefresh_App(); |
925 | } | 978 | } |
926 | 979 | ||
@@ -1048,9 +1101,9 @@ void createUserInterface_Root(iRoot *d) { | |||
1048 | resizeHeightOfChildren_WidgetFlag | | 1101 | resizeHeightOfChildren_WidgetFlag | |
1049 | moveToParentRightEdge_WidgetFlag); | 1102 | moveToParentRightEdge_WidgetFlag); |
1050 | /* Feeds refresh indicator is inside the input field. */ { | 1103 | /* Feeds refresh indicator is inside the input field. */ { |
1051 | iLabelWidget *queryInd = | 1104 | iLabelWidget *queryInd = new_LabelWidget("${status.query} " return_Icon, NULL); |
1052 | new_LabelWidget(uiTextAction_ColorEscape "${status.query} " return_Icon, NULL); | ||
1053 | setId_Widget(as_Widget(queryInd), "input.indicator.search"); | 1105 | setId_Widget(as_Widget(queryInd), "input.indicator.search"); |
1106 | setTextColor_LabelWidget(queryInd, uiTextAction_ColorId); | ||
1054 | setBackgroundColor_Widget(as_Widget(queryInd), uiBackground_ColorId); | 1107 | setBackgroundColor_Widget(as_Widget(queryInd), uiBackground_ColorId); |
1055 | setFrameColor_Widget(as_Widget(queryInd), uiTextAction_ColorId); | 1108 | setFrameColor_Widget(as_Widget(queryInd), uiTextAction_ColorId); |
1056 | setAlignVisually_LabelWidget(queryInd, iTrue); | 1109 | setAlignVisually_LabelWidget(queryInd, iTrue); |
@@ -1060,9 +1113,9 @@ void createUserInterface_Root(iRoot *d) { | |||
1060 | collapse_WidgetFlag | hidden_WidgetFlag); | 1113 | collapse_WidgetFlag | hidden_WidgetFlag); |
1061 | } | 1114 | } |
1062 | /* Feeds refresh indicator is inside the input field. */ { | 1115 | /* Feeds refresh indicator is inside the input field. */ { |
1063 | iLabelWidget *fprog = new_LabelWidget(uiTextCaution_ColorEscape | 1116 | iLabelWidget *fprog = new_LabelWidget("", NULL); |
1064 | "\u2605 ${status.feeds}", NULL); | ||
1065 | setId_Widget(as_Widget(fprog), "feeds.progress"); | 1117 | setId_Widget(as_Widget(fprog), "feeds.progress"); |
1118 | setTextColor_LabelWidget(fprog, uiTextCaution_ColorId); | ||
1066 | setBackgroundColor_Widget(as_Widget(fprog), uiBackground_ColorId); | 1119 | setBackgroundColor_Widget(as_Widget(fprog), uiBackground_ColorId); |
1067 | setAlignVisually_LabelWidget(fprog, iTrue); | 1120 | setAlignVisually_LabelWidget(fprog, iTrue); |
1068 | setNoAutoMinHeight_LabelWidget(fprog, iTrue); | 1121 | setNoAutoMinHeight_LabelWidget(fprog, iTrue); |
@@ -1116,7 +1169,7 @@ void createUserInterface_Root(iRoot *d) { | |||
1116 | setId_Widget(as_Widget(pageMenuButton), "pagemenubutton"); | 1169 | setId_Widget(as_Widget(pageMenuButton), "pagemenubutton"); |
1117 | setFont_LabelWidget(pageMenuButton, uiContentBold_FontId); | 1170 | setFont_LabelWidget(pageMenuButton, uiContentBold_FontId); |
1118 | setAlignVisually_LabelWidget(pageMenuButton, iTrue); | 1171 | setAlignVisually_LabelWidget(pageMenuButton, iTrue); |
1119 | addChildFlags_Widget(urlButtons, iClob(pageMenuButton), embedFlags); | 1172 | addChildFlags_Widget(urlButtons, iClob(pageMenuButton), embedFlags | tight_WidgetFlag); |
1120 | updateSize_LabelWidget(pageMenuButton); | 1173 | updateSize_LabelWidget(pageMenuButton); |
1121 | } | 1174 | } |
1122 | /* Reload button. */ { | 1175 | /* Reload button. */ { |
@@ -1146,11 +1199,11 @@ void createUserInterface_Root(iRoot *d) { | |||
1146 | #if !defined (iHaveNativeMenus) | 1199 | #if !defined (iHaveNativeMenus) |
1147 | # if defined (iPlatformAppleMobile) | 1200 | # if defined (iPlatformAppleMobile) |
1148 | iLabelWidget *navMenu = | 1201 | iLabelWidget *navMenu = |
1149 | makeMenuButton_LabelWidget("\U0001d362", isPhone ? phoneNavMenuItems_ : tabletNavMenuItems_, | 1202 | makeMenuButton_LabelWidget(menu_Icon, isPhone ? phoneNavMenuItems_ : tabletNavMenuItems_, |
1150 | isPhone ? iElemCount(phoneNavMenuItems_) : iElemCount(tabletNavMenuItems_)); | 1203 | isPhone ? iElemCount(phoneNavMenuItems_) : iElemCount(tabletNavMenuItems_)); |
1151 | # else | 1204 | # else |
1152 | iLabelWidget *navMenu = | 1205 | iLabelWidget *navMenu = |
1153 | makeMenuButton_LabelWidget("\U0001d362", navMenuItems_, iElemCount(navMenuItems_)); | 1206 | makeMenuButton_LabelWidget(menu_Icon, navMenuItems_, iElemCount(navMenuItems_)); |
1154 | # endif | 1207 | # endif |
1155 | setAlignVisually_LabelWidget(navMenu, iTrue); | 1208 | setAlignVisually_LabelWidget(navMenu, iTrue); |
1156 | setId_Widget(addChildFlags_Widget(navBar, iClob(navMenu), collapse_WidgetFlag), "navbar.menu"); | 1209 | setId_Widget(addChildFlags_Widget(navBar, iClob(navMenu), collapse_WidgetFlag), "navbar.menu"); |
@@ -1161,11 +1214,11 @@ void createUserInterface_Root(iRoot *d) { | |||
1161 | setId_Widget(mainStack, "stack"); | 1214 | setId_Widget(mainStack, "stack"); |
1162 | addChildFlags_Widget(div, iClob(mainStack), resizeChildren_WidgetFlag | expand_WidgetFlag | | 1215 | addChildFlags_Widget(div, iClob(mainStack), resizeChildren_WidgetFlag | expand_WidgetFlag | |
1163 | unhittable_WidgetFlag); | 1216 | unhittable_WidgetFlag); |
1164 | iWidget *tabBar = makeTabs_Widget(mainStack); | 1217 | iWidget *docTabs = makeTabs_Widget(mainStack); |
1165 | setId_Widget(tabBar, "doctabs"); | 1218 | setId_Widget(docTabs, "doctabs"); |
1166 | setBackgroundColor_Widget(tabBar, uiBackground_ColorId); | 1219 | setBackgroundColor_Widget(docTabs, uiBackground_ColorId); |
1167 | appendTabPage_Widget(tabBar, iClob(new_DocumentWidget()), "Document", 0, 0); | 1220 | appendTabPage_Widget(docTabs, iClob(new_DocumentWidget()), "Document", 0, 0); |
1168 | iWidget *buttons = findChild_Widget(tabBar, "tabs.buttons"); | 1221 | iWidget *buttons = findChild_Widget(docTabs, "tabs.buttons"); |
1169 | setFlags_Widget(buttons, collapse_WidgetFlag | hidden_WidgetFlag | | 1222 | setFlags_Widget(buttons, collapse_WidgetFlag | hidden_WidgetFlag | |
1170 | drawBackgroundToHorizontalSafeArea_WidgetFlag, iTrue); | 1223 | drawBackgroundToHorizontalSafeArea_WidgetFlag, iTrue); |
1171 | if (deviceType_App() == phone_AppDeviceType) { | 1224 | if (deviceType_App() == phone_AppDeviceType) { |
@@ -1177,9 +1230,9 @@ void createUserInterface_Root(iRoot *d) { | |||
1177 | } | 1230 | } |
1178 | /* Sidebars. */ { | 1231 | /* Sidebars. */ { |
1179 | iWidget *content = findChild_Widget(root, "tabs.content"); | 1232 | iWidget *content = findChild_Widget(root, "tabs.content"); |
1180 | iSidebarWidget *sidebar1 = new_SidebarWidget(left_SideBarSide); | 1233 | iSidebarWidget *sidebar1 = new_SidebarWidget(left_SidebarSide); |
1181 | addChildPos_Widget(content, iClob(sidebar1), front_WidgetAddPos); | 1234 | addChildPos_Widget(content, iClob(sidebar1), front_WidgetAddPos); |
1182 | iSidebarWidget *sidebar2 = new_SidebarWidget(right_SideBarSide); | 1235 | iSidebarWidget *sidebar2 = new_SidebarWidget(right_SidebarSide); |
1183 | if (deviceType_App() != phone_AppDeviceType) { | 1236 | if (deviceType_App() != phone_AppDeviceType) { |
1184 | addChildPos_Widget(content, iClob(sidebar2), back_WidgetAddPos); | 1237 | addChildPos_Widget(content, iClob(sidebar2), back_WidgetAddPos); |
1185 | } | 1238 | } |
@@ -1218,6 +1271,7 @@ void createUserInterface_Root(iRoot *d) { | |||
1218 | setHint_InputWidget(input, "${hint.findtext}"); | 1271 | setHint_InputWidget(input, "${hint.findtext}"); |
1219 | setSelectAllOnFocus_InputWidget(input, iTrue); | 1272 | setSelectAllOnFocus_InputWidget(input, iTrue); |
1220 | setEatEscape_InputWidget(input, iFalse); /* unfocus and close with one keypress */ | 1273 | setEatEscape_InputWidget(input, iFalse); /* unfocus and close with one keypress */ |
1274 | setEnterInsertsLF_InputWidget(input, iFalse); | ||
1221 | setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag), | 1275 | setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag), |
1222 | "find.input"); | 1276 | "find.input"); |
1223 | addChild_Widget(searchBar, iClob(newIcon_LabelWidget(" \u2b9f ", 'g', KMOD_PRIMARY, "find.next"))); | 1277 | addChild_Widget(searchBar, iClob(newIcon_LabelWidget(" \u2b9f ", 'g', KMOD_PRIMARY, "find.next"))); |
@@ -1237,7 +1291,6 @@ void createUserInterface_Root(iRoot *d) { | |||
1237 | arrangeHeight_WidgetFlag | arrangeHorizontal_WidgetFlag | | 1291 | arrangeHeight_WidgetFlag | arrangeHorizontal_WidgetFlag | |
1238 | commandOnClick_WidgetFlag | | 1292 | commandOnClick_WidgetFlag | |
1239 | drawBackgroundToBottom_WidgetFlag, iTrue); | 1293 | drawBackgroundToBottom_WidgetFlag, iTrue); |
1240 | setBackgroundColor_Widget(toolBar, tmBannerBackground_ColorId); | ||
1241 | setId_Widget(addChildFlags_Widget(toolBar, | 1294 | setId_Widget(addChildFlags_Widget(toolBar, |
1242 | iClob(newLargeIcon_LabelWidget("\U0001f870", "navigate.back")), | 1295 | iClob(newLargeIcon_LabelWidget("\U0001f870", "navigate.back")), |
1243 | frameless_WidgetFlag), | 1296 | frameless_WidgetFlag), |
@@ -1254,7 +1307,16 @@ void createUserInterface_Root(iRoot *d) { | |||
1254 | iClob(newLargeIcon_LabelWidget(book_Icon, "toolbar.showview arg:-1")), | 1307 | iClob(newLargeIcon_LabelWidget(book_Icon, "toolbar.showview arg:-1")), |
1255 | frameless_WidgetFlag | commandOnClick_WidgetFlag), | 1308 | frameless_WidgetFlag | commandOnClick_WidgetFlag), |
1256 | "toolbar.view"); | 1309 | "toolbar.view"); |
1257 | iLabelWidget *menuButton = makeMenuButton_LabelWidget("\U0001d362", phoneNavMenuItems_, | 1310 | setId_Widget(addChildFlags_Widget(toolBar, |
1311 | iClob(new_LabelWidget("", "toolbar.showident")), | ||
1312 | frameless_WidgetFlag | | ||
1313 | noBackground_WidgetFlag | | ||
1314 | fixedPosition_WidgetFlag | | ||
1315 | fixedSize_WidgetFlag | | ||
1316 | ignoreForParentWidth_WidgetFlag | | ||
1317 | ignoreForParentHeight_WidgetFlag), | ||
1318 | "toolbar.name"); | ||
1319 | iLabelWidget *menuButton = makeMenuButton_LabelWidget(menu_Icon, phoneNavMenuItems_, | ||
1258 | iElemCount(phoneNavMenuItems_)); | 1320 | iElemCount(phoneNavMenuItems_)); |
1259 | setFont_LabelWidget(menuButton, uiLabelLarge_FontId); | 1321 | setFont_LabelWidget(menuButton, uiLabelLarge_FontId); |
1260 | setId_Widget(as_Widget(menuButton), "toolbar.navmenu"); | 1322 | setId_Widget(as_Widget(menuButton), "toolbar.navmenu"); |
@@ -1262,9 +1324,8 @@ void createUserInterface_Root(iRoot *d) { | |||
1262 | iForEach(ObjectList, i, children_Widget(toolBar)) { | 1324 | iForEach(ObjectList, i, children_Widget(toolBar)) { |
1263 | iLabelWidget *btn = i.object; | 1325 | iLabelWidget *btn = i.object; |
1264 | setFlags_Widget(i.object, noBackground_WidgetFlag, iTrue); | 1326 | setFlags_Widget(i.object, noBackground_WidgetFlag, iTrue); |
1265 | setTextColor_LabelWidget(i.object, tmBannerIcon_ColorId); | ||
1266 | // setBackgroundColor_Widget(i.object, tmBannerSideTitle_ColorId); | ||
1267 | } | 1327 | } |
1328 | updateToolbarColors_Root(d); | ||
1268 | const iMenuItem items[] = { | 1329 | const iMenuItem items[] = { |
1269 | { book_Icon " ${sidebar.bookmarks}", 0, 0, "toolbar.showview arg:0" }, | 1330 | { book_Icon " ${sidebar.bookmarks}", 0, 0, "toolbar.showview arg:0" }, |
1270 | { star_Icon " ${sidebar.feeds}", 0, 0, "toolbar.showview arg:1" }, | 1331 | { star_Icon " ${sidebar.feeds}", 0, 0, "toolbar.showview arg:1" }, |
@@ -1346,7 +1407,7 @@ void createUserInterface_Root(iRoot *d) { | |||
1346 | } | 1407 | } |
1347 | } | 1408 | } |
1348 | 1409 | ||
1349 | void showToolbars_Root(iRoot *d, iBool show) { | 1410 | void showToolbar_Root(iRoot *d, iBool show) { |
1350 | /* The toolbar is only used on phone portrait layout. */ | 1411 | /* The toolbar is only used on phone portrait layout. */ |
1351 | if (isLandscape_App()) return; | 1412 | if (isLandscape_App()) return; |
1352 | iWidget *toolBar = findChild_Widget(d->widget, "toolbar"); | 1413 | iWidget *toolBar = findChild_Widget(d->widget, "toolbar"); |
diff --git a/src/ui/root.h b/src/ui/root.h index 96864a15..740e97c9 100644 --- a/src/ui/root.h +++ b/src/ui/root.h | |||
@@ -34,7 +34,8 @@ void postArrange_Root (iRoot *); | |||
34 | void updateMetrics_Root (iRoot *); | 34 | void updateMetrics_Root (iRoot *); |
35 | void updatePadding_Root (iRoot *); /* TODO: is part of metrics? */ | 35 | void updatePadding_Root (iRoot *); /* TODO: is part of metrics? */ |
36 | void dismissPortraitPhoneSidebars_Root (iRoot *); | 36 | void dismissPortraitPhoneSidebars_Root (iRoot *); |
37 | void showToolbars_Root (iRoot *, iBool show); | 37 | void showToolbar_Root (iRoot *, iBool show); |
38 | void updateToolbarColors_Root (iRoot *); | ||
38 | 39 | ||
39 | iInt2 size_Root (const iRoot *); | 40 | iInt2 size_Root (const iRoot *); |
40 | iRect rect_Root (const iRoot *); | 41 | iRect rect_Root (const iRoot *); |
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 27646b22..c0a22e99 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -523,15 +523,17 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
523 | addChild_Widget(div, iClob(makePadding_Widget(gap_UI))); | 523 | addChild_Widget(div, iClob(makePadding_Widget(gap_UI))); |
524 | addChild_Widget(div, iClob(new_LabelWidget("${menu.identity.import}", "ident.import"))); | 524 | addChild_Widget(div, iClob(new_LabelWidget("${menu.identity.import}", "ident.import"))); |
525 | addChildFlags_Widget(div, iClob(new_Widget()), expand_WidgetFlag); /* pad */ | 525 | addChildFlags_Widget(div, iClob(new_Widget()), expand_WidgetFlag); /* pad */ |
526 | iLabelWidget *linkLabel; | ||
526 | setBackgroundColor_Widget( | 527 | setBackgroundColor_Widget( |
527 | addChildFlags_Widget( | 528 | addChildFlags_Widget( |
528 | div, | 529 | div, |
529 | iClob(new_LabelWidget(format_CStr(cstr_Lang("ident.gotohelp"), | 530 | iClob(linkLabel = new_LabelWidget(format_CStr(cstr_Lang("ident.gotohelp"), |
530 | uiTextStrong_ColorEscape, | 531 | uiTextStrong_ColorEscape, |
531 | restore_ColorEscape), | 532 | restore_ColorEscape), |
532 | "!open newtab:1 gotoheading:1.6 url:about:help")), | 533 | "!open newtab:1 gotoheading:1.6 url:about:help")), |
533 | frameless_WidgetFlag | fixedHeight_WidgetFlag | wrapText_WidgetFlag), | 534 | frameless_WidgetFlag | fixedHeight_WidgetFlag), |
534 | uiBackgroundSidebar_ColorId); | 535 | uiBackgroundSidebar_ColorId); |
536 | setWrap_LabelWidget(linkLabel, iTrue); | ||
535 | addChild_Widget(d->blank, iClob(div)); | 537 | addChild_Widget(d->blank, iClob(div)); |
536 | } | 538 | } |
537 | // arrange_Widget(d->blank); | 539 | // arrange_Widget(d->blank); |
@@ -625,13 +627,14 @@ static void updateMetrics_SidebarWidget_(iSidebarWidget *d) { | |||
625 | void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | 627 | void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { |
626 | iWidget *w = as_Widget(d); | 628 | iWidget *w = as_Widget(d); |
627 | init_Widget(w); | 629 | init_Widget(w); |
628 | setId_Widget(w, side == left_SideBarSide ? "sidebar" : "sidebar2"); | 630 | setId_Widget(w, side == left_SidebarSide ? "sidebar" : "sidebar2"); |
629 | initCopy_String(&d->cmdPrefix, id_Widget(w)); | 631 | initCopy_String(&d->cmdPrefix, id_Widget(w)); |
630 | appendChar_String(&d->cmdPrefix, '.'); | 632 | appendChar_String(&d->cmdPrefix, '.'); |
631 | setBackgroundColor_Widget(w, none_ColorId); | 633 | setBackgroundColor_Widget(w, none_ColorId); |
632 | setFlags_Widget(w, | 634 | setFlags_Widget(w, |
633 | collapse_WidgetFlag | hidden_WidgetFlag | arrangeHorizontal_WidgetFlag | | 635 | collapse_WidgetFlag | hidden_WidgetFlag | arrangeHorizontal_WidgetFlag | |
634 | resizeWidthOfChildren_WidgetFlag, | 636 | resizeWidthOfChildren_WidgetFlag | noFadeBackground_WidgetFlag | |
637 | noShadowBorder_WidgetFlag, | ||
635 | iTrue); | 638 | iTrue); |
636 | iZap(d->modeScroll); | 639 | iZap(d->modeScroll); |
637 | d->side = side; | 640 | d->side = side; |
@@ -659,7 +662,7 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
659 | d->actions = NULL; | 662 | d->actions = NULL; |
660 | /* On a phone, the right sidebar is used exclusively for Identities. */ | 663 | /* On a phone, the right sidebar is used exclusively for Identities. */ |
661 | const iBool isPhone = deviceType_App() == phone_AppDeviceType; | 664 | const iBool isPhone = deviceType_App() == phone_AppDeviceType; |
662 | if (!isPhone || d->side == left_SideBarSide) { | 665 | if (!isPhone || d->side == left_SidebarSide) { |
663 | iWidget *buttons = new_Widget(); | 666 | iWidget *buttons = new_Widget(); |
664 | setId_Widget(buttons, "buttons"); | 667 | setId_Widget(buttons, "buttons"); |
665 | for (int i = 0; i < max_SidebarMode; i++) { | 668 | for (int i = 0; i < max_SidebarMode; i++) { |
@@ -678,8 +681,8 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
678 | iClob(buttons), | 681 | iClob(buttons), |
679 | arrangeHorizontal_WidgetFlag | | 682 | arrangeHorizontal_WidgetFlag | |
680 | resizeWidthOfChildren_WidgetFlag | | 683 | resizeWidthOfChildren_WidgetFlag | |
681 | arrangeHeight_WidgetFlag | resizeToParentWidth_WidgetFlag | | 684 | arrangeHeight_WidgetFlag | resizeToParentWidth_WidgetFlag); // | |
682 | drawBackgroundToHorizontalSafeArea_WidgetFlag); | 685 | // drawBackgroundToHorizontalSafeArea_WidgetFlag); |
683 | setBackgroundColor_Widget(buttons, uiBackgroundSidebar_ColorId); | 686 | setBackgroundColor_Widget(buttons, uiBackgroundSidebar_ColorId); |
684 | } | 687 | } |
685 | else { | 688 | else { |
@@ -700,13 +703,13 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
700 | setPadding_Widget(as_Widget(d->list), 0, gap_UI, 0, gap_UI); | 703 | setPadding_Widget(as_Widget(d->list), 0, gap_UI, 0, gap_UI); |
701 | addChildFlags_Widget(listAndActions, | 704 | addChildFlags_Widget(listAndActions, |
702 | iClob(d->list), | 705 | iClob(d->list), |
703 | expand_WidgetFlag | drawBackgroundToHorizontalSafeArea_WidgetFlag); | 706 | expand_WidgetFlag); // | drawBackgroundToHorizontalSafeArea_WidgetFlag); |
704 | setId_Widget(addChildPosFlags_Widget(listAndActions, | 707 | setId_Widget(addChildPosFlags_Widget(listAndActions, |
705 | iClob(d->actions = new_Widget()), | 708 | iClob(d->actions = new_Widget()), |
706 | isPhone ? front_WidgetAddPos : back_WidgetAddPos, | 709 | isPhone ? front_WidgetAddPos : back_WidgetAddPos, |
707 | arrangeHorizontal_WidgetFlag | arrangeHeight_WidgetFlag | | 710 | arrangeHorizontal_WidgetFlag | arrangeHeight_WidgetFlag | |
708 | resizeWidthOfChildren_WidgetFlag | | 711 | resizeWidthOfChildren_WidgetFlag), // | |
709 | drawBackgroundToHorizontalSafeArea_WidgetFlag), | 712 | // drawBackgroundToHorizontalSafeArea_WidgetFlag), |
710 | "actions"); | 713 | "actions"); |
711 | setBackgroundColor_Widget(d->actions, uiBackgroundSidebar_ColorId); | 714 | setBackgroundColor_Widget(d->actions, uiBackgroundSidebar_ColorId); |
712 | d->contextItem = NULL; | 715 | d->contextItem = NULL; |
@@ -715,24 +718,24 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
715 | addChildFlags_Widget(content, iClob(d->blank), resizeChildren_WidgetFlag); | 718 | addChildFlags_Widget(content, iClob(d->blank), resizeChildren_WidgetFlag); |
716 | addChildFlags_Widget(vdiv, iClob(content), expand_WidgetFlag); | 719 | addChildFlags_Widget(vdiv, iClob(content), expand_WidgetFlag); |
717 | setMode_SidebarWidget(d, | 720 | setMode_SidebarWidget(d, |
718 | deviceType_App() == phone_AppDeviceType && d->side == right_SideBarSide ? | 721 | deviceType_App() == phone_AppDeviceType && d->side == right_SidebarSide ? |
719 | identities_SidebarMode : bookmarks_SidebarMode); | 722 | identities_SidebarMode : bookmarks_SidebarMode); |
720 | d->resizer = | 723 | d->resizer = |
721 | addChildFlags_Widget(w, | 724 | addChildFlags_Widget(w, |
722 | iClob(new_Widget()), | 725 | iClob(new_Widget()), |
723 | hover_WidgetFlag | commandOnClick_WidgetFlag | fixedWidth_WidgetFlag | | 726 | hover_WidgetFlag | commandOnClick_WidgetFlag | fixedWidth_WidgetFlag | |
724 | resizeToParentHeight_WidgetFlag | | 727 | resizeToParentHeight_WidgetFlag | |
725 | (side == left_SideBarSide ? moveToParentRightEdge_WidgetFlag | 728 | (side == left_SidebarSide ? moveToParentRightEdge_WidgetFlag |
726 | : moveToParentLeftEdge_WidgetFlag)); | 729 | : moveToParentLeftEdge_WidgetFlag)); |
727 | if (deviceType_App() == phone_AppDeviceType) { | 730 | if (deviceType_App() == phone_AppDeviceType) { |
728 | setFlags_Widget(d->resizer, hidden_WidgetFlag | disabled_WidgetFlag, iTrue); | 731 | setFlags_Widget(d->resizer, hidden_WidgetFlag | disabled_WidgetFlag, iTrue); |
729 | } | 732 | } |
730 | setId_Widget(d->resizer, side == left_SideBarSide ? "sidebar.grab" : "sidebar2.grab"); | 733 | setId_Widget(d->resizer, side == left_SidebarSide ? "sidebar.grab" : "sidebar2.grab"); |
731 | setBackgroundColor_Widget(d->resizer, none_ColorId); | 734 | setBackgroundColor_Widget(d->resizer, none_ColorId); |
732 | d->menu = NULL; | 735 | d->menu = NULL; |
733 | addAction_Widget(w, SDLK_r, KMOD_PRIMARY | KMOD_SHIFT, "feeds.refresh"); | 736 | addAction_Widget(w, SDLK_r, KMOD_PRIMARY | KMOD_SHIFT, "feeds.refresh"); |
734 | updateMetrics_SidebarWidget_(d); | 737 | updateMetrics_SidebarWidget_(d); |
735 | if (side == left_SideBarSide) { | 738 | if (side == left_SidebarSide) { |
736 | postCommand_App("~sidebar.update"); /* unread count */ | 739 | postCommand_App("~sidebar.update"); /* unread count */ |
737 | } | 740 | } |
738 | } | 741 | } |
@@ -773,6 +776,7 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si | |||
773 | const iGmHeading *head = constAt_Array(headings_GmDocument(doc), item->id); | 776 | const iGmHeading *head = constAt_Array(headings_GmDocument(doc), item->id); |
774 | postCommandf_App("document.goto loc:%p", head->text.start); | 777 | postCommandf_App("document.goto loc:%p", head->text.start); |
775 | dismissPortraitPhoneSidebars_Root(as_Widget(d)->root); | 778 | dismissPortraitPhoneSidebars_Root(as_Widget(d)->root); |
779 | setOpenedFromSidebar_DocumentWidget(document_App(), iTrue); | ||
776 | break; | 780 | break; |
777 | } | 781 | } |
778 | case feeds_SidebarMode: { | 782 | case feeds_SidebarMode: { |
@@ -783,7 +787,7 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si | |||
783 | case bookmarks_SidebarMode: | 787 | case bookmarks_SidebarMode: |
784 | case history_SidebarMode: { | 788 | case history_SidebarMode: { |
785 | if (!isEmpty_String(&item->url)) { | 789 | if (!isEmpty_String(&item->url)) { |
786 | postCommandf_Root(get_Root(), "open newtab:%d url:%s", | 790 | postCommandf_Root(get_Root(), "open fromsidebar:1 newtab:%d url:%s", |
787 | openTabMode_Sym(modState_Keys()), | 791 | openTabMode_Sym(modState_Keys()), |
788 | cstr_String(&item->url)); | 792 | cstr_String(&item->url)); |
789 | } | 793 | } |
@@ -799,7 +803,7 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si | |||
799 | updateContextMenu_SidebarWidget_(d); | 803 | updateContextMenu_SidebarWidget_(d); |
800 | arrange_Widget(d->menu); | 804 | arrange_Widget(d->menu); |
801 | openMenu_Widget(d->menu, | 805 | openMenu_Widget(d->menu, |
802 | d->side == left_SideBarSide | 806 | d->side == left_SidebarSide |
803 | ? topRight_Rect(itemRect_ListWidget(d->list, itemIndex)) | 807 | ? topRight_Rect(itemRect_ListWidget(d->list, itemIndex)) |
804 | : addX_I2(topLeft_Rect(itemRect_ListWidget(d->list, itemIndex)), | 808 | : addX_I2(topLeft_Rect(itemRect_ListWidget(d->list, itemIndex)), |
805 | -width_Widget(d->menu))); | 809 | -width_Widget(d->menu))); |
@@ -857,7 +861,7 @@ void setWidth_SidebarWidget(iSidebarWidget *d, float widthAsGaps) { | |||
857 | if (!isFixedWidth) { | 861 | if (!isFixedWidth) { |
858 | /* Even less space if the other sidebar is visible, too. */ | 862 | /* Even less space if the other sidebar is visible, too. */ |
859 | const int otherWidth = | 863 | const int otherWidth = |
860 | width_Widget(findWidget_App(d->side == left_SideBarSide ? "sidebar2" : "sidebar")); | 864 | width_Widget(findWidget_App(d->side == left_SidebarSide ? "sidebar2" : "sidebar")); |
861 | width = iClamp(width, 30 * gap_UI, size_Root(w->root).x - 50 * gap_UI - otherWidth); | 865 | width = iClamp(width, 30 * gap_UI, size_Root(w->root).x - 50 * gap_UI - otherWidth); |
862 | } | 866 | } |
863 | d->widthAsGaps = (float) width / (float) gap_UI; | 867 | d->widthAsGaps = (float) width / (float) gap_UI; |
@@ -938,33 +942,39 @@ static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char * | |||
938 | } | 942 | } |
939 | const iBool isAnimated = prefs_App()->uiAnimations && | 943 | const iBool isAnimated = prefs_App()->uiAnimations && |
940 | argLabel_Command(cmd, "noanim") == 0 && | 944 | argLabel_Command(cmd, "noanim") == 0 && |
941 | (deviceType_App() != phone_AppDeviceType); | 945 | (d->side == left_SidebarSide || deviceType_App() != phone_AppDeviceType); |
942 | int visX = 0; | 946 | int visX = 0; |
943 | if (isVisible_Widget(w)) { | 947 | if (isVisible_Widget(w)) { |
944 | visX = left_Rect(bounds_Widget(w)) - left_Rect(w->root->widget->rect); | 948 | visX = left_Rect(bounds_Widget(w)) - left_Rect(w->root->widget->rect); |
945 | } | 949 | } |
946 | setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w)); | 950 | setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w)); |
951 | /* Safe area inset for mobile. */ | ||
952 | const int safePad = (d->side == left_SidebarSide ? left_Rect(safeRect_Root(w->root)) : 0); | ||
947 | if (isVisible_Widget(w)) { | 953 | if (isVisible_Widget(w)) { |
948 | setFlags_Widget(w, keepOnTop_WidgetFlag, iFalse); | 954 | setFlags_Widget(w, keepOnTop_WidgetFlag, iFalse); |
949 | w->rect.size.x = d->widthAsGaps * gap_UI; | 955 | w->rect.size.x = d->widthAsGaps * gap_UI; |
950 | invalidate_ListWidget(d->list); | 956 | invalidate_ListWidget(d->list); |
951 | if (isAnimated) { | 957 | if (isAnimated) { |
952 | setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); | 958 | setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); |
953 | setVisualOffset_Widget(w, (d->side == left_SideBarSide ? -1 : 1) * w->rect.size.x, 0, 0); | 959 | setVisualOffset_Widget( |
960 | w, (d->side == left_SidebarSide ? -1 : 1) * (w->rect.size.x + safePad), 0, 0); | ||
954 | setVisualOffset_Widget(w, 0, 300, easeOut_AnimFlag | softer_AnimFlag); | 961 | setVisualOffset_Widget(w, 0, 300, easeOut_AnimFlag | softer_AnimFlag); |
955 | } | 962 | } |
956 | } | 963 | } |
957 | else if (isAnimated) { | 964 | else if (isAnimated) { |
958 | setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); | 965 | setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); |
959 | if (d->side == right_SideBarSide) { | 966 | if (d->side == right_SidebarSide) { |
960 | setVisualOffset_Widget(w, visX, 0, 0); | 967 | setVisualOffset_Widget(w, visX, 0, 0); |
961 | setVisualOffset_Widget(w, visX + w->rect.size.x, 300, easeOut_AnimFlag | softer_AnimFlag); | 968 | setVisualOffset_Widget( |
969 | w, visX + w->rect.size.x + safePad, 300, easeOut_AnimFlag | softer_AnimFlag); | ||
962 | } | 970 | } |
963 | else { | 971 | else { |
964 | setFlags_Widget(w, keepOnTop_WidgetFlag, iTrue); | 972 | setFlags_Widget(w, keepOnTop_WidgetFlag, iTrue); |
965 | setVisualOffset_Widget(w, -w->rect.size.x, 300, easeOut_AnimFlag | softer_AnimFlag); | 973 | setVisualOffset_Widget( |
974 | w, -w->rect.size.x - safePad, 300, easeOut_AnimFlag | softer_AnimFlag); | ||
966 | } | 975 | } |
967 | } | 976 | } |
977 | updateToolbarColors_Root(w->root); | ||
968 | arrange_Widget(w->parent); | 978 | arrange_Widget(w->parent); |
969 | /* BUG: Rearranging because the arrange above didn't fully resolve the height. */ | 979 | /* BUG: Rearranging because the arrange above didn't fully resolve the height. */ |
970 | arrange_Widget(w); | 980 | arrange_Widget(w); |
@@ -984,11 +994,21 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
984 | /* Handle commands. */ | 994 | /* Handle commands. */ |
985 | if (isResize_UserEvent(ev)) { | 995 | if (isResize_UserEvent(ev)) { |
986 | checkModeButtonLayout_SidebarWidget_(d); | 996 | checkModeButtonLayout_SidebarWidget_(d); |
987 | if (deviceType_App() == phone_AppDeviceType && d->side == left_SideBarSide) { | 997 | if (deviceType_App() == phone_AppDeviceType && d->side == left_SidebarSide) { |
998 | setFlags_Widget(w, rightEdgeDraggable_WidgetFlag, isPortrait_App()); | ||
988 | /* In landscape, visibility of the toolbar is controlled separately. */ | 999 | /* In landscape, visibility of the toolbar is controlled separately. */ |
989 | if (isVisible_Widget(w)) { | 1000 | if (isVisible_Widget(w)) { |
990 | postCommand_Widget(w, "sidebar.toggle"); | 1001 | postCommand_Widget(w, "sidebar.toggle"); |
991 | } | 1002 | } |
1003 | setFlags_Widget(findChild_Widget(w, "buttons"), | ||
1004 | drawBackgroundToHorizontalSafeArea_WidgetFlag, | ||
1005 | isLandscape_App()); | ||
1006 | setFlags_Widget(findChild_Widget(w, "actions"), | ||
1007 | drawBackgroundToHorizontalSafeArea_WidgetFlag, | ||
1008 | isLandscape_App()); | ||
1009 | setFlags_Widget(as_Widget(d->list), | ||
1010 | drawBackgroundToHorizontalSafeArea_WidgetFlag, | ||
1011 | isLandscape_App()); | ||
992 | return iFalse; | 1012 | return iFalse; |
993 | } | 1013 | } |
994 | } | 1014 | } |
@@ -1029,6 +1049,11 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
1029 | postCommandf_App("sidebar.mode arg:%d toggle:1", identities_SidebarMode); | 1049 | postCommandf_App("sidebar.mode arg:%d toggle:1", identities_SidebarMode); |
1030 | return iTrue; | 1050 | return iTrue; |
1031 | } | 1051 | } |
1052 | else if (isPortraitPhone_App() && isVisible_Widget(w) && d->side == left_SidebarSide && | ||
1053 | equal_Command(cmd, "swipe.forward")) { | ||
1054 | postCommand_App("sidebar.toggle"); | ||
1055 | return iTrue; | ||
1056 | } | ||
1032 | else if (startsWith_CStr(cmd, cstr_String(&d->cmdPrefix))) { | 1057 | else if (startsWith_CStr(cmd, cstr_String(&d->cmdPrefix))) { |
1033 | if (handleSidebarCommand_SidebarWidget_(d, cmd + size_String(&d->cmdPrefix))) { | 1058 | if (handleSidebarCommand_SidebarWidget_(d, cmd + size_String(&d->cmdPrefix))) { |
1034 | return iTrue; | 1059 | return iTrue; |
@@ -1059,7 +1084,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
1059 | const int resMid = d->resizer->rect.size.x / 2; | 1084 | const int resMid = d->resizer->rect.size.x / 2; |
1060 | setWidth_SidebarWidget( | 1085 | setWidth_SidebarWidget( |
1061 | d, | 1086 | d, |
1062 | ((d->side == left_SideBarSide | 1087 | ((d->side == left_SidebarSide |
1063 | ? inner.x | 1088 | ? inner.x |
1064 | : (right_Rect(rect_Root(w->root)) - coord_Command(cmd).x)) + | 1089 | : (right_Rect(rect_Root(w->root)) - coord_Command(cmd).x)) + |
1065 | resMid) / (float) gap_UI); | 1090 | resMid) / (float) gap_UI); |
@@ -1528,15 +1553,17 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) { | |||
1528 | const iRect bounds = bounds_Widget(w); | 1553 | const iRect bounds = bounds_Widget(w); |
1529 | iPaint p; | 1554 | iPaint p; |
1530 | init_Paint(&p); | 1555 | init_Paint(&p); |
1531 | if (flags_Widget(w) & visualOffset_WidgetFlag && | 1556 | if (deviceType_App() != phone_AppDeviceType) { |
1532 | flags_Widget(w) & horizontalOffset_WidgetFlag && isVisible_Widget(w)) { | 1557 | if (flags_Widget(w) & visualOffset_WidgetFlag && |
1533 | fillRect_Paint(&p, boundsWithoutVisualOffset_Widget(w), tmBackground_ColorId); | 1558 | flags_Widget(w) & horizontalOffset_WidgetFlag && isVisible_Widget(w)) { |
1559 | fillRect_Paint(&p, boundsWithoutVisualOffset_Widget(w), tmBackground_ColorId); | ||
1560 | } | ||
1534 | } | 1561 | } |
1535 | draw_Widget(w); | 1562 | draw_Widget(w); |
1536 | if (isVisible_Widget(w)) { | 1563 | if (isVisible_Widget(w)) { |
1537 | drawVLine_Paint( | 1564 | drawVLine_Paint( |
1538 | &p, | 1565 | &p, |
1539 | addX_I2(d->side == left_SideBarSide ? topRight_Rect(bounds) : topLeft_Rect(bounds), -1), | 1566 | addX_I2(d->side == left_SidebarSide ? topRight_Rect(bounds) : topLeft_Rect(bounds), -1), |
1540 | height_Rect(bounds), | 1567 | height_Rect(bounds), |
1541 | uiSeparator_ColorId); | 1568 | uiSeparator_ColorId); |
1542 | } | 1569 | } |
@@ -1782,13 +1809,7 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, | |||
1782 | : uiTextFramelessHover_ColorId) | 1809 | : uiTextFramelessHover_ColorId) |
1783 | : uiTextDim_ColorId; | 1810 | : uiTextDim_ColorId; |
1784 | if (!d->listItem.isSelected && !isUsedOnDomain) { | 1811 | if (!d->listItem.isSelected && !isUsedOnDomain) { |
1785 | /* Draw an outline of the icon. */ | 1812 | drawOutline_Text(font, cPos, metaFg, none_ColorId, range_String(&icon)); |
1786 | for (int off = 0; off < 4; ++off) { | ||
1787 | drawRange_Text(font, | ||
1788 | add_I2(cPos, init_I2(off % 2 == 0 ? -1 : 1, off / 2 == 0 ? -1 : 1)), | ||
1789 | metaFg, | ||
1790 | range_String(&icon)); | ||
1791 | } | ||
1792 | } | 1813 | } |
1793 | drawRange_Text(font, | 1814 | drawRange_Text(font, |
1794 | cPos, | 1815 | cPos, |
diff --git a/src/ui/sidebarwidget.h b/src/ui/sidebarwidget.h index 2e418aa4..130242ab 100644 --- a/src/ui/sidebarwidget.h +++ b/src/ui/sidebarwidget.h | |||
@@ -36,8 +36,8 @@ enum iSidebarMode { | |||
36 | const char * icon_SidebarMode (enum iSidebarMode mode); | 36 | const char * icon_SidebarMode (enum iSidebarMode mode); |
37 | 37 | ||
38 | enum iSidebarSide { | 38 | enum iSidebarSide { |
39 | left_SideBarSide, | 39 | left_SidebarSide, |
40 | right_SideBarSide, | 40 | right_SidebarSide, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | enum iFeedsMode { | 43 | enum iFeedsMode { |
diff --git a/src/ui/text.c b/src/ui/text.c index 55fd4254..edbc6583 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -116,6 +116,7 @@ iDefineTypeConstructionArgs(Glyph, (iChar ch), ch) | |||
116 | 116 | ||
117 | struct Impl_Font { | 117 | struct Impl_Font { |
118 | iBlock * data; | 118 | iBlock * data; |
119 | enum iTextFont family; | ||
119 | stbtt_fontinfo font; | 120 | stbtt_fontinfo font; |
120 | float xScale, yScale; | 121 | float xScale, yScale; |
121 | int vertOffset; /* offset due to scaling */ | 122 | int vertOffset; /* offset due to scaling */ |
@@ -134,6 +135,15 @@ static void init_Font(iFont *d, const iBlock *data, int height, float scale, | |||
134 | enum iFontSize sizeId, iBool isMonospaced) { | 135 | enum iFontSize sizeId, iBool isMonospaced) { |
135 | init_Hash(&d->glyphs); | 136 | init_Hash(&d->glyphs); |
136 | d->data = NULL; | 137 | d->data = NULL; |
138 | d->family = undefined_TextFont; | ||
139 | /* Note: We only use `family` currently for applying a kerning fix to Nunito. */ | ||
140 | if (data == &fontNunitoRegular_Embedded || | ||
141 | data == &fontNunitoBold_Embedded || | ||
142 | data == &fontNunitoExtraBold_Embedded || | ||
143 | data == &fontNunitoLightItalic_Embedded || | ||
144 | data == &fontNunitoExtraLight_Embedded) { | ||
145 | d->family = nunito_TextFont; | ||
146 | } | ||
137 | d->isMonospaced = isMonospaced; | 147 | d->isMonospaced = isMonospaced; |
138 | d->height = height; | 148 | d->height = height; |
139 | iZap(d->font); | 149 | iZap(d->font); |
@@ -306,6 +316,7 @@ static void initFonts_Text_(iText *d) { | |||
306 | { &fontSourceSans3Regular_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, | 316 | { &fontSourceSans3Regular_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, |
307 | { &fontSourceSans3Regular_Embedded, uiSize * 1.333f, 1.0f, uiBig_FontSize }, | 317 | { &fontSourceSans3Regular_Embedded, uiSize * 1.333f, 1.0f, uiBig_FontSize }, |
308 | { &fontSourceSans3Regular_Embedded, uiSize * 1.666f, 1.0f, uiLarge_FontSize }, | 318 | { &fontSourceSans3Regular_Embedded, uiSize * 1.666f, 1.0f, uiLarge_FontSize }, |
319 | { &fontSourceSans3Semibold_Embedded, uiSize * 0.8f, 1.0f, uiNormal_FontSize }, | ||
309 | /* UI fonts: bold weight */ | 320 | /* UI fonts: bold weight */ |
310 | { &fontSourceSans3Bold_Embedded, uiSize, 1.0f, uiNormal_FontSize }, | 321 | { &fontSourceSans3Bold_Embedded, uiSize, 1.0f, uiNormal_FontSize }, |
311 | { &fontSourceSans3Bold_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, | 322 | { &fontSourceSans3Bold_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, |
@@ -389,7 +400,9 @@ static void initCache_Text_(iText *d) { | |||
389 | d->cacheRowAllocStep = iMax(2, textSize / 6); | 400 | d->cacheRowAllocStep = iMax(2, textSize / 6); |
390 | /* Allocate initial (empty) rows. These will be assigned actual locations in the cache | 401 | /* Allocate initial (empty) rows. These will be assigned actual locations in the cache |
391 | once at least one glyph is stored. */ | 402 | once at least one glyph is stored. */ |
392 | for (int h = d->cacheRowAllocStep; h <= 2 * textSize + d->cacheRowAllocStep; h += d->cacheRowAllocStep) { | 403 | for (int h = d->cacheRowAllocStep; |
404 | h <= 2.5 * textSize + d->cacheRowAllocStep; | ||
405 | h += d->cacheRowAllocStep) { | ||
393 | pushBack_Array(&d->cacheRows, &(iCacheRow){ .height = 0 }); | 406 | pushBack_Array(&d->cacheRows, &(iCacheRow){ .height = 0 }); |
394 | } | 407 | } |
395 | d->cacheBottom = 0; | 408 | d->cacheBottom = 0; |
@@ -1010,10 +1023,10 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1010 | prevCh = 0; | 1023 | prevCh = 0; |
1011 | continue; | 1024 | continue; |
1012 | } | 1025 | } |
1013 | if (ch == '\r') { /* color change */ | 1026 | if (ch == '\v') { /* color change */ |
1014 | iChar esc = nextChar_(&chPos, args->text.end); | 1027 | iChar esc = nextChar_(&chPos, args->text.end); |
1015 | int colorNum = args->color; | 1028 | int colorNum = args->color; |
1016 | if (esc == '\r') { /* Extended range. */ | 1029 | if (esc == '\v') { /* Extended range. */ |
1017 | esc = nextChar_(&chPos, args->text.end) + asciiExtended_ColorEscape; | 1030 | esc = nextChar_(&chPos, args->text.end) + asciiExtended_ColorEscape; |
1018 | colorNum = esc - asciiBase_ColorEscape; | 1031 | colorNum = esc - asciiBase_ColorEscape; |
1019 | } | 1032 | } |
@@ -1128,14 +1141,26 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1128 | const iChar next = nextChar_(&peek, args->text.end); | 1141 | const iChar next = nextChar_(&peek, args->text.end); |
1129 | if (enableKerning_Text && !d->manualKernOnly && next) { | 1142 | if (enableKerning_Text && !d->manualKernOnly && next) { |
1130 | const uint32_t nextGlyphIndex = glyphIndex_Font_(glyph->font, next); | 1143 | const uint32_t nextGlyphIndex = glyphIndex_Font_(glyph->font, next); |
1131 | const int kern = stbtt_GetGlyphKernAdvance( | 1144 | int kern = stbtt_GetGlyphKernAdvance( |
1132 | &glyph->font->font, glyph->glyphIndex, nextGlyphIndex); | 1145 | &glyph->font->font, glyph->glyphIndex, nextGlyphIndex); |
1146 | /* Nunito needs some kerning fixes. */ | ||
1147 | if (glyph->font->family == nunito_TextFont) { | ||
1148 | if (ch == 'W' && (next == 'i' || next == 'h')) { | ||
1149 | kern = -30; | ||
1150 | } | ||
1151 | else if (ch == 'T' && next == 'h') { | ||
1152 | kern = -15; | ||
1153 | } | ||
1154 | else if (ch == 'V' && next == 'i') { | ||
1155 | kern = -15; | ||
1156 | } | ||
1157 | } | ||
1133 | if (kern) { | 1158 | if (kern) { |
1134 | // printf("%lc(%u) -> %lc(%u): kern %d (%f)\n", ch, glyph->glyphIndex, next, | 1159 | // printf("%lc(%u) -> %lc(%u): kern %d (%f)\n", ch, glyph->glyphIndex, next, |
1135 | // nextGlyphIndex, | 1160 | // nextGlyphIndex, |
1136 | // kern, d->xScale * kern); | 1161 | // kern, d->xScale * kern); |
1137 | xpos += d->xScale * kern; | 1162 | xpos += glyph->font->xScale * kern; |
1138 | xposExtend += d->xScale * kern; | 1163 | xposExtend += glyph->font->xScale * kern; |
1139 | } | 1164 | } |
1140 | } | 1165 | } |
1141 | } | 1166 | } |
@@ -1313,6 +1338,18 @@ void drawRangeN_Text(int fontId, iInt2 pos, int color, iRangecc text, size_t max | |||
1313 | drawBoundedN_Text_(fontId, pos, 0, color, text, maxChars); | 1338 | drawBoundedN_Text_(fontId, pos, 0, color, text, maxChars); |
1314 | } | 1339 | } |
1315 | 1340 | ||
1341 | void drawOutline_Text(int fontId, iInt2 pos, int outlineColor, int fillColor, iRangecc text) { | ||
1342 | for (int off = 0; off < 4; ++off) { | ||
1343 | drawRange_Text(fontId, | ||
1344 | add_I2(pos, init_I2(off % 2 == 0 ? -1 : 1, off / 2 == 0 ? -1 : 1)), | ||
1345 | outlineColor, | ||
1346 | text); | ||
1347 | } | ||
1348 | if (fillColor != none_ColorId) { | ||
1349 | drawRange_Text(fontId, pos, fillColor, text); | ||
1350 | } | ||
1351 | } | ||
1352 | |||
1316 | iInt2 advanceWrapRange_Text(int fontId, int maxWidth, iRangecc text) { | 1353 | iInt2 advanceWrapRange_Text(int fontId, int maxWidth, iRangecc text) { |
1317 | iInt2 size = zero_I2(); | 1354 | iInt2 size = zero_I2(); |
1318 | const char *endp; | 1355 | const char *endp; |
@@ -1354,6 +1391,31 @@ void drawCentered_Text(int fontId, iRect rect, iBool alignVisual, int color, con | |||
1354 | deinit_Block(&chars); | 1391 | deinit_Block(&chars); |
1355 | } | 1392 | } |
1356 | 1393 | ||
1394 | void drawCenteredOutline_Text(int fontId, iRect rect, iBool alignVisual, int outlineColor, | ||
1395 | int fillColor, const char *format, ...) { | ||
1396 | iBlock chars; | ||
1397 | init_Block(&chars, 0); { | ||
1398 | va_list args; | ||
1399 | va_start(args, format); | ||
1400 | vprintf_Block(&chars, format, args); | ||
1401 | va_end(args); | ||
1402 | } | ||
1403 | if (outlineColor != none_ColorId) { | ||
1404 | for (int off = 0; off < 4; ++off) { | ||
1405 | drawCenteredRange_Text( | ||
1406 | fontId, | ||
1407 | moved_Rect(rect, init_I2(off % 2 == 0 ? -1 : 1, off / 2 == 0 ? -1 : 1)), | ||
1408 | alignVisual, | ||
1409 | outlineColor, | ||
1410 | range_Block(&chars)); | ||
1411 | } | ||
1412 | } | ||
1413 | if (fillColor != none_ColorId) { | ||
1414 | drawCenteredRange_Text(fontId, rect, alignVisual, fillColor, range_Block(&chars)); | ||
1415 | } | ||
1416 | deinit_Block(&chars); | ||
1417 | } | ||
1418 | |||
1357 | void drawCenteredRange_Text(int fontId, iRect rect, iBool alignVisual, int color, iRangecc text) { | 1419 | void drawCenteredRange_Text(int fontId, iRect rect, iBool alignVisual, int color, iRangecc text) { |
1358 | iRect textBounds = alignVisual ? visualBounds_Text(fontId, text) | 1420 | iRect textBounds = alignVisual ? visualBounds_Text(fontId, text) |
1359 | : (iRect){ zero_I2(), advanceRange_Text(fontId, text) }; | 1421 | : (iRect){ zero_I2(), advanceRange_Text(fontId, text) }; |
@@ -1504,9 +1566,10 @@ static void initWrap_TextBuf_(iTextBuf *d, int font, int color, int maxWidth, iB | |||
1504 | if (d->texture) { | 1566 | if (d->texture) { |
1505 | SDL_Texture *oldTarget = SDL_GetRenderTarget(render); | 1567 | SDL_Texture *oldTarget = SDL_GetRenderTarget(render); |
1506 | SDL_SetRenderTarget(render, d->texture); | 1568 | SDL_SetRenderTarget(render, d->texture); |
1569 | SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE); | ||
1570 | SDL_SetRenderDrawColor(render, 255, 255, 255, 0); | ||
1571 | SDL_RenderClear(render); | ||
1507 | SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_NONE); /* blended when TextBuf is drawn */ | 1572 | SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_NONE); /* blended when TextBuf is drawn */ |
1508 | SDL_SetRenderDrawColor(text_.render, 0, 0, 0, 0); | ||
1509 | SDL_RenderClear(text_.render); | ||
1510 | const int fg = color | fillBackground_ColorId; | 1573 | const int fg = color | fillBackground_ColorId; |
1511 | iRangecc range = range_CStr(text); | 1574 | iRangecc range = range_CStr(text); |
1512 | if (maxWidth == 0) { | 1575 | if (maxWidth == 0) { |
diff --git a/src/ui/text.h b/src/ui/text.h index 2f2bcf3a..5a099142 100644 --- a/src/ui/text.h +++ b/src/ui/text.h | |||
@@ -50,6 +50,7 @@ enum iFontId { | |||
50 | defaultMedium_FontId, | 50 | defaultMedium_FontId, |
51 | defaultBig_FontId, | 51 | defaultBig_FontId, |
52 | defaultLarge_FontId, | 52 | defaultLarge_FontId, |
53 | defaultSmall_FontId, | ||
53 | /* UI fonts: bold weight */ | 54 | /* UI fonts: bold weight */ |
54 | defaultBold_FontId, | 55 | defaultBold_FontId, |
55 | defaultMediumBold_FontId, | 56 | defaultMediumBold_FontId, |
@@ -116,7 +117,8 @@ iLocalDef iBool isJapanese_FontId(enum iFontId id) { | |||
116 | #define emojiVariationSelector_Char ((iChar) 0xfe0f) | 117 | #define emojiVariationSelector_Char ((iChar) 0xfe0f) |
117 | 118 | ||
118 | enum iTextFont { | 119 | enum iTextFont { |
119 | nunito_TextFont, | 120 | undefined_TextFont = -1, |
121 | nunito_TextFont = 0, | ||
120 | firaSans_TextFont, | 122 | firaSans_TextFont, |
121 | literata_TextFont, | 123 | literata_TextFont, |
122 | tinos_TextFont, | 124 | tinos_TextFont, |
@@ -162,9 +164,11 @@ void draw_Text (int fontId, iInt2 pos, int color, const char *t | |||
162 | void drawAlign_Text (int fontId, iInt2 pos, int color, enum iAlignment align, const char *text, ...); | 164 | void drawAlign_Text (int fontId, iInt2 pos, int color, enum iAlignment align, const char *text, ...); |
163 | void drawCentered_Text (int fontId, iRect rect, iBool alignVisual, int color, const char *text, ...); | 165 | void drawCentered_Text (int fontId, iRect rect, iBool alignVisual, int color, const char *text, ...); |
164 | void drawCenteredRange_Text (int fontId, iRect rect, iBool alignVisual, int color, iRangecc text); | 166 | void drawCenteredRange_Text (int fontId, iRect rect, iBool alignVisual, int color, iRangecc text); |
167 | void drawCenteredOutline_Text(int fontId, iRect rect, iBool alignVisual, int outlineColor, int fillColor, const char *text, ...); | ||
165 | void drawString_Text (int fontId, iInt2 pos, int color, const iString *text); | 168 | void drawString_Text (int fontId, iInt2 pos, int color, const iString *text); |
166 | void drawRange_Text (int fontId, iInt2 pos, int color, iRangecc text); | 169 | void drawRange_Text (int fontId, iInt2 pos, int color, iRangecc text); |
167 | void drawRangeN_Text (int fontId, iInt2 pos, int color, iRangecc text, size_t maxLen); | 170 | void drawRangeN_Text (int fontId, iInt2 pos, int color, iRangecc text, size_t maxLen); |
171 | void drawOutline_Text (int fontId, iInt2 pos, int outlineColor, int fillColor, iRangecc text); | ||
168 | void drawBoundRange_Text (int fontId, iInt2 pos, int boundWidth, int color, iRangecc text); /* bound does not wrap */ | 172 | void drawBoundRange_Text (int fontId, iInt2 pos, int boundWidth, int color, iRangecc text); /* bound does not wrap */ |
169 | int drawWrapRange_Text (int fontId, iInt2 pos, int maxWidth, int color, iRangecc text); /* returns new Y */ | 173 | int drawWrapRange_Text (int fontId, iInt2 pos, int maxWidth, int color, iRangecc text); /* returns new Y */ |
170 | 174 | ||
diff --git a/src/ui/touch.c b/src/ui/touch.c index 74a22baf..dac1152e 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c | |||
@@ -40,6 +40,10 @@ iDeclareType(TouchState) | |||
40 | #define numHistory_Touch_ 5 | 40 | #define numHistory_Touch_ 5 |
41 | #define lastIndex_Touch_ (numHistory_Touch_ - 1) | 41 | #define lastIndex_Touch_ (numHistory_Touch_ - 1) |
42 | 42 | ||
43 | static const uint32_t longPressSpanMs_ = 500; | ||
44 | static const uint32_t shortPressSpanMs_ = 250; | ||
45 | static const int tapRadiusPt_ = 10; | ||
46 | |||
43 | enum iTouchEdge { | 47 | enum iTouchEdge { |
44 | none_TouchEdge, | 48 | none_TouchEdge, |
45 | left_TouchEdge, | 49 | left_TouchEdge, |
@@ -55,12 +59,13 @@ enum iTouchAxis { | |||
55 | struct Impl_Touch { | 59 | struct Impl_Touch { |
56 | SDL_FingerID id; | 60 | SDL_FingerID id; |
57 | iWidget *affinity; /* widget on which the touch started */ | 61 | iWidget *affinity; /* widget on which the touch started */ |
58 | iWidget *edgeDragging; | 62 | // iWidget *edgeDragging; |
59 | iBool hasMoved; | 63 | iBool hasMoved; |
60 | iBool isTapBegun; | 64 | iBool isTapBegun; |
61 | iBool isLeftDown; | 65 | iBool isLeftDown; |
62 | iBool isTouchDrag; | 66 | iBool isTouchDrag; |
63 | iBool isTapAndHold; | 67 | iBool isTapAndHold; |
68 | iBool didPostEdgeMove; | ||
64 | iBool didBeginOnTouchDrag; | 69 | iBool didBeginOnTouchDrag; |
65 | int pinchId; | 70 | int pinchId; |
66 | enum iTouchEdge edge; | 71 | enum iTouchEdge edge; |
@@ -132,9 +137,6 @@ static iTouch *find_TouchState_(iTouchState *d, SDL_FingerID id) { | |||
132 | return NULL; | 137 | return NULL; |
133 | } | 138 | } |
134 | 139 | ||
135 | static const uint32_t longPressSpanMs_ = 500; | ||
136 | static const int tapRadiusPt_ = 10; | ||
137 | |||
138 | iLocalDef float distance_Touch_(const iTouch *d) { | 140 | iLocalDef float distance_Touch_(const iTouch *d) { |
139 | return length_F3(sub_F3(d->pos[0], d->startPos)); | 141 | return length_F3(sub_F3(d->pos[0], d->startPos)); |
140 | } | 142 | } |
@@ -246,6 +248,11 @@ iLocalDef double accurateTicks_(void) { | |||
246 | return 1000.0 * (double) count / (double) freq; | 248 | return 1000.0 * (double) count / (double) freq; |
247 | } | 249 | } |
248 | 250 | ||
251 | static iFloat3 gestureVector_Touch_(const iTouch *d) { | ||
252 | const size_t lastIndex = iMin(d->posCount - 1, lastIndex_Touch_); | ||
253 | return sub_F3(d->pos[0], d->pos[lastIndex]); | ||
254 | } | ||
255 | |||
249 | static void update_TouchState_(void *ptr) { | 256 | static void update_TouchState_(void *ptr) { |
250 | iTouchState *d = ptr; | 257 | iTouchState *d = ptr; |
251 | /* Check for long presses to simulate right clicks. */ | 258 | /* Check for long presses to simulate right clicks. */ |
@@ -255,6 +262,24 @@ static void update_TouchState_(void *ptr) { | |||
255 | if (touch->pinchId || touch->isTouchDrag) { | 262 | if (touch->pinchId || touch->isTouchDrag) { |
256 | continue; | 263 | continue; |
257 | } | 264 | } |
265 | if (touch->edge) { | ||
266 | const iFloat3 pos = touch->pos[0]; | ||
267 | /* Cancel the swipe if the finger doesn't move or moves mostly vertically. */ | ||
268 | const iFloat3 gestureVector = gestureVector_Touch_(touch); | ||
269 | if (fabsf(2 * x_F3(gestureVector)) < fabsf(y_F3(gestureVector)) || | ||
270 | (isStationary_Touch_(touch) && nowTime - touch->startTime > shortPressSpanMs_)) { | ||
271 | //const int swipeDir = x_F3(gestureVector) > 0 ? +1 : -1; | ||
272 | //dispatchClick_Touch_(touch, | ||
273 | // touch->edge == left_TouchEdge && swipeDir > 0 ? SDL_BUTTON_X1 : | ||
274 | // touch->edge == right_TouchEdge && swipeDir < 0 ? SDL_BUTTON_X2 : 0); | ||
275 | // setHover_Widget(NULL); | ||
276 | postCommandf_App("edgeswipe.ended abort:1 side:%d id:%llu", touch->edge, touch->id); | ||
277 | touch->edge = none_TouchEdge; | ||
278 | /* May be a regular drag along the edge so don't remove. */ | ||
279 | //remove_ArrayIterator(&i); | ||
280 | } | ||
281 | continue; | ||
282 | } | ||
258 | /* Holding a touch will reset previous momentum for this widget. */ | 283 | /* Holding a touch will reset previous momentum for this widget. */ |
259 | if (isStationary_Touch_(touch)) { | 284 | if (isStationary_Touch_(touch)) { |
260 | const int elapsed = nowTime - touch->startTime; | 285 | const int elapsed = nowTime - touch->startTime; |
@@ -340,6 +365,7 @@ static void update_TouchState_(void *ptr) { | |||
340 | } | 365 | } |
341 | } | 366 | } |
342 | 367 | ||
368 | #if 0 | ||
343 | static iWidget *findSlidePanel_Widget_(iWidget *d) { | 369 | static iWidget *findSlidePanel_Widget_(iWidget *d) { |
344 | for (iWidget *w = d; w; w = parent_Widget(w)) { | 370 | for (iWidget *w = d; w; w = parent_Widget(w)) { |
345 | if (isVisible_Widget(w) && flags_Widget(w) & edgeDraggable_WidgetFlag) { | 371 | if (isVisible_Widget(w) && flags_Widget(w) & edgeDraggable_WidgetFlag) { |
@@ -348,6 +374,7 @@ static iWidget *findSlidePanel_Widget_(iWidget *d) { | |||
348 | } | 374 | } |
349 | return NULL; | 375 | return NULL; |
350 | } | 376 | } |
377 | #endif | ||
351 | 378 | ||
352 | static void checkNewPinch_TouchState_(iTouchState *d, iTouch *newTouch) { | 379 | static void checkNewPinch_TouchState_(iTouchState *d, iTouch *newTouch) { |
353 | iWidget *affinity = newTouch->affinity; | 380 | iWidget *affinity = newTouch->affinity; |
@@ -365,6 +392,12 @@ static void checkNewPinch_TouchState_(iTouchState *d, iTouch *newTouch) { | |||
365 | pinch.touchIds[1] = other->id; | 392 | pinch.touchIds[1] = other->id; |
366 | newTouch->pinchId = other->pinchId = pinch.id; | 393 | newTouch->pinchId = other->pinchId = pinch.id; |
367 | clearWidgetMomentum_TouchState_(d, affinity); | 394 | clearWidgetMomentum_TouchState_(d, affinity); |
395 | if (other->edge && other->didPostEdgeMove) { | ||
396 | postCommandf_App("edgeswipe.ended abort:1 side:%d id:%llu", other->edge, other->id); | ||
397 | other->didPostEdgeMove = iFalse; | ||
398 | } | ||
399 | other->edge = none_TouchEdge; | ||
400 | newTouch->edge = none_TouchEdge; | ||
368 | /* Remember current positions to determine pinch amount. */ | 401 | /* Remember current positions to determine pinch amount. */ |
369 | newTouch->startPos = newTouch->pos[0]; | 402 | newTouch->startPos = newTouch->pos[0]; |
370 | other->startPos = other->pos[0]; | 403 | other->startPos = other->pos[0]; |
@@ -452,6 +485,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
452 | edge = right_TouchEdge; | 485 | edge = right_TouchEdge; |
453 | } | 486 | } |
454 | iWidget *aff = hitChild_Window(window, init_I2(iRound(x), iRound(y_F3(pos)))); | 487 | iWidget *aff = hitChild_Window(window, init_I2(iRound(x), iRound(y_F3(pos)))); |
488 | #if 0 | ||
455 | if (edge == left_TouchEdge) { | 489 | if (edge == left_TouchEdge) { |
456 | dragging = findSlidePanel_Widget_(aff); | 490 | dragging = findSlidePanel_Widget_(aff); |
457 | if (dragging) { | 491 | if (dragging) { |
@@ -460,6 +494,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
460 | setFlags_Widget(dragging, dragged_WidgetFlag, iTrue); | 494 | setFlags_Widget(dragging, dragged_WidgetFlag, iTrue); |
461 | } | 495 | } |
462 | } | 496 | } |
497 | #endif | ||
463 | /* TODO: We must retain a reference to the affinity widget, or otherwise it might | 498 | /* TODO: We must retain a reference to the affinity widget, or otherwise it might |
464 | be destroyed during the gesture. */ | 499 | be destroyed during the gesture. */ |
465 | // printf("aff:[%p] %s:'%s'\n", aff, aff ? class_Widget(aff)->name : "-", | 500 | // printf("aff:[%p] %s:'%s'\n", aff, aff ? class_Widget(aff)->name : "-", |
@@ -469,7 +504,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
469 | iTouch newTouch = { | 504 | iTouch newTouch = { |
470 | .id = fing->fingerId, | 505 | .id = fing->fingerId, |
471 | .affinity = aff, | 506 | .affinity = aff, |
472 | .edgeDragging = dragging, | 507 | // .edgeDragging = dragging, |
473 | .didBeginOnTouchDrag = (flags_Widget(aff) & touchDrag_WidgetFlag) != 0, | 508 | .didBeginOnTouchDrag = (flags_Widget(aff) & touchDrag_WidgetFlag) != 0, |
474 | .edge = edge, | 509 | .edge = edge, |
475 | .startTime = nowTime, | 510 | .startTime = nowTime, |
@@ -487,6 +522,16 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
487 | } | 522 | } |
488 | else if (ev->type == SDL_FINGERMOTION) { | 523 | else if (ev->type == SDL_FINGERMOTION) { |
489 | iTouch *touch = find_TouchState_(d, fing->fingerId); | 524 | iTouch *touch = find_TouchState_(d, fing->fingerId); |
525 | if (touch && touch->edge) { | ||
526 | clear_Array(d->moms); | ||
527 | pushPos_Touch_(touch, pos, nowTime); | ||
528 | postCommandf_App("edgeswipe.moved arg:%d side:%d id:%llu", | ||
529 | (int) (x_F3(pos) - x_F3(touch->startPos)), | ||
530 | touch->edge, | ||
531 | touch->id); | ||
532 | touch->didPostEdgeMove = iTrue; | ||
533 | return iTrue; | ||
534 | } | ||
490 | if (touch && touch->affinity) { | 535 | if (touch && touch->affinity) { |
491 | if (touch->isTouchDrag) { | 536 | if (touch->isTouchDrag) { |
492 | dispatchMotion_Touch_(pos, SDL_BUTTON_LMASK); | 537 | dispatchMotion_Touch_(pos, SDL_BUTTON_LMASK); |
@@ -556,36 +601,18 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
556 | touch->axis = y_TouchAxis; | 601 | touch->axis = y_TouchAxis; |
557 | } | 602 | } |
558 | } | 603 | } |
559 | /* Edge swipe aborted? */ | 604 | iAssert(touch->edge == none_TouchEdge); |
560 | if (touch->edge == left_TouchEdge) { | ||
561 | if (fing->dx < 0 && x_F3(touch->pos[0]) < tapRadiusPt_ * window->pixelRatio) { | ||
562 | touch->edge = none_TouchEdge; | ||
563 | if (touch->edgeDragging) { | ||
564 | setFlags_Widget(touch->edgeDragging, dragged_WidgetFlag, iFalse); | ||
565 | setVisualOffset_Widget(touch->edgeDragging, 0, 200, easeOut_AnimFlag); | ||
566 | touch->edgeDragging = NULL; | ||
567 | } | ||
568 | } | ||
569 | else if (touch->edgeDragging) { | ||
570 | setVisualOffset_Widget(touch->edgeDragging, x_F3(pos) - x_F3(touch->startPos), 10, 0); | ||
571 | } | ||
572 | } | ||
573 | if (touch->edge == right_TouchEdge && fing->dx > 0) { | ||
574 | touch->edge = none_TouchEdge; | ||
575 | } | ||
576 | if (touch->edge) { | ||
577 | pixels.y = 0; | ||
578 | } | ||
579 | if (touch->axis == x_TouchAxis) { | 605 | if (touch->axis == x_TouchAxis) { |
580 | pixels.y = 0; | 606 | pixels.y = 0; |
581 | } | 607 | } |
582 | if (touch->axis == y_TouchAxis) { | 608 | if (touch->axis == y_TouchAxis) { |
583 | pixels.x = 0; | 609 | pixels.x = 0; |
584 | } | 610 | } |
585 | // printf("%p (%s) py: %i wy: %f acc: %f\n", | 611 | // printf("%p (%s) py: %i wy: %f acc: %f edge: %d\n", |
586 | // touch->affinity, | 612 | // touch->affinity, |
587 | // class_Widget(touch->affinity)->name, | 613 | // class_Widget(touch->affinity)->name, |
588 | // pixels.y, y_F3(amount), y_F3(touch->accum)); | 614 | // pixels.y, y_F3(amount), y_F3(touch->accum), |
615 | // touch->edge); | ||
589 | if (pixels.x || pixels.y) { | 616 | if (pixels.x || pixels.y) { |
590 | setFocus_Widget(NULL); | 617 | setFocus_Widget(NULL); |
591 | dispatchMotion_Touch_(touch->pos[0], 0); | 618 | dispatchMotion_Touch_(touch->pos[0], 0); |
@@ -612,9 +639,21 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
612 | endPinch_TouchState_(d, touch->pinchId); | 639 | endPinch_TouchState_(d, touch->pinchId); |
613 | break; | 640 | break; |
614 | } | 641 | } |
642 | #if 0 | ||
615 | if (touch->edgeDragging) { | 643 | if (touch->edgeDragging) { |
616 | setFlags_Widget(touch->edgeDragging, dragged_WidgetFlag, iFalse); | 644 | setFlags_Widget(touch->edgeDragging, dragged_WidgetFlag, iFalse); |
617 | } | 645 | } |
646 | #endif | ||
647 | if (touch->edge && !isStationary_Touch_(touch)) { | ||
648 | const iFloat3 gesture = gestureVector_Touch_(touch); | ||
649 | const float pixel = window->pixelRatio; | ||
650 | const int moveDir = x_F3(gesture) < -pixel ? -1 : x_F3(gesture) > pixel ? +1 : 0; | ||
651 | const int didAbort = (touch->edge == left_TouchEdge && moveDir < 0) || | ||
652 | (touch->edge == right_TouchEdge && moveDir > 0); | ||
653 | postCommandf_App("edgeswipe.ended abort:%d side:%d id:%llu", didAbort, touch->edge, touch->id); | ||
654 | remove_ArrayIterator(&i); | ||
655 | continue; | ||
656 | } | ||
618 | if (flags_Widget(touch->affinity) & touchDrag_WidgetFlag) { | 657 | if (flags_Widget(touch->affinity) & touchDrag_WidgetFlag) { |
619 | if (!touch->isLeftDown && !touch->isTapAndHold) { | 658 | if (!touch->isLeftDown && !touch->isTapAndHold) { |
620 | /* This will be a click on a touchDrag widget. */ | 659 | /* This will be a click on a touchDrag widget. */ |
@@ -638,6 +677,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
638 | const uint32_t duration = nowTime - touch->startTime; | 677 | const uint32_t duration = nowTime - touch->startTime; |
639 | const iFloat3 gestureVector = sub_F3(pos, touch->pos[lastIndex]); | 678 | const iFloat3 gestureVector = sub_F3(pos, touch->pos[lastIndex]); |
640 | iFloat3 velocity = zero_F3(); | 679 | iFloat3 velocity = zero_F3(); |
680 | #if 0 | ||
641 | if (touch->edge && fabsf(2 * x_F3(gestureVector)) > fabsf(y_F3(gestureVector)) && | 681 | if (touch->edge && fabsf(2 * x_F3(gestureVector)) > fabsf(y_F3(gestureVector)) && |
642 | !isStationary_Touch_(touch)) { | 682 | !isStationary_Touch_(touch)) { |
643 | const int swipeDir = x_F3(gestureVector) > 0 ? +1 : -1; | 683 | const int swipeDir = x_F3(gestureVector) > 0 ? +1 : -1; |
@@ -646,7 +686,9 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
646 | touch->edge == right_TouchEdge && swipeDir < 0 ? SDL_BUTTON_X2 : 0); | 686 | touch->edge == right_TouchEdge && swipeDir < 0 ? SDL_BUTTON_X2 : 0); |
647 | setHover_Widget(NULL); | 687 | setHover_Widget(NULL); |
648 | } | 688 | } |
649 | else { | 689 | else |
690 | #endif | ||
691 | { | ||
650 | const uint32_t elapsed = fing->timestamp - touch->posTime[lastIndex]; | 692 | const uint32_t elapsed = fing->timestamp - touch->posTime[lastIndex]; |
651 | const float minVelocity = 400.0f; | 693 | const float minVelocity = 400.0f; |
652 | if (elapsed < 150) { | 694 | if (elapsed < 150) { |
diff --git a/src/ui/util.c b/src/ui/util.c index c4fb8886..e0b05a44 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -710,7 +710,8 @@ iWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) { | |||
710 | menu, | 710 | menu, |
711 | iClob(newKeyMods_LabelWidget(labelText, item->key, item->kmods, item->command)), | 711 | iClob(newKeyMods_LabelWidget(labelText, item->key, item->kmods, item->command)), |
712 | noBackground_WidgetFlag | frameless_WidgetFlag | alignLeft_WidgetFlag | | 712 | noBackground_WidgetFlag | frameless_WidgetFlag | alignLeft_WidgetFlag | |
713 | drawKey_WidgetFlag | (isInfo ? wrapText_WidgetFlag : 0) | itemFlags); | 713 | drawKey_WidgetFlag | itemFlags); |
714 | setWrap_LabelWidget(label, isInfo); | ||
714 | haveIcons |= checkIcon_LabelWidget(label); | 715 | haveIcons |= checkIcon_LabelWidget(label); |
715 | updateSize_LabelWidget(label); /* drawKey was set */ | 716 | updateSize_LabelWidget(label); /* drawKey was set */ |
716 | if (isInfo) { | 717 | if (isInfo) { |
@@ -776,7 +777,7 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) { | |||
776 | if (isInstance_Object(i.object, &Class_LabelWidget)) { | 777 | if (isInstance_Object(i.object, &Class_LabelWidget)) { |
777 | iLabelWidget *label = i.object; | 778 | iLabelWidget *label = i.object; |
778 | const iBool isCaution = startsWith_String(text_LabelWidget(label), uiTextCaution_ColorEscape); | 779 | const iBool isCaution = startsWith_String(text_LabelWidget(label), uiTextCaution_ColorEscape); |
779 | if (flags_Widget(as_Widget(label)) & wrapText_WidgetFlag) { | 780 | if (isWrapped_LabelWidget(label)) { |
780 | continue; | 781 | continue; |
781 | } | 782 | } |
782 | if (deviceType_App() == desktop_AppDeviceType) { | 783 | if (deviceType_App() == desktop_AppDeviceType) { |
@@ -979,8 +980,8 @@ static void addTabPage_Widget_(iWidget *tabs, enum iWidgetAddPos addPos, iWidget | |||
979 | iClob(newKeyMods_LabelWidget(label, key, kmods, format_CStr("tabs.switch page:%p", page))), | 980 | iClob(newKeyMods_LabelWidget(label, key, kmods, format_CStr("tabs.switch page:%p", page))), |
980 | addPos); | 981 | addPos); |
981 | setFlags_Widget(button, selected_WidgetFlag, isSel); | 982 | setFlags_Widget(button, selected_WidgetFlag, isSel); |
982 | setFlags_Widget( | 983 | setFlags_Widget(button, commandOnClick_WidgetFlag | expand_WidgetFlag, iTrue); |
983 | button, noTopFrame_WidgetFlag | commandOnClick_WidgetFlag | expand_WidgetFlag, iTrue); | 984 | setNoTopFrame_LabelWidget((iLabelWidget *) button, iTrue); |
984 | addChildPos_Widget(pages, page, addPos); | 985 | addChildPos_Widget(pages, page, addPos); |
985 | if (tabCount_Widget(tabs) > 1) { | 986 | if (tabCount_Widget(tabs) > 1) { |
986 | setFlags_Widget(buttons, hidden_WidgetFlag, iFalse); | 987 | setFlags_Widget(buttons, hidden_WidgetFlag, iFalse); |
@@ -1317,7 +1318,7 @@ void updateValueInput_Widget(iWidget *d, const char *title, const char *prompt) | |||
1317 | 1318 | ||
1318 | static iBool messageHandler_(iWidget *msg, const char *cmd) { | 1319 | static iBool messageHandler_(iWidget *msg, const char *cmd) { |
1319 | /* Almost any command dismisses the sheet. */ | 1320 | /* Almost any command dismisses the sheet. */ |
1320 | /* TODO: Use a "notification" prefix (like `) to ignore all types of commands line this? */ | 1321 | /* TODO: Add a "notification" type of user events to separate them from user actions. */ |
1321 | if (!(equal_Command(cmd, "media.updated") || | 1322 | if (!(equal_Command(cmd, "media.updated") || |
1322 | equal_Command(cmd, "media.player.update") || | 1323 | equal_Command(cmd, "media.player.update") || |
1323 | equal_Command(cmd, "bookmarks.request.finished") || | 1324 | equal_Command(cmd, "bookmarks.request.finished") || |
@@ -1326,6 +1327,7 @@ static iBool messageHandler_(iWidget *msg, const char *cmd) { | |||
1326 | equal_Command(cmd, "document.request.updated") || | 1327 | equal_Command(cmd, "document.request.updated") || |
1327 | equal_Command(cmd, "scrollbar.fade") || | 1328 | equal_Command(cmd, "scrollbar.fade") || |
1328 | equal_Command(cmd, "widget.overflow") || | 1329 | equal_Command(cmd, "widget.overflow") || |
1330 | equal_Command(cmd, "edgeswipe.ended") || | ||
1329 | startsWith_CStr(cmd, "window."))) { | 1331 | startsWith_CStr(cmd, "window."))) { |
1330 | setupSheetTransition_Mobile(msg, iFalse); | 1332 | setupSheetTransition_Mobile(msg, iFalse); |
1331 | destroy_Widget(msg); | 1333 | destroy_Widget(msg); |
@@ -1599,8 +1601,6 @@ iWidget *makePreferences_Widget(void) { | |||
1599 | /* General preferences. */ { | 1601 | /* General preferences. */ { |
1600 | appendTwoColumnPage_(tabs, "${heading.prefs.general}", '1', &headings, &values); | 1602 | appendTwoColumnPage_(tabs, "${heading.prefs.general}", '1', &headings, &values); |
1601 | #if defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT) | 1603 | #if defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT) |
1602 | //addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.downloads}"))); | ||
1603 | //setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.downloads"); | ||
1604 | addPrefsInputWithHeading_(headings, values, "prefs.downloads", iClob(new_InputWidget(0))); | 1604 | addPrefsInputWithHeading_(headings, values, "prefs.downloads", iClob(new_InputWidget(0))); |
1605 | #endif | 1605 | #endif |
1606 | iInputWidget *searchUrl; | 1606 | iInputWidget *searchUrl; |
@@ -1608,12 +1608,6 @@ iWidget *makePreferences_Widget(void) { | |||
1608 | setUrlContent_InputWidget(searchUrl, iTrue); | 1608 | setUrlContent_InputWidget(searchUrl, iTrue); |
1609 | addChild_Widget(headings, iClob(makePadding_Widget(bigGap))); | 1609 | addChild_Widget(headings, iClob(makePadding_Widget(bigGap))); |
1610 | addChild_Widget(values, iClob(makePadding_Widget(bigGap))); | 1610 | addChild_Widget(values, iClob(makePadding_Widget(bigGap))); |
1611 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.collapsepreonload}"))); | ||
1612 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.collapsepreonload"))); | ||
1613 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.plaintext.wrap}"))); | ||
1614 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.plaintext.wrap"))); | ||
1615 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.centershort}"))); | ||
1616 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.centershort"))); | ||
1617 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.hoverlink}"))); | 1611 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.hoverlink}"))); |
1618 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.hoverlink"))); | 1612 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.hoverlink"))); |
1619 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.archive.openindex}"))); | 1613 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.archive.openindex}"))); |
@@ -1674,26 +1668,6 @@ iWidget *makePreferences_Widget(void) { | |||
1674 | } | 1668 | } |
1675 | /* User Interface. */ { | 1669 | /* User Interface. */ { |
1676 | appendTwoColumnPage_(tabs, "${heading.prefs.interface}", '2', &headings, &values); | 1670 | appendTwoColumnPage_(tabs, "${heading.prefs.interface}", '2', &headings, &values); |
1677 | #if defined (iPlatformApple) || defined (iPlatformMSys) | ||
1678 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.ostheme}"))); | ||
1679 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.ostheme"))); | ||
1680 | #endif | ||
1681 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.theme}"))); | ||
1682 | iWidget *themes = new_Widget(); | ||
1683 | /* Themes. */ { | ||
1684 | setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("${prefs.theme.black}", "theme.set arg:0"))), "prefs.theme.0"); | ||
1685 | setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("${prefs.theme.dark}", "theme.set arg:1"))), "prefs.theme.1"); | ||
1686 | setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("${prefs.theme.light}", "theme.set arg:2"))), "prefs.theme.2"); | ||
1687 | setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("${prefs.theme.white}", "theme.set arg:3"))), "prefs.theme.3"); | ||
1688 | } | ||
1689 | addChildFlags_Widget(values, iClob(themes), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | ||
1690 | /* Accents. */ | ||
1691 | iWidget *accent = new_Widget(); { | ||
1692 | setId_Widget(addChild_Widget(accent, iClob(new_LabelWidget("${prefs.accent.teal}", "accent.set arg:0"))), "prefs.accent.0"); | ||
1693 | setId_Widget(addChild_Widget(accent, iClob(new_LabelWidget("${prefs.accent.orange}", "accent.set arg:1"))), "prefs.accent.1"); | ||
1694 | } | ||
1695 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.accent}"))); | ||
1696 | addChildFlags_Widget(values, iClob(accent), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | ||
1697 | #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) | 1671 | #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) |
1698 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.customframe}"))); | 1672 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.customframe}"))); |
1699 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.customframe"))); | 1673 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.customframe"))); |
@@ -1718,6 +1692,27 @@ iWidget *makePreferences_Widget(void) { | |||
1718 | } | 1692 | } |
1719 | /* Colors. */ { | 1693 | /* Colors. */ { |
1720 | appendTwoColumnPage_(tabs, "${heading.prefs.colors}", '3', &headings, &values); | 1694 | appendTwoColumnPage_(tabs, "${heading.prefs.colors}", '3', &headings, &values); |
1695 | makeTwoColumnHeading_("${heading.prefs.uitheme}", headings, values); | ||
1696 | #if defined (iPlatformApple) || defined (iPlatformMSys) | ||
1697 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.ostheme}"))); | ||
1698 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.ostheme"))); | ||
1699 | #endif | ||
1700 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.theme}"))); | ||
1701 | iWidget *themes = new_Widget(); | ||
1702 | /* Themes. */ { | ||
1703 | setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("${prefs.theme.black}", "theme.set arg:0"))), "prefs.theme.0"); | ||
1704 | setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("${prefs.theme.dark}", "theme.set arg:1"))), "prefs.theme.1"); | ||
1705 | setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("${prefs.theme.light}", "theme.set arg:2"))), "prefs.theme.2"); | ||
1706 | setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("${prefs.theme.white}", "theme.set arg:3"))), "prefs.theme.3"); | ||
1707 | } | ||
1708 | addChildFlags_Widget(values, iClob(themes), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | ||
1709 | /* Accents. */ | ||
1710 | iWidget *accent = new_Widget(); { | ||
1711 | setId_Widget(addChild_Widget(accent, iClob(new_LabelWidget("${prefs.accent.teal}", "accent.set arg:0"))), "prefs.accent.0"); | ||
1712 | setId_Widget(addChild_Widget(accent, iClob(new_LabelWidget("${prefs.accent.orange}", "accent.set arg:1"))), "prefs.accent.1"); | ||
1713 | } | ||
1714 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.accent}"))); | ||
1715 | addChildFlags_Widget(values, iClob(accent), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | ||
1721 | makeTwoColumnHeading_("${heading.prefs.pagecontent}", headings, values); | 1716 | makeTwoColumnHeading_("${heading.prefs.pagecontent}", headings, values); |
1722 | for (int i = 0; i < 2; ++i) { | 1717 | for (int i = 0; i < 2; ++i) { |
1723 | const iBool isDark = (i == 0); | 1718 | const iBool isDark = (i == 0); |
@@ -1750,14 +1745,15 @@ iWidget *makePreferences_Widget(void) { | |||
1750 | } | 1745 | } |
1751 | addChildFlags_Widget(values, iClob(sats), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | 1746 | addChildFlags_Widget(values, iClob(sats), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); |
1752 | } | 1747 | } |
1753 | /* Layout. */ { | 1748 | /* Fonts. */ { |
1754 | setId_Widget(appendTwoColumnPage_(tabs, "${heading.prefs.style}", '4', &headings, &values), "prefs.page.style"); | 1749 | setId_Widget(appendTwoColumnPage_(tabs, "${heading.prefs.fonts}", '4', &headings, &values), "prefs.page.fonts"); |
1755 | makeTwoColumnHeading_("${heading.prefs.fonts}", headings, values); | ||
1756 | /* Fonts. */ { | 1750 | /* Fonts. */ { |
1757 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.headingfont}"))); | 1751 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.headingfont}"))); |
1758 | addFontButtons_(values, "headingfont"); | 1752 | addFontButtons_(values, "headingfont"); |
1759 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font}"))); | 1753 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font}"))); |
1760 | addFontButtons_(values, "font"); | 1754 | addFontButtons_(values, "font"); |
1755 | addChild_Widget(headings, iClob(makePadding_Widget(bigGap))); | ||
1756 | addChild_Widget(values, iClob(makePadding_Widget(bigGap))); | ||
1761 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.mono}"))); | 1757 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.mono}"))); |
1762 | iWidget *mono = new_Widget(); { | 1758 | iWidget *mono = new_Widget(); { |
1763 | iWidget *tog; | 1759 | iWidget *tog; |
@@ -1789,9 +1785,18 @@ iWidget *makePreferences_Widget(void) { | |||
1789 | updateSize_LabelWidget((iLabelWidget *) tog); | 1785 | updateSize_LabelWidget((iLabelWidget *) tog); |
1790 | } | 1786 | } |
1791 | addChildFlags_Widget(values, iClob(boldLink), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | 1787 | addChildFlags_Widget(values, iClob(boldLink), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); |
1792 | addPrefsInputWithHeading_(headings, values, "prefs.userfont", iClob(new_InputWidget(0))); | 1788 | addChild_Widget(headings, iClob(makePadding_Widget(bigGap))); |
1793 | } | 1789 | addChild_Widget(values, iClob(makePadding_Widget(bigGap))); |
1794 | makeTwoColumnHeading_("${heading.prefs.paragraph}", headings, values); | 1790 | /* Custom font. */ { |
1791 | iInputWidget *customFont = new_InputWidget(0); | ||
1792 | setHint_InputWidget(customFont, "${hint.prefs.userfont}"); | ||
1793 | addPrefsInputWithHeading_(headings, values, "prefs.userfont", iClob(customFont)); | ||
1794 | } | ||
1795 | } | ||
1796 | } | ||
1797 | /* Style. */ { | ||
1798 | setId_Widget(appendTwoColumnPage_(tabs, "${heading.prefs.style}", '5', &headings, &values), "prefs.page.style"); | ||
1799 | // makeTwoColumnHeading_("${heading.prefs.paragraph}", headings, values); | ||
1795 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.linewidth}"))); | 1800 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.linewidth}"))); |
1796 | iWidget *widths = new_Widget(); | 1801 | iWidget *widths = new_Widget(); |
1797 | /* Line widths. */ { | 1802 | /* Line widths. */ { |
@@ -1811,14 +1816,20 @@ iWidget *makePreferences_Widget(void) { | |||
1811 | addChildFlags_Widget(values, iClob(quote), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | 1816 | addChildFlags_Widget(values, iClob(quote), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); |
1812 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.biglede}"))); | 1817 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.biglede}"))); |
1813 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.biglede"))); | 1818 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.biglede"))); |
1819 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.plaintext.wrap}"))); | ||
1820 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.plaintext.wrap"))); | ||
1821 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.collapsepreonload}"))); | ||
1822 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.collapsepreonload"))); | ||
1814 | // makeTwoColumnHeading_("${heading.prefs.widelayout}", headings, values); | 1823 | // makeTwoColumnHeading_("${heading.prefs.widelayout}", headings, values); |
1815 | addChild_Widget(headings, iClob(makePadding_Widget(bigGap))); | 1824 | addChild_Widget(headings, iClob(makePadding_Widget(bigGap))); |
1816 | addChild_Widget(values, iClob(makePadding_Widget(bigGap))); | 1825 | addChild_Widget(values, iClob(makePadding_Widget(bigGap))); |
1817 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.sideicon}"))); | 1826 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.sideicon}"))); |
1818 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.sideicon"))); | 1827 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.sideicon"))); |
1828 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.centershort}"))); | ||
1829 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.centershort"))); | ||
1819 | } | 1830 | } |
1820 | /* Network. */ { | 1831 | /* Network. */ { |
1821 | appendTwoColumnPage_(tabs, "${heading.prefs.network}", '5', &headings, &values); | 1832 | appendTwoColumnPage_(tabs, "${heading.prefs.network}", '6', &headings, &values); |
1822 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.decodeurls}"))); | 1833 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.decodeurls}"))); |
1823 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls"))); | 1834 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls"))); |
1824 | /* Cache size. */ { | 1835 | /* Cache size. */ { |
@@ -1832,6 +1843,17 @@ iWidget *makePreferences_Widget(void) { | |||
1832 | resizeToParentHeight_WidgetFlag); | 1843 | resizeToParentHeight_WidgetFlag); |
1833 | setContentPadding_InputWidget(cache, 0, width_Widget(unit) - 4 * gap_UI); | 1844 | setContentPadding_InputWidget(cache, 0, width_Widget(unit) - 4 * gap_UI); |
1834 | } | 1845 | } |
1846 | /* Memory size. */ { | ||
1847 | iInputWidget *mem = new_InputWidget(4); | ||
1848 | setSelectAllOnFocus_InputWidget(mem, iTrue); | ||
1849 | addPrefsInputWithHeading_(headings, values, "prefs.memorysize", iClob(mem)); | ||
1850 | iWidget *unit = | ||
1851 | addChildFlags_Widget(as_Widget(mem), | ||
1852 | iClob(new_LabelWidget("${mb}", NULL)), | ||
1853 | frameless_WidgetFlag | moveToParentRightEdge_WidgetFlag | | ||
1854 | resizeToParentHeight_WidgetFlag); | ||
1855 | setContentPadding_InputWidget(mem, 0, width_Widget(unit) - 4 * gap_UI); | ||
1856 | } | ||
1835 | makeTwoColumnHeading_("${heading.prefs.certs}", headings, values); | 1857 | makeTwoColumnHeading_("${heading.prefs.certs}", headings, values); |
1836 | addPrefsInputWithHeading_(headings, values, "prefs.ca.file", iClob(new_InputWidget(0))); | 1858 | addPrefsInputWithHeading_(headings, values, "prefs.ca.file", iClob(new_InputWidget(0))); |
1837 | addPrefsInputWithHeading_(headings, values, "prefs.ca.path", iClob(new_InputWidget(0))); | 1859 | addPrefsInputWithHeading_(headings, values, "prefs.ca.path", iClob(new_InputWidget(0))); |
@@ -1843,7 +1865,7 @@ iWidget *makePreferences_Widget(void) { | |||
1843 | /* Keybindings. */ | 1865 | /* Keybindings. */ |
1844 | if (deviceType_App() == desktop_AppDeviceType) { | 1866 | if (deviceType_App() == desktop_AppDeviceType) { |
1845 | iBindingsWidget *bind = new_BindingsWidget(); | 1867 | iBindingsWidget *bind = new_BindingsWidget(); |
1846 | appendFramelessTabPage_(tabs, iClob(bind), "${heading.prefs.keys}", '6', KMOD_PRIMARY); | 1868 | appendFramelessTabPage_(tabs, iClob(bind), "${heading.prefs.keys}", '7', KMOD_PRIMARY); |
1847 | } | 1869 | } |
1848 | addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI))); | 1870 | addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI))); |
1849 | updatePreferencesLayout_Widget(dlg); | 1871 | updatePreferencesLayout_Widget(dlg); |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 543b8bc9..992f115d 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -82,10 +82,10 @@ static void visualOffsetAnimation_Widget_(void *ptr) { | |||
82 | 82 | ||
83 | void deinit_Widget(iWidget *d) { | 83 | void deinit_Widget(iWidget *d) { |
84 | releaseChildren_Widget(d); | 84 | releaseChildren_Widget(d); |
85 | //#if !defined (NDEBUG) | 85 | #if 0 && !defined (NDEBUG) |
86 | // printf("widget %p (%s) deleted (on top:%d)\n", d, cstr_String(&d->id), | 86 | printf("widget %p (%s) deleted (on top:%d)\n", d, cstr_String(&d->id), |
87 | // d->flags & keepOnTop_WidgetFlag ? 1 : 0); | 87 | d->flags & keepOnTop_WidgetFlag ? 1 : 0); |
88 | //#endif | 88 | #endif |
89 | deinit_String(&d->id); | 89 | deinit_String(&d->id); |
90 | if (d->flags & keepOnTop_WidgetFlag) { | 90 | if (d->flags & keepOnTop_WidgetFlag) { |
91 | removeAll_PtrArray(onTop_Root(d->root), d); | 91 | removeAll_PtrArray(onTop_Root(d->root), d); |
@@ -321,7 +321,6 @@ static iBool setWidth_Widget_(iWidget *d, int width) { | |||
321 | d->rect.size.x = width; | 321 | d->rect.size.x = width; |
322 | TRACE(d, "width has changed to %d", width); | 322 | TRACE(d, "width has changed to %d", width); |
323 | if (class_Widget(d)->sizeChanged) { | 323 | if (class_Widget(d)->sizeChanged) { |
324 | const int oldHeight = d->rect.size.y; | ||
325 | class_Widget(d)->sizeChanged(d); | 324 | class_Widget(d)->sizeChanged(d); |
326 | } | 325 | } |
327 | return iTrue; | 326 | return iTrue; |
@@ -407,6 +406,11 @@ static void boundsOfChildren_Widget_(const iWidget *d, iRect *bounds_out) { | |||
407 | iRect childRect = child->rect; | 406 | iRect childRect = child->rect; |
408 | if (child->flags & ignoreForParentWidth_WidgetFlag) { | 407 | if (child->flags & ignoreForParentWidth_WidgetFlag) { |
409 | childRect.size.x = 0; | 408 | childRect.size.x = 0; |
409 | childRect.pos.x = bounds_out->pos.x; | ||
410 | } | ||
411 | if (child->flags & ignoreForParentHeight_WidgetFlag) { | ||
412 | childRect.size.y = 0; | ||
413 | childRect.pos.y = bounds_out->pos.y; | ||
410 | } | 414 | } |
411 | if (isEmpty_Rect(*bounds_out)) { | 415 | if (isEmpty_Rect(*bounds_out)) { |
412 | *bounds_out = childRect; | 416 | *bounds_out = childRect; |
@@ -760,6 +764,27 @@ void arrange_Widget(iWidget *d) { | |||
760 | } | 764 | } |
761 | } | 765 | } |
762 | 766 | ||
767 | iBool isBeingVisuallyOffsetByReference_Widget(const iWidget *d) { | ||
768 | return visualOffsetByReference_Widget(d) != 0; | ||
769 | } | ||
770 | |||
771 | int visualOffsetByReference_Widget(const iWidget *d) { | ||
772 | if (d->offsetRef && d->flags & refChildrenOffset_WidgetFlag) { | ||
773 | int offX = 0; | ||
774 | iConstForEach(ObjectList, i, children_Widget(d->offsetRef)) { | ||
775 | const iWidget *child = i.object; | ||
776 | if (child == d) continue; | ||
777 | if (child->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { | ||
778 | // const float factor = width_Widget(d) / (float) size_Root(d->root).x; | ||
779 | const int invOff = width_Widget(d) - iRound(value_Anim(&child->visualOffset)); | ||
780 | offX -= invOff / 4; | ||
781 | } | ||
782 | } | ||
783 | return offX; | ||
784 | } | ||
785 | return 0; | ||
786 | } | ||
787 | |||
763 | static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { | 788 | static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { |
764 | if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { | 789 | if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { |
765 | const int off = iRound(value_Anim(&d->visualOffset)); | 790 | const int off = iRound(value_Anim(&d->visualOffset)); |
@@ -774,14 +799,7 @@ static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { | |||
774 | pos->y -= value_Anim(d->animOffsetRef); | 799 | pos->y -= value_Anim(d->animOffsetRef); |
775 | } | 800 | } |
776 | if (d->flags & refChildrenOffset_WidgetFlag) { | 801 | if (d->flags & refChildrenOffset_WidgetFlag) { |
777 | iConstForEach(ObjectList, i, children_Widget(d->offsetRef)) { | 802 | pos->x += visualOffsetByReference_Widget(d); |
778 | const iWidget *child = i.object; | ||
779 | if (child == d) continue; | ||
780 | if (child->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { | ||
781 | const int invOff = size_Root(d->root).x - iRound(value_Anim(&child->visualOffset)); | ||
782 | pos->x -= invOff / 4; | ||
783 | } | ||
784 | } | ||
785 | } | 803 | } |
786 | } | 804 | } |
787 | 805 | ||
@@ -1057,10 +1075,38 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
1057 | isCommand_UserEvent(ev, "widget.overflow")) { | 1075 | isCommand_UserEvent(ev, "widget.overflow")) { |
1058 | scrollOverflow_Widget(d, 0); /* check bounds */ | 1076 | scrollOverflow_Widget(d, 0); /* check bounds */ |
1059 | } | 1077 | } |
1060 | if (ev->user.code == command_UserEventCode && d->commandHandler && | 1078 | if (ev->user.code == command_UserEventCode) { |
1061 | d->commandHandler(d, ev->user.data1)) { | 1079 | const char *cmd = command_UserEvent(ev); |
1062 | iAssert(get_Root() == d->root); | 1080 | if (d->flags & (leftEdgeDraggable_WidgetFlag | rightEdgeDraggable_WidgetFlag) && |
1063 | return iTrue; | 1081 | isVisible_Widget(d) && ~d->flags & disabled_WidgetFlag && |
1082 | equal_Command(cmd, "edgeswipe.moved")) { | ||
1083 | /* Check the side. */ | ||
1084 | const int side = argLabel_Command(cmd, "side"); | ||
1085 | if ((side == 1 && d->flags & leftEdgeDraggable_WidgetFlag) || | ||
1086 | (side == 2 && d->flags & rightEdgeDraggable_WidgetFlag)) { | ||
1087 | if (~d->flags & dragged_WidgetFlag) { | ||
1088 | setFlags_Widget(d, dragged_WidgetFlag, iTrue); | ||
1089 | } | ||
1090 | setVisualOffset_Widget(d, arg_Command(command_UserEvent(ev)) * | ||
1091 | width_Widget(d) / size_Root(d->root).x, | ||
1092 | 10, 0); | ||
1093 | return iTrue; | ||
1094 | } | ||
1095 | } | ||
1096 | if (d->flags & dragged_WidgetFlag && equal_Command(cmd, "edgeswipe.ended")) { | ||
1097 | if (argLabel_Command(cmd, "abort")) { | ||
1098 | setVisualOffset_Widget(d, 0, 200, easeOut_AnimFlag); | ||
1099 | } | ||
1100 | else { | ||
1101 | postCommand_Widget( | ||
1102 | d, argLabel_Command(cmd, "side") == 1 ? "swipe.back" : "swipe.forward"); | ||
1103 | } | ||
1104 | setFlags_Widget(d, dragged_WidgetFlag, iFalse); | ||
1105 | } | ||
1106 | if (d->commandHandler && d->commandHandler(d, ev->user.data1)) { | ||
1107 | iAssert(get_Root() == d->root); | ||
1108 | return iTrue; | ||
1109 | } | ||
1064 | } | 1110 | } |
1065 | break; | 1111 | break; |
1066 | } | 1112 | } |
@@ -1091,6 +1137,17 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
1091 | return iFalse; | 1137 | return iFalse; |
1092 | } | 1138 | } |
1093 | 1139 | ||
1140 | int backgroundFadeColor_Widget(void) { | ||
1141 | switch (colorTheme_App()) { | ||
1142 | case light_ColorTheme: | ||
1143 | return gray25_ColorId; | ||
1144 | case pureWhite_ColorTheme: | ||
1145 | return gray50_ColorId; | ||
1146 | default: | ||
1147 | return black_ColorId; | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1094 | void drawBackground_Widget(const iWidget *d) { | 1151 | void drawBackground_Widget(const iWidget *d) { |
1095 | if (d->flags & noBackground_WidgetFlag) { | 1152 | if (d->flags & noBackground_WidgetFlag) { |
1096 | return; | 1153 | return; |
@@ -1107,14 +1164,13 @@ void drawBackground_Widget(const iWidget *d) { | |||
1107 | shadowBorder = iFalse; | 1164 | shadowBorder = iFalse; |
1108 | } | 1165 | } |
1109 | } | 1166 | } |
1110 | if (shadowBorder) { | 1167 | if (shadowBorder && ~d->flags & noShadowBorder_WidgetFlag) { |
1111 | iPaint p; | 1168 | iPaint p; |
1112 | init_Paint(&p); | 1169 | init_Paint(&p); |
1113 | drawSoftShadow_Paint(&p, bounds_Widget(d), 12 * gap_UI, black_ColorId, 30); | 1170 | drawSoftShadow_Paint(&p, bounds_Widget(d), 12 * gap_UI, black_ColorId, 30); |
1114 | } | 1171 | } |
1115 | const iBool isFaded = fadeBackground && | 1172 | const iBool isFaded = fadeBackground && |
1116 | ~d->flags & noFadeBackground_WidgetFlag;/* && | 1173 | ~d->flags & noFadeBackground_WidgetFlag; |
1117 | ~d->flags & destroyPending_WidgetFlag;*/ | ||
1118 | if (isFaded) { | 1174 | if (isFaded) { |
1119 | iPaint p; | 1175 | iPaint p; |
1120 | init_Paint(&p); | 1176 | init_Paint(&p); |
@@ -1125,19 +1181,7 @@ void drawBackground_Widget(const iWidget *d) { | |||
1125 | p.alpha *= (area > 0 ? visibleArea / area : 0.0f); | 1181 | p.alpha *= (area > 0 ? visibleArea / area : 0.0f); |
1126 | } | 1182 | } |
1127 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); | 1183 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); |
1128 | int fadeColor; | 1184 | fillRect_Paint(&p, rect_Root(d->root), backgroundFadeColor_Widget()); |
1129 | switch (colorTheme_App()) { | ||
1130 | default: | ||
1131 | fadeColor = black_ColorId; | ||
1132 | break; | ||
1133 | case light_ColorTheme: | ||
1134 | fadeColor = gray25_ColorId; | ||
1135 | break; | ||
1136 | case pureWhite_ColorTheme: | ||
1137 | fadeColor = gray50_ColorId; | ||
1138 | break; | ||
1139 | } | ||
1140 | fillRect_Paint(&p, rect_Root(d->root), fadeColor); | ||
1141 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); | 1185 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); |
1142 | } | 1186 | } |
1143 | if (d->bgColor >= 0 || d->frameColor >= 0) { | 1187 | if (d->bgColor >= 0 || d->frameColor >= 0) { |
diff --git a/src/ui/widget.h b/src/ui/widget.h index 8de62b7a..41784b99 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h | |||
@@ -87,12 +87,12 @@ enum iWidgetFlag { | |||
87 | }; | 87 | }; |
88 | 88 | ||
89 | /* 64-bit extended flags */ | 89 | /* 64-bit extended flags */ |
90 | //#define wasCollapsed_WidgetFlag iBit64(32) | 90 | #define rightEdgeDraggable_WidgetFlag iBit64(31) |
91 | #define disabledWhenHidden_WidgetFlag iBit64(32) | 91 | #define disabledWhenHidden_WidgetFlag iBit64(32) |
92 | #define centerHorizontal_WidgetFlag iBit64(33) | 92 | #define centerHorizontal_WidgetFlag iBit64(33) |
93 | #define moveToParentLeftEdge_WidgetFlag iBit64(34) | 93 | #define moveToParentLeftEdge_WidgetFlag iBit64(34) |
94 | #define moveToParentRightEdge_WidgetFlag iBit64(35) | 94 | #define moveToParentRightEdge_WidgetFlag iBit64(35) |
95 | #define wrapText_WidgetFlag iBit64(36) | 95 | #define noShadowBorder_WidgetFlag iBit64(36) |
96 | #define borderTop_WidgetFlag iBit64(37) | 96 | #define borderTop_WidgetFlag iBit64(37) |
97 | #define overflowScrollable_WidgetFlag iBit64(38) | 97 | #define overflowScrollable_WidgetFlag iBit64(38) |
98 | #define focusRoot_WidgetFlag iBit64(39) | 98 | #define focusRoot_WidgetFlag iBit64(39) |
@@ -103,7 +103,7 @@ enum iWidgetFlag { | |||
103 | #define drawBackgroundToVerticalSafeArea_WidgetFlag iBit64(44) | 103 | #define drawBackgroundToVerticalSafeArea_WidgetFlag iBit64(44) |
104 | #define visualOffset_WidgetFlag iBit64(45) | 104 | #define visualOffset_WidgetFlag iBit64(45) |
105 | #define parentCannotResize_WidgetFlag iBit64(46) | 105 | #define parentCannotResize_WidgetFlag iBit64(46) |
106 | #define noTopFrame_WidgetFlag iBit64(47) | 106 | #define ignoreForParentHeight_WidgetFlag iBit64(47) |
107 | #define unpadded_WidgetFlag iBit64(48) /* ignore parent's padding */ | 107 | #define unpadded_WidgetFlag iBit64(48) /* ignore parent's padding */ |
108 | #define extraPadding_WidgetFlag iBit64(49) | 108 | #define extraPadding_WidgetFlag iBit64(49) |
109 | #define borderBottom_WidgetFlag iBit64(50) | 109 | #define borderBottom_WidgetFlag iBit64(50) |
@@ -117,8 +117,8 @@ enum iWidgetFlag { | |||
117 | #define parentCannotResizeHeight_WidgetFlag iBit64(58) | 117 | #define parentCannotResizeHeight_WidgetFlag iBit64(58) |
118 | #define ignoreForParentWidth_WidgetFlag iBit64(59) | 118 | #define ignoreForParentWidth_WidgetFlag iBit64(59) |
119 | #define noFadeBackground_WidgetFlag iBit64(60) | 119 | #define noFadeBackground_WidgetFlag iBit64(60) |
120 | #define destroyPending_WidgetFlag iBit64(61) /* TODO: needed? */ | 120 | #define destroyPending_WidgetFlag iBit64(61) |
121 | #define edgeDraggable_WidgetFlag iBit64(62) | 121 | #define leftEdgeDraggable_WidgetFlag iBit64(62) |
122 | #define refChildrenOffset_WidgetFlag iBit64(63) /* visual offset determined by the offset of referenced children */ | 122 | #define refChildrenOffset_WidgetFlag iBit64(63) /* visual offset determined by the offset of referenced children */ |
123 | 123 | ||
124 | enum iWidgetAddPos { | 124 | enum iWidgetAddPos { |
@@ -242,8 +242,9 @@ iBool isSelected_Widget (const iAnyObject *); | |||
242 | iBool isUnderKeyRoot_Widget (const iAnyObject *); | 242 | iBool isUnderKeyRoot_Widget (const iAnyObject *); |
243 | iBool isCommand_Widget (const iWidget *d, const SDL_Event *ev, const char *cmd); | 243 | iBool isCommand_Widget (const iWidget *d, const SDL_Event *ev, const char *cmd); |
244 | iBool hasParent_Widget (const iWidget *d, const iWidget *someParent); | 244 | iBool hasParent_Widget (const iWidget *d, const iWidget *someParent); |
245 | iBool isAffectedByVisualOffset_Widget | 245 | iBool isAffectedByVisualOffset_Widget (const iWidget *); |
246 | (const iWidget *); | 246 | iBool isBeingVisuallyOffsetByReference_Widget (const iWidget *); |
247 | int visualOffsetByReference_Widget (const iWidget *); | ||
247 | void setId_Widget (iWidget *, const char *id); | 248 | void setId_Widget (iWidget *, const char *id); |
248 | void setFlags_Widget (iWidget *, int64_t flags, iBool set); | 249 | void setFlags_Widget (iWidget *, int64_t flags, iBool set); |
249 | void setPos_Widget (iWidget *, iInt2 pos); | 250 | void setPos_Widget (iWidget *, iInt2 pos); |
@@ -276,6 +277,8 @@ void refresh_Widget (const iAnyObject *); | |||
276 | 277 | ||
277 | iBool equalWidget_Command (const char *cmd, const iWidget *widget, const char *checkCommand); | 278 | iBool equalWidget_Command (const char *cmd, const iWidget *widget, const char *checkCommand); |
278 | 279 | ||
280 | int backgroundFadeColor_Widget (void); | ||
281 | |||
279 | void setFocus_Widget (iWidget *); | 282 | void setFocus_Widget (iWidget *); |
280 | iWidget * focus_Widget (void); | 283 | iWidget * focus_Widget (void); |
281 | void setHover_Widget (iWidget *); | 284 | void setHover_Widget (iWidget *); |
diff --git a/src/ui/window.c b/src/ui/window.c index 96a22fee..f71d8102 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -69,10 +69,6 @@ iDefineTypeConstructionArgs(Window, (iRect rect), rect) | |||
69 | 69 | ||
70 | /* TODO: Define menus per platform. */ | 70 | /* TODO: Define menus per platform. */ |
71 | 71 | ||
72 | #if defined (iPlatformAppleDesktop) | ||
73 | # define iHaveNativeMenus | ||
74 | #endif | ||
75 | |||
76 | #if defined (iHaveNativeMenus) | 72 | #if defined (iHaveNativeMenus) |
77 | /* Using native menus. */ | 73 | /* Using native menus. */ |
78 | static const iMenuItem fileMenuItems_[] = { | 74 | static const iMenuItem fileMenuItems_[] = { |
@@ -202,7 +198,7 @@ static void windowSizeChanged_Window_(iWindow *d) { | |||
202 | } | 198 | } |
203 | 199 | ||
204 | static void setupUserInterface_Window(iWindow *d) { | 200 | static void setupUserInterface_Window(iWindow *d) { |
205 | #if defined (iPlatformAppleDesktop) | 201 | #if defined (iHaveNativeMenus) |
206 | insertMacMenus_(); | 202 | insertMacMenus_(); |
207 | #endif | 203 | #endif |
208 | /* One root is created by default. */ | 204 | /* One root is created by default. */ |
@@ -913,7 +909,7 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { | |||
913 | } | 909 | } |
914 | } | 910 | } |
915 | if (isCommand_UserEvent(&event, "lang.changed")) { | 911 | if (isCommand_UserEvent(&event, "lang.changed")) { |
916 | #if defined (iPlatformAppleDesktop) | 912 | #if defined (iHaveNativeMenus) |
917 | /* Retranslate the menus. */ | 913 | /* Retranslate the menus. */ |
918 | removeMacMenus_(); | 914 | removeMacMenus_(); |
919 | insertMacMenus_(); | 915 | insertMacMenus_(); |