[Grace-core] Cross platform graphics library

Alex Sandilands sandilands.alex at gmail.com
Sun Jan 26 15:40:02 PST 2014


Thanks for the feedback! I'll just note here that I wrote up the pdf on
Friday afternoon, quite a rushed job so it might not be completely easy to
follow.
We were more interested in just getting it out there so we could get some
feedback. If you want to see how to library actually feels when using it in
programs I suggest
looking at some of the test_Graphics_* files in
https://github.com/AlexSandilands/grace-phix/tree/master/testing

Thanks for all the great questions and suggestions, I'd like to respond to
all of them but this email would be far too long :(
I'll try to just go over a few of the major ones.


There were so few objects in the interfaces


I think I made a mistake in the design of the api. I didn't make clear that
sections 2 to 7 are grace modules. So section 2 covers the graphics.grace
module, section 3 is window.grace etc.
Section 7 covers three utility modules.

The only modules that don't use objects are graphics.grace and the
utilities, and this was a design choice. All the other modules use objects.

As I explained in the graphics.grace section, that module is a listing of
constructors for the objects that are in the library. It didn't make sense
to me for
graphics.grace to use an object for this. Let me explain with some example
programs

// 1

import "graphics" as g

def w = g.createWindow

w.display

// 2

import "graphics" as g

def gObj = g.aGraphicsObj

def w = gObj.createWindow

w.display

As you can see it just makes another line of code that isn't necessary in
my opinion. Since there are only constructor methods in graphics.grace,
there doesn't need to be an object
to pass around, as any file that imports graphics.grace has access to
exactly the same information, and that information isn't changeable.
You might argue that it isn't necessary for there to be a module that is
dedicated to listing the object constructors since you could just import
window.grace, canvas.grace etc,
but this way when you want to write a program using Grace-Phix the only
import you need is graphics.grace. This takes away a big nasty load of
imports that you have to deal with, something that
Java does badly. This way seems nicer to me.

Exactly the same reasoning for GMath.grace, it wouldn't make sense to me to
create a math object, then use that object to perform operations. It's not
like we require GMath itself to store any user data.
It just has methods that perform calculations. One of the notes suggested
that all the methods should just be on Numbers, which is probably a good
idea. However, I kind of like the idea of Numbers
having all the basic operations like +, - etc, then when you want to start
doing complex math you import a math module. Probably something worth
talking about.

Color.grace is slightly different. There is a color object as this is
something that needs to be passed around, and store user data. However
there are also a bunch of constructor methods in the module outside
of the color object which just make it easier to use.

For example you could do

import "Color" as col

def c1 = col.aColor(1, 0, 0)

// Or, to make it easier and more readable

def c2 = col.red

red() is a method inside the Color module, but it isn't inside the Color
object, why would/should it be? Create an object so you can create another
object?
In Grace you can't overload/override constructors. class aColor -> Color {
... } is really just sugar for a method that constructs and returns an
object, right?
Since we can't overload that, what I like to do in Grace is have the class
aColor ... etc and also have a list of methods in the module that construct
the object in different ways. A nice way to replace overloading in my
opinion. Is this not something that was intended in the language?

Apart from those, everything else is an object. Unless I am
misunderstanding what you mean.

--------------------------------------

It seems there was some confusion as to how a canvas works, so I'll clear
that up now.
Canvas is a component that you can call paint() on. One of the notes said
that I haven't explained what the display buffer is so you don't yet know
what I mean by that.
Well, it all depends on which backend you're using, which is why I didn't
elaborate. With the GTK backend the canvas is a gtk.drawing_area, with the
JS backend it is a canvas.

The Grace-Phix canvas object has a list of Drawable objects. When you call
paint on the canvas, every Drawable on this list has their draw methods
called  (unless one of them has been set as hidden etc).
There are two ways that you can add Drawables to the canvas. Either use
graphics.grace to construct a Drawable object then add it to the canvas,
like this:

import "graphics" as g
import "Color" as col

...

def can = g.createCanvas
def cir = g.createCircleAround(20, 20) radius(5) colored(col.blue)
canvas.add(cir)

...

or you can call the drawing methods that the canvas object itself has, like
this:

import "graphics" as g
import "Color" as col

...

def can = g.createCanvas
can.color := col.blue
canvas.drawCircleAround(20, 20) radius(5)

...


Both of those code excerpts do exactly the same thing.

I like having the two options available. This way you can create your own
Drawable objects, such as a Teeshirt from Kim's example, and add them to
the canvas,
or if you are needing to do a loop or something and draw hundreds of basic
shapes, all of the same color, you can just set the canvas to have that
color and
start calling the canvas draw methods.

-----------------------

There were some questions about the Drawable objects themselves. A Drawable
is essentially just something that has Cartesian coordinates and a draw
method, which takes
a graphical drawing object. ie if using the GTK backend the draw method
would take a Cairo object, if using the JavaScript backend the draw method
would take a canvas context object.
This shows off some of the flexibility of the library. If you wanted to use
a different backend, all you need to do to get the Drawable module working
is change is the body of the draw methods. Everything else
will work just fine.

-------------------------

There were some good suggestions for changing method names and things like,
I'll go through and do that, thanks.

The idea is that when both the GTK and JavaScript backends are finished, we
will rewrite ObjectDraw using Grace-Phix. Then any applications written
with the new ObjectDraw will run on gtk and the WebIDE
in a very elegant and flexible way.





On Sat, Jan 25, 2014 at 9:29 PM, Andrew P Black <black at cs.pdx.edu> wrote:

> Alex,
>
> Thanks so much for sharing this.  I have put a few comments throughout the
> document, as little yellow “post-it notes”.  Most are suggestions for
> renaming, simplification, or completeness.
>
> Overall, it’s great that you are discussing this interface.  I was a bit
> surprised, though, that there were so few objects in the interfaces; it
> read more like a functional language library, where everything had to be a
> top-level function because they don’t have objects and methods.  I think
> that Phix can be simplified a lot if you take advantage of objects.
>
>         Andrew
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailhost.cecs.pdx.edu/pipermail/grace-core/attachments/20140127/40aebc5f/attachment.html>


More information about the Grace-core mailing list