cosmetix
[amper.git] / egfx / backx.d
blob57e404350cd3411b91087ff9dc77fb579b6c8298
1 /* E-Mail Client
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 egfx.backx;
19 private:
21 import arsd.simpledisplay;
23 import iv.cmdcon;
24 import iv.cmdcongl;
26 import egfx.base;
28 version = egfx_more_backbuffers;
31 // ////////////////////////////////////////////////////////////////////////// //
32 public class EWindow {
33 protected:
34 int mWidth, mHeight;
35 bool mActive;
36 EWidget[] widgets;
37 int mActiveWidget = -1;
39 public:
40 this (int awidth, int aheight) {
41 if (awidth < 1) awidth = 1;
42 if (aheight < 1) aheight = 1;
43 mWidth = awidth;
44 mHeight = aheight;
47 final @property int width () const pure nothrow @safe @nogc { pragma(inline, true); return mWidth; }
48 final @property int height () const pure nothrow @safe @nogc { pragma(inline, true); return mHeight; }
50 void setSize (int awdt, int ahgt) {
51 if (awdt < 1) awdt = 1;
52 if (ahgt < 1) ahgt = 1;
53 mWidth = awdt;
54 mHeight = ahgt;
57 EWidget addWidget (EWidget w) {
58 if (w is null) return null;
59 if (w.parent !is null) throw new Exception("widget already owned");
60 widgets ~= w;
61 w.parent = this;
62 return w;
65 void defocused () {
66 if (mActive) {
67 activeWidget = null;
68 mActive = false;
69 glconPostScreenRebuild();
73 void focused () {
74 if (!active) {
75 mActive = true;
76 glconPostScreenRebuild();
80 final void focusChanged (bool focused) { if (focused) this.focused(); else this.defocused(); }
82 final @property bool active () const pure nothrow @safe @nogc { pragma(inline, true); return mActive; }
83 final @property void active (bool v) { if (mActive == v) return; if (v) focused(); else defocused(); }
85 final @property EWidget activeWidget () pure nothrow @safe @nogc { pragma(inline, true); return (mActiveWidget >= 0 && mActiveWidget < widgets.length ? widgets[mActiveWidget] : null); }
87 final @property void activeWidget (EWidget w) {
88 EWidget oaw = (mActiveWidget >= 0 && mActiveWidget < widgets.length ? widgets[mActiveWidget] : null);
89 if (w is null || w.parent !is this) {
90 mActiveWidget = -1;
91 if (oaw !is null) oaw.onDeactivate();
92 return;
94 foreach (immutable idx, EWidget ww; widgets) {
95 if (ww is w) {
96 if (mActiveWidget == idx) return;
97 mActiveWidget = cast(int)idx;
98 if (oaw !is null) oaw.onDeactivate();
99 ww.onActivate();
100 return;
103 mActiveWidget = -1;
104 if (oaw !is null) oaw.onDeactivate();
107 final EWidget widgetAt (int x, int y) pure nothrow @safe @nogc {
108 foreach_reverse (EWidget w; widgets) {
109 if (w.rc.inside(x, y)) return w;
111 return null;
114 protected void paintWidgets () {
115 foreach (EWidget w; widgets) {
116 gxClipRect = w.rc;
117 w.onPaint();
121 protected void paintBackground () {}
122 protected void paintFinished () {}
124 void onPaint () {
125 paintBackground();
126 paintWidgets();
127 paintFinished();
130 bool onKeyPre (KeyEvent event) { return false; }
131 bool onKeyPost (KeyEvent event) { return false; }
133 bool onKey (KeyEvent event) {
134 if (onKeyPre(event)) return true;
135 if (auto aw = activeWidget) {
136 if (aw.onKey(event)) return true;
138 if (onKeyPost(event)) return true;
139 return false;
142 bool onCharPre (dchar ch) { return false; }
143 bool onCharPost (dchar ch) { return false; }
145 bool onChar (dchar ch) {
146 if (onCharPre(ch)) return true;
147 if (auto aw = activeWidget) {
148 if (aw.onChar(ch)) return true;
150 if (onCharPost(ch)) return true;
151 return false;
154 bool onMousePre (MouseEvent event) { return false; }
155 bool onMousePost (MouseEvent event) { return false; }
157 bool onMouse (MouseEvent event) {
158 bool wasAwOrAct = false;
159 if (onMousePre(event)) return true;
160 auto aw = activeWidget;
161 if (aw !is null) {
162 if (aw.onMouse(event)) return true;
163 wasAwOrAct = true;
165 if (auto ww = widgetAt(event.x, event.y)) {
166 if (ww !is aw) {
167 if (ww.onMouse(event)) return true;
168 wasAwOrAct = true;
171 if (onMousePost(event)) return true;
172 if (wasAwOrAct && event.type != MouseEventType.motion) return true;
173 return false;
178 // ////////////////////////////////////////////////////////////////////////// //
179 public class EWidget {
180 EWindow parent;
181 GxRect rc;
183 this (GxRect arc) {
184 rc = arc;
187 final @property bool active () nothrow @trusted @nogc { pragma(inline, true); return (parent !is null && parent.activeWidget is this); }
188 final @property void active (bool v) { pragma(inline, true); if (parent !is null) parent.activeWidget = this; }
190 void onPaint () {}
192 void onActivate () {} // parent.activeWidget is this
193 void onDeactivate () {} // parent.activeWidget already changed
195 bool onKey (KeyEvent event) { return false; }
196 bool onChar (dchar ch) { return false; }
197 bool onMouse (MouseEvent event) { return false; }
201 // ////////////////////////////////////////////////////////////////////////// //
202 shared static this () {
203 import core.stdc.stdlib : malloc;
204 vglTexBuf = cast(uint*)malloc((VBufWidth*VBufHeight+4)*4);
205 if (vglTexBuf is null) assert(0, "out of memory!");
206 vglTexBuf[0..VBufWidth*VBufHeight] = 0;
210 // ////////////////////////////////////////////////////////////////////////// //
211 // resize buffer, reinitialize OpenGL texture
213 public void egxResizeBuffer (int wdt, int hgt, int ascale=1) {
214 if (wdt < 1) wdt = 1;
215 if (hgt < 1) hgt = 1;
217 if (wdt > 8192) wdt = 8192;
218 if (hgt > 8192) hgt = 8192;
220 bool sizeChanged = (wdt != VBufWidth || hgt != VBufHeight);
221 VBufWidth = wdt;
222 VBufHeight = hgt;
224 if (vglTexBuf is null || sizeChanged) {
225 import core.stdc.stdlib : realloc;
226 vglTexBuf = cast(uint*)realloc(vglTexBuf, (VBufWidth*VBufHeight+4)*vglTexBuf[0].sizeof);
227 if (vglTexBuf is null) assert(0, "out of memory!");
228 vglTexBuf[0..VBufWidth*VBufHeight] = 0;
231 if (ascale < 1) ascale = 1;
232 if (ascale > 32) ascale = 32;
233 vbufEffScale = cast(ubyte)ascale;
238 // ////////////////////////////////////////////////////////////////////////// //
239 __gshared EgfxWindow mainwin;
241 public void egfxSetMainWindow (EgfxWindow win) {
242 if (win !is null) {
243 if (mainwin is win) return;
244 static if (is(typeof(&mainwin.closeQuery))) {
245 if (mainwin !is null) mainwin.closeQuery = null;
247 mainwin = win;
248 static if (is(typeof(&mainwin.closeQuery))) {
249 mainwin.closeQuery = delegate () { concmd("quit"); glconPostDoConCommands(); };
251 glconBackBuffer = win.backbuf;
252 } else {
253 glconBackBuffer = null;
258 // ////////////////////////////////////////////////////////////////////////// //
259 public class EgfxWindow : SimpleWindow {
260 EWindow ampw;
261 Image backbuf;
262 version(egfx_more_backbuffers) uint* egxBackBuf;
264 // minsize will be taken from aampw
265 // if resizestep is zero, size on that dimension is fixed
266 this (EWindow aampw, string winclass, string title, int resizeXStep=0, int resizeYStep=0) {
267 if (aampw is null) assert(0, "wtf?! no EWindow!");
268 if (winclass.length) sdpyWindowClass = winclass;
269 ampw = aampw;
270 int minw = aampw.width;
271 int maxw = aampw.width;
272 int minh = aampw.height;
273 int maxh = aampw.height;
274 super(minw, minh, title, OpenGlOptions.no, Resizability.allowResizing, WindowTypes.undecorated);
275 if (resizeXStep > 0) maxw = 4096;
276 if (resizeYStep > 0) maxh = 4096;
277 setMinSize(minw, minh);
278 setMaxSize(maxw, maxh);
279 if (resizeXStep > 0 || resizeYStep > 0) {
280 if (resizeXStep <= 0) resizeXStep = 1;
281 if (resizeYStep <= 0) resizeYStep = 1;
282 setResizeGranularity(resizeXStep, resizeYStep);
284 ampw = aampw;
285 backbuf = new Image(minw, minh);
286 setupHandlers();
289 private void freeBackBuffer () {
290 version(egfx_more_backbuffers) {
291 if (egxBackBuf !is null) {
292 import core.stdc.stdlib : free;
293 free(egxBackBuf);
294 egxBackBuf = null;
299 version(egfx_more_backbuffers) ~this () { freeBackBuffer(); }
301 override void close () {
302 freeBackBuffer();
303 super.close();
306 void redraw () {
307 if (closed || backbuf is null) return;
309 auto saveVBufWidth = VBufWidth;
310 auto saveVBufHeight = VBufHeight;
311 auto savevglTexBuf = vglTexBuf;
312 scope(exit) {
313 VBufWidth = saveVBufWidth;
314 VBufHeight = saveVBufHeight;
315 vglTexBuf = savevglTexBuf;
317 //conwriteln("backbuf size: (", backbuf.width, "x", backbuf.height, ")");
318 VBufWidth = backbuf.width;
319 VBufHeight = backbuf.height;
320 version(egfx_more_backbuffers) {
321 if (egxBackBuf is null) {
322 import core.stdc.stdlib : realloc;
323 egxBackBuf = cast(uint*)realloc(egxBackBuf, (VBufWidth*VBufHeight+4)*egxBackBuf[0].sizeof);
324 if (egxBackBuf is null) assert(0, "out of memory!");
325 egxBackBuf[0..VBufWidth*VBufHeight] = 0;
327 vglTexBuf = egxBackBuf;
328 } else {
329 vglTexBuf = cast(uint*)backbuf.getDataPointer;
331 ampw.onPaint();
332 version(egfx_more_backbuffers) {
333 import core.stdc.string;
334 memcpy(backbuf.getDataPointer, vglTexBuf, VBufWidth*VBufHeight*4);
337 if (mainwin is this) glconDraw();
339 auto painter = this.draw();
340 painter.drawImage(Point(0, 0), backbuf);
344 protected void setupHandlers () {
345 handleKeyEvent = delegate (KeyEvent event) {
346 scope(exit) if (!conQueueEmpty()) glconPostDoConCommands();
347 if (mainwin is this && glconKeyEvent(event)) { glconPostScreenRepaint(); return; }
348 if (isQuitRequested) { close(); return; }
349 ampw.onKey(event);
350 glconPostScreenRebuild();
353 handleMouseEvent = delegate (MouseEvent event) {
354 scope(exit) if (!conQueueEmpty()) glconPostDoConCommands();
355 if (isQuitRequested) { close(); return; }
356 //event.x /= vbufEffScale;
357 //event.y /= vbufEffScale;
358 ampw.onMouse(event);
359 glconPostScreenRebuild();
362 handleCharEvent = delegate (dchar ch) {
363 scope(exit) if (!conQueueEmpty()) glconPostDoConCommands();
364 if (mainwin is this && glconCharEvent(ch)) { glconPostScreenRepaint(); return; }
365 if (isQuitRequested) { close(); return; }
366 ampw.onChar(ch);
367 glconPostScreenRebuild();
370 windowResized = delegate (int wdt, int hgt) {
371 scope(exit) if (!conQueueEmpty()) glconPostDoConCommands();
372 if (isQuitRequested) { close(); return; }
373 if (wdt < 1) wdt = 1;
374 if (hgt < 1) hgt = 1;
375 if (mainwin is this) glconResize(wdt, hgt);
376 if (backbuf.width != wdt || backbuf.height != hgt) {
377 //delete backbuf;
378 backbuf = new Image(wdt, hgt);
379 if (mainwin is this) glconBackBuffer = this.backbuf;
380 freeBackBuffer();
382 ampw.mWidth = wdt;
383 ampw.mHeight = hgt;
384 redraw();
385 //glconPostScreenRebuild();
388 onFocusChange = delegate (bool focused) { ampw.active = focused; };