textlayouter: added simple and incomplete text selection tools
[iv.d.git] / egra / package.d
blobbb923137fc9efbb63b16573cb3506025ed4cee8a
1 /*
2 * Simple Framebuffer Gfx/GUI lib
4 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
5 * Understanding is not required. Only obedience.
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 module iv.egra /*is aliced*/;
21 private import arsd.simpledisplay;
23 public import iv.egra.gfx;
24 public import iv.egra.gui;
26 // so rdmd will know that we need it
27 static if (EGfxOpenGLBackend) {
28 private import iv.glbinds;
30 import iv.cmdcon;
31 import iv.cmdcongl;
32 public import iv.dynstring;
35 // ////////////////////////////////////////////////////////////////////////// //
36 // set this to `true` if you have fullscreen window
37 public __gshared bool egraSkipScreenClear = false;
38 public __gshared bool egraX11Direct = false;
40 private __gshared ubyte vbufNewScale = 1; // new window scale
41 private __gshared bool vbufVSync = false;
42 private __gshared bool vbufEffVSync = false;
44 private __gshared int lastWinWidth, lastWinHeight;
45 private __gshared bool firstTimeInited = false;
47 public class EgraDoConsoleCommandsEvent {}
48 private __gshared EgraDoConsoleCommandsEvent evDoConCommands;
50 private __gshared QuitEvent evQuitEvent;
53 public void egraPostDoConCommands () {
54 pragma(inline, true);
55 if (vbwin !is null && !vbwin.eventQueued!EgraDoConsoleCommandsEvent) vbwin.postEvent(evDoConCommands);
58 public void postQuitEvent () {
59 pragma(inline, true);
60 if (vbwin !is null && !vbwin.eventQueued!QuitEvent) vbwin.postEvent(evQuitEvent);
63 //public int egraGetScale () nothrow @trusted @nogc { pragma(inline, true); return vbufNewScale; }
66 // ////////////////////////////////////////////////////////////////////////// //
67 shared static this () {
68 evDoConCommands = new EgraDoConsoleCommandsEvent();
69 evQuitEvent = new QuitEvent();
71 conRegVar!vbufNewScale(1, 4, "v_scale", "window scale: [1..3]");
73 conRegVar!bool("v_vsync", "sync to video refresh rate?",
74 (ConVarBase self) => vbufVSync,
75 (ConVarBase self, bool nv) {
76 static if (EGfxOpenGLBackend) {
77 if (vbufVSync != nv) {
78 vbufVSync = nv;
79 postScreenRepaint();
85 vbufNewScale = cast(ubyte)screenEffScale;
86 vbufEffVSync = vbufVSync;
90 // ////////////////////////////////////////////////////////////////////////// //
91 public void egraProcessConsole () {
92 scope(exit) if (!conQueueEmpty()) egraPostDoConCommands();
93 consoleLock();
94 scope(exit) consoleUnlock();
95 conProcessQueue();
99 // ////////////////////////////////////////////////////////////////////////// //
100 public bool egraOnKey (KeyEvent event) {
101 if (vbwin is null) return false;
102 scope(exit) if (!conQueueEmpty()) egraPostDoConCommands();
103 if (vbwin.closed) return false;
104 if (isQuitRequested()) postQuitEvent();
105 if (glconKeyEvent(event)) {
106 postScreenRepaint();
107 return true;
109 if ((event.modifierState&ModifierState.numLock) == 0) {
110 switch (event.key) {
111 case Key.Pad0: event.key = Key.Insert; break;
112 case Key.Pad1: event.key = Key.End; break;
113 case Key.Pad2: event.key = Key.Down; break;
114 case Key.Pad3: event.key = Key.PageDown; break;
115 case Key.Pad4: event.key = Key.Left; break;
116 //case Key.Pad5: event.key = Key.Insert; break;
117 case Key.Pad6: event.key = Key.Right; break;
118 case Key.Pad7: event.key = Key.Home; break;
119 case Key.Pad8: event.key = Key.Up; break;
120 case Key.Pad9: event.key = Key.PageUp; break;
121 case Key.PadEnter: event.key = Key.Enter; break;
122 case Key.PadDot: event.key = Key.Delete; break;
123 default: break;
125 } else {
126 if (event.key == Key.PadEnter) event.key = Key.Enter;
128 if (dispatchEvent(event)) return true;
129 return false;
133 // ////////////////////////////////////////////////////////////////////////// //
134 public bool egraOnMouse (MouseEvent event) {
135 if (vbwin is null) return false;
136 scope(exit) if (!conQueueEmpty()) egraPostDoConCommands();
137 if (vbwin.closed) return false;
138 lastMouseXUnscaled = event.x;
139 lastMouseYUnscaled = event.y;
140 if (event.type == MouseEventType.buttonPressed) lastMouseButton |= event.button;
141 else if (event.type == MouseEventType.buttonReleased) lastMouseButton &= ~event.button;
142 egraMouseMoved();
143 if (dispatchEvent(event)) return true;
144 return false;
148 // ////////////////////////////////////////////////////////////////////////// //
149 public bool egraOnChar (dchar ch) {
150 if (vbwin is null) return false;
151 scope(exit) if (!conQueueEmpty()) egraPostDoConCommands();
152 if (vbwin.closed) return false;
153 if (glconCharEvent(ch)) {
154 postScreenRepaint();
155 return true;
157 if (dispatchEvent(ch)) return true;
158 return false;
162 // ////////////////////////////////////////////////////////////////////////// //
163 // vbwin.onFocusChange = &egraSdpyOnFocusChange;
164 public void egraSdpyOnFocusChange (bool focused) {
165 vbfocused = focused;
166 if (!focused) {
167 lastMouseButton = 0;
168 eguiLostGlobalFocus();
169 } else {
170 lastMouseButton = 0;
172 postScreenRebuild();
176 //vbwin.windowResized = &egraSdpyOnWindowResized;
177 public void egraSdpyOnWindowResized (int wdt, int hgt) {
178 // TODO: fix gui sizes
179 if (vbwin.closed) return;
181 if (lastWinWidth == wdt && lastWinHeight == hgt) return;
182 glconResize(wdt, hgt);
184 if (wdt < vbufNewScale*32) wdt = vbufNewScale;
185 if (hgt < vbufNewScale*32) hgt = vbufNewScale;
186 int newwdt = (wdt+vbufNewScale-1)/vbufNewScale;
187 int newhgt = (hgt+vbufNewScale-1)/vbufNewScale;
189 lastWinWidth = wdt;
190 lastWinHeight = hgt;
192 vglResizeBuffer(newwdt, newhgt, vbufNewScale);
194 egraMouseMoved();
196 egraRebuildScreen();
200 // return `true` to prevent backbuffer copying by sdpy
201 public bool egraX11Expose (int x, int y, int width, int height, int eventsLeft) {
202 //conwriteln("EXPOSE! x=", x, "; y=", y, "; width=", width, "; height=", height, "; eventsLeft=", eventsLeft);
203 if (eventsLeft == 0) egraRepaintScreen();
204 //return egraX11Direct;
205 return true;
209 // ////////////////////////////////////////////////////////////////////////// //
210 public SimpleWindow egraCreateSystemWindow (string wintitle, bool allowResize=false) {
211 assert(vbwin is null || vbwin.closed);
213 firstTimeInited = false;
215 static if (EGfxOpenGLBackend) {
216 vbwin = new SimpleWindow(screenWidthScaled, screenHeightScaled, wintitle, OpenGlOptions.yes, (allowResize ? Resizability.allowResizing : Resizability.fixedSize));
217 vbwin.hideCursor();
218 glconAllowOpenGLRender = true;
219 } else {
220 vbwin = new SimpleWindow(screenWidthScaled, screenHeightScaled, wintitle, OpenGlOptions.no, (allowResize ? Resizability.allowResizing : Resizability.fixedSize));
223 version(egfx_opengl_backend) {
224 } else {
225 vbwin.handleExpose = delegate (int x, int y, int width, int height, int eventsLeft) {
226 return egraX11Expose(x, y, width, height, eventsLeft);
228 XSetWindowBackground(vbwin.impl.display, vbwin.impl.window, 0);
231 vbwin.visibleForTheFirstTime = delegate () {
232 egraFirstTimeInit();
235 vbwin.addEventListener((EgraDoConsoleCommandsEvent evt) {
236 bool sendAnother = false;
237 bool prevVisible = isConsoleVisible;
239 consoleLock();
240 scope(exit) consoleUnlock();
241 conProcessQueue();
242 sendAnother = !conQueueEmpty();
244 if (sendAnother) egraPostDoConCommands();
245 if (vbwin.closed) return;
246 if (isQuitRequested()) postQuitEvent();
247 if (prevVisible || isConsoleVisible) postScreenRepaintDelayed();
250 vbwin.onFocusChange = (bool focused) { egraSdpyOnFocusChange(focused); };
252 vbwin.windowResized = (int wdt, int hgt) { egraSdpyOnWindowResized(wdt, hgt); };
254 vbwin.addEventListener((HideMouseEvent evt) {
255 if (vbwin.closed) return;
256 if (isQuitRequested()) postQuitEvent();
257 if (repostHideMouse) egraRepaintScreen();
260 vbwin.addEventListener((ScreenRebuildEvent evt) {
261 if (vbwin.closed) return;
262 if (isQuitRequested()) postQuitEvent();
263 egraRebuildScreen();
264 if (isConsoleVisible) postScreenRepaintDelayed();
267 vbwin.addEventListener((ScreenRepaintEvent evt) {
268 if (vbwin.closed) return;
269 if (isQuitRequested()) postQuitEvent();
270 egraRepaintScreen();
271 if (isConsoleVisible) postScreenRepaintDelayed();
274 vbwin.addEventListener((CursorBlinkEvent evt) {
275 if (vbwin.closed) return;
276 egraRebuildScreen();
279 vbwin.redrawOpenGlScene = delegate () {
280 if (vbwin.closed) return;
281 egraOnGLRepaint();
284 return vbwin;
288 // ////////////////////////////////////////////////////////////////////////// //
289 // call this in `vbwin.visibleForTheFirstTime()` to initialise GUI
290 // note that you cannot use EGUI with more than one window yet!
291 public void egraFirstTimeInit () {
292 if (firstTimeInited) return;
293 firstTimeInited = true;
295 vbufEffVSync = vbufVSync;
296 static if (EGfxOpenGLBackend) {
297 assert(vbwin !is null);
298 import iv.glbinds;
299 vbwin.setAsCurrentOpenGlContext();
300 vbwin.vsync = vbufEffVSync;
303 lastWinWidth = screenWidthScaled;
304 lastWinHeight = screenHeightScaled;
306 vglResizeBuffer(screenWidth, screenHeight);
307 vglCreateArrowTexture();
309 glconInit(screenWidthScaled, screenHeightScaled);
311 egraRebuildScreen();
315 // ////////////////////////////////////////////////////////////////////////// //
316 // call this from `win.redrawOpenGlScene()`
317 public void egraOnGLRepaint () {
318 pragma(inline, true);
319 egraDoRepaint(fromGLHandler:true, doRebuild:false);
323 // ////////////////////////////////////////////////////////////////////////// //
324 public void egraDoRepaint (immutable bool fromGLHandler, bool doRebuild) {
325 scope(exit) if (isQuitRequested()) postQuitEvent();
326 if (vbwin is null || vbwin.closed) return;
328 bool resizeWin = false;
331 consoleLock();
332 scope(exit) consoleUnlock();
334 if (!conQueueEmpty()) egraPostDoConCommands();
336 if (vbufNewScale != screenEffScale) {
337 // window scale changed
338 resizeWin = true;
340 if (vbufEffVSync != vbufVSync) {
341 vbufEffVSync = vbufVSync;
342 vbwin.vsync = vbufEffVSync;
346 if (resizeWin) {
347 vbwin.resize(screenWidthScaled, screenHeightScaled);
348 glconResize(screenWidthScaled, screenHeightScaled);
349 //vglResizeBuffer(screenWidth, screenHeight, vbufNewScale);
350 doRebuild = true;
353 if (doRebuild) {
354 gxClipReset();
355 if (!egraSkipScreenClear) gxClearScreen(0);
356 paintSubWindows();
357 vglUpdateTexture(); // this does nothing for X11, but required for OpenGL
360 static if (EGfxOpenGLBackend) {
361 if (!fromGLHandler) vbwin.setAsCurrentOpenGlContext();
363 scope(exit) {
364 static if (EGfxOpenGLBackend) {
365 if (!fromGLHandler) vbwin.releaseCurrentOpenGlContext();
369 static if (EGfxOpenGLBackend) {
370 vglBlitTexture();
371 } else {
372 //vglBlitTexture(vbwin, egraX11Direct);
375 if (vArrowTextureId) {
376 if (isMouseVisible) {
377 int px = lastMouseX;
378 int py = lastMouseY;
379 static if (EGfxOpenGLBackend) {
380 glColor4f(1, 1, 1, mouseAlpha);
382 vglBlitArrow(px, py);
386 static if (EGfxOpenGLBackend) {
387 glconDrawWindow = null;
388 glconDrawDirect = false;
389 glconDraw();
390 } else {
391 if (egraX11Direct) {
392 vglBlitTexture(vbwin, true);
393 glconDrawWindow = vbwin;
394 glconDrawDirect = true;
395 glconDraw();
396 glconDrawWindow = null;
397 } else {
398 auto painter = vbwin.draw();
399 vglBlitTexture(vbwin, false);
400 glconDrawWindow = vbwin;
401 glconDrawDirect = false;
402 glconDraw();
403 glconDrawWindow = null;
409 // ////////////////////////////////////////////////////////////////////////// //
410 public void egraRebuildScreen () {
411 if (vbwin !is null && !vbwin.closed && !vbwin.hidden) {
412 static if (EGfxOpenGLBackend) {
413 // rebuild
414 gxClipReset();
415 if (!egraSkipScreenClear) gxClearScreen(0);
416 paintSubWindows();
417 vglUpdateTexture(); // this does nothing for X11, but required for OpenGL
418 // and redraw
419 vbwin.redrawOpenGlSceneNow();
420 } else {
421 egraDoRepaint(fromGLHandler:false, doRebuild:true);
427 // ////////////////////////////////////////////////////////////////////////// //
428 public void egraRepaintScreen () {
429 __gshared bool lastvisible = false;
430 if (vbwin !is null && !vbwin.closed && !vbwin.hidden) {
431 bool curvisible = isConsoleVisible;
432 if (lastvisible != curvisible || curvisible) {
433 lastvisible = curvisible;
434 egraRebuildScreen();
435 return;
437 static if (EGfxOpenGLBackend) {
438 vbwin.redrawOpenGlSceneNow();
439 } else {
440 egraDoRepaint(fromGLHandler:false, doRebuild:false);