don't center cursor on message tree rebuild
[knntp.git] / egui.d
blob9427c532a24851696a0a33f710ff626e55344fc7
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 {}
50 __gshared ScreenUpdateEvent evScrReady;
51 __gshared ScreenRepaintEvent evScreenRepaint;
52 __gshared HideMouseEvent evHideMouse;
53 __gshared DoConsoleCommandsEvent evDoConCommands;
56 shared static this () {
57 evScrReady = new ScreenUpdateEvent();
58 evScreenRepaint = new ScreenRepaintEvent();
59 evHideMouse = new HideMouseEvent();
60 evDoConCommands = new DoConsoleCommandsEvent();
64 // ////////////////////////////////////////////////////////////////////////// //
65 public void postScreenUpdate () {
66 if (vbwin !is null && !vbwin.eventQueued!ScreenUpdateEvent) vbwin.postEvent(evScrReady);
69 public void postScreenRepaint () {
70 if (vbwin !is null && !vbwin.eventQueued!ScreenRepaintEvent && !vbwin.eventQueued!ScreenUpdateEvent) vbwin.postEvent(evScreenRepaint);
73 public void postDoConCommands () {
74 if (vbwin !is null && !vbwin.eventQueued!DoConsoleCommandsEvent) vbwin.postEvent(evDoConCommands);
78 // ////////////////////////////////////////////////////////////////////////// //
79 __gshared MonoTime lastMouseMove;
80 enum MouseHideTime = 1000;
83 public bool isMouseVisible () {
84 auto ctt = MonoTime.currTime;
85 return ((ctt-lastMouseMove).total!"msecs" < MouseHideTime);
89 // returns `false` if there is no need to repost the event, and the mouse should be hidden
90 public bool repostHideMouse () {
91 if (vbwin is null || vbwin.eventQueued!HideMouseEvent) return false;
92 auto ctt = MonoTime.currTime;
93 auto tms = (ctt-lastMouseMove).total!"msecs";
94 if (tms >= MouseHideTime) return false;
95 vbwin.postTimeout(evHideMouse, MouseHideTime);
96 return true;
100 public void mouseMoved () {
101 lastMouseMove = MonoTime.currTime;
102 if (vbwin !is null && !vbwin.eventQueued!HideMouseEvent) vbwin.postTimeout(evHideMouse, MouseHideTime);
106 // ////////////////////////////////////////////////////////////////////////// //
107 public __gshared SubWindow[] subwins;
108 public __gshared bool ignoreSubWinChar = false;
111 public abstract class SubWindow {
112 public:
113 bool immuneToLock = false;
114 int winx, winy, winw, winh;
115 bool closed = false;
117 public:
118 this (int ax, int ay, int aw, int ah) {
119 winx = ax;
120 winy = ay;
121 winw = aw;
122 winh = ah;
125 this (int aw, int ah) {
126 winx = (VBufWidth-aw)/2;
127 winy = (VBufHeight-ah)/2;
128 winw = aw;
129 winh = ah;
132 void onPaint ();
133 void onKey (KeyEvent event);
134 void onMouse (MouseEvent event);
135 void onChar (dchar ch);
137 final void setupClip () {
138 clipReset();
139 clipX0 = winx;
140 clipX1 = winx+winw-1;
141 clipY0 = winy;
142 clipY1 = winy+winh-1;
145 final void setupClientClip () {
146 setupClip();
147 clipX0 += 2;
148 clipX1 -= 2;
149 clipY0 += 12;
150 clipY1 -= 2;
153 void close () {
154 if (closed) return;
155 closed = true;
156 import std.algorithm : remove;
157 foreach (immutable idx, SubWindow w; subwins) {
158 if (w is this) {
159 subwins = subwins.remove(idx);
160 if (!vbwin.eventQueued!(typeof(evScrReady))) vbwin.postEvent(evScrReady);
161 return;
166 void add (bool fromKeyboard=true) {
167 if (fromKeyboard) ignoreSubWinChar = true;
168 foreach (immutable idx, SubWindow w; subwins) {
169 if (w is this) {
170 if (idx != subwins.length-1) {
171 import std.algorithm : remove;
172 subwins = subwins.remove(idx);
173 subwins ~= this;
175 if (!vbwin.eventQueued!(typeof(evScrReady))) vbwin.postEvent(evScrReady);
176 return;
179 subwins ~= this;
180 if (!vbwin.eventQueued!(typeof(evScrReady))) vbwin.postEvent(evScrReady);
185 // ////////////////////////////////////////////////////////////////////////// //
186 // setup cliprect first
187 public final class LineEdit {
188 private:
189 int pos;
190 int lskip;
191 string s;
193 public:
194 bool active;
196 public:
197 this () {}
199 @property string str () const pure nothrow @safe @nogc { return s; }
200 @property void str (string ns) nothrow @safe @nogc { s = ns; pos = s.utflen; }
202 void makeCursorVisible () {
203 int w = clipWidth-2;
204 if (w < 6*3) w = 6*3;
205 int tw = gxTextWidthUtf(s);
206 if (tw < w) { lskip = 0; return; }
207 if (lskip > tw-w) lskip = tw-w;
208 // left
209 int px = gxTextWidthUtf(s.utfleft(pos));
210 if (px < lskip) lskip = px-6;
211 if (lskip < 0) lskip = 0;
212 // right
213 int vx = px-lskip;
214 if (px >= w) lskip = px-(w-6);
215 if (lskip < 0) lskip = 0;
218 void onPaint () {
219 makeCursorVisible();
220 gxFillRect(clipX0, clipY0, clipWidth, 10, gxRGB!(0, 0, 0));
221 clipX0 += 2;
222 clipX1 -= 2;
223 gxDrawTextUtf(clipX0-lskip, clipY0+1, s, (active ? gxRGB!(220, 220, 80) : gxRGB!(220, 220, 0)));
224 if (active) gxVLine(clipX0-lskip+gxTextWidthUtf(s.utfleft(pos)), clipY0+1, gxTextHeightUtf, gxRGB!(255, 255, 255));
225 if (lskip > 0) gxDrawTextOutP(clipX0+1, clipY0+1, "\x1b", gxRGB!(0, 220, 220), gxRGB!(0, 0, 0));
226 int pxlen = gxTextWidthUtf(s);
227 if (clipX0-lskip+pxlen-1 > clipX1) gxDrawTextOutP(clipX1-6, clipY0+1, "\x1a", gxRGB!(0, 220, 220), gxRGB!(0, 0, 0));
230 void onKey (KeyEvent event) {
231 if (!event.pressed) return;
232 if (event == "Left" || event == "Pad4") { if (pos > 0) --pos; return; }
233 if (event == "Right" || event == "Pad6") { if (pos < s.utflen) ++pos; return; }
234 if (event == "Home" || event == "Pad7") { pos = 0; return; }
235 if (event == "End" || event == "Pad1") { pos = s.utflen; return; }
236 if (event == "Delete" || event == "PadDot") { if (pos < s.utflen) s = s.utfdel(pos, 1); return; }
237 if (event == "S-Insert") {
238 getClipboardText(vbwin, delegate (in char[] text) {
239 Utf8DecoderFast dc;
240 foreach (char ch; text) {
241 if (dc.decode(cast(ubyte)ch)) {
242 dchar dch = dc.codepoint;
243 if (dc.isValidDC(dch) && dch != 8) onChar(dch);
250 void onChar (dchar ch) {
251 if (ch == 8) {
252 if (pos > 0) {
253 --pos;
254 s = s.utfdel(pos, 1);
256 return;
258 if (ch < ' ' || ch == 127) return;
259 string t = s.utfleft(pos);
260 t ~= ch;
261 t ~= s.utfskip(pos);
262 if (t.length > 255) return;
263 s = t;
264 ++pos;