summaryrefslogtreecommitdiff
path: root/src/ui/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/util.c')
-rw-r--r--src/ui/util.c194
1 files changed, 168 insertions, 26 deletions
diff --git a/src/ui/util.c b/src/ui/util.c
index 9f4768d9..dfe364a5 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -1,8 +1,32 @@
1/* Copyright 2020 Jaakko Keränen <jaakko.keranen@iki.fi>
2
3Redistribution and use in source and binary forms, with or without
4modification, are permitted provided that the following conditions are met:
5
61. Redistributions of source code must retain the above copyright notice, this
7 list of conditions and the following disclaimer.
82. Redistributions in binary form must reproduce the above copyright notice,
9 this list of conditions and the following disclaimer in the documentation
10 and/or other materials provided with the distribution.
11
12THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
13ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
16ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22
1#include "util.h" 23#include "util.h"
2 24
3#include "app.h" 25#include "app.h"
26#include "bookmarks.h"
4#include "color.h" 27#include "color.h"
5#include "command.h" 28#include "command.h"
29#include "gmutil.h"
6#include "labelwidget.h" 30#include "labelwidget.h"
7#include "inputwidget.h" 31#include "inputwidget.h"
8#include "widget.h" 32#include "widget.h"
@@ -157,7 +181,13 @@ static iBool menuHandler_(iWidget *menu, const char *cmd) {
157 /* Don't reopen self; instead, root will close the menu. */ 181 /* Don't reopen self; instead, root will close the menu. */
158 return iFalse; 182 return iFalse;
159 } 183 }
160 if (!equal_Command(cmd, "window.resized")) { 184 if (equal_Command(cmd, "mouse.clicked") && arg_Command(cmd)) {
185 /* Dismiss open menus when clicking outside them. */
186 closeMenu_Widget(menu);
187 return iTrue;
188 }
189 if (!equal_Command(cmd, "window.resized") &&
190 !(equal_Command(cmd, "mouse.clicked") && !arg_Command(cmd)) /* ignore button release */) {
161 closeMenu_Widget(menu); 191 closeMenu_Widget(menu);
162 } 192 }
163 } 193 }
@@ -234,7 +264,7 @@ void closeMenu_Widget(iWidget *d) {
234} 264}
235 265
236int checkContextMenu_Widget(iWidget *menu, const SDL_Event *ev) { 266int checkContextMenu_Widget(iWidget *menu, const SDL_Event *ev) {
237 if (ev->type == SDL_MOUSEBUTTONDOWN && ev->button.button == SDL_BUTTON_RIGHT) { 267 if (menu && ev->type == SDL_MOUSEBUTTONDOWN && ev->button.button == SDL_BUTTON_RIGHT) {
238 if (isVisible_Widget(menu)) { 268 if (isVisible_Widget(menu)) {
239 closeMenu_Widget(menu); 269 closeMenu_Widget(menu);
240 return 0x1; 270 return 0x1;
@@ -476,6 +506,7 @@ iBool filePathHandler_(iWidget *dlg, const char *cmd) {
476 506
477iWidget *makeSheet_Widget(const char *id) { 507iWidget *makeSheet_Widget(const char *id) {
478 iWidget *sheet = new_Widget(); 508 iWidget *sheet = new_Widget();
509 setPadding1_Widget(sheet, 3 * gap_UI);
479 setId_Widget(sheet, id); 510 setId_Widget(sheet, id);
480 setFrameColor_Widget(sheet, uiSeparator_ColorId); 511 setFrameColor_Widget(sheet, uiSeparator_ColorId);
481 setBackgroundColor_Widget(sheet, uiBackground_ColorId); 512 setBackgroundColor_Widget(sheet, uiBackground_ColorId);
@@ -483,9 +514,6 @@ iWidget *makeSheet_Widget(const char *id) {
483 mouseModal_WidgetFlag | keepOnTop_WidgetFlag | arrangeVertical_WidgetFlag | 514 mouseModal_WidgetFlag | keepOnTop_WidgetFlag | arrangeVertical_WidgetFlag |
484 arrangeSize_WidgetFlag, 515 arrangeSize_WidgetFlag,
485 iTrue); 516 iTrue);
486 // const iInt2 rootSize = rootSize_Window(get_Window());
487 // setSize_Widget(sheet, init_I2(rootSize.x / 2, 0));
488 // setFlags_Widget(sheet, fixedHeight_WidgetFlag, iFalse);
489 return sheet; 517 return sheet;
490} 518}
491 519
@@ -529,11 +557,13 @@ void makeFilePath_Widget(iWidget * parent,
529 557
530static void acceptValueInput_(iWidget *dlg) { 558static void acceptValueInput_(iWidget *dlg) {
531 const iInputWidget *input = findChild_Widget(dlg, "input"); 559 const iInputWidget *input = findChild_Widget(dlg, "input");
532 const iString *val = text_InputWidget(input); 560 if (!isEmpty_String(id_Widget(dlg))) {
533 postCommandf_App("%s arg:%d value:%s", 561 const iString *val = text_InputWidget(input);
534 cstr_String(id_Widget(dlg)), 562 postCommandf_App("%s arg:%d value:%s",
535 toInt_String(val), 563 cstr_String(id_Widget(dlg)),
536 cstr_String(val)); 564 toInt_String(val),
565 cstr_String(val));
566 }
537} 567}
538 568
539static void updateValueInputWidth_(iWidget *dlg) { 569static void updateValueInputWidth_(iWidget *dlg) {
@@ -560,6 +590,7 @@ iBool valueInputHandler_(iWidget *dlg, const char *cmd) {
560 } 590 }
561 else { 591 else {
562 postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg))); 592 postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg)));
593 setId_Widget(dlg, ""); /* no further commands to emit */
563 } 594 }
564 destroy_Widget(dlg); 595 destroy_Widget(dlg);
565 return iTrue; 596 return iTrue;
@@ -568,6 +599,7 @@ iBool valueInputHandler_(iWidget *dlg, const char *cmd) {
568 } 599 }
569 else if (equal_Command(cmd, "cancel")) { 600 else if (equal_Command(cmd, "cancel")) {
570 postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg))); 601 postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg)));
602 setId_Widget(dlg, ""); /* no further commands to emit */
571 destroy_Widget(dlg); 603 destroy_Widget(dlg);
572 return iTrue; 604 return iTrue;
573 } 605 }
@@ -633,11 +665,12 @@ static iBool messageHandler_(iWidget *msg, const char *cmd) {
633 return iFalse; 665 return iFalse;
634} 666}
635 667
636void makeMessage_Widget(const char *title, const char *msg) { 668iWidget *makeMessage_Widget(const char *title, const char *msg) {
637 iWidget *dlg = makeQuestion_Widget( 669 iWidget *dlg = makeQuestion_Widget(
638 title, msg, (const char *[]){ "Continue" }, (const char *[]){ "message.ok" }, 1); 670 title, msg, (const char *[]){ "Continue" }, (const char *[]){ "message.ok" }, 1);
639 addAction_Widget(dlg, SDLK_ESCAPE, 0, "message.ok"); 671 addAction_Widget(dlg, SDLK_ESCAPE, 0, "message.ok");
640 addAction_Widget(dlg, SDLK_SPACE, 0, "message.ok"); 672 addAction_Widget(dlg, SDLK_SPACE, 0, "message.ok");
673 return dlg;
641} 674}
642 675
643iWidget *makeQuestion_Widget(const char *title, 676iWidget *makeQuestion_Widget(const char *title,
@@ -666,9 +699,11 @@ iWidget *makeQuestion_Widget(const char *title,
666} 699}
667 700
668void setToggle_Widget(iWidget *d, iBool active) { 701void setToggle_Widget(iWidget *d, iBool active) {
669 setFlags_Widget(d, selected_WidgetFlag, active); 702 if (d) {
670 updateText_LabelWidget((iLabelWidget *) d, 703 setFlags_Widget(d, selected_WidgetFlag, active);
671 collectNewFormat_String("%s", isSelected_Widget(d) ? "YES" : "NO")); 704 updateText_LabelWidget((iLabelWidget *) d,
705 collectNewFormat_String("%s", isSelected_Widget(d) ? "YES" : "NO"));
706 }
672} 707}
673 708
674static iBool toggleHandler_(iWidget *d, const char *cmd) { 709static iBool toggleHandler_(iWidget *d, const char *cmd) {
@@ -684,8 +719,9 @@ static iBool toggleHandler_(iWidget *d, const char *cmd) {
684} 719}
685 720
686iWidget *makeToggle_Widget(const char *id) { 721iWidget *makeToggle_Widget(const char *id) {
687 iWidget *toggle = as_Widget(new_LabelWidget("YES", 0, 0, "toggle")); 722 iWidget *toggle = as_Widget(new_LabelWidget("YES", 0, 0, "toggle")); /* "YES" for sizing */
688 setId_Widget(toggle, id); 723 setId_Widget(toggle, id);
724 updateTextCStr_LabelWidget((iLabelWidget *) toggle, "NO"); /* actual initial value */
689 setCommandHandler_Widget(toggle, toggleHandler_); 725 setCommandHandler_Widget(toggle, toggleHandler_);
690 return toggle; 726 return toggle;
691} 727}
@@ -702,9 +738,11 @@ iWidget *makePreferences_Widget(void) {
702 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); 738 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
703 iWidget *values = addChildFlags_Widget( 739 iWidget *values = addChildFlags_Widget(
704 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); 740 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
705// setBackgroundColor_Widget(headings, none_ColorId); 741#if defined (iPlatformApple) || defined (iPlatformMSys)
706// setBackgroundColor_Widget(values, none_ColorId); 742 addChild_Widget(headings, iClob(makeHeading_Widget("Use system theme:")));
707 addChild_Widget(headings, iClob(makeHeading_Widget("Theme:"))); 743 addChild_Widget(values, iClob(makeToggle_Widget("prefs.ostheme")));
744#endif
745 addChild_Widget(headings, iClob(makeHeading_Widget("Theme:")));
708 iWidget *themes = new_Widget(); 746 iWidget *themes = new_Widget();
709 /* Themes. */ { 747 /* Themes. */ {
710 setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("Pure Black", 0, 0, "theme.set arg:0"))), "prefs.theme.0"); 748 setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("Pure Black", 0, 0, "theme.set arg:0"))), "prefs.theme.0");
@@ -717,8 +755,18 @@ iWidget *makePreferences_Widget(void) {
717 addChild_Widget(values, iClob(makeToggle_Widget("prefs.retainwindow"))); 755 addChild_Widget(values, iClob(makeToggle_Widget("prefs.retainwindow")));
718 addChild_Widget(headings, iClob(makeHeading_Widget("UI scale factor:"))); 756 addChild_Widget(headings, iClob(makeHeading_Widget("UI scale factor:")));
719 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(8))), "prefs.uiscale"); 757 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(8))), "prefs.uiscale");
758 addChild_Widget(headings, iClob(makeHeading_Widget(uiHeading_ColorEscape "Proxies")));
759 addChild_Widget(values, iClob(makeHeading_Widget("")));
760 addChild_Widget(headings, iClob(makeHeading_Widget("HTTP proxy:")));
761 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.http");
762 addChild_Widget(headings, iClob(makeHeading_Widget("Gopher proxy:")));
763 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.gopher");
720 arrange_Widget(dlg); 764 arrange_Widget(dlg);
721// as_Widget(songDir)->rect.size.x = dlg->rect.size.x - headings->rect.size.x; 765 /* Text input widths. */ {
766 const int inputWidth = width_Rect(page->rect) - width_Rect(headings->rect);
767 as_Widget(findChild_Widget(values, "prefs.proxy.http"))->rect.size.x = inputWidth;
768 as_Widget(findChild_Widget(values, "prefs.proxy.gopher"))->rect.size.x = inputWidth;
769 }
722 iWidget *div = new_Widget(); { 770 iWidget *div = new_Widget(); {
723 setFlags_Widget(div, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue); 771 setFlags_Widget(div, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue);
724 addChild_Widget(div, iClob(new_LabelWidget("Dismiss", SDLK_ESCAPE, 0, "prefs.dismiss"))); 772 addChild_Widget(div, iClob(new_LabelWidget("Dismiss", SDLK_ESCAPE, 0, "prefs.dismiss")));
@@ -731,9 +779,11 @@ iWidget *makePreferences_Widget(void) {
731 779
732iWidget *makeBookmarkEditor_Widget(void) { 780iWidget *makeBookmarkEditor_Widget(void) {
733 iWidget *dlg = makeSheet_Widget("bmed"); 781 iWidget *dlg = makeSheet_Widget("bmed");
734 addChildFlags_Widget(dlg, 782 setId_Widget(addChildFlags_Widget(
735 iClob(new_LabelWidget(uiHeading_ColorEscape "EDIT BOOKMARK", 0, 0, NULL)), 783 dlg,
736 frameless_WidgetFlag); 784 iClob(new_LabelWidget(uiHeading_ColorEscape "EDIT BOOKMARK", 0, 0, NULL)),
785 frameless_WidgetFlag),
786 "bmed.heading");
737 iWidget *page = new_Widget(); 787 iWidget *page = new_Widget();
738 addChild_Widget(dlg, iClob(page)); 788 addChild_Widget(dlg, iClob(page));
739 setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue); 789 setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue);
@@ -741,9 +791,8 @@ iWidget *makeBookmarkEditor_Widget(void) {
741 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); 791 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
742 iWidget *values = addChildFlags_Widget( 792 iWidget *values = addChildFlags_Widget(
743 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); 793 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
744 iInputWidget *inputs[4]; 794 iInputWidget *inputs[3];
745 iWidget *hd; 795 addChild_Widget(headings, iClob(makeHeading_Widget("Title:")));
746 addChild_Widget(headings, iClob(hd = makeHeading_Widget("Title:")));
747 setId_Widget(addChild_Widget(values, iClob(inputs[0] = new_InputWidget(0))), "bmed.title"); 796 setId_Widget(addChild_Widget(values, iClob(inputs[0] = new_InputWidget(0))), "bmed.title");
748 addChild_Widget(headings, iClob(makeHeading_Widget("URL:"))); 797 addChild_Widget(headings, iClob(makeHeading_Widget("URL:")));
749 setId_Widget(addChild_Widget(values, iClob(inputs[1] = new_InputWidget(0))), "bmed.url"); 798 setId_Widget(addChild_Widget(values, iClob(inputs[1] = new_InputWidget(0))), "bmed.url");
@@ -759,7 +808,100 @@ iWidget *makeBookmarkEditor_Widget(void) {
759 addChild_Widget( 808 addChild_Widget(
760 div, 809 div,
761 iClob(new_LabelWidget( 810 iClob(new_LabelWidget(
762 uiTextCaution_ColorEscape "Save", SDLK_RETURN, KMOD_PRIMARY, "bmed.accept"))); 811 uiTextCaution_ColorEscape "Save Bookmark", SDLK_RETURN, KMOD_PRIMARY, "bmed.accept")));
812 }
813 addChild_Widget(dlg, iClob(div));
814 addChild_Widget(get_Window()->root, iClob(dlg));
815 centerSheet_Widget(dlg);
816 return dlg;
817}
818
819static iBool handleBookmarkCreationCommands_SidebarWidget_(iWidget *editor, const char *cmd) {
820 if (equal_Command(cmd, "bmed.accept") || equal_Command(cmd, "cancel")) {
821 if (equal_Command(cmd, "bmed.accept")) {
822 const iString *title = text_InputWidget(findChild_Widget(editor, "bmed.title"));
823 const iString *url = text_InputWidget(findChild_Widget(editor, "bmed.url"));
824 const iString *tags = text_InputWidget(findChild_Widget(editor, "bmed.tags"));
825 add_Bookmarks(bookmarks_App(),
826 url,
827 title,
828 tags,
829 first_String(label_LabelWidget(findChild_Widget(editor, "bmed.icon"))));
830 postCommand_App("bookmarks.changed");
831 }
832 destroy_Widget(editor);
833 return iTrue;
834 }
835 return iFalse;
836}
837
838iWidget *makeBookmarkCreation_Widget(const iString *url, const iString *title, iChar icon) {
839 iWidget *dlg = makeBookmarkEditor_Widget();
840 setId_Widget(dlg, "bmed.create");
841 setTextCStr_LabelWidget(findChild_Widget(dlg, "bmed.heading"),
842 uiHeading_ColorEscape "ADD BOOKMARK");
843 iUrl parts;
844 init_Url(&parts, url);
845 setTextCStr_InputWidget(findChild_Widget(dlg, "bmed.title"),
846 title ? cstr_String(title) : cstr_Rangecc(parts.host));
847 setText_InputWidget(findChild_Widget(dlg, "bmed.url"), url);
848 setId_Widget(
849 addChildFlags_Widget(
850 dlg,
851 iClob(new_LabelWidget(cstrCollect_String(newUnicodeN_String(&icon, 1)), 0, 0, NULL)),
852 collapse_WidgetFlag | hidden_WidgetFlag | disabled_WidgetFlag),
853 "bmed.icon");
854 setCommandHandler_Widget(dlg, handleBookmarkCreationCommands_SidebarWidget_);
855 return dlg;
856}
857
858iWidget *makeIdentityCreation_Widget(void) {
859 iWidget *dlg = makeSheet_Widget("ident");
860 setId_Widget(addChildFlags_Widget(
861 dlg,
862 iClob(new_LabelWidget(uiHeading_ColorEscape "NEW IDENTITY", 0, 0, NULL)),
863 frameless_WidgetFlag),
864 "ident.heading");
865 iWidget *page = new_Widget();
866 addChildFlags_Widget(
867 dlg,
868 iClob(
869 new_LabelWidget("Creating a 2048-bit self-signed RSA certificate.", 0, 0, NULL)),
870 frameless_WidgetFlag);
871 addChild_Widget(dlg, iClob(page));
872 setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue);
873 iWidget *headings = addChildFlags_Widget(
874 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
875 iWidget *values = addChildFlags_Widget(
876 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
877 iInputWidget *inputs[6];
878 addChild_Widget(headings, iClob(makeHeading_Widget("Common name:")));
879 setId_Widget(addChild_Widget(values, iClob(inputs[0] = new_InputWidget(0))), "ident.common");
880 addChild_Widget(headings, iClob(makeHeading_Widget("Email:")));
881 setId_Widget(addChild_Widget(values, iClob(inputs[1] = newHint_InputWidget(0, "optional"))), "ident.email");
882 addChild_Widget(headings, iClob(makeHeading_Widget("User ID:")));
883 setId_Widget(addChild_Widget(values, iClob(inputs[2] = newHint_InputWidget(0, "optional"))), "ident.userid");
884 addChild_Widget(headings, iClob(makeHeading_Widget("Domain:")));
885 setId_Widget(addChild_Widget(values, iClob(inputs[3] = newHint_InputWidget(0, "optional"))), "ident.domain");
886 addChild_Widget(headings, iClob(makeHeading_Widget("Organization:")));
887 setId_Widget(addChild_Widget(values, iClob(inputs[4] = newHint_InputWidget(0, "optional"))), "ident.org");
888 addChild_Widget(headings, iClob(makeHeading_Widget("Country:")));
889 setId_Widget(addChild_Widget(values, iClob(inputs[5] = newHint_InputWidget(0, "optional"))), "ident.country");
890 addChild_Widget(headings, iClob(makeHeading_Widget("Valid until:")));
891 setId_Widget(addChild_Widget(values, iClob(newHint_InputWidget(19, "YYYY-MM-DD HH:MM:SS"))), "ident.until");
892 addChild_Widget(headings, iClob(makeHeading_Widget("Temporary:")));
893 addChild_Widget(values, iClob(makeToggle_Widget("ident.temp")));
894 arrange_Widget(dlg);
895 for (size_t i = 0; i < iElemCount(inputs); ++i) {
896 as_Widget(inputs[i])->rect.size.x = 100 * gap_UI - headings->rect.size.x;
897 }
898 iWidget *div = new_Widget(); {
899 setFlags_Widget(div, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue);
900 addChild_Widget(div, iClob(new_LabelWidget("Cancel", SDLK_ESCAPE, 0, "cancel")));
901 addChild_Widget(
902 div,
903 iClob(new_LabelWidget(
904 uiTextAction_ColorEscape "Create Identity", SDLK_RETURN, KMOD_PRIMARY, "ident.accept")));
763 } 905 }
764 addChild_Widget(dlg, iClob(div)); 906 addChild_Widget(dlg, iClob(div));
765 addChild_Widget(get_Window()->root, iClob(dlg)); 907 addChild_Widget(get_Window()->root, iClob(dlg));