OFSET Planet (English only)

To content | To menu | To search

Tag - pharo

Entries feed - Comments feed

Friday, June 11 2010

Archetype Polymorph Application

We present a typical Polymorph application featuring Window, menu, toolbar and drawing canvas.The example is a painter application we present step by step.

The complete example is at http://www.squeaksource.com/CollaborActiveBook. The example exposes several aspects in UI programming: Morph layout, Polymorph, Traits, graphic and form display manipulations, mouse handling, announcement.

Painter application example

The application is divided in two classes. A top level class Painter and a canvas class PaintCanvas, a kind of Morph. In the following section we explain in detail those implementations.


Our application comes with a main window, a menubar, a toolbar and a drawing area. Naturally we have an instance for each one.

Object subclass: #Painter
   instanceVariableNames: 'window menubar toolbar 
   classVariableNames: ''
   poolDictionaries: ''
   category: 'PharoCollaborActiveBook-GUI'

Installing the components

At the initialization time we install all the application components:

   super initialize.
   self installMenubar.
   self installToolbar.
   self installDrawingArea.
   self window openInWorld.
   self window  extent: 300@250

The layout component use the technic explained in the previous section about Layout. For example to install the menu it looks like:

   self window 
      addMorph: self menubar
      fullFrame: (LayoutFrame
         fractions: (0@0 corner: 1@0)
         offsets: (0@0 
            corner:  0@self menubar minExtent y))

At first, we write the menu should occupy 0% vertically, but we statically shift its bottom position to its y extent.

The toolbar installation is a bit more complex as we need to shift its vertical position according to the menu y extent. As for the menu, we write the toolbar should occupy 0% vertically, then we shift statically both its top and bottom positions:

   self window 
      addMorph: self toolbar
      fullFrame: (LayoutFrame
         fractions: (0@0 corner: 1@0)
         offsets: (0@self menubar minExtent y 
            corner:  0@ self menubar minExtent y + 
               self toolbar minExtent y))

Instantiating the components

To create the menu, we use #newMenu and #newToolDockingBar, there are controls provided by the windows.

   ^ menubar ifNil: [ | menu |
      menu := self window newMenu.
         addToggle: 'Load'
         target: self
         selector: #load.
         addToggle: 'Save'
         target: self
         selector: #save.
      menubar := self window newToolDockingBar.
         add: 'File'
         font: self window theme menuBarFont
         icon: nil
         help: 'File operations'
         subMenu: menu.

To understand from where are coming from these controls, we need to look at the windows instantiation:

   ^ window ifNil: [
      window := StandardWindow labelled: 'Painter'.
      window announcer
         on: WindowResizing 
         do: [:ann | 
            self drawingArea extent: ann newSize].

Our window is a StandardWindow, it comes with the TEasilyThemed traits, all the controls are coming from this traits:

SystemWindow subclass: #StandardWindow
   uses: TEasilyThemed - {#theme}
   instanceVariableNames: ''
   classVariableNames: ''
   poolDictionaries: ''
   category: 'Polymorph-Widgets-Windows'

At the window instantiation we are defining an announcement: it says we should send #extent: to the drawingArea when the window is resized.

The drawing area instantiation itself is straight full:

   ^ drawingArea ifNil: [
      drawingArea := PaintCanvas new]

It is time now to look at the PaintCanvas class itself in the next section.

Paint Canvas

Our paint canvas is a Morh instance. As we can not draw directly into a Morph, we use a FormCanvas object to draw into it. When the Moprh needs to be updated, the FormCanvas content is copied in the Morph canvas. Our paint canvas comes with two instances, one is a FormCanvas, the other a Color:


Morph subclass: #PaintCanvas
   instanceVariableNames: 'area paintingColor'
   classVariableNames: ''
   poolDictionaries: ''
   category: 'PharoCollaborActiveBook-GUI'

The area instance is initialized as a FormCanvas, with a default size identical to the Morph extent:

   ^ area ifNil: [
      area := FormCanvas extent: self extent.
      self clear.

It is filled with white color:

   self area fillColor: Color white.
   self changed

Update operation

The #changed message informs the morph something changed and redrawing is necessary. The drawing itself only consists to copy the area content in the rendering Morph canvas:

drawOn: aCanvas
      drawImage: self area form 
      at: self position

Now you should remember the announcement we added in our main application window (if no, read the previous section about the Painter). This announcement states the message #extent: is sent to our Paint Canvas at WindowResize announcement. Now we need to override the #extent: method here:

extent: aPoint
   | newArea |
   super extent: aPoint.
   newArea := FormCanvas extent: aPoint.
      fillColor: Color white;
      drawImage: self area form at: 0@0.
   area := newArea

Here, we just create a FormCanvas matching the new window extent, then we copy the content of the old FormCanvas in the new one. Mouse handling and drawing operation

To effectively paint we need to handle mouse operations. First we inform we want to handle the mouse down event whatever the clicked button:

handlesMouseDown: evt
   ^ true

Then when the mouse is moved, we paint in our FormCanvas:

mouseMove: anEvent
   self area 
      fillOval: (Rectangle 
         center: anEvent cursorPoint - self position 
         extent: 4@4)
      color: self paintingColor.
   self changed.

Monday, June 7 2010

DrGeoII new user interface

Here is a DrGeoII screenshot under the Pharo environment and language. The exposed construction is about a circle tangent to the blue line and crossing two points A and B. The Pharo user interface theme is Watery 2.

Next change will be with the macro-construction user interface to implement a Polymorph wizard dialog.

DrGeoII can be installed in Pharo from its source code repository.


Tuesday, May 18 2010

Pharo gettext package

I have been porting the Gettext package from Etoys to Pharo, so Polymorph DrGeoII can be localised in several languages. So far I have French and Spanish locales for DrGeoII. Seaside people also get interested to localise web application.

The Gettext package is located in the Monticello PharoInbox repository.

Wednesday, April 21 2010

Some more about Polymorph for DrGeo

Someone asked for a more elaborated UI for DrGeo, here are some progresses in this polymorphization of DrGeo. Known to work with Pharo 1.0.

In its latest Monticello package one can grab DrGeo at http://www.squeaksource.com/DrGeoII

DrGeo Polymorphization

To start a DrGeo instance, do a DrGeo new in a workspace and enjoy the UI.

Beware, style tools does not work in the toolbar.

It is also possible to use DrGeo as a service for Etoys when executing a DrGeo sample openInWorld

It is also possible to load XML description of DrGeo 1.1 geometric sketch, if one is interested you can grab it at http://svn.gnome.org/viewvc/drgeo/trunk/examples/figures/ and load a sketch with a command: DrGeo newXml: path

Beware sketch with embedded Scheme code will not work (just try)

Working sketch: mercedes, euler-line,

DrGeoII comes with a better interface for scripting with Smalltalk script, empowered by the IDE, nicer than the former Scheme one. See this elaborated demonstration (automatic translation link with Google in a comment, at the end of the article)

Thursday, April 15 2010

Pharo Smalltalk 1.0 is out

Pharo is a new Smalltalk programming environment, derived from Squeak. It is largely used by the Seaside web framework.

The 15 of April, the version 1.0 was released

Saturday, April 10 2010

UI with Pharo

How to write GUI application with Pharo Smalltalk?

In this series of articles I will use DrGeo Smalltalk porting effort to Pharo UI as an example. The articles use Pharo 1.0, but it should work with newer version without modification.

Do not hesitate to comment.

I start with with a kind of StandardWindow class I nammed DrGeoWindow, it is the main UI element of DrGeo:

StandardWindow subclass: #DrGeoWindow
     instanceVariableNames: 'view presenter domain'
     classVariableNames: ''
     poolDictionaries: ''
     category: 'DrGeoII-App'

If you look at the StandardWindow class definition, you see it uses a trait coming from the Polymorph UI framework:

SystemWindow subclass: #StandardWindow
	uses: TEasilyThemed - {#theme}
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Polymorph-Widgets-Windows'

In a few words, a trait is a mechanism to import in a given class, an interface of methods, without the need of subclassing or poly- inheritance.

This keyword uses: TEasilyThemed - {#theme} says import the methods from trait TEasilyThemed without the method named @theme@.

So what is coming along this trait TEasilyThemed?

The screen shot bellow shows the hierarchy of the DrGeoWindow class, its direct ancestor is selected so we can see its interface. The methods imported from the trait are emphasized:

DrGeoWindow hierarchy

For the UI developer, the trait brings two advantages:

  1. Services of UI elements like dialogs: question dialog, file dialog, ...
  2. Controls to build up your own complex UI elements in your window: controls like button, menu, toolbar, entry,...

In a next article, we will learn how to use these controls to enhance our window features.

Friday, April 9 2010

DrGeo move to new user interface

DrGeo user interface is rewritten to use the Polymorph UI framework. Pharo comes by default with this framework. Polymorph comes with a load of widgets and it is themable. Following screenshot was taken with W2K theme:

DrGeo polymorph

Saturday, April 3 2010

DrGeo for Pharo Smalltalk

Pharo uses the Metacello system to install a source package with its dependencies.

I have updated DrGeo to make it compliant with Pharo 1.0. I also took the opportunity to write a ConfigurationOfDrGeo using Metacello package management facility.

The Configuration is for now in the DrGeo repository: http://squeaksource.com/DrGeoII

To install it, execute in a Workspace:

Gofer new
   url: 'http://www.squeaksource.com/DrGeoII'  ;
   package: 'ConfigurationOfDrGeo';
(Smalltalk at: #ConfigurationOfDrGeo) perform:#load.

To start DrGeo, execute in Worspace:

DrGeo sample openInWorld

page 2 of 2 -