switched to GPLv3 ONLY, because i don't trust FSF anymore
[knntp.git] / egui.d
blobef701a3d0654253cbfce16e7320071a79fff14b7
1 /* DigitalMars NNTP reader
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module egui is aliced;
18 private:
20 import core.time;
22 import arsd.simpledisplay;
24 import egfx;
26 import iv.cmdcon;
27 import iv.utfutil;
30 // ////////////////////////////////////////////////////////////////////////// //
31 public __gshared SimpleWindow vbwin; // main window
32 public __gshared bool vbfocused = false;
33 public __gshared uint zxtexid; // OpenGL texture id
34 public __gshared int guiGroupListWidth = 110;
35 public __gshared int guiThreadListHeight = 210;
36 public __gshared int lastWinWidth, lastWinHeight;
37 public __gshared bool vbwinLocked = false;
38 public __gshared bool vbufVSync = false;
39 public __gshared bool vbufEffVSync = false;
42 // ////////////////////////////////////////////////////////////////////////// //
43 public class HideMouseEvent {}
44 public class ScreenUpdateEvent {}
45 public class ScreenRepaintEvent {}
46 public class DoConsoleCommandsEvent {}
47 public class QuitEvent {}
48 public class CursorBlinkEvent {}
50 __gshared ScreenUpdateEvent evScrReady;
51 __gshared ScreenRepaintEvent evScreenRepaint;
52 __gshared HideMouseEvent evHideMouse;
53 __gshared DoConsoleCommandsEvent evDoConCommands;
54 __gshared CursorBlinkEvent evCurBlink;
57 shared static this () {
58 evScrReady = new ScreenUpdateEvent();
59 evScreenRepaint = new ScreenRepaintEvent();
60 evHideMouse = new HideMouseEvent();
61 evDoConCommands = new DoConsoleCommandsEvent();
62 evCurBlink = new CursorBlinkEvent();
66 // ////////////////////////////////////////////////////////////////////////// //
67 public void postScreenUpdate () {
68 if (vbwin !is null && !vbwin.eventQueued!ScreenUpdateEvent) vbwin.postEvent(evScrReady);
71 public void postScreenRepaint () {
72 if (vbwin !is null && !vbwin.eventQueued!ScreenRepaintEvent && !vbwin.eventQueued!ScreenUpdateEvent) vbwin.postEvent(evScreenRepaint);
75 public void postDoConCommands () {
76 if (vbwin !is null && !vbwin.eventQueued!DoConsoleCommandsEvent) vbwin.postEvent(evDoConCommands);
79 public void postCurBlink () {
80 if (vbwin !is null && !vbwin.eventQueued!CursorBlinkEvent) {
81 //conwriteln("curblink posted!");
82 vbwin.postTimeout(evCurBlink, 100);
87 // ////////////////////////////////////////////////////////////////////////// //
88 __gshared MonoTime lastMouseMove;
89 enum MouseHideTime = 1000;
92 public bool isMouseVisible () {
93 auto ctt = MonoTime.currTime;
94 return ((ctt-lastMouseMove).total!"msecs" < MouseHideTime);
98 // returns `false` if there is no need to repost the event, and the mouse should be hidden
99 public bool repostHideMouse () {
100 if (vbwin is null || vbwin.eventQueued!HideMouseEvent) return false;
101 auto ctt = MonoTime.currTime;
102 auto tms = (ctt-lastMouseMove).total!"msecs";
103 if (tms >= MouseHideTime) return false;
104 vbwin.postTimeout(evHideMouse, MouseHideTime);
105 return true;
109 public void mouseMoved () {
110 lastMouseMove = MonoTime.currTime;
111 if (vbwin !is null && !vbwin.eventQueued!HideMouseEvent) vbwin.postTimeout(evHideMouse, MouseHideTime);
115 // ////////////////////////////////////////////////////////////////////////// //
116 public void drawTextCursor (int x, int y, int hgt=-666) nothrow @trusted @nogc {
117 if (hgt == -666) hgt = gxTextHeightUtf;
118 if (hgt < 1) return;
119 auto ctt = (MonoTime.currTime.ticks*1000/MonoTime.ticksPerSecond)/100;
120 int doty = ctt%(hgt*2-1);
121 if (doty >= hgt) doty = hgt*2-doty-1;
122 gxVLine(x, y, hgt, (ctt%10 < 5 ? gxRGB!(255, 255, 255) : gxRGB!(200, 200, 200)));
123 gxPutPixel(x, y+doty, gxRGB!(0, 255, 255));
127 // ////////////////////////////////////////////////////////////////////////// //
128 public __gshared SubWindow[] subwins;
129 public __gshared bool ignoreSubWinChar = false;
130 public __gshared bool subwinDrag = false;
131 public __gshared int subwinDragXSpot, subwinDragYSpot;
134 public bool hasWindowClass(T:SubWindow) () {
135 string name = typeid(T).name;
136 foreach (SubWindow w; subwins) if (typeid(w).name == name) return true;
137 return false;
140 public bool hasWindowClass(T:SubWindow) (T ww) { return hasWindowClass!T(); }
143 public abstract class SubWindow {
144 public:
145 int winx, winy, winw, winh;
146 bool immuneToLock = true;
147 bool closed = false;
149 public:
150 this (int ax, int ay, int aw, int ah) {
151 winx = ax;
152 winy = ay;
153 winw = aw;
154 winh = ah;
157 this (int aw, int ah) {
158 winx = (VBufWidth-aw)/2;
159 winy = (VBufHeight-ah)/2;
160 winw = aw;
161 winh = ah;
164 void onPaint ();
165 void onKey (KeyEvent event);
166 void onMouse (MouseEvent event);
167 void onChar (dchar ch);
169 final void setupClip () {
170 clipReset();
171 clipX0 = winx;
172 clipX1 = winx+winw-1;
173 clipY0 = winy;
174 clipY1 = winy+winh-1;
177 final void setupClientClip () {
178 setupClip();
179 clipX0 += 2;
180 clipX1 -= 2;
181 clipY0 += 12;
182 clipY1 -= 2;
185 void close () {
186 if (closed) return;
187 closed = true;
188 if (subwins.length && subwins[$-1] is this) subwinDrag = false;
189 import std.algorithm : remove;
190 foreach (immutable idx, SubWindow w; subwins) {
191 if (w is this) {
192 subwins = subwins.remove(idx);
193 if (!vbwin.eventQueued!(typeof(evScrReady))) vbwin.postEvent(evScrReady);
194 return;
199 void add (bool fromKeyboard=true) {
200 if (subwins.length && subwins[$-1] is this) return;
201 subwinDrag = false;
202 foreach (immutable idx, SubWindow w; subwins) {
203 if (w is this) {
204 if (idx != subwins.length-1) {
205 import std.algorithm : remove;
206 subwins = subwins.remove(idx);
207 subwins ~= this;
209 if (fromKeyboard) ignoreSubWinChar = true;
210 if (!vbwin.eventQueued!(typeof(evScrReady))) vbwin.postEvent(evScrReady);
211 return;
214 subwins ~= this;
215 if (fromKeyboard) ignoreSubWinChar = true;
216 if (!vbwin.eventQueued!(typeof(evScrReady))) vbwin.postEvent(evScrReady);
221 // ////////////////////////////////////////////////////////////////////////// //
222 // setup cliprect first
223 public final class LineEdit {
224 private:
225 int pos;
226 int lskip;
227 string s;
229 public:
230 bool active;
232 public:
233 this () {}
235 @property string str () const pure nothrow @safe @nogc { return s; }
236 @property void str (string ns) nothrow @safe @nogc { s = ns; pos = s.utflen; }
238 void makeCursorVisible () {
239 int w = clipWidth-2;
240 if (w < 6*3) w = 6*3;
241 int tw = gxTextWidthUtf(s);
242 if (tw < w) { lskip = 0; return; }
243 if (lskip > tw-w) lskip = tw-w;
244 // left
245 int px = gxTextWidthUtf(s.utfleft(pos));
246 if (px < lskip) lskip = px-6;
247 if (lskip < 0) lskip = 0;
248 // right
249 int vx = px-lskip;
250 if (px >= w) lskip = px-(w-6);
251 if (lskip < 0) lskip = 0;
254 void onPaint () {
255 makeCursorVisible();
256 gxFillRect(clipX0, clipY0, clipWidth, 10, gxRGB!(0, 0, 0));
257 clipX0 += 2;
258 clipX1 -= 2;
259 gxDrawTextUtf(clipX0-lskip, clipY0+1, s, (active ? gxRGB!(220, 220, 80) : gxRGB!(220, 220, 0)));
260 if (active) {
261 drawTextCursor(clipX0-lskip+gxTextWidthUtf(s.utfleft(pos)), clipY0+1);
262 postCurBlink();
264 if (lskip > 0) gxDrawTextOutP(clipX0, clipY0+1, arrowLeftStr, gxRGB!(0, 220, 220), gxRGB!(0, 0, 0));
265 int pxlen = gxTextWidthUtf(s);
266 if (clipX0-lskip+pxlen-1 > clipX1) gxDrawTextOutP(clipX1-1-gxTextWidthUtf(arrowRightStr)-2, clipY0+1, arrowRightStr, gxRGB!(0, 220, 220), gxRGB!(0, 0, 0));
269 void onKey (KeyEvent event) {
270 if (!event.pressed) return;
271 if (event == "Left" || event == "Pad4") { if (pos > 0) --pos; return; }
272 if (event == "Right" || event == "Pad6") { if (pos < s.utflen) ++pos; return; }
273 if (event == "Home" || event == "Pad7") { pos = 0; return; }
274 if (event == "End" || event == "Pad1") { pos = s.utflen; return; }
275 if (event == "Delete" || event == "PadDot") { if (pos < s.utflen) s = s.utfdel(pos, 1); return; }
276 if (event == "S-Insert") {
277 getClipboardText(vbwin, delegate (in char[] text) {
278 Utf8DecoderFast dc;
279 foreach (char ch; text) {
280 if (dc.decode(cast(ubyte)ch)) {
281 dchar dch = dc.codepoint;
282 if (dc.isValidDC(dch) && dch != 8) onChar(dch);
289 void onChar (dchar ch) {
290 if (ch == 8) {
291 if (pos > 0) {
292 --pos;
293 s = s.utfdel(pos, 1);
295 return;
297 if (ch < ' ' || ch == 127) return;
298 string t = s.utfleft(pos);
299 t ~= ch;
300 t ~= s.utfskip(pos);
301 if (t.length > 255) return;
302 s = t;
303 ++pos;