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/>.
21 import arsd
.simpledisplay
;
28 version = egfx_more_backbuffers
;
31 // ////////////////////////////////////////////////////////////////////////// //
32 public class EWindow
{
37 int mActiveWidget
= -1;
40 this (int awidth
, int aheight
) {
41 if (awidth
< 1) awidth
= 1;
42 if (aheight
< 1) aheight
= 1;
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;
57 EWidget
addWidget (EWidget w
) {
58 if (w
is null) return null;
59 if (w
.parent
!is null) throw new Exception("widget already owned");
69 glconPostScreenRebuild();
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) {
91 if (oaw
!is null) oaw
.onDeactivate();
94 foreach (immutable idx
, EWidget ww
; widgets
) {
96 if (mActiveWidget
== idx
) return;
97 mActiveWidget
= cast(int)idx
;
98 if (oaw
!is null) oaw
.onDeactivate();
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
;
114 protected void paintWidgets () {
115 foreach (EWidget w
; widgets
) {
121 protected void paintBackground () {}
122 protected void 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;
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;
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
;
162 if (aw
.onMouse(event
)) return true;
165 if (auto ww
= widgetAt(event
.x
, event
.y
)) {
167 if (ww
.onMouse(event
)) return true;
171 if (onMousePost(event
)) return true;
172 if (wasAwOrAct
&& event
.type
!= MouseEventType
.motion
) return true;
178 // ////////////////////////////////////////////////////////////////////////// //
179 public class EWidget
{
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; }
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);
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
) {
243 if (mainwin
is win
) return;
244 static if (is(typeof(&mainwin
.closeQuery
))) {
245 if (mainwin
!is null) mainwin
.closeQuery
= null;
248 static if (is(typeof(&mainwin
.closeQuery
))) {
249 mainwin
.closeQuery
= delegate () { concmd("quit"); glconPostDoConCommands(); };
251 glconBackBuffer
= win
.backbuf
;
253 glconBackBuffer
= null;
258 // ////////////////////////////////////////////////////////////////////////// //
259 public class EgfxWindow
: SimpleWindow
{
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
;
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
);
285 backbuf
= new Image(minw
, minh
);
289 private void freeBackBuffer () {
290 version(egfx_more_backbuffers
) {
291 if (egxBackBuf
!is null) {
292 import core
.stdc
.stdlib
: free
;
299 version(egfx_more_backbuffers
) ~this () { freeBackBuffer(); }
301 override void close () {
307 if (closed || backbuf
is null) return;
309 auto saveVBufWidth
= VBufWidth
;
310 auto saveVBufHeight
= VBufHeight
;
311 auto savevglTexBuf
= vglTexBuf
;
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
;
329 vglTexBuf
= cast(uint*)backbuf
.getDataPointer
;
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; }
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;
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; }
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
) {
378 backbuf
= new Image(wdt
, hgt
);
379 if (mainwin
is this) glconBackBuffer
= this.backbuf
;
385 //glconPostScreenRebuild();
388 onFocusChange
= delegate (bool focused
) { ampw
.active
= focused
; };