"C-Period" to find my messages; "C-Insert" to copy post URL to clipboard
[knntp.git] / egui.d
blobef37dbd0e98382c53e156ee8c37e97a0164d9e06
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, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 module egui is aliced;
19 private:
21 import core.time;
23 import arsd.simpledisplay;
25 import egfx;
27 import iv.cmdcon;
28 import iv.utfutil;
31 // ////////////////////////////////////////////////////////////////////////// //
32 public __gshared SimpleWindow vbwin; // main window
33 public __gshared bool vbfocused = false;
34 public __gshared uint zxtexid; // OpenGL texture id
35 public __gshared int guiGroupListWidth = 110;
36 public __gshared int guiThreadListHeight = 210;
37 public __gshared int lastWinWidth, lastWinHeight;
38 public __gshared bool vbwinLocked = false;
39 public __gshared bool vbufVSync = false;
40 public __gshared bool vbufEffVSync = false;
43 // ////////////////////////////////////////////////////////////////////////// //
44 public class HideMouseEvent {}
45 public class ScreenUpdateEvent {}
46 public class ScreenRepaintEvent {}
47 public class DoConsoleCommandsEvent {}
48 public class QuitEvent {}
49 public class CursorBlinkEvent {}
51 __gshared ScreenUpdateEvent evScrReady;
52 __gshared ScreenRepaintEvent evScreenRepaint;
53 __gshared HideMouseEvent evHideMouse;
54 __gshared DoConsoleCommandsEvent evDoConCommands;
55 __gshared CursorBlinkEvent evCurBlink;
58 shared static this () {
59 evScrReady = new ScreenUpdateEvent();
60 evScreenRepaint = new ScreenRepaintEvent();
61 evHideMouse = new HideMouseEvent();
62 evDoConCommands = new DoConsoleCommandsEvent();
63 evCurBlink = new CursorBlinkEvent();
67 // ////////////////////////////////////////////////////////////////////////// //
68 public void postScreenUpdate () {
69 if (vbwin !is null && !vbwin.eventQueued!ScreenUpdateEvent) vbwin.postEvent(evScrReady);
72 public void postScreenRepaint () {
73 if (vbwin !is null && !vbwin.eventQueued!ScreenRepaintEvent && !vbwin.eventQueued!ScreenUpdateEvent) vbwin.postEvent(evScreenRepaint);
76 public void postDoConCommands () {
77 if (vbwin !is null && !vbwin.eventQueued!DoConsoleCommandsEvent) vbwin.postEvent(evDoConCommands);
80 public void postCurBlink () {
81 if (vbwin !is null && !vbwin.eventQueued!CursorBlinkEvent) {
82 //conwriteln("curblink posted!");
83 vbwin.postTimeout(evCurBlink, 100);
88 // ////////////////////////////////////////////////////////////////////////// //
89 __gshared MonoTime lastMouseMove;
90 enum MouseHideTime = 1000;
93 public bool isMouseVisible () {
94 auto ctt = MonoTime.currTime;
95 return ((ctt-lastMouseMove).total!"msecs" < MouseHideTime);
99 // returns `false` if there is no need to repost the event, and the mouse should be hidden
100 public bool repostHideMouse () {
101 if (vbwin is null || vbwin.eventQueued!HideMouseEvent) return false;
102 auto ctt = MonoTime.currTime;
103 auto tms = (ctt-lastMouseMove).total!"msecs";
104 if (tms >= MouseHideTime) return false;
105 vbwin.postTimeout(evHideMouse, MouseHideTime);
106 return true;
110 public void mouseMoved () {
111 lastMouseMove = MonoTime.currTime;
112 if (vbwin !is null && !vbwin.eventQueued!HideMouseEvent) vbwin.postTimeout(evHideMouse, MouseHideTime);
116 // ////////////////////////////////////////////////////////////////////////// //
117 public void drawTextCursor (int x, int y, int hgt=-666) nothrow @trusted @nogc {
118 if (hgt == -666) hgt = gxTextHeightUtf;
119 if (hgt < 1) return;
120 auto ctt = (MonoTime.currTime.ticks*1000/MonoTime.ticksPerSecond)/100;
121 int doty = ctt%(hgt*2-1);
122 if (doty >= hgt) doty = hgt*2-doty-1;
123 gxVLine(x, y, hgt, (ctt%10 < 5 ? gxRGB!(255, 255, 255) : gxRGB!(200, 200, 200)));
124 gxPutPixel(x, y+doty, gxRGB!(0, 255, 255));
128 // ////////////////////////////////////////////////////////////////////////// //
129 public __gshared SubWindow[] subwins;
130 public __gshared bool ignoreSubWinChar = false;
131 public __gshared bool subwinDrag = false;
132 public __gshared int subwinDragXSpot, subwinDragYSpot;
135 public abstract class SubWindow {
136 public:
137 bool immuneToLock = false;
138 int winx, winy, winw, winh;
139 bool closed = false;
141 public:
142 this (int ax, int ay, int aw, int ah) {
143 winx = ax;
144 winy = ay;
145 winw = aw;
146 winh = ah;
149 this (int aw, int ah) {
150 winx = (VBufWidth-aw)/2;
151 winy = (VBufHeight-ah)/2;
152 winw = aw;
153 winh = ah;
156 void onPaint ();
157 void onKey (KeyEvent event);
158 void onMouse (MouseEvent event);
159 void onChar (dchar ch);
161 final void setupClip () {
162 clipReset();
163 clipX0 = winx;
164 clipX1 = winx+winw-1;
165 clipY0 = winy;
166 clipY1 = winy+winh-1;
169 final void setupClientClip () {
170 setupClip();
171 clipX0 += 2;
172 clipX1 -= 2;
173 clipY0 += 12;
174 clipY1 -= 2;
177 void close () {
178 if (closed) return;
179 closed = true;
180 if (subwins.length && subwins[$-1] is this) subwinDrag = false;
181 import std.algorithm : remove;
182 foreach (immutable idx, SubWindow w; subwins) {
183 if (w is this) {
184 subwins = subwins.remove(idx);
185 if (!vbwin.eventQueued!(typeof(evScrReady))) vbwin.postEvent(evScrReady);
186 return;
191 void add (bool fromKeyboard=true) {
192 if (subwins.length && subwins[$-1] is this) return;
193 subwinDrag = false;
194 foreach (immutable idx, SubWindow w; subwins) {
195 if (w is this) {
196 if (idx != subwins.length-1) {
197 import std.algorithm : remove;
198 subwins = subwins.remove(idx);
199 subwins ~= this;
201 if (fromKeyboard) ignoreSubWinChar = true;
202 if (!vbwin.eventQueued!(typeof(evScrReady))) vbwin.postEvent(evScrReady);
203 return;
206 subwins ~= this;
207 if (fromKeyboard) ignoreSubWinChar = true;
208 if (!vbwin.eventQueued!(typeof(evScrReady))) vbwin.postEvent(evScrReady);
213 // ////////////////////////////////////////////////////////////////////////// //
214 // setup cliprect first
215 public final class LineEdit {
216 private:
217 int pos;
218 int lskip;
219 string s;
221 public:
222 bool active;
224 public:
225 this () {}
227 @property string str () const pure nothrow @safe @nogc { return s; }
228 @property void str (string ns) nothrow @safe @nogc { s = ns; pos = s.utflen; }
230 void makeCursorVisible () {
231 int w = clipWidth-2;
232 if (w < 6*3) w = 6*3;
233 int tw = gxTextWidthUtf(s);
234 if (tw < w) { lskip = 0; return; }
235 if (lskip > tw-w) lskip = tw-w;
236 // left
237 int px = gxTextWidthUtf(s.utfleft(pos));
238 if (px < lskip) lskip = px-6;
239 if (lskip < 0) lskip = 0;
240 // right
241 int vx = px-lskip;
242 if (px >= w) lskip = px-(w-6);
243 if (lskip < 0) lskip = 0;
246 void onPaint () {
247 makeCursorVisible();
248 gxFillRect(clipX0, clipY0, clipWidth, 10, gxRGB!(0, 0, 0));
249 clipX0 += 2;
250 clipX1 -= 2;
251 gxDrawTextUtf(clipX0-lskip, clipY0+1, s, (active ? gxRGB!(220, 220, 80) : gxRGB!(220, 220, 0)));
252 if (active) {
253 drawTextCursor(clipX0-lskip+gxTextWidthUtf(s.utfleft(pos)), clipY0+1);
254 postCurBlink();
256 if (lskip > 0) gxDrawTextOutP(clipX0, clipY0+1, arrowLeftStr, gxRGB!(0, 220, 220), gxRGB!(0, 0, 0));
257 int pxlen = gxTextWidthUtf(s);
258 if (clipX0-lskip+pxlen-1 > clipX1) gxDrawTextOutP(clipX1-1-gxTextWidthUtf(arrowRightStr)-2, clipY0+1, arrowRightStr, gxRGB!(0, 220, 220), gxRGB!(0, 0, 0));
261 void onKey (KeyEvent event) {
262 if (!event.pressed) return;
263 if (event == "Left" || event == "Pad4") { if (pos > 0) --pos; return; }
264 if (event == "Right" || event == "Pad6") { if (pos < s.utflen) ++pos; return; }
265 if (event == "Home" || event == "Pad7") { pos = 0; return; }
266 if (event == "End" || event == "Pad1") { pos = s.utflen; return; }
267 if (event == "Delete" || event == "PadDot") { if (pos < s.utflen) s = s.utfdel(pos, 1); return; }
268 if (event == "S-Insert") {
269 getClipboardText(vbwin, delegate (in char[] text) {
270 Utf8DecoderFast dc;
271 foreach (char ch; text) {
272 if (dc.decode(cast(ubyte)ch)) {
273 dchar dch = dc.codepoint;
274 if (dc.isValidDC(dch) && dch != 8) onChar(dch);
281 void onChar (dchar ch) {
282 if (ch == 8) {
283 if (pos > 0) {
284 --pos;
285 s = s.utfdel(pos, 1);
287 return;
289 if (ch < ' ' || ch == 127) return;
290 string t = s.utfleft(pos);
291 t ~= ch;
292 t ~= s.utfskip(pos);
293 if (t.length > 255) return;
294 s = t;
295 ++pos;