Why develop yet another GUI API with yet another interface? While I understand there are reasons to re-implement an API to use D idioms, there are plenty of good APIs out there whose designs could be lifted. Reminds me of the quote: "The nice thing about standards is there are so many of them."<div>
<br></div><div>Have you considered patterning your API off an existing (preferably popular) one?</div><div><br></div><div>- Cliff<br><div><br><div class="gmail_quote">On Fri, Apr 8, 2011 at 1:26 PM, Adam D. Ruppe <span dir="ltr"><<a href="mailto:destructionator@gmail.com">destructionator@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">We discussed this first in the GUI library thread, but since it<br>
meandered so much, I decided to split off into a new subject. Much<br>
of what I say here will be old to anyone who saw the previous thread.<br>
There's some new stuff nearer to the bottom though.<br>
<br>
I, with input from others, have started writing a little module<br>
for simple uses of a display. You can write to a bitmap, display it<br>
to a window, and handle events all in an easy way. The basics are<br>
cross platform, but you can use native function calls too.<br>
<br>
<a href="http://arsdnet.net/dcode/simpledisplay.d" target="_blank">http://arsdnet.net/dcode/simpledisplay.d</a><br>
<br>
It's still very much in progress, but I think it's now at the point<br>
where the direction I'm taking it is clear.<br>
<br>
First, the simplest usage:<br>
<br>
====<br>
import simpledisplay;<br>
<br>
void main() {<br>
auto image = new Image(255, 255);<br>
<br>
foreach(a; 0..255)<br>
foreach(b; 0..255)<br>
image.putPixel(a, b, Color(a, b, ((a + b) % 16) * 16));<br>
<br>
image.display();<br>
}<br>
===<br>
<br>
Compile: dmd test.d simpledisplay.d<br>
<br>
<br>
When run, it will pop up a window with a gradient thing with little<br>
bars through it. Press any key and the window closes, exiting the<br>
program.<br>
<br>
On Windows, it uses GDI functions. On other systems, it tries to<br>
use X Windows. Linux is the only one I've personally tested, but it<br>
should work on OSX and FreeBSD too (without changing the code).<br>
<br>
<br>
If you are making some data, then just want to display it, this<br>
works. But, what if you want some interactivity?<br>
<br>
Here's a simple HSL color picker:<br>
<a href="http://arsdnet.net/dcode/simpledisplay_test2.d" target="_blank">http://arsdnet.net/dcode/simpledisplay_test2.d</a><br>
<br>
Use these keys to pick your color: q/a change hue. s/w changes S.<br>
e/d changes L. Press ESC to exit. Your color in rgb is printed to<br>
stdout.<br>
<br>
<br>
Here's the relevant parts of the code:<br>
<br>
void main() {<br>
auto image = new Image(255, 255);<br>
auto win = new SimpleWindow(image);<br>
win.eventLoop(0,<br>
(dchar c) {<br>
writeln("Got a char event: ", c);<br>
<br>
if(c == 'q')<br>
h += 15;<br>
// ...snip...<br>
<br>
foreach(a; 0..255)<br>
foreach(b; 0..255)<br>
image.putPixel(a, b, fromHsl(h, s, l));<br>
<br>
win.image = image;<br>
},<br>
(int key) {<br>
writeln("Got a keydown event: ", key);<br>
if(key == KEY_ESCAPE) {<br>
auto color = fromHsl(h, s, l);<br>
writefln("%02x%02x%02x", color.r, color.g, color.b);<br>
win.close();<br>
}<br>
});<br>
}<br>
<br>
First, we create an image. Then, a window based on that image. At<br>
line two, your window will show up on the screen, just like<br>
image.display() did above. But, here, instead of blocking, it<br>
moves on to a user specified event loop.<br>
<br>
SimpleWindow.eventLoop was inspired by std.concurrency.receive.<br>
The first parameter is a pulse timer amount (not yet implemented).<br>
If you set one, you'll get one of your delegates called at the<br>
requested interval. The idea there is to make animations or games<br>
easy to get started.<br>
<br>
After that comes a list of delegates. They are matched to different<br>
events by their signature. (dchar c) {} means a key was pressed,<br>
and it passes you the character corresponding to that key.<br>
<br>
(int c) {} is almost certain to change, but right now it matches<br>
to key press events, and passes the platform-specific keycode. I'm<br>
planning to put symbolic constants in with the same name across<br>
platform to make that easier to use, but the values themselves are<br>
likely to be platform-specific.<br>
<br>
<br>
<br>
When we get a key event here, the image is redrawn with a new<br>
color. win.image = image tells it you want the image redrawn with<br>
the new image. It's a blunt instrument, but a simple and fairly<br>
effective one.<br>
<br>
<br>
<br>
The advantage of this approach is you can just have fun with<br>
those pixels and handle keys, all right there inside main() - no<br>
need to do subclasses just for a simple program. At the same time,<br>
you can move those event handlers around easily enough, or even<br>
change them at runtime, simply by using named delegates and assignment.<br>
<br>
I plan to add more event possibilities so you can actually<br>
make this do some good work for you. Ultimately, they'll also<br>
be an (XEvent) {} and (HWND, LPARAM, WPARAM) event for when what<br>
I provide isn't good enough, so you can always build more off it.<br>
It's meant to be simple, but not horribly limiting.<br>
<br>
<br>
======<br>
<br>
<br>
Since last time I posted, I've reorganized the code inside<br>
simpledisplay.d quite a bit. Instead of version Windows vs version<br>
linux, it's now Windows and X11, reflecting the fact that X is<br>
available on many operating systems. (Including Windows, actually,<br>
but meh).<br>
<br>
The Color struct is now rgba, but it doesn't use a. I like the<br>
suggestion to template on different color spaces, but haven't gotten<br>
around to that yet.<br>
<br>
Next, Image and SimpleWindow are done pretty differently than before.<br>
Now, the platform specific parts are put into a separate mixin<br>
template: NativeImageImplementation!() and NativeSimpleWindowImpl...().<br>
The public methods forward to those.<br>
<br>
The reason for this is three fold:<br>
<br>
a) It makes the public code a lot easier on the eyes. It was getting<br>
into spaghetti version territory for a bit there... now it's nice<br>
and clean.<br>
<br>
b) The implementations can now be moved to their own modules. I haven't<br>
simply because a single file is easier to distribute and play with,<br>
but the final thing probably should split it up, and now it can.<br>
<br>
c) It should be more obvious when something isn't implemented for an<br>
operating system, while keeping the public ddoc all in one place.<br>
versions<br>
<br>
<br>
Before, Image was simply a byte array in a single format, meaning<br>
to get to the native OS format for blitting, it had to be copied. Now,<br>
the actual format is hidden inside impl. I'll add operator overloads<br>
or structs (I really like Nick's idea of a fast vs cropped access<br>
point) to hide it.<br>
<br>
In the mean time though, the putPixel function forwards to the OS<br>
implementation, which writes right to the image format expected there.<br>
<br>
It's still not ultimately efficient, but it's better than copying<br>
it twice every time we make a change.<br>
<br>
I still like the idea of a set binary format being available so<br>
we can save as a file, but that will be made a conversion function<br>
instead of the default use. Actually, probably some kind of forward<br>
range. Then the file save functions can accept those ranges and<br>
translate them into .bmp or .png files as it streams in. (probably<br>
image.byScanLine would be pretty useful for this!)<br>
<br>
My HSL -> RGB converter is also in simpledisplay.d. It's actually<br>
less than 500 lines, excluding the bindings pasted in at the bottom.<br>
Not too bad.<br>
</blockquote></div><br></div></div>