egra: better selectors (they can be customised with return type now, and has proper...
[iv.d.git] / egra / gui / dialogs.d
blobfe27f9e79fd82c32eeb9141f1ba3a0a0395e0dbc
1 /*
2 * Simple Framebuffer Gfx/GUI lib
4 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
5 * Understanding is not required. Only obedience.
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 module iv.egra.gui.dialogs /*is aliced*/;
20 private:
22 import arsd.simpledisplay;
24 import iv.alice;
25 import iv.cmdcon;
26 import iv.dynstring;
27 import iv.strex;
28 import iv.utfutil;
29 import iv.vfs;
31 import iv.egra.gfx;
32 import iv.egra.gui.subwindows;
33 import iv.egra.gui.widgets;
36 // ////////////////////////////////////////////////////////////////////////// //
37 public dynstring[] buildAutoCompletion (ConString prefix) {
38 import std.file : DirEntry, SpanMode, dirEntries;
40 if (prefix.length == 0) return null;
42 ConString path, namepfx;
44 if (prefix[$-1] == '/') {
45 path = prefix;
46 namepfx = null;
47 } else {
48 auto lspos = prefix.lastIndexOf('/');
49 if (lspos < 0) {
50 path = null;
51 namepfx = prefix;
52 } else {
53 path = prefix[0..lspos+1];
54 namepfx = prefix[lspos+1..$];
58 //conwriteln("path=[", path, "]; namepfx=[", namepfx, "]");
60 dynstring[] res;
61 foreach (DirEntry de; dirEntries(path.idup, SpanMode.shallow)) {
62 if (namepfx.length != 0) {
63 import std.path : baseName;
64 //conwriteln(" [", de.baseName, "]");
65 if (!de.baseName.startsWith(namepfx)) continue;
67 try {
68 dynstring ds = de.name;
69 if (de.isDir) ds ~= "/";
70 res ~= ds;
71 //if (de.isDir) res ~= de.name~"/"; else res ~= de.name;
72 } catch (Exception e) {}
75 if (res.length > 1) {
76 import std.algorithm : sort;
77 sort(res);
80 return res;
84 // ////////////////////////////////////////////////////////////////////////// //
85 public class SelectCompletionWindow : SubWindow {
86 dynstring[] list;
88 void delegate (dynstring str) onSelected;
90 this (const(char)[] prefix, dynstring[] clist, bool aspath) {
91 createRoot();
92 int xhgt = 0;
93 int xwdt = 0;
94 bool idxset = false;
96 SimpleListBoxWidget lb = new SimpleListBoxWidget(rootWidget);
97 lb.id = "main-listbox";
98 foreach (dynstring s; clist) {
99 if (aspath && s.length) {
100 usize lspos = s.length;
101 if (s[$-1] == '/') --lspos;
102 while (lspos > 0 && s.ptr[lspos-1] != '/') --lspos;
103 s = s[lspos..$];
105 lb.appendItem(s);
106 if (s == prefix) { idxset = true; lb.curidx = lb.length-1; }
107 if (!idxset && s.startsWith(prefix)) { idxset = true; lb.curidx = lb.length-1; }
108 int w = gxTextWidthUtf(s)+2;
109 if (xwdt < w) xwdt = w;
110 xhgt += gxTextHeightUtf;
113 if (xhgt == 0) { super(); return; }
114 if (xhgt > screenHeight) xhgt = screenHeight-decorationSizeY;
116 if (xwdt > screenWidth-decorationSizeX) xwdt = screenWidth-decorationSizeX;
118 super("Select Completion", GxSize(xwdt+decorationSizeX, xhgt+decorationSizeY));
119 lb.width = clientWidth;
120 lb.height = clientHeight;
121 list = clist;
123 lb.onAction = delegate (self) {
124 if (onSelected !is null && lb.curidx >= 0 && lb.curidx < list.length) {
125 close();
126 onSelected(list[lb.curidx]);
127 return;
129 vbwin.beep();
132 addModal();
135 override bool onKeyBubble (KeyEvent event) {
136 if (event.pressed) {
137 if (event == "Escape") { close(); return true; }
138 if (event == "Enter") {
139 if (auto lb = querySelector!Widget("#main-listbox")) {
140 lb.doAction();
141 return true;
145 return super.onKeyBubble(event);
150 // ////////////////////////////////////////////////////////////////////////// //
151 public class YesNoWindow : SubWindow {
152 public:
153 void delegate () onYes;
154 void delegate () onNo;
156 protected:
157 dynstring msgMessage;
158 bool defaction = true;
160 public:
161 this (const(char)[] atitle, const(char)[] amessage, bool adefaction=true) {
162 msgMessage = amessage;
163 defaction = adefaction;
164 super(atitle);
167 override void createWidgets () {
168 new SpacerWidget(8);
170 (new HBoxWidget).enter{
171 new SpacerWidget(4);
172 with (new LabelWidget(msgMessage, LabelWidget.HAlign.Center, LabelWidget.VAlign.Center)) {
173 flex = 1;
175 new SpacerWidget(4);
178 new SpacerWidget(8);
180 (new HBoxWidget).enter{
181 new SpacerWidget(2);
182 new SpringWidget(1);
183 with (new ButtonExWidget("&Yes")) {
184 hsizeId = "yesno";
185 deftype = Default.Accept;
186 if (width < 96) width = 96;
187 onAction = delegate (self) { close(); if (onYes !is null) onYes(); };
188 if (defaction) focus();
190 new SpacerWidget(4);
191 with (new ButtonExWidget("&No")) {
192 hsizeId = "yesno";
193 deftype = Default.Cancel;
194 onAction = delegate (self) { close(); if (onNo !is null) onNo(); };
195 onCheckHotkey = delegate (self, event) { return (event == "C-Q"); };
196 if (!defaction) focus();
198 new SpringWidget(1);
199 new SpacerWidget(2);
202 new SpacerWidget(2);
204 relayoutResize();
205 centerWindow();
208 override void finishCreating () {
209 addModal();