727 lines
34 KiB
Rexx
Executable File
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
|
|
|