1 /* coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
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/>.
20 import arsd
.simpledisplay
;
27 version = egfx_more_backbuffers
;
30 // ////////////////////////////////////////////////////////////////////////// //
31 public class EWindow
{
36 int mActiveWidget
= -1;
39 this (int awidth
, int aheight
) {
40 if (awidth
< 1) awidth
= 1;
41 if (aheight
< 1) aheight
= 1;
46 final @property int width () const pure nothrow @safe @nogc { pragma(inline
, true); return mWidth
; }
47 final @property int height () const pure nothrow @safe @nogc { pragma(inline
, true); return mHeight
; }
49 void setSize (int awdt
, int ahgt
) {
50 if (awdt
< 1) awdt
= 1;
51 if (ahgt
< 1) ahgt
= 1;
56 EWidget
addWidget (EWidget w
) {
57 if (w
is null) return null;
58 if (w
.parent
!is null) throw new Exception("widget already owned");
68 glconPostScreenRebuild();
75 glconPostScreenRebuild();
79 final void focusChanged (bool focused
) { if (focused
) this.focused(); else this.defocused(); }
81 final @property bool active () const pure nothrow @safe @nogc { pragma(inline
, true); return mActive
; }
82 final @property void active (bool v
) { if (mActive
== v
) return; if (v
) focused(); else defocused(); }
84 final @property EWidget
activeWidget () pure nothrow @safe @nogc { pragma(inline
, true); return (mActiveWidget
>= 0 && mActiveWidget
< widgets
.length ? widgets
[mActiveWidget
] : null); }
86 final @property void activeWidget (EWidget w
) {
87 EWidget oaw
= (mActiveWidget
>= 0 && mActiveWidget
< widgets
.length ? widgets
[mActiveWidget
] : null);
88 if (w
is null || w
.parent
!is this) {
90 if (oaw
!is null) oaw
.onDeactivate();
93 foreach (immutable idx
, EWidget ww
; widgets
) {
95 if (mActiveWidget
== idx
) return;
96 mActiveWidget
= cast(int)idx
;
97 if (oaw
!is null) oaw
.onDeactivate();
103 if (oaw
!is null) oaw
.onDeactivate();
106 final EWidget
widgetAt (int x
, int y
) pure nothrow @safe @nogc {
107 foreach_reverse (EWidget w
; widgets
) {
108 if (w
.rc
.inside(x
, y
)) return w
;
113 protected void paintWidgets () {
114 foreach (EWidget w
; widgets
) {
120 protected void paintBackground () {}
121 protected void paintFinished () {}
131 bool onKeyPre (KeyEvent event
) { return false; }
132 bool onKeyPost (KeyEvent event
) { return false; }
134 bool onKey (KeyEvent event
) {
135 if (onKeyPre(event
)) return true;
136 if (auto aw
= activeWidget
) {
137 if (aw
.onKey(event
)) return true;
139 if (onKeyPost(event
)) return true;
143 bool onCharPre (dchar ch
) { return false; }
144 bool onCharPost (dchar ch
) { return false; }
146 bool onChar (dchar ch
) {
147 if (onCharPre(ch
)) return true;
148 if (auto aw
= activeWidget
) {
149 if (aw
.onChar(ch
)) return true;
151 if (onCharPost(ch
)) return true;
155 bool onMousePre (MouseEvent event
) { return false; }
156 bool onMousePost (MouseEvent event
) { return false; }
158 bool onMouse (MouseEvent event
) {
159 bool wasAwOrAct
= false;
160 if (onMousePre(event
)) return true;
161 auto aw
= activeWidget
;
163 if (aw
.onMouse(event
)) return true;
166 if (auto ww
= widgetAt(event
.x
, event
.y
)) {
168 if (ww
.onMouse(event
)) return true;
172 if (onMousePost(event
)) return true;
173 if (wasAwOrAct
&& event
.type
!= MouseEventType
.motion
) return true;
179 // ////////////////////////////////////////////////////////////////////////// //
180 public class EWidget
{
188 final @property bool active () nothrow @trusted @nogc { pragma(inline
, true); return (parent
!is null && parent
.activeWidget
is this); }
189 final @property void active (bool v
) { pragma(inline
, true); if (parent
!is null) parent
.activeWidget
= this; }
193 void onActivate () {} // parent.activeWidget is this
194 void onDeactivate () {} // parent.activeWidget already changed
196 bool onKey (KeyEvent event
) { return false; }
197 bool onChar (dchar ch
) { return false; }
198 bool onMouse (MouseEvent event
) { return false; }
202 // ////////////////////////////////////////////////////////////////////////// //
203 shared static this () {
204 import core
.stdc
.stdlib
: malloc
;
205 vglTexBuf
= cast(uint*)malloc((VBufWidth
*VBufHeight
+4)*4);
206 if (vglTexBuf
is null) assert(0, "out of memory!");
207 vglTexBuf
[0..VBufWidth
*VBufHeight
] = 0;
211 // ////////////////////////////////////////////////////////////////////////// //
212 // resize buffer, reinitialize OpenGL texture
214 public void egxResizeBuffer (int wdt, int hgt, int ascale=1) {
215 if (wdt < 1) wdt = 1;
216 if (hgt < 1) hgt = 1;
218 if (wdt > 8192) wdt = 8192;
219 if (hgt > 8192) hgt = 8192;
221 bool sizeChanged = (wdt != VBufWidth || hgt != VBufHeight);
225 if (vglTexBuf is null || sizeChanged) {
226 import core.stdc.stdlib : realloc;
227 vglTexBuf = cast(uint*)realloc(vglTexBuf, (VBufWidth*VBufHeight+4)*vglTexBuf[0].sizeof);
228 if (vglTexBuf is null) assert(0, "out of memory!");
229 vglTexBuf[0..VBufWidth*VBufHeight] = 0;
232 if (ascale < 1) ascale = 1;
233 if (ascale > 32) ascale = 32;
234 vbufEffScale = cast(ubyte)ascale;
239 // ////////////////////////////////////////////////////////////////////////// //
240 __gshared EgfxWindow mainwin
;
242 public void egfxSetMainWindow (EgfxWindow win
) {
244 if (mainwin
is win
) return;
245 static if (is(typeof(&mainwin
.closeQuery
))) {
246 if (mainwin
!is null) mainwin
.closeQuery
= null;
249 static if (is(typeof(&mainwin
.closeQuery
))) {
250 mainwin
.closeQuery
= delegate () { concmd("quit"); glconPostDoConCommands(); };
252 glconBackBuffer
= win
.backbuf
;
254 glconBackBuffer
= null;
259 // ////////////////////////////////////////////////////////////////////////// //
260 public class EgfxWindow
: SimpleWindow
{
263 version(egfx_more_backbuffers
) uint* egxBackBuf
;
265 // minsize will be taken from aampw
266 // if resizestep is zero, size on that dimension is fixed
267 this (EWindow aampw
, string winclass
, string title
, int resizeXStep
=0, int resizeYStep
=0) {
268 if (aampw
is null) assert(0, "wtf?! no EWindow!");
269 if (winclass
.length
) sdpyWindowClass
= winclass
;
271 int minw
= aampw
.width
;
272 int maxw
= aampw
.width
;
273 int minh
= aampw
.height
;
274 int maxh
= aampw
.height
;
275 super(minw
, minh
, title
, OpenGlOptions
.no
, Resizability
.allowResizing
, WindowTypes
.undecorated
);
276 if (resizeXStep
> 0) maxw
= 4096;
277 if (resizeYStep
> 0) maxh
= 4096;
278 setMinSize(minw
, minh
);
279 setMaxSize(maxw
, maxh
);
280 if (resizeXStep
> 0 || resizeYStep
> 0) {
281 if (resizeXStep
<= 0) resizeXStep
= 1;
282 if (resizeYStep
<= 0) resizeYStep
= 1;
283 setResizeGranularity(resizeXStep
, resizeYStep
);
286 backbuf
= new Image(minw
, minh
);
290 private void freeBackBuffer () {
291 version(egfx_more_backbuffers
) {
292 if (egxBackBuf
!is null) {
293 import core
.stdc
.stdlib
: free
;
300 version(egfx_more_backbuffers
) ~this () { freeBackBuffer(); }
302 override void close () {
308 if (closed || backbuf
is null) return;
310 auto saveVBufWidth
= VBufWidth
;
311 auto saveVBufHeight
= VBufHeight
;
312 auto savevglTexBuf
= vglTexBuf
;
314 VBufWidth
= saveVBufWidth
;
315 VBufHeight
= saveVBufHeight
;
316 vglTexBuf
= savevglTexBuf
;
318 //conwriteln("backbuf size: (", backbuf.width, "x", backbuf.height, ")");
319 VBufWidth
= backbuf
.width
;
320 VBufHeight
= backbuf
.height
;
321 version(egfx_more_backbuffers
) {
322 if (egxBackBuf
is null) {
323 import core
.stdc
.stdlib
: realloc
;
324 egxBackBuf
= cast(uint*)realloc(egxBackBuf
, (VBufWidth
*VBufHeight
+4)*egxBackBuf
[0].sizeof
);
325 if (egxBackBuf
is null) assert(0, "out of memory!");
326 egxBackBuf
[0..VBufWidth
*VBufHeight
] = 0;
328 vglTexBuf
= egxBackBuf
;
330 vglTexBuf
= cast(uint*)backbuf
.getDataPointer
;
334 version(egfx_more_backbuffers
) {
335 import core
.stdc
.string
;
336 memcpy(backbuf
.getDataPointer
, vglTexBuf
, VBufWidth
*VBufHeight
*4);
339 if (mainwin
is this) glconDraw();
341 auto painter
= this.draw();
342 painter
.drawImage(Point(0, 0), backbuf
);
346 protected void setupHandlers () {
347 handleKeyEvent
= delegate (KeyEvent event
) {
348 scope(exit
) if (!conQueueEmpty()) glconPostDoConCommands();
349 if (mainwin
is this && glconKeyEvent(event
)) { glconPostScreenRepaint(); return; }
350 if (isQuitRequested
) { close(); return; }
351 if ((event
.modifierState
&ModifierState
.numLock
) == 0) {
353 case Key
.Pad0
: event
.key
= Key
.Insert
; break;
354 case Key
.Pad1
: event
.key
= Key
.End
; break;
355 case Key
.Pad2
: event
.key
= Key
.Down
; break;
356 case Key
.Pad3
: event
.key
= Key
.PageDown
; break;
357 case Key
.Pad4
: event
.key
= Key
.Left
; break;
358 //case Key.Pad5: event.key = Key.Insert; break;
359 case Key
.Pad6
: event
.key
= Key
.Right
; break;
360 case Key
.Pad7
: event
.key
= Key
.Home
; break;
361 case Key
.Pad8
: event
.key
= Key
.Up
; break;
362 case Key
.Pad9
: event
.key
= Key
.PageUp
; break;
363 case Key
.PadEnter
: event
.key
= Key
.Enter
; break;
364 case Key
.PadDot
: event
.key
= Key
.Delete
; break;
368 if (event
.key
== Key
.PadEnter
) event
.key
= Key
.Enter
;
371 glconPostScreenRebuild();
374 handleMouseEvent
= delegate (MouseEvent event
) {
375 scope(exit
) if (!conQueueEmpty()) glconPostDoConCommands();
376 if (isQuitRequested
) { close(); return; }
377 //event.x /= vbufEffScale;
378 //event.y /= vbufEffScale;
380 glconPostScreenRebuild();
383 handleCharEvent
= delegate (dchar ch
) {
384 scope(exit
) if (!conQueueEmpty()) glconPostDoConCommands();
385 if (mainwin
is this && glconCharEvent(ch
)) { glconPostScreenRepaint(); return; }
386 if (isQuitRequested
) { close(); return; }
388 glconPostScreenRebuild();
391 windowResized
= delegate (int wdt
, int hgt
) {
392 scope(exit
) if (!conQueueEmpty()) glconPostDoConCommands();
393 if (isQuitRequested
) { close(); return; }
394 if (wdt
< 1) wdt
= 1;
395 if (hgt
< 1) hgt
= 1;
396 if (mainwin
is this) glconResize(wdt
, hgt
);
397 if (backbuf
.width
!= wdt || backbuf
.height
!= hgt
) {
399 backbuf
= new Image(wdt
, hgt
);
400 if (mainwin
is this) glconBackBuffer
= this.backbuf
;
406 //glconPostScreenRebuild();
409 onFocusChange
= delegate (bool focused
) { ampw
.active
= focused
; };