4 import arsd
.simpledisplay
;
12 //version = use_framebuffer;
15 // ////////////////////////////////////////////////////////////////////////// //
16 uint c2i (uint v
) pure nothrow @safe @nogc { pragma(inline
, true); return (v
&0xff_00ff00u)|
((v
>>16)&0x00_0000ffu)|
((v
<<16)&0x00_ff
0000u); }
19 // ////////////////////////////////////////////////////////////////////////// //
20 public class BmpWindow
: SimpleWindow
{
25 int pximgwdt
, pximghgt
, pximgscl
;
28 int rcx0
, rcy0
, rcx1
, rcy1
;
32 int dragxofs
, dragyofs
;
35 // minsize will be taken from aampw
36 // if resizestep is zero, size on that dimension is fixed
37 this (MemoryImage aimg
) {
38 if (aimg
is null) assert(0, "wtf?!");
39 img
= aimg
.getAsTrueColorImage
;
40 sdpyWindowClass
= "BMPVIEW_WINDOW";
41 super(img
.width
, img
.height
, "Bitmap Viewer", OpenGlOptions
.no
, Resizability
.allowResizing
);
42 setMinSize(img
.width
, img
.height
);
44 //backbuf = new Image(img.width*scale, img.height*scale);
45 //glconBackBuffer = this.backbuf;
47 glconCtlWindow
= this;
48 //glconResize(img.width, img.height);
49 glconCtlWindow
.addEventListener((GLConScreenRebuildEvent evt
) { redraw(true); });
50 glconCtlWindow
.addEventListener((GLConScreenRepaintEvent evt
) { redraw(false); });
53 final @property int scale () const pure nothrow @safe @nogc { pragma(inline
, true); return mScale
; }
54 final @property void scale (int v
) pure nothrow @safe @nogc { pragma(inline
, true); if (v
< 1) v
= 1; else if (v
> 16) v
= 16; mScale
= v
; }
56 final void freePixmap () {
58 if (pximg
) { XFreePixmap(impl
.display
, pximg
); pximg
= 0; flushGui(); }
64 override void close () {
69 final int rcpixel (int x
, int y
) nothrow @safe @nogc {
71 immutable int x0
= (rcx0
<= rcx1 ? rcx0
: rcx1
);
72 immutable int x1
= (rcx0
<= rcx1 ? rcx1
: rcx0
);
73 immutable int y0
= (rcy0
<= rcy1 ? rcy0
: rcy1
);
74 immutable int y1
= (rcy0
<= rcy1 ? rcy1
: rcy0
);
75 if (x
< x0 || y
< y0 || x
> x1 || y
> y1
) return 0;
77 if (y
== y0
) pixnum
= (x
>= x0
&& x
<= x1 ? x
-x0
: -1);
78 else if (x
== x1
) pixnum
= (y
> y0
&& y
<= y1 ?
(x1
-x0
+1)+(y
-y0
-1) : -1);
79 else if (y
== y1
) pixnum
= (x
>= x0
&& x
< x1 ?
(x1
-x0
+1)+(y1
-y0
+1)+(x1
-x
) : -1);
80 else if (x
== x0
) pixnum
= (y
> y0
&& y
< y1 ?
(x1
-x0
+1)*2+(y1
-y0
+1)+(y1
-y
-1) : -1);
81 return (pixnum
>= 0 ? pixnum
%2+1 : 0);
84 final int rcwidth () nothrow @safe @nogc {
85 immutable int x0
= (rcx0
<= rcx1 ? rcx0
: rcx1
);
86 immutable int x1
= (rcx0
<= rcx1 ? rcx1
: rcx0
);
87 return (x0
<= x1 ? x1
-x0
+1 : 0);
90 final int rcheight () nothrow @safe @nogc {
91 immutable int y0
= (rcy0
<= rcy1 ? rcy0
: rcy1
);
92 immutable int y1
= (rcy0
<= rcy1 ? rcy1
: rcy0
);
93 return (y0
<= y1 ? y1
-y0
+1 : 0);
96 final void drawChar (int x
, int y
, char ch
, Color clr
) {
97 immutable int bbwdt
= fontbuf
.width
;
98 immutable int bbhgt
= fontbuf
.height
;
99 if (x
< 0 || y
< 0 || x
> bbwdt
-10 || y
> bbhgt
-10) return;
100 uint v
= clr
.asUint
.c2i
;
101 //uint* destp = (cast(uint*)backbuf.getDataPointer)+y*bbwdt+x;
102 uint* destp
= (cast(uint*)fontbuf
.getDataPointer
)+y
*bbwdt
+x
;
103 foreach (immutable dy
; 0..10) {
104 ushort vv
= glConFont10
.ptr
[cast(uint)ch
*10+dy
];
106 foreach (immutable dx
; 0..10) {
107 if (vv
&0x8000) *dp
= v
;
115 final void drawStr (int x
, int y
, const(char)[] s
, Color clr
) {
116 foreach (char ch
; s
) {
117 drawChar(x
, y
, ch
, clr
);
122 final void drawStrOut (int x
, int y
, const(char)[] s
, Color clr
, Color outline
=Color
.black
) {
123 foreach (immutable int dy
; -1..2) {
124 foreach (immutable int dx
; -1..2) {
125 if (dx || dy
) drawStr(x
+dx
, y
+dy
, s
, outline
);
128 drawStr(x
, y
, s
, clr
);
131 final void createPixmap (bool forceredraw
=false) {
132 if (mScale
< 1) mScale
= 1; else if (mScale
> 16) mScale
= 16;
133 immutable int scl
= mScale
;
134 immutable int iwdt
= img
.width
;
135 immutable int ihgt
= img
.height
;
136 //conwriteln("mScale=", mScale, "; scl=", scl, "; pximgscl=", pximgscl);
137 if (pximgwdt
!= iwdt
*scl || pximghgt
!= ihgt
*scl || pximg
== 0 || backbuf
is null) {
138 if (pximg
) { XFreePixmap(impl
.display
, pximg
); pximg
= 0; }
143 backbuf
= new Image(pximgwdt
, pximghgt
, true);
144 pximg
= XCreatePixmap(display
, cast(Drawable
)window
, pximgwdt
, pximghgt
, 24);
148 } else if (pximgscl
!= scl
) {
153 //conwriteln("mScale=", mScale, "; scl=", scl, "; pximgscl=", pximgscl, "; pw=", pximgwdt, "; ph=", pximghgt, "; w=", iwdt, "; h=", ihgt, "; bw=", backbuf.width, "; bh=", backbuf.height);
154 auto srcp
= cast(const(Color
)*)img
.imageData
.colors
.ptr
;
155 auto destp
= cast(uint*)backbuf
.getDataPointer
;
157 foreach (immutable int sy
; 0..ihgt
) {
159 destp
+= pximgwdt
*scl
;
160 foreach (immutable int sx
; 0..iwdt
) {
161 if (auto pn
= rcpixel(sx
, sy
)) {
162 clr
= Color(pn
== 1 ?
255 : 0, 0, pn
!= 1 ?
255 : 0);
166 immutable uint v
= clr
.asUint
.c2i
;
167 foreach (immutable int dy
; 0..scl
) dp
[pximgwdt
*dy
..pximgwdt
*dy
+scl
] = v
;
172 if (backbuf
.usingXshm
) {
173 XShmPutImage(impl
.display
, cast(Drawable
)pximg
, impl
.gc
, backbuf
.handle
, 0, 0, 0, 0, pximgwdt
, pximghgt
, false);
175 XPutImage(impl
.display
, cast(Drawable
)pximg
, impl
.gc
, backbuf
.handle
, 0, 0, 0, 0, pximgwdt
, pximghgt
);
178 if (fontbuf
is null) fontbuf
= new Image(32*10+20, 10+4, true);
179 auto fbu
= cast(uint*)fontbuf
.getDataPointer
;
180 fbu
[0..fontbuf
.width
*fontbuf
.height
] = 0;
181 import core
.stdc
.stdio
: snprintf
;
182 char[128] buf
= void;
183 auto len
= snprintf(buf
.ptr
, buf
.length
, "pos: %d,%d size: %d,%d", rcx0
, rcy0
, rcwidth
, rcheight
);
184 drawStrOut(2, 2, buf
[0..len
], Color(0, 255, 0));
190 void redraw (bool forceredraw
) {
191 if (closed || backbuf
is null) return;
192 createPixmap(forceredraw
);
193 XCopyArea(impl
.display
, cast(Drawable
)pximg
, cast(Drawable
)impl
.window
, impl
.gc
, 0, 0, pximgwdt
, pximghgt
, xofs
*mScale
, yofs
*mScale
);
194 Color clr
= Color(128, 128, 128);
195 XSetForeground(impl
.display
, impl
.gc
, cast(uint)((clr
.r
<<16)|
(clr
.g
<<8)|clr
.b
));
196 XSetBackground(impl
.display
, impl
.gc
, cast(uint)((clr
.r
<<16)|
(clr
.g
<<8)|clr
.b
));
197 int sx
= xofs
*mScale
;
198 int sy
= yofs
*mScale
;
199 int ex
= sx
+pximgwdt
;
200 int ey
= sy
+pximghgt
;
205 if (sx
> 0) XFillRectangle(impl
.display
, cast(Drawable
)impl
.window
, impl
.gc
, 0, 0, sx
, height
);
206 if (sy
> 0) XFillRectangle(impl
.display
, cast(Drawable
)impl
.window
, impl
.gc
, sx
, 0, width
-sx
, sy
);
207 if (ex
< width
) XFillRectangle(impl
.display
, cast(Drawable
)impl
.window
, impl
.gc
, ex
, 0, width
-ex
, height
); else ex
= width
;
208 if (ey
< height
) XFillRectangle(impl
.display
, cast(Drawable
)impl
.window
, impl
.gc
, 0, ey
, ex
, height
-ey
);
209 if (hasrc
&& fontbuf
!is null) {
210 if (fontbuf
.usingXshm
) {
211 XShmPutImage(impl
.display
, cast(Drawable
)impl
.window
, impl
.gc
, fontbuf
.handle
, 0, 0, 0, 0, fontbuf
.width
, fontbuf
.height
, false);
213 XPutImage(impl
.display
, cast(Drawable
)impl
.window
, impl
.gc
, fontbuf
.handle
, 0, 0, 0, 0, fontbuf
.width
, fontbuf
.height
);
219 auto painter = this.draw();
220 painter.drawImage(Point(0, 0), backbuf);
226 protected void setupHandlers () {
227 handleExpose
= delegate (int x
, int y
, int wdt
, int hgt
, int eventsLeft
) {
228 if (eventsLeft
== 0) redraw(false);
231 visibilityChanged
= delegate (bool visible
) {
232 if (visible
) createPixmap(); else freePixmap();
234 handleKeyEvent
= delegate (KeyEvent event
) {
235 scope(exit
) if (!conQueueEmpty()) glconPostDoConCommands();
236 //if (glconKeyEvent(event)) { glconPostScreenRepaint(); return; }
237 if (isQuitRequested
) { close(); return; }
238 if ((event
.modifierState
&ModifierState
.numLock
) == 0) {
240 case Key
.Pad0
: event
.key
= Key
.Insert
; break;
241 case Key
.Pad1
: event
.key
= Key
.End
; break;
242 case Key
.Pad2
: event
.key
= Key
.Down
; break;
243 case Key
.Pad3
: event
.key
= Key
.PageDown
; break;
244 case Key
.Pad4
: event
.key
= Key
.Left
; break;
245 //case Key.Pad5: event.key = Key.Insert; break;
246 case Key
.Pad6
: event
.key
= Key
.Right
; break;
247 case Key
.Pad7
: event
.key
= Key
.Home
; break;
248 case Key
.Pad8
: event
.key
= Key
.Up
; break;
249 case Key
.Pad9
: event
.key
= Key
.PageUp
; break;
250 case Key
.PadEnter
: event
.key
= Key
.Enter
; break;
251 case Key
.PadDot
: event
.key
= Key
.Delete
; break;
255 if (event
.key
== Key
.PadEnter
) event
.key
= Key
.Enter
;
258 //conwriteln(event.toStr);
259 if (event
== "C-Q") { close(); return; }
260 if (event
== "Escape") { msdown
= false; hasrc
= false; glconPostScreenRepaint(); return; }
261 if (event
== "Plus") { scale
= scale
+1; glconPostScreenRepaint(); return; }
262 if (event
== "Minus") { scale
= scale
-1; glconPostScreenRepaint(); return; }
263 if (event
== "Left") { xofs
+= 1; glconPostScreenRepaint(); return; }
264 if (event
== "Right") { xofs
-= 1; glconPostScreenRepaint(); return; }
265 if (event
== "Up") { yofs
+= 1; glconPostScreenRepaint(); return; }
266 if (event
== "Down") { yofs
-= 1; glconPostScreenRepaint(); return; }
267 if (event
== "Home") { xofs
= yofs
= 0; glconPostScreenRepaint(); return; }
271 handleMouseEvent
= delegate (MouseEvent event
) {
272 scope(exit
) if (!conQueueEmpty()) glconPostDoConCommands();
273 if (isQuitRequested
) { close(); return; }
274 immutable int scl
= mScale
;
275 immutable int mx
= event
.x
/scl
-xofs
;
276 immutable int my
= event
.y
/scl
-yofs
;
277 if (event
.type
== MouseEventType
.buttonPressed
) {
278 if (event
.modifierState
&ModifierState
.ctrl
) {
279 if (event
.button
== MouseButton
.wheelUp
) { scale
= scale
+1; glconPostScreenRepaint(); return; }
280 if (event
.button
== MouseButton
.wheelDown
) { scale
= scale
-1; glconPostScreenRepaint(); return; }
282 if (event
.button
== MouseButton
.left
) {
283 if (event
.modifierState
&(ModifierState
.ctrl|ModifierState
.alt
)) {
290 glconPostScreenRepaint();
295 //conwriteln("pos: ", mx, ", ", my);
298 glconPostScreenRepaint();
301 if (event
.button
== MouseButton
.right
) conwriteln(mx
, ", ", my
);
304 if (event
.type
== MouseEventType
.buttonReleased
) {
305 if (event
.button
== MouseButton
.left
) { msdown
= msdrag
= false; glconPostScreenRepaint(); }
308 if (event
.type
== MouseEventType
.motion
&& msdown
) {
309 immutable int ow
= rcwidth
, oh
= rcheight
;
312 if (ow
!= rcwidth || oh
!= rcheight
) glconPostScreenRepaint();
315 if (event
.type
== MouseEventType
.motion
&& msdrag
) {
316 immutable int dx
= (event
.x
-dragmx0
)/scl
;
317 immutable int dy
= (event
.y
-dragmy0
)/scl
;
318 immutable int nxofs
= dragxofs
+dx
;
319 immutable int nyofs
= dragyofs
+dy
;
320 if (nxofs
!= xofs || nyofs
!= yofs
) {
323 glconPostScreenRepaint();
329 handleCharEvent
= delegate (dchar ch
) {
330 scope(exit
) if (!conQueueEmpty()) glconPostDoConCommands();
331 //if (glconCharEvent(ch)) { glconPostScreenRepaint(); return; }
332 if (isQuitRequested
) { close(); return; }
335 windowResized
= delegate (int wdt
, int hgt
) {
336 scope(exit
) if (!conQueueEmpty()) glconPostDoConCommands();
337 if (isQuitRequested
) { close(); return; }
338 if (wdt
< 1) wdt
= 1;
339 if (hgt
< 1) hgt
= 1;
340 //glconResize(wdt, hgt);
341 if (backbuf
.width
!= wdt || backbuf
.height
!= hgt
) {
343 //backbuf = new Image(wdt, hgt);
344 //glconBackBuffer = this.backbuf;
349 onFocusChange
= delegate (bool focused
) { msdown
= msdrag
= false; };
354 void main (string
[] args
) {
355 glconAllowOpenGLRender
= false;
356 if (args
.length
== 1) args
~= "MAIN.bmp";
358 conProcessArgs
!true(args
);
359 conProcessQueue(int.max
/4);
361 auto win
= new BmpWindow(loadImageFromFile(VFile(args
[1])));
366 conProcessQueue(int.max
/4);