rexx-things/modules/windows/oodialog/menus/ContextMenu.rex
2025-03-12 20:50:48 +00:00

727 lines
34 KiB
Rexx
Executable File

/*----------------------------------------------------------------------------*/
/* */
/* Copyright (c) 2008-2014 Rexx Language Association. All rights reserved. */
/* */
/* This program and the accompanying materials are made available under */
/* the terms of the Common Public License v1.0 which accompanies this */
/* distribution. A copy is also available at the following address: */
/* https://www.oorexx.org/license.html */
/* */
/* Redistribution and use in source and binary forms, with or */
/* without modification, are permitted provided that the following */
/* conditions are met: */
/* */
/* Redistributions of source code must retain the above copyright */
/* notice, this list of conditions and the following disclaimer. */
/* Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in */
/* the documentation and/or other materials provided with the distribution. */
/* */
/* Neither the name of Rexx Language Association nor the names */
/* of its contributors may be used to endorse or promote products */
/* derived from this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
/* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/*----------------------------------------------------------------------------*/
/* A demonstration of some of the Menu features in ooDialog.
*
* This example focuses on context menus. Two different context menus are used
* in this example, showing 2 different ways to create the context menus. One
* of the context menus is shown when the user right-clicks on the list view
* control. The other context menu is shown when the user right-clicks on any
* other place on the dialog. The first menu is specific to the list view, the
* other menu is specific to the dialog.
*
* The list view menu is created by loading a menu from a resource script file.
* Menus created from a resouce script are always menu bars. In this example,
* the menu bar is *not* attached to the dialog, rather it is simply used as the
* source of the list view context menu.
*
* The second context menu is created dynamically using methods of the PopupMenu
* class.
*/
-- Locate the directory our source code is in. Then this program can be
-- executed from anywhere. It will work if the program is dragged and dropped
-- on ooDialog.exe for instance.
srcDir = locate()
-- When using symbolic IDs with menus, as this program does, the programmer
-- *must* use the global constant directory, (.constDir,) rather than the
-- constDir attribute of a dialog. Menus are independent of dialogs.
--
-- The use of the global constant directory is controlled by the .Application
-- object. The .Application object is also used to set other application-wide
-- defaults or values. In this program, we also want to make the default for
-- automatic data detection to be off. Both of these requirements can be done
-- with one method call to the .Application object. As a convenience, the
-- setDefaults() method will also populate the .constDir with symbols.
--
-- In this invokcation, the application is set to use the .constDir only, "O",
-- symbols are loaded into the .constDir from the file: ContextMenu.h, and the
-- default for automatic data detection is set to off (.false.) Note that we
-- create a complete path name for ContextMenu.h
.application~setDefaults("O", srcDir'ContextMenu.h', .false)
-- The folloing demonstrates that menu objects are distinct from dialogs.
--
-- You can create a menu completely indepedent of a dialog. Note that at this
-- point in the program, there is no dialog object at all. Once created, the
-- menu object can then be used where ever it is convenient.
--
-- The code for creating the list view menu is put in a separate function so
-- that people can focus on only one thing at a time. The function is at the
-- end of this file. In createListViewMenu(), the context menu is created
-- dynamically and passed back to us.
contextMenu = createListViewMenu()
-- Create a RcDialog as normally done.
dlg = .ContextMenuDlg~new(srcDir"ContextMenu.rc", IDD_CONTEXT)
-- putMenu() is a method added to our dialog class. It is used to pass the
-- context menu object to the dialog. There are any number of ways to
-- accomplish this. For instance the menu object could have been passed in
-- as an argument to new() above.
dlg~putMenu(contextMenu)
-- Excute the dialog as usual.
if dlg~initCode = 0 then do
dlg~execute("SHOWTOP")
end
else do
say 'Error creating the context menu dialog initCode:' dlg~initCode
return 99
end
return 0
-- End of entry point.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
Directives, Classes, or Routines.
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
::requires "ooDialog.cls"
::class 'ContextMenuDlg' subclass RcDialog
/** init()
*
* The init() method is invoked for every object instantiation. This is part of
* ooRexx and has nothing to do with ooDialog, except for this:
*
* ooDialog programming is primarily based on subclassing the dialog classes
* provided by the ooDialog framework. If you over-ride the init() method, you
* *must* initialize the base class, with the proper arguments for the base
* class, before you invoke any methods of the base class.
*
* Here with create the second context menu and create some arrays that contain
* the list view items. Both of these tasks do not need to be done in this
* method, they could be done elsewhere.
*/
::method init
expose dlgPopup
use arg rcScript, dlgID
forward class (super) continue
-- A menu bar can be loaded from a resource script file using the
-- .ScriptMenuBar class.
--
-- The first argument to init(), rcScript, is the .rc file that contains the
-- dialog template. That .rc file also contains the menu template for the
-- dialog context menu. In the new method of the .ScriptMenuBar the .rc file
-- is parsed and the menu with symbolic resource id of: IDM_RC_DLG is loaded
-- into memory.
menuBar = .ScriptMenuBar~new(rcScript, IDM_RC_DLG)
-- If an error occurs in a menu object initialization, then a condition is
-- always raised. menuBar will never be 0
if menuBar == 0 then do
-- This code will never execute because if the menu bar was not created, a
-- condition was raised.
say 'ERROR: menubar shold be good, not 0.'
say 'A condition should have been raised.'
say 'SystemErrorCode:' .SystemErrorCode SysGetErrortext(.SystemErrorCode)
self~initCode = 1
return
end
-- A menu bar is made up of a number of pop up menus. You can get one of
-- those pop up menus by specifying either its resource ID or its position.
--
-- In this program, the menu bar itself is not used. It contains only 1 pop
-- up menu, which is used as a context menu in this program. Which pop up
-- menu to get is specified either by its resource ID or by its position in
-- the menu. Here, we get it by its position, which is 1. Since both a
-- resource ID and a position are numbers, we need to denote whether we are
-- getting the menu by position or by resource ID. The second argument is the
-- 'byPosition' argument. If true, the first arugment is a position. If
-- false, the first argument is a resource ID. The default is .false.
dlgPopup = menubar~getPopup(1, .true)
-- Start with the menu item to enable the list view greyed out.
dlgPopup~disable(IDM_RC_ENABLE_LV)
-- Create an array of items for the list view control. This could be done in
-- initDialog(), or anywhere convenient.
self~createArrays()
/** initDialog()
*
* initDialog() is invoked automatically by the dialog framework as soon as the
* underlying Windows dialog is created. This is the place to do any
* initialization of the dialog controls, initialization that requires the
* underlying dialog or dialog control to exist.
*
* We would not necessarily need to make the menu connections here. However,
* as you will see in makeMenuConnections() method, we are using the window
* handles of the dialog and the list view to filter the context menu
* notifications. This does require that the underlying dialog and controls do
* exist.
*/
::method initDialog
self~makeMenuConnections
self~initListView
/** makeMenuConnections()
*
* Connects the menu related events to event handling methods in this dialog.
*
* There are 2 types of connections made here.
*
* 1.) The context menu event is connected. The context menu event is generated
* when ever the user right clicks on the dialog, types the shift-F10 keyboard
* combination, or the VK_APPS key (Natural keyboard.) The context menu event
* needs to be connected to a method that shows the context menu.
*
* 2.) The menu item command events are connected. A menu item command event is
* generated when the user selects a menu item.
*/
::method makeMenuConnections private
expose lvPopup dlgPopup
-- Connect a click on a menu item in the short cut menus to this dialog.
--
-- For the dialog popup menu, we connect all menu items to the same method,
-- onMenuCommand(). onMenuCommand() will recieve the resource ID of the menu
-- item selected, and we use that to decide what action to take.
if \ dlgPopup~connectAllCommandEvents(onMenuCommand, self) then do
say 'Error conecting menu items. SystemErrorCode:' || -
.SystemErrorCode SysGetErrortext(.SystemErrorCode)
end
-- To understand this explanation, note this point: although menu objects are
-- independent of dialog objects, at the time a menu is shown, the operating
-- system requires that the underlying menu be assigned to an underlying
-- dialog. For menu bars, the assigned dialog is the dialog the menu bar is
-- attached to. For pop up menus, the menu could be assigned to a dialog each
-- time the context menu is shown. But, it is usually more convenient to just
-- assign the menu to a dialog one time. That is what the assignTo() method
-- does.
--
-- For the list view pop up menu, we connect each menu item to its own method.
-- There are menu methods to connect individual menu items. But there are
-- also a number of convenience methods to connect a number of menu items at
-- one time.
--
-- The second optional arguement in assignTo() turns on automatic menu item
-- connection. The default is off. The third optional argument is the name
-- of a method to connect all the items to. So, you can either connect each
-- menu item to its own method, (omit the third argument,) or you can connect
-- all menu items to one method. When each menu item is connected to its own
-- method, the method name is constructed by the ooDialog framework using the
-- text of the menu item.
--
-- For example, if the menu item text is 'Blow your own horn' then the method
-- name will be blowYourOwnHorn().
--
-- This is what we do here, assign the list view menu to this dialog, and at
-- the same time connect all the menu item comand events to an individual
-- method.
if \ lvPopup~assignTo(self, .true) then do
say 'Error conecting menu items. SystemErrorCode:' || -
.SystemErrorCode SysGetErrortext(.SystemErrorCode)
end
say
-- Next we connect the context menu message (right mouse click) with two
-- methods. If you supply a window handle as the second, optional, parameter,
-- then the event notifications are filtered by that window handle. In this
-- way you can easily show a context menu specific to a certain control. If
-- you do not use a window handle to filter the event notifications, you can
-- still do the same thing, you just need to determine the mouse position at
-- the time of the event and relate that position to the context menu you
-- want to show
--
-- Here we send all right-clicks on the list-view control to one method and
-- all clicks on the dialog to a second method.
if \ lvPopup~connectContextMenu(onListViewContext, self~newListView(IDC_LV)~hwnd) then do
say 'Error conecting context menu. SystemErrorCode:' || -
.SystemErrorCode SysGetErrortext(.SystemErrorCode)
end
-- If we only use the first connectContextMenu(), then right clicks on the Ok
-- and cancel buttons are ignored. The shift-F10 and VK_APPS events are
-- also ignored when either of the buttons has the focus.
--
-- That's perfectly fine, but it depends on what you want. Here, we pretend
-- that we don't want that behavior, and show how to prevent it. Simply add
-- filtered connections for the Ok and Cancel push buttons.
--
-- You can play with this to see it works. Comment out the third and forth
-- connections and then tab to the Ok or Cancel key and use Shift-F10. There
-- will be no context menu. Or right click on one of those buttons, no
-- context menu. Uncomment the connections and try the same thing.
if \ dlgPopup~connectContextMenu(onDialogContext, self~hwnd, self) then do
say 'Error conecting context menu. SystemErrorCode:' || -
.SystemErrorCode SysGetErrortext(.SystemErrorCode)
end
else if \ dlgPopup~connectContextMenu(onDialogContext, self~newPushButton(IDOK)~hwnd, self) then do
say 'Error conecting context menu. SystemErrorCode:' || -
.SystemErrorCode SysGetErrortext(.SystemErrorCode)
end
else if \ dlgPopup~connectContextMenu(onDialogContext, self~newPushButton(IDCANCEL)~hwnd, self) then do
say 'Error conecting context menu. SystemErrorCode:' || -
.SystemErrorCode SysGetErrortext(.SystemErrorCode)
end
/** onListViewContext()
*
* This is an event handler for the context menu event.
*
* The context menu event is generated when the user right-clicks the mouse,
* types the shift-F10 key combination, or types the VK_APPS key. In this
* program, onListViewContext() is only generated when the mouse is right
* clicked on the list view control, or if the list view has the input focus and
* shift-F10 or VK_APPS are used.
*
* Look at the makeMenuConnections() method to see how the connection is made.
*
* Three arguments are passed to the event handler for the context menu event:
* the window handle of the window clicked, (or that has the focus if it is a
* keyboard event,) and x / y co-ordinates. For a mouse click, the x / y co-
* ordinates are the position of the mouse, in pixels. For the keyboard keys, x
* and y are both -1.
*
* When the x and y arguments are -1, we need to decide where to place the
* context menu when it is shown. This is a design decision, there is no real
* right answer. A normal thing to do here would be to place it at the selected
* list view item. Instead, I decided to place at the lower right corner of the
* list view. However, the list view has a vertical scroll bar which is within
* the area of the list view and I didn't like the look of that.
*
* So, I decided to move it to the left of the scroll bar. I still didn't like
* that because of the shadowing, so I take that point and shift it up and over
* 15 pixels.
*/
::method onListViewContext
expose lvPopup listView
use arg hwnd, x, y
if x == -1, y == -1 then do
-- The keyboard was used, not the mouse. Position the context menu as
-- described in the comments above.
rect = listView~windowRect
x = rect~right - .SM~cxVScroll + 15
y = rect~bottom - 15
end
-- pos is the point on the screen, in pixels, to place the context menu.
pos = .Point~new(x, y)
-- We show the menu. The second optional argument is the dialog to assign the
-- the menu to, but we've already done that in makeMenuConnections().
ret = lvPopup~show(pos)
if ret == -1 then do
say 'lvPopup~show() failed SystemErrorCode:' || -
.SystemErrorCode SysGetErrortext(.SystemErrorCode)
end
/** onDialogContext()
*
* This is an event handler for the context menu event.
*
* The comments for onListViewContext() above apply here. This method is
* invoked when the user rigth clicks anywhere but the list-view, or for the
* keyboard context menu event, whenever the list view does not have the focus.
*
* Here we also need to decide where to position the context menu for the
* keyboard event. I decided to place it in the rectangluar space between the
* rigth edge of the list view and the right edge of the dialog, in the center.
* I don't count the dialog caption bar as part of that space.
*/
::method onDialogContext
expose dlgPopup listView
use arg hwnd, x, y
if x == -1, y == -1 then do
-- The keyboard was used, not the mouse. Position the context menu as
-- described in the comments above.
lvR = listView~windowRect
dlgR = self~windowRect
xOffset = (dlgR~right - lvR~right) % 2
yOffset = (dlgR~bottom - (dlgR~top + .SM~cyCaption)) % 2
x = lvR~right + xOffset
y = dlgR~bottom - yOffset
end
-- This is the point where the context menu is positioned.
pos = .Point~new(x, y)
-- In contrast to the list view pop up menu, the dialog pop up menu has never
-- been assigned to a dialog. Therefore, each time we show it, we need to
-- specify the dialog owner. Which is done in the second arguemnt.
ret = dlgPopup~show(pos, self)
if ret == -1 then do
say 'dlgPopup~show() failed SystemErrorCode:' || -
.SystemErrorCode SysGetErrortext(.SystemErrorCode)
end
/** onMenuCommand()
*
* This is the event handler for any menu item selected in the dialog pop up
* menu. We simply determine which menu item was selected through the id
* argument and take the appropriate action.
*/
::method onMenuCommand unguarded
use arg id
select
when id == .constDir[IDM_RC_SHOW ] then self~showMessage
when id == .constDir[IDM_RC_ENABLE_LV ] then self~enableListView(.true)
when id == .constDir[IDM_RC_DISABLE_LV] then self~enableListView(.false)
when id == .constDir[IDM_RC_BEEP ] then beep(330, 250)
when id == .constDir[IDM_RC_QUIT ] then return self~ok
end
-- End select
/** sort()
*
* The event handler when the Sort menu item is selected in the list view pop up
* menu.
*/
::method sort
expose sArray
self~rearrangeItems(sArray)
/** jumble()
*
* The event handler when the Jumble menu item is selected in the list view pop
* up menu.
*
* Here we re-order the list view items in a somewhat random order.
*/
::method jumble
expose nArray
tempArray = .array~new(11)
indexes = .set~new
do while indexes~items < 11
count = indexes~items
do while indexes~items == count
i = random(1, 11)
if \ indexes~hasItem(i) then do
tempArray~append(nArray[i])
indexes~put(i)
end
end
end
self~rearrangeItems(tempArray)
/** reverseSort()
*
* The event handler when the Reverse Sort menu item is selected in the list
* view pop up menu.
*/
::method reverseSort
expose rsArray
self~rearrangeItems(rsArray)
/** orderByFirstName()
*
* The event handler when the Order By First Name menu item is selected in the
* list view pop up menu.
*/
::method orderByFirstName
expose fnArray
self~rearrangeItems(fnArray)
/** orderByLastName()
*
* The event handler when the Order By Last Name menu item is selected in the
* list view pop up menu.
*/
::method orderByLastName
expose lnArray
self~rearrangeItems(lnArray)
/** orderByProfession()
*
* The event handler when the Order By Profession menu item is selected in the
* list view pop up menu.
*/
::method orderByProfession
expose profArray
self~rearrangeItems(profArray)
/** restoreOriginalOrder()
*
* The event handler when the Restore Original Order menu item is selected in
* the list view pop up menu.
*/
::method restoreOriginalOrder
expose nArray
self~rearrangeItems(nArray)
/** rearrangeItems()
*
* Places the list view items in the order specified. As explained elsewhere,
* the purpose of this example program is to show how context menus work, not
* to show how list view controls work.
*
* Therefore we don't actually sort the list view items, we just use some pre-
* ordered arrays of the items. To change the order, we delete all the existing
* items and replace them using the an array of the same items in a different
* order. The array is passed in here as the 'a' argument.
*
* The disable, delete, prepare ... enable redraw sequence seems, to me, to
* reduce flicker in the list view. However, there are not enough items in the
* list view to tell for sure. An interesting experiment would be to try it
* with several hundreds of items.
*/
::method rearrangeItems private
expose listView
use strict arg a
listView~disable
listView~deleteAll
listView~prepare4nItems(11)
do r over a
listView~addRow( , , r~fName, r~lName, r~profession)
end
listView~enable
listView~redrawItems
/** showMessage()
*
* Helper method. Shows a simple message to the user in response to the Show
* Message menu item.
*/
::method showMessage private
msg = "This is a good example of context menus."
z = MessageDialog(msg, self~hwnd, "Context Menu Message", "OK", "INFORMATION")
/** enableListView()
*
* Helper method. Enables or disables the list view control in response to the
* Enable List View or Disable List View menu items.
*
* When the list view control is enabled, we disable the Enable List View menu
* item and enable the Disable List View menu item. When the list view is
* disabled we do the reverse. Note that when the list view is disabled, it is
* no longer possible for the user to trigger the list view context menu.
*/
::method enableListView private
expose listView dlgPopup
use strict arg enable
if enable then do
dlgPopup~disable(IDM_RC_ENABLE_LV)
dlgPopup~enable(IDM_RC_DISABLE_LV)
listView~enable
end
else do
dlgPopup~disable(IDM_RC_DISABLE_LV)
dlgPopup~enable(IDM_RC_ENABLE_LV)
listView~disable
end
/** initListView()
*
* Initializes the list view by adding the columns, setting the extended list
* view style, and adding the list view items.
*/
::method initListView private
expose nArray listView
listView = self~newListView(IDC_LV)
listView~addExtendedStyle("FULLROWSELECT DOUBLEBUFFER GRIDLINES")
listView~insertColumnPX(1, 'First Name', 68)
listView~insertColumnPX(2, 'Last Name', 70)
listView~insertColumnPX(3, 'Profession', 102)
do r over nArray
listView~addRow( , , r~fName, r~lName, r~profession)
end
/** createArrays()
*
* The purpose of this example program is to demonstrate how context menus work,
* not how list view controls work. Rather than actually sort the list view
* items, we just produce some pre-sorted arrays to use.
*
* The n, ln, fn, etc., prefixes stand for normal, first name, last name,
* profession, sorted, and reverse sorted.
*/
::method createArrays private
expose nArray lnArray fnArray profArray sArray rsArray
nArray = .array~new(11)
lnArray = .array~new(11)
fnArray = .array~new(11)
profArray = .array~new(11)
sArray = .array~new(11)
rsArray = .array~new(11)
nArray[1 ] = .directory~new~~put('Mark', fName)~~put('Thompson', lName)~~put('Mechanic', profession)
nArray[2 ] = .directory~new~~put('Sue', fName)~~put('Lamont', lName)~~put('Nurse', profession)
nArray[3 ] = .directory~new~~put('Mary', fName)~~put('Greensmith', lName)~~put('CEO', profession)
nArray[4 ] = .directory~new~~put('Susan', fName)~~put('Dunn', lName)~~put('Stock broker', profession)
nArray[5 ] = .directory~new~~put('Hank', fName)~~put('Miller', lName)~~put('Librarian', profession)
nArray[6 ] = .directory~new~~put('Larry', fName)~~put('Williams', lName)~~put('Doctor', profession)
nArray[7 ] = .directory~new~~put('Alice', fName)~~put('Toklas', lName)~~put('Dentist', profession)
nArray[8 ] = .directory~new~~put('Bill', fName)~~put('Maher', lName)~~put('Lawyer', profession)
nArray[9 ] = .directory~new~~put('Vail', fName)~~put('Miesfeld', lName)~~put('Software Engineer', profession)
nArray[10] = .directory~new~~put('Eric', fName)~~put('Clapton', lName)~~put('Cook', profession)
nArray[11] = .directory~new~~put('Christin', fName)~~put('Henesy', lName)~~put('Detective', profession)
lnArray[1 ] = .directory~new~~put('Eric', fName)~~put('Clapton', lName)~~put('Cook', profession)
lnArray[2 ] = .directory~new~~put('Susan', fName)~~put('Dunn', lName)~~put('Stock broker', profession)
lnArray[3 ] = .directory~new~~put('Mary', fName)~~put('Greensmith', lName)~~put('CEO', profession)
lnArray[4 ] = .directory~new~~put('Christin', fName)~~put('Henesy', lName)~~put('Detective', profession)
lnArray[5 ] = .directory~new~~put('Sue', fName)~~put('Lamont', lName)~~put('Nurse', profession)
lnArray[6 ] = .directory~new~~put('Bill', fName)~~put('Maher', lName)~~put('Lawyer', profession)
lnArray[7 ] = .directory~new~~put('Vail', fName)~~put('Miesfeld', lName)~~put('Software Engineer', profession)
lnArray[8 ] = .directory~new~~put('Hank', fName)~~put('Miller', lName)~~put('Librarian', profession)
lnArray[9 ] = .directory~new~~put('Mark', fName)~~put('Thompson', lName)~~put('Mechanic', profession)
lnArray[10] = .directory~new~~put('Alice', fName)~~put('Toklas', lName)~~put('Dentist', profession)
lnArray[11] = .directory~new~~put('Larry', fName)~~put('Williams', lName)~~put('Doctor', profession)
fnArray[1 ] = .directory~new~~put('Alice', fName)~~put('Toklas', lName)~~put('Dentist', profession)
fnArray[2 ] = .directory~new~~put('Bill', fName)~~put('Maher', lName)~~put('Lawyer', profession)
fnArray[3 ] = .directory~new~~put('Christin', fName)~~put('Henesy', lName)~~put('Detective', profession)
fnArray[4 ] = .directory~new~~put('Eric', fName)~~put('Clapton', lName)~~put('Cook', profession)
fnArray[5 ] = .directory~new~~put('Hank', fName)~~put('Miller', lName)~~put('Librarian', profession)
fnArray[6 ] = .directory~new~~put('Larry', fName)~~put('Williams', lName)~~put('Doctor', profession)
fnArray[7 ] = .directory~new~~put('Mark', fName)~~put('Thompson', lName)~~put('Mechanic', profession)
fnArray[8 ] = .directory~new~~put('Mary', fName)~~put('Greensmith', lName)~~put('CEO', profession)
fnArray[9 ] = .directory~new~~put('Sue', fName)~~put('Lamont', lName)~~put('Nurse', profession)
fnArray[10] = .directory~new~~put('Susan', fName)~~put('Dunn', lName)~~put('Stock broker', profession)
fnArray[11] = .directory~new~~put('Vail', fName)~~put('Miesfeld', lName)~~put('Software Engineer', profession)
profArray[1 ] = .directory~new~~put('Mary', fName)~~put('Greensmith', lName)~~put('CEO', profession)
profArray[2 ] = .directory~new~~put('Eric', fName)~~put('Clapton', lName)~~put('Cook', profession)
profArray[3 ] = .directory~new~~put('Alice', fName)~~put('Toklas', lName)~~put('Dentist', rprofession)
profArray[4 ] = .directory~new~~put('Christin', fName)~~put('Henesy', lName)~~put('Detective', profession)
profArray[5 ] = .directory~new~~put('Larry', fName)~~put('Williams', lName)~~put('Doctor', profession)
profArray[6 ] = .directory~new~~put('Bill', fName)~~put('Maher', lName)~~put('Lawyer', profession)
profArray[7 ] = .directory~new~~put('Hank', fName)~~put('Miller', lName)~~put('Librarian', profession)
profArray[8 ] = .directory~new~~put('Mark', fName)~~put('Thompson', lName)~~put('Mechanic', profession)
profArray[9 ] = .directory~new~~put('Sue', fName)~~put('Lamont', lName)~~put('Nurse', profession)
profArray[10] = .directory~new~~put('Vail', fName)~~put('Miesfeld', lName)~~put('Software Engineer', profession)
profArray[11] = .directory~new~~put('Susan', fName)~~put('Dunn', lName)~~put('Stock broker', profession)
-- Sorted array is same as fnArray
sArray[1 ] = .directory~new~~put('Alice', fName)~~put('Toklas', lName)~~put('Dentist', profession)
sArray[2 ] = .directory~new~~put('Bill', fName)~~put('Maher', lName)~~put('Lawyer', profession)
sArray[3 ] = .directory~new~~put('Christin', fName)~~put('Henesy', lName)~~put('Detective', profession)
sArray[4 ] = .directory~new~~put('Eric', fName)~~put('Clapton', lName)~~put('Cook', profession)
sArray[5 ] = .directory~new~~put('Hank', fName)~~put('Miller', lName)~~put('Librarian', profession)
sArray[6 ] = .directory~new~~put('Larry', fName)~~put('Williams', lName)~~put('Doctor', profession)
sArray[7 ] = .directory~new~~put('Mark', fName)~~put('Thompson', lName)~~put('Mechanic', profession)
sArray[8 ] = .directory~new~~put('Mary', fName)~~put('Greensmith', lName)~~put('CEO', profession)
sArray[9 ] = .directory~new~~put('Sue', fName)~~put('Lamont', lName)~~put('Nurse', profession)
sArray[10] = .directory~new~~put('Susan', fName)~~put('Dunn', lName)~~put('Stock broker', profession)
sArray[11] = .directory~new~~put('Vail', fName)~~put('Miesfeld', lName)~~put('Software Engineer', profession)
-- Just reverse the array indexes
rsArray[11] = .directory~new~~put('Alice', fName)~~put('Toklas', lName)~~put('Dentist', profession)
rsArray[10] = .directory~new~~put('Bill', fName)~~put('Maher', lName)~~put('Lawyer', profession)
rsArray[9 ] = .directory~new~~put('Christin', fName)~~put('Henesy', lName)~~put('Detective', profession)
rsArray[8 ] = .directory~new~~put('Eric', fName)~~put('Clapton', lName)~~put('Cook', profession)
rsArray[7 ] = .directory~new~~put('Hank', fName)~~put('Miller', lName)~~put('Librarian', profession)
rsArray[6 ] = .directory~new~~put('Larry', fName)~~put('Williams', lName)~~put('Doctor', profession)
rsArray[5 ] = .directory~new~~put('Mark', fName)~~put('Thompson', lName)~~put('Mechanic', profession)
rsArray[4 ] = .directory~new~~put('Mary', fName)~~put('Greensmith', lName)~~put('CEO', profession)
rsArray[3 ] = .directory~new~~put('Sue', fName)~~put('Lamont', lName)~~put('Nurse', profession)
rsArray[2 ] = .directory~new~~put('Susan', fName)~~put('Dunn', lName)~~put('Stock broker', profession)
rsArray[1 ] = .directory~new~~put('Vail', fName)~~put('Miesfeld', lName)~~put('Software Engineer', profession)
-- The putMenu() method simply provides a convenient way to pass in the menu
-- object created in the program entry code to this dialog.
::method putMenu
expose lvPopup
use strict arg lvPopup
/** routine::createListViewMenu()
*
* This routine creates the list view context menu dynamically using methods of
* the .PopupMenu. It is very easy to use. Menu items can be inserted or
* removed from a menu at any time.
*
* The other point that is being made by creating this menu in a routine is that
* menu objects are truely independent of a dialog. A menu object can be
* created without any existing dialogs. The object can then be used with any
* dialog.
*/
::routine createListViewMenu
use strict arg
-- Create a new empty pop up menu.
m = .PopupMenu~new(IDM_LV_BAR)
-- Insert the menu items. The first argument is the resource ID of the item
-- before which the inserted item goes. The second argument is the resource
-- ID of the item to insert.
--
-- For the first item, since there are no items in the menu, the insert before
-- argument does not matter. I ususally just use the same resource ID as the
-- item being inserted. You could use any positive number.
--
-- For the rest of the items, here they are just sort of in a random order.
-- This is to demonstrate how the 'insert before' works. I usually insert the
-- items in a last comes first order because it makes it a little easy to
-- visualize how the menu will look, if you picture the menu upside down.
m~insertItem(IDM_LV_RESTORE, IDM_LV_RESTORE, "Restore Original Order")
m~insertItem(IDM_LV_RESTORE, IDM_LV_PROFESSION, "Order by Profession")
m~insertItem(IDM_LV_PROFESSION, IDM_LV_FNAME, "Order by First Name")
m~insertItem(IDM_LV_FNAME, IDM_LV_REVERSE, "Reverse Sort")
m~insertItem(IDM_LV_REVERSE, IDM_LV_SORT, "Sort")
m~insertItem(IDM_LV_REVERSE, IDM_LV_JUMBLE, "Jumble")
m~insertItem(IDM_LV_PROFESSION, IDM_LV_LNAME, "Order by Last Name")
m~insertSeparator(IDM_LV_FNAME, IDM_LV_SEP1)
m~insertSeparator(IDM_LV_RESTORE, IDM_LV_SEP2)
return m