FrameWork
and TextEdit
modules to create a simple text editor. The functionality
of the editor is very basic: you can open multiple files, type text and use
cut/copy/paste. The main intention is to explain the use of FrameWork, really.
Application
__init__
routine
to do your own initializations and override makeusermenus
to create your menus
(your menu callback routines may be here too, but this is by no means necessary).
The event handling code can be overridden at various levels, from very low-level (the
dispatch
method) to intermedeate level (do_keyDown
, for instance)
to high-level (do_key
). The application class knows about the Window
objects you create, and will forward events to the appropriate window (So, normally you
would have a do_key
method in your window object, not your application object).
MenuBar
, Menu
and MenuItem
SubMenu
) handle your menus. You would not
normally override them but use them as-is. The idiom for creating menus is a bit strange,
see the test code at the bottom of FrameWork for sample use. The apple menu is handled for you
by MenuBar
and Application
.
Window
open
. Your
open method should call do_postopen
to let the base class handle linking in to
the application object. Similarly with close
and do_postclose
. The
rest of the code is mainly event-oriented: you override do_postresize
,
do_contentclick
, do_update
, do_activate
and do_key
to "do your thing". When these methods are called the relevant environment
has been setup (like BeginDrawing
has been called for updates, etc).
windowbounds
ControlsWindow
do_controlhit
.
ScrolledWindow
do_activate
or do_postresize
you must call the ScrolledWindow methods at the end of your override.
You call scrollbars
to enable/disable scrollbars and updatescrollbars
to
update them. You provide getscrollbarvalues
to return the current x/y values (a helper
method scalebarvalues
is available) and scrollbarcallback
to update your
display after the user has used the scrollbars.
DialogWindow
Ped creates two classes, TEWindow
and Ped
. Let us start with the latter one,
which is a subclass of FrameWork.Application
and our main application. The init function
has little to do aside from the standard init: it remembers a window sequence number (for untitled windows),
and sets things up for menu disable to work. Remember, the makeusermenus
is called
automatically.
Makeusermenus
creates the File
and Edit
menus. It also initializes
a couple of lists that are used later to correctly enable and disable menu items (and complete menus) depending
on whether a window is open, text is selected, etc. The callback functions for the menu items are
all methods of this class.
Updatemenubar
handles greying out (and re-enabling) of menu items depending on whether there
is a current window and its state.
The rest of the methods are all callbacks and simple to understand. They check whether there is an active
window (and complain loudly if there is none: the corresponding menu entry should have been disabled
in that case!) and call the appropriate window method. Only the _open
method (the common code
for Open
and New
) deserves some mention. It instantiates a TEWindow
object and opens it with the title, filename and contents of the file to edit. Note that FrameWork takes
care of remembering the window object. A minor note on opening the file in binary mode: this is because
TextEdit expects MacOS style carriage-return terminated lines, not python/unix/C style newline-terminated
lines.
Oh yes: the quit
callback does a little magic too. It closes all windows, and only if this
succeeds it actually quits. This gives the user a chance to cancel the operation if some files are unsaved.
Quitting itself is also a bit strange: you raise self
to break out of the main loop. This bit
of idiom was invented by Guido, so blame him:-).
Lastly, there is the idle
method, called by the Application base class when no event
is available. It is forwarded to the active window, so it can blink the text caret.
The TEWindow
object handles a single window. Due to this structuring it is absolutely no
problem to have multiple windows open at the same time (although a real application should exercise care when
two windows refer to the same document). TEWindow uses the standard init code inherited from
ScrolledWindow
, and sets itself up at the time of the open
call. It obtains screen
coordinates, opens the window, creates rectangles for TextEdit to work in (the magical number 15
here is the size of a normal scroll bar: unfortunately there is no symbolic constant for it),
creates the TextEdit object and initializes it with our data. Finally, the scroll bars are created (the
initial values will be obtained automatically through getscrollbarvalues
) and we activate
ourselves (this is unfortunately not done automatically by the MacOS event handling code).
Do_idle
simply calls the TextEdit routine that blinks the cursor. Getscrollbarvalues
returns the current X and Y scrollbar values, scaled to 0..32767
. For X we return None
,
which means "no scrollbar, please", for Y we use the scaler provided by ScrolledWindow
.
Scrollbar_callback
is called when the user uses the scrollbar. It is passed a string 'x'
or 'y'
, one of 'set', '-', '--', '+', '++'
and (for set
) an absolute
value. Note that the sign of the value passed to TEPinScroll
is counter-intuitive.
do_activate
(de)activates the scrollbars and calls the relevant TextEdit routine. Moreover, it
tells the application object if we are now the active window, and updates the menubar. The next few methods
are update and menu callbacks, and pretty straightforward. Note that do_close
can
return without closing the window (if the document is changed and the users cancels out of the operation).
Also note the "magic" in menu_save_as
that set the correct window title.
Things get moderately interesting again at the cut/copy/paste handling, since the TextEdit scrap is
separate from the desktop scrap. For that reason there are various calls to routines that move the scrap
back and forth. Have_selection
is called by the menubar update code to determine whether cut and
copy should be enabled.
Understanding the main program is left as an exercise to the reader.