Vision4Mac Documentation

Revision as of 02:05, 19 May 2007 by Dfurrer (Talk | contribs) (setup_layout)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Guidelines

I'm trying to collect some information here on how (and why) we do some things in our implementation so we can be consistent for things we use in multiple places.

1) make vs initialize

What should be done where and why? Where should events be registered? -> make (for no reason)


Style

ret: INTEGER or err as return value?

a: INT or a : INT --manus 19:16, 30 March 2007 (CEST) It should be a: INTEGER

Object creation

The way classes will be created is somewhat special in Eiffel Vision. Take a look at EV_ANY (, EV_ANY_I)

Here's a bit of it:


 --|----------------------------------------------------------------
 --| Creation sequence for all Vision2 objects is like this:
 --|
 --| - Default_create is defined once in EV_ANY.
 --| - create_implementation is defined in descendants, default_create calls them
 --| - After it is created, initialize is called on the implementation, this will
 --|   do extra setup work but need not be redefined in every descendant.
 --|   (Probably redefined in EV_WIDGET_IMP but not too many other places)
 --|   Next default_create calls initialize on Current.
 --|
 --| `default_create' must be called during creation to satisfy the invariant.
 --| The normal pattern is that default_create will produce a properly
 --| initialized default object and any special convenience creation features
 --| will call default_create then do their extra work.
 --|
 --| The postcondition of `default_create' checks `is_in_default_state', this
 --| returns True by default but should be redefined by decendants to check for
 --| proper initial results from class queries.
 --|----------------------------------------------------------------

	frozen default_create is
			-- Standard creation procedure.
			--| Must be called exactly once during creation.
		do
			check
				not_already_called: not default_create_called
					--| Calling default_create twice is not
					--| allowed. This means that reusing
					--| objects is not allowed unless a
					--| special purpose feature is provided.
			end
			check
				application_exists: application_exists
			end
			default_create_called := True
			create_implementation
			implementation.initialize
			initialize
		ensure then
			is_coupled: implementation /= Void
			is_initialized: is_initialized
			default_create_called_set: default_create_called
			is_in_default_state: is_in_default_state
		end

Event Handling

Due to some limitations of the wrapper generater we are using event handling is not quite trivial, but here's what you have to do if you want to add a new event:

In the creation procedure you need to have something like this:

id := app_implementation.get_id (current)
target := get_event_control_target_external(control)
app_implementation.install_event_handler (id, target, {carbonevents_anon_enums}.kEventClassControl, {carbonevents_anon_enums}.kEventMouseDown)

This code first gets an application-wide unique ID. The system needs this to find out which object triggered the event.

??What exactly does the target specify??

And the last line says that we would like to catch all events with the given id that are of a specific type. (here: MouseDown Events on a Control)

on_callback

-> The on_callback function is getting really ugly, here is my idea what we could do about that: we could create a on_callback* function in the WIDGET_IMP class and then only do the selection (which event type goes to which widget?) in the on_callback function of APPLICATION_IMP. The specifics could then be done in the widget's function.

EV_CARBON_DATABROWSER

This class is an abstraction for Carbon's powerful DataBrowser [1] which is used by Vision controls like EV_TREE, EV_LIST and EV_MULTI_COLUMN_LIST.

This is only an experimental idea so far, but it seems to work out quite okay. So the idea I currently have is the following: It would be nice to have a heavily platform specific class which supports all the neat OS X features and interacts directly with the wrapper. The Vision conrols could then transparently use that other widget. Now, if an experienced user (a Mac user :)) wants to write something OS X specific, he could also use that class directly.

Container Structure, embedding and removing

The structure of the widgets in a program is a tree. The root of the tree is a window, the leafs are primitives and the inner nodes are containers.

If a primitive or a container widget changes the minimum size (for example by adding some text to a button or by extending a container) this change has to be propagated to the next ancestor who is a viewport, a scrollable_area or a window (only this containers do not change their minimum_sizes even if a child has changed their minimum size). All elements in the subtree of this container, have now to reorganize their layout. We do this by recursion.

Class EV_CONTAINER_IMP (which is an ancestor of all containers) has three main features to keep this structure propre:

child_has_resized (a_widget: EV_WIDGET_IMP; a_height, a_width: INTEGER)

  1. save old minimum_sizes
  2. calculate the new minimum_sizes from a_height and a_width. A_height means, that a_widgets minimum_height is now a_height larger. This calculation differs for the various containers.
  3. If Container is a viewport or a scrollable_area then setup_layout
  4. If not a viewport or scrollable_area then do parent.child_has_resized (current, (minimum_height - old_minimum_height), (minimum_width - old_minimum_width))

setup_layout

  1. reorganize the layout of the container
  2. do setup_layout on every child

layout

reorganizes the layout of the current container.