A Canvas is something which can be drawn on and supports basic drawing operations.
Every Canvas has a model, which is asked to draw itself on a canvas, and react to events.
The Canvas API needs enhancing to support:
I would change Canvas by:
Here, the "drawer" is the object which draws (as opposed to the furniture item).
One of the enhancements would be to add child canvases. Child canvases could be used in many ways, for example:
Sub-canvases would be useful for caching bitmaps and moving them across the screen smoothly. For example, a 2-D scrolling game could be made using sub-canvases to draw the actors and layers of the background.
Sub-canvases have a z-index.
Sub-canvases could support transparency to be very cool.
A sub-canvas is clipped to the bounds of it's parent canvas, for security. This prevents a canvas drawing over controls that do not belong to it. A sub-canvas acting as a window would have a relative position to it's parent which it cannot change (but the parent can).
Sub-canvases are hidable or could be rendered in multiple places (e.g. for flyweights).
One sub-canvas would have the keyboard focus and would receive keyboard events.
A canvas might be special, e.g. an OpenGL canvas for 3-D graphics, or an MPEG canvas for hardware accelerated movies, or perhaps an image canvas that only takes a bitmap and can be used as a child canvas.
Every sub-canvas has a small mouse-pointer canvas which is what is used to draw the mouse pointer when it is hovering over that canvas.
A FormCanvas has other FormCanvas's as sub-canvases.
Every canvas can have a location attached to it that will be visited if the user clicks that canvas. A clickable link would then be a transparent sub-canvas with a location attached to it.
Types of Sub-canvases:
How would you create a GLCanvas on a FormCanvas?
FormCanvas addChildCanvas: (GLCanvas new: 10000@10000) ??
or
newCanvas := FormCanvas addGLCanvasAt: 10000@10000 size: 20000@20000.
Perhaps a Canvas can have a fall-back rendering mechanism? If a particular parent canvas does not support the child canvas's rendering methods, it can fall back on either raster or bitmapped graphics mapped to the parent?
Perhaps use a factory somehow - make the parent canvas be a factory, or something?
Possible types of Canvas include:
Several of these canvases support native sub-canvases (XCanvas with Windows, GLCanvas with display lists, VNCCanvas, ...). Those that don't can emulate this.
Several support antialiasing (Rome, GLCanvas, ...?).
Some support transparency (GLCanvas). XCanvas notably doesn't, although there may be modern extensions that allow this, or the library could hack around this.
Some have native font support (XCanvas, Win32, Rome).
GLCanvas can also be 3-D, meaning that a sub-canvas stack can really be in 3-D. This API is limited to 2-D except for the stacking nature of canvases; a 3-D API would be more general (and real 3-D buttons that stick out would be very cool).
A Canvas could also do fancy effects: sub-canvases may drop shadows on the canvases below them, or cast a subtle light. It would be very cool if the shadow respected the transparent parts of a canvas. The canvas with active keyboard focus may be more illuminated than others. Canvases might be slightly reflective or have reflective parts, making them reflect the canvases above them. Fancy effects like this are much more suited to a proper 3-D environment than a 2-D drawing API.
For now: The Canvas implementation does it's best to render commands given to it. If it does not support anti-aliasing, then anti-aliasing is simply not done. If it does not support transparency, that is not done either. Programmers using canvases just need to be aware of this and not rely on transparency or antialiasing.
Because various renderable objects have a lot of properties, it might be better to render a particular object on a canvas rather than add special methods such as #lineFrom:to:colour:. These objects can be made immutable so that the canvas can cache them (if the canvas is of the caching sort).
Lines have:
Maybe lines are really rectangles - they have a width, a length and a fill colour!
Dots must have a circumference. They are really a circle.
Bezier or other curves?
Circles, eclipses, arcs?
Paths (rectangles, polygons) have:
If fills and solid colours are actually special canvases, then perhaps they could be replaced with another canvas, such as an image?
A lazily drawn Canvas could then be used for any fill. This would also be useful for viewports. A canvas can be lazily drawn using a dirty-marking mechanism that asks the renderer of the canvas to redraw it.
What coordinate system should a canvas use? Currently they use pixel-based coordinate systems, with the top-left corner being 0@0 (or 1@1?).
The options are:
If a pixel-based system is used, then coordinates could either represent the center of each pixel, or integral coordinates representing the edges between pixels.
My preference is either of the metric units. These are device and resolution independent. Operations on pixels are usually basic operations - adding, dividing, comparing, so the same code would work with either floating point or integer operations except for equality comparisons.
An integer-based system could have a method that returns the size of the pixel (e.g. 257 micrometers), so pixel-by-pixel control can still be achieved with multiplication. For example, on my current monitor, each pixel is 282 micromillimeters (exactly!). If the GUI API provided a method for returning the pixel size (both horizonally and vertically) then an application can choose to align graphics with pixels, or alternatively just ignore them and use absolute coordinates instead (e.g. 100mm x 200mm).
Juan Vuletich's Morphic 3 has a very flexible coordinate system.
--> Leave this for later - for now, just use whatever Canvas already provides. Implement an improved UI device in version 2.0.
--> Or maybe this should go in; version 1.0 should provide a uniform graphics API.
Should 0@0 be at the top left or bottom left?
Arguing for bottom-left:
Arguing top-right:
This is really an arbitrary decision. Whichever approach is taken will have only a minor effect on code.
Canvases typically have a model. The model is the target for events, and is asked to redraw the canvas.
Subcanvases each have their own model. The redrawing of a sub-canvas does not influence the redrawing of it's parents, and the drawing of a parent canvas does not influence the drawing of child canvases. Each is updated separately, although perhaps by the same thread for efficiency.
When an application starts up, the main canvas is passed to the model, which then adds sub-canvases to the model. For example:
SiteBrowser>>navigateTo: aSite
currentCanvas reset. "remove all sub-canvases, remove all steppers, clear contents"
aSite setUpCanvas: currentCanvas.
currentCanvas markDirty: (currentCanvas bounds).
MySite>>setUpCanvas: canvas
canvas setModel: self. "Start receiving events."
canvas addSubCanvas: (set up a sub-canvas here).
MySite>>drawOn: aCanvas bounds: bounds
"The bounds is the area that needs redrawing; I can choose to redraw just that, or everything. "
... canvas drawing commands...
A Canvas can be persistent; it survives screen refreshes. An application can safely hold a reference to a Canvas and draw on any part of it at any time.
Every Canvas has a model which it can invoke "drawOn: canvas bounds: bounds" to have that canvas redrawn. The bounds exist to redraw a part of the canvas, such as for example when that canvas is only exposed through a clipping canvas or is occluded.
Some ways of caching canvases would be:
If the Canvas is cached in a display list or bitmap, then redrawing is not necessary for most move/expose operations. If the Canvas does not store state, then a redraw may occur whenever the canvas is exposed on the screen (e.g. brought to the front) or moved.
The Canvas needs to know when drawing is complete. One way is to mark the area on the canvas as "clean". Another is to return successfully from the drawOn:bounds: method.
Mouse events have a screen location, which is a point position on the canvas that they occurred on.
Redrawing a sub-canvas could occur as an event. Redrawing would only occur when a canvas is damaged by some other canvas moving over it.
Keyboard events don't have a particular position. Keyboard events would be sent to the canvas which has "keyboard focus".
Events such as the morphic "stepping" architecture could be done externally to this.
Types of events:
Events regarding redrawing or resizing need to be separate. Resizing events will cause the GUI framework to resize each widget.
Some modern keyboards have special keys for many functions, e.g. "zoom in/out", "print", "back" etc. These could be mapped to "commands" which are sent to the canvas's model, as an event, to be interpreted as that particular command.
The root class of the Canvas hierarchy has:
Some Canvases have:
Some rough ideas:
Perhaps:
Canvas - bounds, position
e.g. the ClippedView:
ParentCanvas -> ClippedCanvas -> ImageCanvas.
The ClippedViewCanvas has coordinates for rendering on the parent, and coordinates for which part of its child canvas is rendered. An application would do drawOn: the ImageCanvas, and the results would be visible on the ParentCanvas. How this is implemented depends on the platform. E.g. for a BitBlt implementation, maybe there are renderOn: methods which are called from the parent canvas down to redraw the UI?
The user of the Canvas does not need to worry about the actual rendering to the screen. The Canvas architecture does that - the user of the canvas is concerned with drawing on the canvas when it receives a "please redraw on me" event.
If you have a TransformingCanvas that sees through to a canvas with children, those children should also be transformed.
Some of these won't accept drawing commands - does that mean they aren't Canvases? Perhaps Canvas needs a superclass called maybe Window which has sub-windows (and Canvas does not), or perhaps Window is a separate class of which the above are superclasses?
The Subcanvas API will probably also require a text API, because text can be handled differently by different APIs.
See Pango tutorial: http://www.ibm.com/developerworks/library/l-u-pango1/ for some text rendering concerns.
Text is rendered using:
OpenType seems to be a well understood font format.
Kerning is best done on a per-paragraph basis (see TeX), so it might be necessary to have a rectangle/paragraph of text. The width would be set; the height would depend on the text. Kerning would be done by the canvas rather than by the application. Paragraphs need to support centering, full-alignment, right/left alignment, text direction etc. Paragraphs would need to support mark-up: colours, bold/italic/small-caps/underlining,
The application should also be able to specify non-wrapped text for a single line; perhaps by setting the width to zero?
Font metrics need to be exposed to the client for special effects such as highlighting up to a particular character, or for putting fancy underlining on characters.
All sizes should be converted to micrometers.
Text could be either rendered using pre-build featherweight glyphs, or by rendering each character individually to the subpixels.
The API needs to have enough primitives to allow the advanced user to implement his own rendering. This could be as simple as rendering individual glyphs. One possibility is to make text layout a custom package.
FreeType only renders individual glyphs and provides metrics about them. FreeType generates bitmaps, so the Canvas only really needs to support some BitBlting mechanism with font rendering and text layout being done externally.
...perhaps I could only include support for rendering a particular glyph at a time? But then ligatures would not be supported...?
If Postscript stores text as a string and does it's own kerning, then it is more efficient to make an API which can handle whole paragraphs.
It would be nice to have a test screen of some sort, like this: http://en.wikipedia.org/wiki/Image:Pm5544-768.png.
This could be showen when the system is busy booting or loading up.
This needs testing:
Lessphic: http://piumarta.com/software
http://en.wikipedia.org/wiki/Windows_Presentation_Foundation
See the Java APIs for Swing and Java2D for inspiration.
http://www.antigrain.com/research/font_rasterization/
Font rendering and text handling: http://www.pango.org/
http://www.w3.org/TR/css3-webfonts/
Page Information
|
Wiki Information |
Recent PBwiki Blog Posts |