| 
									
										
										
										
											1996-04-19 15:56:08 +00:00
										 |  |  | <HTML><HEAD><TITLE>Using FrameWork and TextEdit</TITLE></HEAD> | 
					
						
							|  |  |  | <BODY> | 
					
						
							|  |  |  | <H1>Using FrameWork and TextEdit</H1> | 
					
						
							|  |  |  | <HR> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In this document we use the <CODE>FrameWork</CODE> and <CODE>TextEdit</CODE> | 
					
						
							|  |  |  | 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. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <H2>FrameWork</H2> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The FrameWork module provides you with a skeleton application. It declares a | 
					
						
							|  |  |  | number of classes suitable for subclassing in your application, thereby | 
					
						
							|  |  |  | releaving you of the burden of doing all event handling, etc. yourself. For a | 
					
						
							|  |  |  | real understanding you will have to browse the source. Here is a short overview | 
					
						
							|  |  |  | of the classes and what functionality they provide. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <dl> | 
					
						
							|  |  |  | <dt> <CODE>Application</CODE> | 
					
						
							|  |  |  | <dd> | 
					
						
							|  |  |  | This is the toplevel class you will override. It maintains the menu bar and contains | 
					
						
							|  |  |  | the main event handling code. Normal use is to override the <code>__init__</code> routine | 
					
						
							|  |  |  | to do your own initializations and override <code>makeusermenus</code> 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 | 
					
						
							|  |  |  | <code>dispatch</code> method) to intermedeate level (<code>do_keyDown</code>, for instance) | 
					
						
							|  |  |  | to high-level (<code>do_key</code>). The application class knows about the <code>Window</code> | 
					
						
							|  |  |  | objects you create, and will forward events to the appropriate window (So, normally you | 
					
						
							|  |  |  | would have a <code>do_key</code> method in your window object, not your application object). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <dt> <CODE>MenuBar</CODE>, <CODE>Menu</CODE> and <CODE>MenuItem</CODE> | 
					
						
							|  |  |  | <dd> | 
					
						
							|  |  |  | These classes (and a few friends like <CODE>SubMenu</CODE>) 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 <CODE>MenuBar</CODE> and <CODE>Application</CODE>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <dt> <CODE>Window</CODE> | 
					
						
							|  |  |  | <dd> | 
					
						
							|  |  |  | The basic window. Again, a class that you normally subclass in your application, possibly | 
					
						
							|  |  |  | multiple times if you have different types of windows. The init call instantiates the data | 
					
						
							|  |  |  | structure but actually opening the window is delayed until you call <code>open</code>. Your | 
					
						
							|  |  |  | open method should call <code>do_postopen</code> to let the base class handle linking in to | 
					
						
							|  |  |  | the application object. Similarly with <code>close</code> and <code>do_postclose</code>. The | 
					
						
							|  |  |  | rest of the code is mainly event-oriented: you override <code>do_postresize</code>, | 
					
						
							|  |  |  | <code>do_contentclick</code>, <code>do_update</code>, <code>do_activate</code> | 
					
						
							|  |  |  | and <code>do_key</code> to "do your thing". When these methods are called the relevant environment | 
					
						
							|  |  |  | has been setup (like <code>BeginDrawing</code> has been called for updates, etc). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <dt> <CODE>windowbounds</CODE> | 
					
						
							|  |  |  | <dd> | 
					
						
							|  |  |  | Not a class but a function: you pass it a width and height and it will return you a rectangle | 
					
						
							|  |  |  | you can use to create your window. It will take care of staggering windows and it will try | 
					
						
							|  |  |  | to fit the window on the screen (but the resulting rect will <em>always</em> have the size you | 
					
						
							|  |  |  | specify). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <dt> <CODE>ControlsWindow</CODE> | 
					
						
							|  |  |  | <dd> | 
					
						
							|  |  |  | A subclass of Window which automatically handles drawing and clicking for controls. You override | 
					
						
							|  |  |  | the same methods as for Window (if you need to: control-related things are done automatically) and | 
					
						
							|  |  |  | <code>do_controlhit</code>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <dt> <CODE>ScrolledWindow</CODE> | 
					
						
							|  |  |  | <dd> | 
					
						
							|  |  |  | A subclass of ControlsWindow, a window with optional scrollbars. If you override <code>do_activate</code> | 
					
						
							|  |  |  | or <code>do_postresize</code> you must call the ScrolledWindow methods at the end of your override. | 
					
						
							|  |  |  | You call <code>scrollbars</code> to enable/disable scrollbars and <code>updatescrollbars</code> to | 
					
						
							|  |  |  | update them. You provide <code>getscrollbarvalues</code> to return the current x/y values (a helper | 
					
						
							|  |  |  | method <code>scalebarvalues</code> is available) and <code>scrollbarcallback</code> to update your | 
					
						
							|  |  |  | display after the user has used the scrollbars. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <dt> <CODE>DialogWindow</CODE> | 
					
						
							|  |  |  | <dd> | 
					
						
							|  |  |  | A modeless dialog window initialized from a DLOG resource. See the | 
					
						
							|  |  |  | <A HREF="example2.html">second Interslip example</A> for its useage. | 
					
						
							|  |  |  | </dl> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <H2>A sample text editor</H2> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Let us have a look at <A HREF="textedit/ped.py">ped.py</A> (in the Demo:textedit folder), the Pathetic | 
					
						
							|  |  |  | EDitor. It has multiple windows, cut/copy/paste and keyboard input, but that is about all. It looks | 
					
						
							|  |  |  | as if you can resize the window but it does not work. Still, it serves as an example. We will improve | 
					
						
							|  |  |  | on ped later, in a <A HREF="waste.html">waste-based example</A>. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Ped creates two classes, <code>TEWindow</code> and <code>Ped</code>. Let us start with the latter one, | 
					
						
							|  |  |  | which is a subclass of <code>FrameWork.Application</code> 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 <code>makeusermenus</code> is called | 
					
						
							|  |  |  | automatically. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <code>Makeusermenus</code> creates the <code>File</code> and <code>Edit</code> 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. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <code>Updatemenubar</code> handles greying out (and re-enabling) of menu items depending on whether there | 
					
						
							|  |  |  | is a current window and its state. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 <code>_open</code> method (the common code | 
					
						
							|  |  |  | for <code>Open</code> and <code>New</code>) deserves some mention. It instantiates a <code>TEWindow</code> | 
					
						
							|  |  |  | 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. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Oh yes: the <code>quit</code> 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. | 
					
						
							| 
									
										
										
										
											1996-09-17 12:39:12 +00:00
										 |  |  | <p> | 
					
						
							| 
									
										
										
										
											1996-04-19 15:56:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Lastly, there is the <code>idle</code> 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. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The <code>TEWindow</code> 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 | 
					
						
							|  |  |  | <code>ScrolledWindow</code>, and sets itself up at the time of the <code>open</code> call. It obtains screen | 
					
						
							|  |  |  | coordinates, opens the window, creates rectangles for TextEdit to work in (the magical number <code>15</code> | 
					
						
							|  |  |  | 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 <code>getscrollbarvalues</code>) and we activate | 
					
						
							|  |  |  | ourselves (this is unfortunately not done automatically by the MacOS event handling code). <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <code>Do_idle</code> simply calls the TextEdit routine that blinks the cursor. <code>Getscrollbarvalues</code> | 
					
						
							|  |  |  | returns the current X and Y scrollbar values, scaled to <code>0..32767</code>. For X we return <code>None</code>, | 
					
						
							|  |  |  | which means "no scrollbar, please", for Y we use the scaler provided by <code>ScrolledWindow</code>. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <code>Scrollbar_callback</code> is called when the user uses the scrollbar. It is passed a string <code>'x'</code> | 
					
						
							|  |  |  | or <code>'y'</code>, one of <code>'set', '-', '--', '+', '++'</code> and (for <code>set</code>) an absolute | 
					
						
							|  |  |  | value. Note that the sign of the value passed to <code>TEPinScroll</code> is counter-intuitive. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <code>do_activate</code> (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 <code>do_close</code> can | 
					
						
							|  |  |  | return without closing the window (if the document is changed and the users cancels out of the operation). | 
					
						
							|  |  |  | Also note the "magic" in <code>menu_save_as</code> | 
					
						
							|  |  |  | that set the correct window title. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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. <code>Have_selection</code> is called by the menubar update code to determine whether cut and | 
					
						
							|  |  |  | copy should be enabled. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Understanding the main program is left as an exercise to the reader. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <hr> | 
					
						
							|  |  |  | That's all for this example, you could now continue with the <A HREF="waste.html">next example</A>, where we use WASTE, a more-or-less | 
					
						
							|  |  |  | TextEdit compatible library with more functionality, to rebuild our editor. Or you can | 
					
						
							|  |  |  | return to the <A HREF="index.html">table of contents</A> to pick another topic. <p> |