Generic App
Volume Number: 2
Issue Number: 2
Column Tag: Threaded Code: Neon
A Generic Application 
By Jörg Langowski, EMBL, c/o I.L.L, Grenoble, Cedex, France,
MacTutor Editorial Board
The Edit window
The Hanoi towers were fun to play with. Today, we'll start doing something
'serious' and develop a template application in NEON, which will eventually develop
into the skeleton of a terminal program. In this issue, we'll first set up the object
definitions and the appropriate methods that are necessary to handle TextEdit records.
'Application templates' in NEON
The word 'application template' has a somewhat different meaning under NEON
than, let's say, in assembly language or C, since NEON provides you with a lot of the
event handling support that has to be taken care of explicitly otherwise. In principle,
one could setup an application shell - e.g. a window that supports text editing and has
the basic File and Edit menus and the appropriate event handlers - in NEON from
scratch. One would start by defining windows, controls and menus using only toolbox
definitions and the basic Object class to build on. But this would mean reinventing the
wheel and not taking advantage of the features that are already built into NEON. If any of
these standard definitions will ever have to be changed, one can even do that because
their source code is part of the NEON system.
So for the time being we will use the classes that are already provided by the
NEON system. This way the main 'event loop' becomes very simple; the NEON manual
suggests to handle almost all the important events by just saying
begin key key: xywindow again
with an arbitrary window xy window, or even
begin
key key: [ frontwindow ] again
where frontwindow generates the address of the frontmost window object (by calling
FrontWindow from the toolbox).
This will be the complete event loop, the reason being that key waits for a
keystroke, which is the thing that will in most cases have to be processed separately by
your application. While waiting, key automatically tracks all mouse events and
associated window activate and update events. The routines that handle these events are
defined separately by the actions: method for windows and controls, and in the menu
definition file for menus.
Events other than keystrokes detected by key will be sent to the appropriate
( window, control, menu) objects, and theses objects will take care of handling them as
the action words have been set up accordingly. [Important note: as far as I have found
out on my review NEON 1.0 version, even Control- keystrokes will not cause key to
exit but will be sent to the menu bar].
Fig. 1 gives an illustration of the action of key.
This is the structure that most NEON programs should make use of since
different window and control objects can be defined in a very straightforward way,
very independent of one another.
This is also how we are going to proceed to develop a simple NEON application: a
TextEdit window that can be grown and dragged, which will accept text from the
keyboard and whose text may be copied, cut and pasted through an Edit menu. A File
menu will have Quit as its only option.
There is one problem, however, with using key as defined in NEON when one calls
the TextEdit routines. The convention is that you call TEIdle in the main event loop as
often as possible so that the blinking caret is updated. key does not do this, so when
manipulating a TextEdit record in the window one has to write a loop that is cycled often
enough and does not stop at key waiting for a keystroke.I'll come back to this issue after
having described the class definitions.
The editwindow class
We will first define the main object in our application, which is a window that
contains a vertical scroll bar and has a TE record associated with it. Other than in
MacForth, there is no predefined space in a window record to hold a pointer of a TE
record, nor are there predefined routines that will do the editing on such a window. This
is good and bad; bad since it requires work on the part of the programmer and good
because we can define the object exactly the way we want it to be and know the structure
of the methods that we associated with it.
Refer to Listing 1 for our program example. An editwindow is defined as an
object of the superclass ctl window, and you will have to load ctl, ctlwind and vscroll
into the NEON system before loading this definition. Associated with this window are the
instance variables text, TEscrollbar and position. text is a TErecord object, and we'll
get to its definition soon. TEscrollbar is a variable that holds the address of a vscroll
object (for reasons that are explained in detail in the NEON manual, a control cannot be
an instance variable itself).
position will be used to keep track of the current position within the text. The
reason why this has to be done is that after a call to TEcaltext (recalculate line
positions after resizing the destRect), the start position of the text put into the
destination rectangle is reset to the beginning of the text. However, the value of the
vertical scroll bar will not have been reset, and it will show a position somewhere
within the edited text while what is actually displayed is the very beginning.
So there remain two possibilities: after recalculating the text, one can either
reset the control to zero or scroll the newly aligned text back to the position given by
the scroll bar. We choose the latter alternative here.
In our example, the scroll bar will not reflect the relative position in the text,
but rather the absolute position counted in pixels from the beginning (mainly because
of my laziness to write a separate scaling routine). The scroll bar range will be 0 to
2000, and the up/down arrows will change the control by 10 on every click, while page
up/page down will change it by 100.
When the editwindow object is created, a vertical scroll bar is generated on the
heap and its address put into the instance variable. The text edit record has to be
initialized separately using the teinit: method
Behavior of the Edit Window
The function of the edit window is very largely determined by the draw: method.
This method will be called automatically whenever an update event for that window
occurs, e.g. after dragging or resizing.
In our case, the view and destination rectangles of the TE record will always be
equal to the content region of the window minus the rectangle containing the vertical
scroll bar. draw: first calculates the new scroll bar and puts it in the right position
into the window (which might have been resized). Then the window itself is drawn by
calling the draw: method of the superclass. For displaying the text, the new view and
destination rectangles are then calculated by the getcont: method, the text is
recalculated and scrolled into the position given by the value of the scroll bar.
Thereafter the window contents are updated by setting the whole of the content
region invalid and doing a TEupdate between calls to BeginUpdate and EndUpdate.
A redefinition of the draw: method of a window is one way to define its update
behavior. The other possibility, also given in the NEON manual, is by putting the cfa of
a colon definition into the draw vector using the actions: method. After playing around
with this feature for a while and getting bombed down quite a few times, I looked into the
source code of draw: to see what had gone wrong.
The logic behind NEONs built-in draw: method is the following: First, the window
is redrawn doing the appropriate updating between calls to BeginUpdate and EndUpdate.
The last statement in the method definition is exec: draw. This jumps to the
user-defined action vector, then exits the method. The code that you put into your action
vector would then consist of updating code sandwiched between BeginUpdate and
EndUpdate. Of course, if you make the mistake to send draw: to your window from within
this code, you will get an infinite recursion which you probably never wanted in the
first place.... therefore the bomb.
The updating that we do here manipulates the windows own TextEdit record. Since
we prefer to hide this from the outside world as much as possible, we redefine draw:
within the window rather than by changing the action vector.
Editing - the TErecord class
The actual text editing methods such as cut, copy, paste, handling of mouse clicks
and scrolling are just passed through by the edit window to its own TE record, where
they have been defined. This leads to the definition of the TErecord class.
A NEON TErecord object constitutes the interface to the Toolbox's TextEdit record
(whose structure has been explained in several different columns in MacTutor,
includingh this one). Just to refresh your mind, this data structure contains a handle to