summaryrefslogtreecommitdiff
path: root/src/ui/mobile.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/mobile.c')
-rw-r--r--src/ui/mobile.c427
1 files changed, 20 insertions, 407 deletions
diff --git a/src/ui/mobile.c b/src/ui/mobile.c
index af17b78c..f0c471de 100644
--- a/src/ui/mobile.c
+++ b/src/ui/mobile.c
@@ -815,413 +815,26 @@ void initPanels_Mobile(iWidget *panels, iWidget *parentWidget,
815// printTree_Widget(panels); 815// printTree_Widget(panels);
816} 816}
817 817
818#if 0 818/*
819 /* The sheet contents are completely rearranged and restyled on a phone. 819 Landscape Layout Portrait Layout
820 We'll set up a linear fullscreen arrangement of the widgets. Sheets are already 820
821 scrollable so they can be taller than the display. In hindsight, it may have been 821┌─────────┬──────Detail─Stack─────┐ ┌─────────┬ ─ ─ ─ ─ ┐
822 easier to create phone versions of each dialog, but at least this works with any 822│ │┌───────────────────┐ │ │ │Detail
823 future changes to the UI (..."works"). At least this way it is possible to enforce 823│ ││┌──────────────────┴┐ │ │ │Stack │
824 a consistent styling. */ 824│ │││┌──────────────────┴┐│ │ │┌──────┐
825 if (useMobileSheetLayout_() && parent_Widget(sheet) == root_Widget(sheet)) { 825│ ││││ ││ │ ││┌─────┴┐│
826 if (~flags_Widget(sheet) & keepOnTop_WidgetFlag) { 826│ ││││ ││ │ │││ │
827 /* Already finalized. */ 827│Top Panel││││ ││ │Top Panel│││ ││
828 arrange_Widget(sheet); 828│ ││││ Panels ││ │ │││Panels│
829 postRefresh_App(); 829│ ││││ ││ │ │││ ││
830 return; 830│ │└┤│ ││ │ │││ │
831 } 831│ │ └┤ ││ │ │└┤ ││
832 /* TODO: In portrait, top panel and detail stack are all stacked together. 832│ │ └───────────────────┘│ │ │ └──────┘
833 833└─────────┴───────────────────────┘ └─────────┴ ─ ─ ─ ─ ┘
834 Landscape Layout Portrait Layout 834 underneath
835 835
836 ┌─────────┬──────Detail─Stack─────┐ ┌─────────┬ ─ ─ ─ ─ ┐ 836In portrait, top panel and detail stack are all stacked together.
837 │ │┌───────────────────┐ │ │ │Detail 837*/
838 │ ││┌──────────────────┴┐ │ │ │Stack │
839 │ │││┌──────────────────┴┐│ │ │┌──────┐
840 │ ││││ ││ │ ││┌─────┴┐│
841 │ ││││ ││ │ │││ │
842 │Top Panel││││ ││ │Top Panel│││ ││
843 │ ││││ Panels ││ │ │││Panels│
844 │ ││││ ││ │ │││ ││
845 │ │└┤│ ││ │ │││ │
846 │ │ └┤ ││ │ │└┤ ││
847 │ │ └───────────────────┘│ │ │ └──────┘
848 └─────────┴───────────────────────┘ └─────────┴ ─ ─ ─ ─ ┘
849 underneath
850 */
851 /* Modify the top sheet to act as a fullscreen background. */
852 setPadding1_Widget(sheet, 0);
853 setBackgroundColor_Widget(sheet, uiBackground_ColorId);
854 setFlags_Widget(sheet,
855 keepOnTop_WidgetFlag |
856 parentCannotResize_WidgetFlag |
857 arrangeSize_WidgetFlag |
858 centerHorizontal_WidgetFlag |
859 arrangeVertical_WidgetFlag |
860 arrangeHorizontal_WidgetFlag |
861 overflowScrollable_WidgetFlag,
862 iFalse);
863 setFlags_Widget(sheet,
864 frameless_WidgetFlag |
865 //resizeWidthOfChildren_WidgetFlag |
866 leftEdgeDraggable_WidgetFlag |
867 commandOnClick_WidgetFlag,
868 iTrue);
869 iPtrArray * contents = collect_PtrArray(new_PtrArray()); /* two-column pages */
870 iPtrArray * panelButtons = collect_PtrArray(new_PtrArray());
871 iWidget * prefsTabs = findChild_Widget(sheet, "prefs.tabs");
872 iWidget * dialogHeading = (prefsTabs ? NULL : child_Widget(sheet, 0));
873 const iBool isPrefs = (prefsTabs != NULL);
874 const int64_t panelButtonFlags = borderBottom_WidgetFlag | alignLeft_WidgetFlag |
875 frameless_WidgetFlag | extraPadding_WidgetFlag;
876 iWidget *mainDetailSplit = makeHDiv_Widget();
877 setCommandHandler_Widget(mainDetailSplit, mainDetailSplitHandler_);
878 setFlags_Widget(mainDetailSplit, resizeHeightOfChildren_WidgetFlag, iFalse);
879 setId_Widget(mainDetailSplit, "mdsplit");
880 iWidget *topPanel = new_Widget(); {
881 setId_Widget(topPanel, "panel.top");
882 setCommandHandler_Widget(topPanel, topPanelHandler_);
883 setFlags_Widget(topPanel,
884 arrangeVertical_WidgetFlag |
885 resizeWidthOfChildren_WidgetFlag |
886 arrangeHeight_WidgetFlag |
887 overflowScrollable_WidgetFlag |
888 commandOnClick_WidgetFlag,
889 iTrue);
890 addChild_Widget(mainDetailSplit, iClob(topPanel));
891 }
892 iWidget *detailStack = new_Widget(); {
893 setId_Widget(detailStack, "detailstack");
894 setFlags_Widget(detailStack, collapse_WidgetFlag | resizeWidthOfChildren_WidgetFlag, iTrue);
895 addChild_Widget(mainDetailSplit, iClob(detailStack));
896 }
897 addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));
898 /* Slide top panel with detail panels. */ {
899 setFlags_Widget(topPanel, refChildrenOffset_WidgetFlag, iTrue);
900 topPanel->offsetRef = detailStack;
901 }
902 if (prefsTabs) {
903 iRelease(removeChild_Widget(sheet, child_Widget(sheet, 0))); /* heading */
904 iRelease(removeChild_Widget(sheet, findChild_Widget(sheet, "dialogbuttons")));
905 /* Pull out the pages and make them panels. */
906 iWidget *pages = findChild_Widget(prefsTabs, "tabs.pages");
907 size_t pageCount = tabCount_Widget(prefsTabs);
908 for (size_t i = 0; i < pageCount; i++) {
909 iString *text = copy_String(text_LabelWidget(tabPageButton_Widget(prefsTabs, tabPage_Widget(prefsTabs, 0))));
910 iWidget *page = removeTabPage_Widget(prefsTabs, 0);
911 iWidget *pageContent = child_Widget(page, 1); /* surrounded by padding widgets */
912 pushBack_PtrArray(contents, ref_Object(pageContent));
913 iLabelWidget *panelButton;
914 pushBack_PtrArray(panelButtons,
915 addChildFlags_Widget(topPanel,
916 iClob(panelButton = makePanelButton_(
917 i == 1 ? "${heading.prefs.userinterface}" : cstr_String(text),
918 "panel.open")),
919 (i == 0 ? borderTop_WidgetFlag : 0) |
920 chevron_WidgetFlag));
921 const iChar icons[] = {
922 0x02699, /* gear */
923 0x1f4f1, /* mobile phone */
924 0x1f3a8, /* palette */
925 0x1f5da, /* aA */
926 0x1f660, /* pointing bud */
927 0x1f5a7, /* computer network */
928 };
929 setIcon_LabelWidget(panelButton, icons[i]);
930// setFont_LabelWidget(panelButton, labelFont_());
931// setBackgroundColor_Widget(as_Widget(panelButton), uiBackgroundSidebar_ColorId);
932 iRelease(page);
933 delete_String(text);
934 }
935 destroy_Widget(prefsTabs);
936 }
937 iForEach(ObjectList, i, children_Widget(sheet)) {
938 iWidget *child = i.object;
939 if (isTwoColumnPage_(child)) {
940 pushBack_PtrArray(contents, removeChild_Widget(sheet, child));
941 }
942 else {
943 removeChild_Widget(sheet, child);
944 addChild_Widget(topPanel, child);
945 iRelease(child);
946 }
947 }
948 const iBool useSlidePanels = (size_PtrArray(contents) == size_PtrArray(panelButtons));
949 addChild_Widget(sheet, iClob(mainDetailSplit));
950 iForEach(PtrArray, j, contents) {
951 iWidget *owner = topPanel;
952 if (useSlidePanels) {
953 /* Create a new child panel. */
954 iLabelWidget *button = at_PtrArray(panelButtons, index_PtrArrayIterator(&j));
955 owner = addChildPanel_(detailStack, button,
956 collect_String(upper_String(text_LabelWidget(button))));
957 }
958 iWidget *pageContent = j.ptr;
959 iWidget *headings = child_Widget(pageContent, 0);
960 iWidget *values = child_Widget(pageContent, 1);
961 enum iPrefsElement prevElement = panelTitle_PrefsElement;
962 /* Identify the types of controls in the dialog and restyle/organize them. */
963 while (!isEmpty_ObjectList(children_Widget(headings))) {
964 iWidget *heading = child_Widget(headings, 0);
965 iWidget *value = child_Widget(values, 0);
966 removeChild_Widget(headings, heading);
967 removeChild_Widget(values, value);
968 /* Can we ignore these widgets? */
969 if (isOmittedPref_(id_Widget(value)) ||
970 (class_Widget(heading) == &Class_Widget &&
971 class_Widget(value) == &Class_Widget) /* just padding */) {
972 iRelease(heading);
973 iRelease(value);
974 continue;
975 }
976 enum iPrefsElement element = toggle_PrefsElement;
977 iLabelWidget *headingLabel = NULL;
978 iLabelWidget *valueLabel = NULL;
979 iInputWidget *valueInput = NULL;
980 const iBool isMenuButton = findChild_Widget(value, "menu") != NULL;
981 if (isInstance_Object(heading, &Class_LabelWidget)) {
982 headingLabel = (iLabelWidget *) heading;
983 stripTrailingColon_(headingLabel);
984 }
985 if (isInstance_Object(value, &Class_LabelWidget)) {
986 valueLabel = (iLabelWidget *) value;
987 setFont_LabelWidget(valueLabel, labelFont_());
988 }
989 if (isInstance_Object(value, &Class_InputWidget)) {
990 valueInput = (iInputWidget *) value;
991 setFlags_Widget(value, borderBottom_WidgetFlag, iFalse);
992 element = textInput_PrefsElement;
993 }
994 if (childCount_Widget(value) >= 2) {
995 if (isInstance_Object(child_Widget(value, 0), &Class_InputWidget)) {
996 element = textInput_PrefsElement;
997 setPadding_Widget(value, 0, 0, gap_UI, 0);
998 valueInput = child_Widget(value, 0);
999 }
1000 }
1001 if (valueInput) {
1002 setFont_InputWidget(valueInput, labelFont_());
1003 setContentPadding_InputWidget(valueInput, 3 * gap_UI, 0);
1004 }
1005 /* Toggles have the button on the right. */
1006 if (valueLabel && cmp_String(command_LabelWidget(valueLabel), "toggle") == 0) {
1007 element = toggle_PrefsElement;
1008 addPanelChild_(owner,
1009 iClob(makeValuePaddingWithHeading_(headingLabel, value)),
1010 0,
1011 element,
1012 prevElement);
1013 }
1014 else if (valueLabel && isEmpty_String(text_LabelWidget(valueLabel))) {
1015 element = heading_PrefsElement;
1016 iRelease(value);
1017 addPanelChild_(owner, iClob(heading), 0, element, prevElement);
1018 setFont_LabelWidget(headingLabel, uiLabel_FontId);
1019 }
1020 else if (isMenuButton) {
1021 element = dropdown_PrefsElement;
1022 setFlags_Widget(value,
1023 alignRight_WidgetFlag | noBackground_WidgetFlag |
1024 frameless_WidgetFlag, iTrue);
1025 setFlags_Widget(value, alignLeft_WidgetFlag, iFalse);
1026 iWidget *pad = addPanelChild_(owner, iClob(makeValuePaddingWithHeading_(headingLabel, value)), 0,
1027 element, prevElement);
1028 pad->padding[2] = gap_UI;
1029 }
1030 else if (valueInput) {
1031 addPanelChild_(owner, iClob(makeValuePaddingWithHeading_(headingLabel, value)), 0,
1032 element, prevElement);
1033 }
1034 else {
1035 if (childCount_Widget(value) >= 2) {
1036 element = radioButton_PrefsElement;
1037 /* Always padding before radio buttons. */
1038 addChild_Widget(owner, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));
1039 }
1040 addChildFlags_Widget(owner, iClob(heading), borderBottom_WidgetFlag);
1041 if (headingLabel) {
1042 setTextColor_LabelWidget(headingLabel, uiSubheading_ColorId);
1043 setText_LabelWidget(headingLabel,
1044 collect_String(upper_String(text_LabelWidget(headingLabel))));
1045 }
1046 addPanelChild_(owner, iClob(value), 0, element, prevElement);
1047 /* Radio buttons expand to fill the space. */
1048 if (element == radioButton_PrefsElement) {
1049 setBackgroundColor_Widget(value, uiBackgroundSidebar_ColorId);
1050 setPadding_Widget(value, 4 * gap_UI, 2 * gap_UI, 4 * gap_UI, 2 * gap_UI);
1051 setFlags_Widget(value, arrangeWidth_WidgetFlag, iFalse);
1052 setFlags_Widget(value,
1053 borderBottom_WidgetFlag |
1054 resizeToParentWidth_WidgetFlag |
1055 resizeWidthOfChildren_WidgetFlag,
1056 iTrue);
1057 iForEach(ObjectList, sub, children_Widget(value)) {
1058 if (isInstance_Object(sub.object, &Class_LabelWidget)) {
1059 iLabelWidget *opt = sub.object;
1060 setFont_LabelWidget(opt, uiLabelMedium_FontId);
1061 setFlags_Widget(as_Widget(opt), noBackground_WidgetFlag, iTrue);
1062 }
1063 }
1064 }
1065 }
1066 prevElement = element;
1067 }
1068 addPanelChild_(owner, NULL, 0, 0, prevElement);
1069 destroy_Widget(pageContent);
1070 }
1071 destroyPending_Root(sheet->root);
1072 /* Additional elements for preferences. */
1073 if (isPrefs) {
1074 addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));
1075 /* Management. */ {
1076 iLabelWidget *idManButton = addChildFlags_Widget(topPanel,
1077 iClob(makePanelButton_(person_Icon " ${sidebar.identities}", "panel.open")),
1078 chevron_WidgetFlag | borderTop_WidgetFlag);
1079 }
1080 addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));
1081 iLabelWidget *aboutButton = addChildFlags_Widget(topPanel,
1082 iClob(makePanelButton_(planet_Icon " ${menu.about}", "panel.open")),
1083 chevron_WidgetFlag | borderTop_WidgetFlag);
1084 addChildFlags_Widget(topPanel,
1085 iClob(makePanelButton_(info_Icon " ${menu.help}", "!open url:about:help")), 0);
1086 /* The About panel. */ {
1087 iWidget *panel = addChildPanel_(detailStack, aboutButton, NULL);
1088 iString *msg = collectNew_String();
1089 setCStr_String(msg, "Lagrange " LAGRANGE_APP_VERSION);
1090#if defined (iPlatformAppleMobile)
1091 appendCStr_String(msg, " (" LAGRANGE_IOS_VERSION ")");
1092#endif
1093 addChildFlags_Widget(panel, iClob(new_LabelWidget(cstr_String(msg), NULL)),
1094 frameless_WidgetFlag);
1095 addChildFlags_Widget(panel,
1096 iClob(makePanelButton_(globe_Icon " By @jk@skyjake.fi",
1097 "!open url:https://skyjake.fi/@jk")),
1098 borderTop_WidgetFlag);
1099 addChildFlags_Widget(panel,
1100 iClob(makePanelButton_(clock_Icon " ${menu.releasenotes}",
1101 "!open url:about:version")),
1102 0);
1103 addChildFlags_Widget(panel,
1104 iClob(makePanelButton_(info_Icon " ${menu.aboutpages}",
1105 "!open url:about:about")),
1106 0);
1107 addChildFlags_Widget(panel,
1108 iClob(makePanelButton_(bug_Icon " ${menu.debug}",
1109 "!open url:about:debug")),
1110 0);
1111 }
1112 }
1113 else {
1114 setFlags_Widget(topPanel, overflowScrollable_WidgetFlag, iTrue);
1115 /* Update heading style. */
1116 setFont_LabelWidget((iLabelWidget *) dialogHeading, uiLabelLargeBold_FontId);
1117 setFlags_Widget(dialogHeading, alignLeft_WidgetFlag, iTrue);
1118 }
1119 if (findChild_Widget(sheet, "valueinput.prompt")) {
1120 iWidget *prompt = findChild_Widget(sheet, "valueinput.prompt");
1121 setFlags_Widget(prompt, alignLeft_WidgetFlag, iTrue);
1122 iInputWidget *input = findChild_Widget(sheet, "input");
1123 removeChild_Widget(parent_Widget(input), input);
1124 addChild_Widget(topPanel, iClob(makeValuePadding_(as_Widget(input))));
1125 }
1126 /* Top padding for each panel, to account for the overlaid navbar. */ {
1127 setId_Widget(addChildPos_Widget(topPanel,
1128 iClob(makePadding_Widget(0)), front_WidgetAddPos),
1129 "panel.toppad");
1130 }
1131 /* Navbar. */ {
1132 iWidget *navi = new_Widget();
1133 setId_Widget(navi, "panel.navi");
1134 setBackgroundColor_Widget(navi, uiBackground_ColorId);
1135 addChild_Widget(navi, iClob(makePadding_Widget(0)));
1136 iLabelWidget *back = addChildFlags_Widget(navi,
1137 iClob(new_LabelWidget(leftAngle_Icon " ${panel.back}", "panel.close")),
1138 noBackground_WidgetFlag | frameless_WidgetFlag |
1139 alignLeft_WidgetFlag | extraPadding_WidgetFlag);
1140 checkIcon_LabelWidget(back);
1141 setId_Widget(as_Widget(back), "panel.back");
1142 setFont_LabelWidget(back, labelFont_());
1143 if (!isPrefs) {
1144 /* Pick up the dialog buttons for the navbar. */
1145 iWidget *buttons = findChild_Widget(sheet, "dialogbuttons");
1146 iLabelWidget *cancel = findMenuItem_Widget(buttons, "cancel");
1147// if (!cancel) {
1148// cancel = findMenuItem_Widget(buttons, "translation.cancel");
1149// }
1150 if (cancel) {
1151 updateText_LabelWidget(back, text_LabelWidget(cancel));
1152 setCommand_LabelWidget(back, command_LabelWidget(cancel));
1153 }
1154 iLabelWidget *def = (iLabelWidget *) lastChild_Widget(buttons);
1155 if (def && !cancel) {
1156 updateText_LabelWidget(back, text_LabelWidget(def));
1157 setCommand_LabelWidget(back, command_LabelWidget(def));
1158 setFlags_Widget(as_Widget(back), alignLeft_WidgetFlag, iFalse);
1159 setFlags_Widget(as_Widget(back), alignRight_WidgetFlag, iTrue);
1160 setIcon_LabelWidget(back, 0);
1161 setFont_LabelWidget(back, labelBoldFont_());
1162 }
1163 else if (def != cancel) {
1164 removeChild_Widget(buttons, def);
1165 setFont_LabelWidget(def, labelBoldFont_());
1166 setFlags_Widget(as_Widget(def),
1167 frameless_WidgetFlag | extraPadding_WidgetFlag |
1168 noBackground_WidgetFlag, iTrue);
1169 addChildFlags_Widget(as_Widget(back), iClob(def), moveToParentRightEdge_WidgetFlag);
1170 updateSize_LabelWidget(def);
1171 }
1172 /* Action buttons are added in the bottom as extra buttons. */ {
1173 iBool isFirstAction = iTrue;
1174 iForEach(ObjectList, i, children_Widget(buttons)) {
1175 if (isInstance_Object(i.object, &Class_LabelWidget) &&
1176 i.object != cancel && i.object != def) {
1177 iLabelWidget *item = i.object;
1178 setBackgroundColor_Widget(i.object, uiBackgroundSidebar_ColorId);
1179 setFont_LabelWidget(item, labelFont_());
1180 removeChild_Widget(buttons, item);
1181 addChildFlags_Widget(topPanel, iClob(item), panelButtonFlags |
1182 (isFirstAction ? borderTop_WidgetFlag : 0));
1183 updateSize_LabelWidget(item);
1184 isFirstAction = iFalse;
1185 }
1186 }
1187 }
1188 iRelease(removeChild_Widget(parent_Widget(buttons), buttons));
1189 /* Styling for remaining elements. */
1190 iForEach(ObjectList, i, children_Widget(topPanel)) {
1191 if (isInstance_Object(i.object, &Class_LabelWidget) &&
1192 isEmpty_String(command_LabelWidget(i.object)) &&
1193 isEmpty_String(id_Widget(i.object))) {
1194 setFlags_Widget(i.object, alignLeft_WidgetFlag, iTrue);
1195 if (font_LabelWidget(i.object) == uiLabel_FontId) {
1196 setFont_LabelWidget(i.object, uiContent_FontId);
1197 }
1198 }
1199 }
1200 }
1201 addChildFlags_Widget(sheet, iClob(navi),
1202 drawBackgroundToVerticalSafeArea_WidgetFlag |
1203 arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag |
1204 resizeToParentWidth_WidgetFlag | arrangeVertical_WidgetFlag);
1205 }
1206 if (isPrefs && isSideBySideLayout_()) {
1207 /* Show the General panel. */
1208 postCommand_Widget(at_PtrArray(panelButtons, 0), "panel.open");
1209 }
1210 mainDetailSplitHandler_(mainDetailSplit, "window.resized"); /* make it resize the split */
1211 updatePanelSheetMetrics_(sheet);
1212 iAssert(sheet->parent);
1213 arrange_Widget(sheet->parent);
1214 postCommand_App("widget.overflow"); /* with the correct dimensions */
1215 }
1216 else {
1217 arrange_Widget(sheet);
1218 }
1219 if (!useMobileSheetLayout_()) {
1220 setupSheetTransition_Mobile(sheet, iTrue);
1221 }
1222 postRefresh_App();
1223}
1224#endif
1225 838
1226void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) { 839void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) {
1227 if (!isUsingPanelLayout_Mobile()) { 840 if (!isUsingPanelLayout_Mobile()) {