Introduction | Chapter 1 | Chapter 2 | Chapter 3 | Chapter 4 | Chapter 5 | Chapter 6 | CLOS Intro

Allegro CL version 8.0

## Chapter 3: Create the Curves Dialog

1. Start Allegro CL if you exited in Chapter 2. Open the gui-builder-tutorial project we left in Chapter 2. If you have restarted Allegro CL, a dialog may appear asking if you want to open that project, along with any other projects recently worked on. If not, use File | Open Project and choose the file gui-builder-tutorial.lpr in your tutorial project directory, which is C:\Program Files\allegro-projects\gui-builder-tutorial\ or allegro-projects/gui-builder-tutorial/ on Linux if you used the defaults. The Recent menu may also provide a way to open the project. You should now be where you stopped at the end of Chapter 2.
2. In this chapter, you will create a Curves dialog that looks like the following picture (the contents may be different but the dialog will be similar).

3. Click on the New-Form button (or click File | New Form) and make sure that dialog is selected in the New Form dialog that appears. Click on OK to create the new form.

> > ### Selecting a Form: why more choices now?

> > You may notice that there is now a form of type doodler in the list of choices of forms to create. This is because you created a new subclass of dialog of type doodler.

> > Lisp keeps track of all your subclasses in what is most easily described as a giant table. You will begin to see the classes you create appearing in this list whenever you create a new Form. They will all appear regardless of what project you are working in.

4. Resize the new form roughly to match the proportions of the final Curves dialog shown in Step 2.
5. Inspect the new form and change its name to :curve-dialog, its title to Curves, resizable to nil, pop-up to t, maximize-button to nil (if it is not already), and miminize-button to nil (if it is not already). Make sure the child-p property is nil and change it to nil if it is not.

> > ### Naming conventions

> > We recommend that names of windows and controls be mnemonic, begin with a colon, and with the words in each name separated by hyphens. Thus, the name of the curve-dialog window is :curve-dialog, not curvedialog or curve_dialog.

> > ### Changes Made in the Inspector: when do they appear on the application?

> > You will see most of these changes as soon as you move the focus in the inspector, i.e., when you click away from the value you've just changed.

> > But certain changes are not visible on the form while it is in design mode. For example, you’ll have to run this form to see that it is no longer resizable. All forms are resizable in design mode no matter what their resizable property is set to; we want you to be able to resize your application while you are designing it.

> > It is likely to be confusing at first that most changes to the GUI Builder do instantly display in a design-stage form, but some do not. All changes will be evident in the running forms. If you are in doubt about the effect of a change, try evaluating the changed expression, saving your code and running the form.

> > CLOS permits these sorts of dynamic changes. Whether or not a property change will be visible instantly in the design stage will gradually become obvious to you.

6. View the Project Manager dialog (by clicking View | Project Manager). The General Tab should be visible. If not, click on it to bring it forward.
7. Select the curve-dialog and click on the View Selected Code button. You will be placed in the curve-dialog.cl buffer of the Editor Workbook.

8. In the editor, enter:

>     (defclass curve-dialog (dialog)
>       ())

9. Evaluate the defclass form by placing the cursor inside the parentheses or just after the final parenthesis, and clicking Tools | Incremental Evaluation.
10. In the inspector for the curve-dialog, change the class to curve-dialog.

> > Since you are going to make changes to curve-dialog via events and methods, you need to protect dialog from any changes by changing the class property.

11. Sketch a single-item-list control onto the curve-dialog, roughly following the proportions shown in the illustration. (The single-item-list icon shows a rectangle with several lines, one of which is selected. To the right is the multi-item-list, with several lines selected; and to the left the combo-box, with the top line wider than the rest.)

> 1. Click on the single-item-list button on the Components toolbar.
> 2. Click on the curve-dialog form where you want the list control placed.
> 3. Resize it once you've placed it where it should be on the form.

12. Inspect the single-item-list control and change the name to :curve-list, the range to nil, and the value to nil.
13. In the upper-right corner of the curve-dialog, sketch in a default-button. Refer to the diagram in Step 2 for placement of the button. (The default-button icon is third from the left, after button and picture-button.)
14. Inspect the default-button and change its name to :edit-button, its title to "~Edit...".

> > ### Visual Cues and Quick Key Functionality: the ellipsis points & tilde character

> > The tilde character (~) and the ellipsis points (…) are important on this and many other following steps for creating buttons. This is standard application design style; you may choose to implement some other visual flag for these options in making your own applications. Microsoft Word uses an underlined character to indicate a quick key shortcut, for example. Some other applications use a bold or brightly colored character to indicate a shortcut.

> > - You'll need the tilde for special quick key functionality. Inserting a tilde character (~) into the title of a widget (or the value of a static-text) causes the character that follows the tilde to act as a keyboard shortcut to the widget. That character will be underlined when the label is drawn (the tilde itself will not appear). The user may press the key for that character while holding down the Alt key to move the keyboard focus to that widget, and sometimes to simulate a mouse click on the widget, as with buttons and check-boxes. Tildes may be used in menu-item titles in a similar way.
> > - The ellipsis points in a button label (or a menu command) indicate more choices will be required of your users to complete that button’s command once they click it.

15. Click on the icon for a plain button (the first icon from the left, not cancel-button or default-button) and position it below the edit button. Refer to the illustration at step 2 if you need a reminder of what the completed dialog should look like.
16. Inspect the new button and changes its name to :add-button and title to "~Add...".
17. Select the add-button on the form and copy it using the Edit | Copy command. Select the curve-dialog form and paste the copied button onto it using the Edit | Paste command. Position the new button below the Add button.
18. Change the name of the new button to :delete-button and its title to "De~lete".
19. Select the delete-button and copy it using the Edit | Copy command. Then, select the curve-dialog form and paste the button below the Delete button. See the illustration in Step 2 for reference.
20. Change the name of the new button to :draw-all-button and its title to "~Draw All".

> > ### Evenly Spacing Controls on a Form

> > You can Drag-select several widgets on a form by selecting the form. Place the mouse cursor just above the top-most widget of interest and to the left of all widgets of interest. Depress the left mouse key and drag the mouse down and to the right until all desired widgets are included in the region formed by the rubber-band outline that appears. Release the mouse button. All selected widgets should have small white boxes in their corners.

> > Drag-select all the button controls and use the Form | Space Equally command to evenly distribute them over the height of the single-item-list box.

> > Space Equally distributes the buttons in the distance between the two end buttons. Set each of the end buttons where you’d like them to be (at the top and bottom edges of the list) first, then issue the command.

21. Sketch a group-box around the buttons and the single-item-list. Change its name to :group-box and its title to be empty (delete all text from the title property's value).

22. Click on the Save All button on the standard toolbar or click File | Save All, and save your new work to a file called curve-dialog.cl in the tutorial project directory.

## Displaying the Curves Dialog from the Doodler's Window: writing an event handler

23. In the Project Manager dialog, click on doodler and click on the View Selected Code button.
24. Change the defclass for doodler to match the following. This change adds a single slot-specifier to the doodler class.

> >     (defclass doodler (non-refreshing-window)
> >         ((doodler-curve-dialog
> >           :accessor doodler-curve-dialog
> >           :initform nil)))

> > > ### Naming Slots and Accessor Functions

> > > Slot names and their accessor functions should have the same names. This is a convention we use and endorse; it keeps things much simpler.

> > > ### Style Hint

> > > It is better programming style to add a slot than a global variable in this step, because you could have multiple Doodlers running, each with its own curve dialog. Adding a global variable would create a conflict there.

25. Evaluate the new doodler defclass (put the cursor in or at the end of the form and click Tools | Incremental Evaluation).

> > > ### The Status Bar

> > > Evaluating the defclass awakens Lisp to the new class relationships. You can also see the results of your evaluations and other actions in the Status Bar (the gray band at the bottom of the Project Window directly underneath the Standard Toolbar on the left side).

26. Inspect the multi-picture-button on the doodler's toolbar.
27. In the inspector change to the Events tab, select on-change value by clicking the right-hand field. Enter doodler-toolbar-click.

> > This is (or will be) the name of the on-change event-handler function for the multi-picture-button (which you placed in the doodler form’s toolbar). You are about to write this event handler.

28. Click on the button with three dots just to the right of doodler-toolbar-click. This displays the doodler buffer of the Editor Workbook. You'll see some skeleton code for the on-change handler. Because you just gave it a name in the inspector, the handler is already named doodler-toolbar-click.
29. Edit the on-change function definition to match the following:

> >     (defun doodler-toolbar-click
> >            (widget new-value old-value)
> >        (declare
> >          (ignore-if-unused widget new-value old-value))
> >        ;; Do the action only when a button is
> >        ;; being pressed (not unpressed)
> >      (when new-value
> >       (let ((doodler (parent (parent widget))))
> >             (case (first new-value)
> >               (:curve
> >                 (show-curve-dialog doodler))
> >               (t nil)))
> >          )
> >        (not new-value))

> > You do this by replacing the whole definition with the above or adding this part where the cursor is placed:

> >     (let ((doodler (parent (parent widget))))
> >           (case (first new-value)
> >             (:curve
> >               (show-curve-dialog doodler))
> >           (t nil)))

> > and replacing the t in the last line with

> >     (not new-value)

> > Do not evaluate the new definition yet. (If you do, you will get a warning that the function show-curve-dialog is undefined. We are about to define it.)

30. Now add the show-curve-dialog method and the close :before method to the same buffer.

> >     (defmethod show-curve-dialog ((window doodler))
> >        (let* ((dialog (doodler-curve-dialog window)))
> >           (when (or (not dialog)
> >                     (not (windowp dialog)))
> >              (setq dialog
> >                    (make-curve-dialog :owner window))
> >              (setf (doodler-curve-dialog window) dialog))
> >           (select-window dialog)))

> >     (defmethod close :before ((window doodler) &key)
> >        (let ((curve-dialog (doodler-curve-dialog window)))
> >           (when (and (windowp curve-dialog) curve-dialog)
> >              (close curve-dialog))
> >           (setf (doodler-curve-dialog window) nil)))

> > > ### What’s going on here?

> > > The show-curve-dialog method is responsible for creating displaying, and initializing the curve-dialog. It first checks to see if there is a valid curve-dialog, and if needed will create one and save it in the doodler-curve-dialog slot. Then it selects the curve-dialog; selecting the dialog un-hides it and brings it to the front of the display.

> > > Since the doodler creates the curve-dialog, it must also close it. Closing the doodler automatically closes all of its child windows, but curve-dialog is a pop-up window, not a child window.

> > > The owner window of the curve-dialog is the doodler, therefore the doodler must explicitly close the curve-dialog. Use a :before method on close so that the curve-dialog is closed before the doodler.

31. Save the doodler.cl editor (click File | Save All or clicking the Save All button).
32. Select all contents of the buffer using the Edit | Select All command.
33. Evaluate using the Compile Definition button (or click Tools | Incremental Evaluation).

> > You may see a warning about show-curve-dialog being undefined in a message box. If so, click OK and ignore the warning.

34. Focus on the Doodler window and run the doodler project (with the Run button or Run | Run Project). Try displaying the curve-dialog by clicking on the Curve button in the Doodler. The Curves dialog should float in front of the Doodler window, but none of the buttons will work yet. (You may be prompted to save the project files. Do so.)
35. Leave the Doodler form running and the Curves dialog open. Continue to the next step.
36. In the doodler buffer, change the show-curve-dialog method to match the following:

>     (defmethod show-curve-dialog ((window doodler))
>        (let* ((dialog (doodler-curve-dialog window)))
>           (when (or (not dialog)
>                     (not (windowp dialog)))
>              (setq dialog
>                    (make-curve-dialog :owner window))
>              (setf (doodler-curve-dialog window) dialog)
>           ;; Position the dialog to the
>           ;; left of the main window.
>          (let* ((pos (window-to-screen-units
>                        window
>                       (make-position
>                         (- (+ (exterior-width dialog) 10))
>                            40))))
>            ;; But don't let it go off the left
>            ;; edge of the screen.
>            (setf (position-x pos)
>                  (max 0 (position-x pos)))
>            (move-window dialog pos)))
>          (select-window dialog)))

> > ### What’s going on?

> > This revised method makes the dialog float in a position downward and to the left of the running Doodler. You’ll verify this change in a few steps.

> > Because CLOS is dynamic, you can incrementally change code, evaluate it, and try it without leaving run mode. Make incremental changes in your code to verify that it works before adding further capabilities. This is good programming practice.

> > With the change you’ve just made to show-curve-dialog, the Curves dialog will be positioned in a new place. Before you verify that, you’ll test a feature called Complete Symbol that may speed up your future programming work.

> > The second change to show-curve-dialog places the coordinates for a single cycloidal curve in the Curves dialog. You’ll make that change after you verify the first change.

37. Evaluate the new method. Move the running Doodler upward toward the top edge of the screen to insure that you can see at least a portion of the title bar before continuing to the next step (move the ACL Project window down if necessary).
38. Choose Tools | Get Component. The cursor should change to a cross.
39. Click on the title bar of the running doodler window (the cursor will be an arrow when over the Doodler window).
40. Move focus to the Debug window. The cursor should have changed back to normal now. The running Doodler will now have disappeared behind other windows and forms.
41. Type in * and hit enter. Notice that * is bound to the running doodler window. The value will be something like

> >     #<doodler :doodler in Run Project :gui-builder-tutorial @ #x20f4190a>

42. Type in (setf doodler *) and hit the ENTER key.
43. At the prompt, type in (close (do and use the Search | Complete Symbol command.

> The system will display all symbols starting with do. There are a lot of them. You will have to type more text in for Complete Symbol to be useful. You will do this in the next steps. Use the ESC key to get rid of the pop-up list of symbol completions for now.

44. Type in odler-c so that the prompt now shows (close (doodler-c. Use the Search | Complete Symbol command again. This time the symbol should complete to doodler-curve-dialog.
45. Finish the expression so that you have

> >     (close (doodler-curve-dialog doodler))

> at the prompt. Then evaluate it by pressing ENTER. The result should be t. Note that the curve-dialog has disappeared.

> > ### What happened?

> > You just used Get Component, Complete Symbol, and a small amount of Lisp to find and close the curve-dialog while the application was still running.

46. Save your work using the Save All button.
47. Close the running Doodler and run the project again using the Run Project button.
48. Click on the Curve button on the toolbar in the running Doodler window. Notice that the Curves dialog is displayed downward and toward the left with respect to the running Doodler window now. The single-item-list should still be empty.
49. When you are finished reviewing the progress, stop running the Doodler with the Stop button.
50. In the doodler.cl editor, change show-curve-dialog to match the following:

> >     (defmethod show-curve-dialog ((window doodler))
> >        (let ((dialog (doodler-curve-dialog window))
> >              (curve-list nil)) ; step 50
> >          (when (or (not dialog)
> >                    (not (windowp dialog)))
> >             (setq dialog
> >                   (make-curve-dialog :owner window))
> >             (setf (doodler-curve-dialog window) dialog)
> >             (setq curve-list ; step 50
> >             (find-component :curve-list dialog))
> >             (setf (range curve-list) ; step 50
> >                   (list
> >                     (make-instance 'cycloidal-curve)))
> >          ;; Position the dialog to the
> >          ;; left of the main window.
> >          (let* ((pos (window-to-screen-units
> >                        window
> >                       (make-position
> >                        (- (+ (exterior-width dialog) 10))
> >                           40))))
> >            ;; But don't let it go off the left
> >            ;; edge of the screen.
> >            (setf (position-x pos)
> >                  (max 0 (position-x pos)))
> >            (move-window dialog pos)))
> >          (select-window dialog)))

51. Click on the Save All button to save all changes.
52. Run the doodler using the Run Project button or the Run | Run Project command.
53. In the running Doodler, click on the Curve button on the toolbar. The Curves dialog single-item-list should display the parameters for a single cycloidal curve. The buttons on the Curves dialog will click, but nothing will happen yet when they are clicked. You still shouldn't be able to draw anything. You'll activate the Draw All button in the next Chapter.
54. Stop the running Doodler when you are finished testing it.
55. Go to chapter 4. If you wish to, you can stop working on the tutorial now and return to it later. All the work you have done has been saved.

Copyright © 2001-2004 Franz Inc. All rights reserved.

Introduction | Chapter 1 | Chapter 2 | Chapter 3 | Chapter 4 | Chapter 5 | Chapter 6 | CLOS Intro

Allegro CL version 8.0