rexx-things/modules/windows/oodialog/propertysheet.tabControls/ticketWizard.rex
2025-03-12 20:50:48 +00:00

1276 lines
41 KiB
Rexx
Executable File

/*----------------------------------------------------------------------------*/
/* */
/* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
/* Copyright (c) 2005-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. */
/* */
/*----------------------------------------------------------------------------*/
/** Propery Sheet / Wizard97 example
*
* This example demonstrates how to use the PropertySheetDialog to create a
* Wizard. There are two main wizard styles for a property sheet, the Wizard97
* style and the Aero style. Wizard97 will run on any Windows version supported
* by ooRexx. The Aero wizard needs Windows Vista or later.
*
* This example creates all the pages as UserDialogs where the programmer lays
* each dialog template in the defineDialog() method. This is really rather
* tedious. It is much easier to use a resource editor, especially here where
* the programmer wants to create a number of page dialogs that are all the same
* size.
*
* However, it is a good opportunity to give examples of how to correctly
* convert between pixels and dialog units in the defineDialog() method to get
* the dialog template laid out correctly when different fonts are used for the
* dialog. To facilate that part of the example, the user is allowed to pick
* different fonts and font sizes for the wizard before it is displayed. This
* may not be the best sample program for that, because it is not possible, at
* this time, to change the font of the wizard itself.
*
* This is a rather complex program. The commenting is not 100%. Be sure to
* read the ooDialog documentation on the PropertySheetDialog to fully under-
* stand this program.
*
* Note: this program uses the public routine, locate(), to get the full path
* name to the directory this source code file is located. In places, the
* variable holding this value has been callously abbreviated to 'sd' which
* stands for source directory.
*
*/
sd = locate()
.application~useGlobalConstDir('O', sd"rc\ticketWizard.h")
-- Let the user select a font for the example program.
oldFont = setFont()
-- We show a timed message to explain what the upcoming example is about.
-- This is a hold-over from the original ooRexx examples. The reality is, it
-- gets rather annoying after the first 2 or 3 times you run the example. I
-- would prefer to eliminate this code.
msg = "The upcoming dialog demonstrates a Wizard 97 style dialog."
title = "Wizard 97 Dialog"
dlg = .TimedMessage~new(msg, title, 2000)
dlg~execute
-- First we create the dialogs for each page, and set any of the attributes
-- we need to. We want each dialog to be the same size.
outPageSize = .Size~new(267, 193)
inPageSize = .Size~new(267, 143)
intro = .IntroDlg~new( , , "", "ooRexx Movie Ticket Selectitron")
intro~setSize(outPageSize)
p1 = .MoviesDlg~new( , , "", "Movies")
p1~setSize(inPageSize)
p1~headerTitle = "Select the movie(s) you want tickets for."
p1~headerSubtitle = "When a movie is selected, information on the movie, such as director, actors, " -
"etc., will also be displayed."
p2 = .CinemasDlg~new( , , "", "Cinemas" )
p2~setSize(inPageSize)
p2~headerTitle = "Pick a movie theater for the movie(s)."
p2~headerSubtitle = "Pick a theater for each movie you've selected. Use the drop down list to switch movies. " -
"Theaters in your vicinity showing the movie(s) this week are listed. "
p3 = .DaysDlg~new( , , "", "Days" )
p3~setSize(inPageSize)
p3~headerTitle = "Choose a day to watch the movie(s)."
p3~headerSubtitle = "Use the drop down list to switch movies. Pick the day most suitable for the movie."
p4 = .TicketDlg~new( , , "", "Ticket Information" )
p4~setSize(inPageSize)
p4~headerTitle = "Validate your selections and indicate the time desired."
p4~headerSubtitle = "Pick a time for each movie selected. Ticket information for each movie can be displayed " -
"using the drop down list. To change any selections use the Back button."
complete = .CompletionDlg~new( , , "", "Enjoy Your Movie")
complete~setSize(outPageSize)
pages = .array~of(intro, p1, p2, p3, p4, complete)
-- Create the property sheet using the dialog pages and set its attributes.
wizDlg = .TicketWizard97~new(pages, "Wizard97", "Let's Go To The Movies")
wizDlg~header = .Image~getImage(sd"rc\ticketWizardTheater.bmp")
wizDlg~watermark = .Image~getImage(sd"rc\ticketWizardRexxLA.bmp")
-- Execute the wizard.
wizDlg~execute
ret = restoreFont(oldFont)
return
::requires "ooDialog.cls"
-- TicketWizard97
-- The property sheet for the example program. Although the
-- PropertySheetDialog has a number of methods, we do not need to over-ride
-- any of the methods. So, we just need the class definition line here.
::class 'TicketWizard97' subclass PropertySheetDialog
-- IntroDlg
-- Dialog for first page (exterior page, introduction.)
::class 'IntroDlg' subclass UserPSPDialog
::method defineDialog
-- Watermark bitmap is 164 x 316. The wizard does not stretch the bitmap,
-- its size remains constant. So, the size taken up by the bitmap, in
-- dialog units, changes as the font size changes. Use pixel2dlgUnit() to
-- convert the pixel size of the watermark to the correct dialog units for
-- the font this dialog is using.
s = .Size~new(164, 314)
self~pixel2dlgUnit(s)
x = s~width + 6
y = 8 -- From the Wizard97 specification.
cx = self~sizeX - x -- To the right side of the template, the wizard automatically adds 14 dlus.
cy = 3 * 12 -- Using 12 point font, takes 3 lines for the msg.
self~createStaticText(IDC_ST_INTRO_MSG, x, y, cx, cy, "", "")
y += cy + 8 -- Space the next static 8 dlus below the first.
cy = 8 * 8 -- Arbitray height to fit the info text.
self~createStaticText(IDC_ST_INTRO_INFO, x, y, cx, cy, "", "")
cy = 8 -- Normal font size height.
y = self~sizeY - 7 - cy -- From the Wizard97 specification, leave 7 dlus margin on bottom.
self~createStaticText(IDC_ST_INTRO_LAST_MSG, x, y, cx, cy, "", "")
::method setActive unguarded
use arg propSheet
-- Back button disabled, Next button enabled.
propSheet~setWizButtons("NEXT")
return 0
::method initDialog
msg = "Welcome to the ooRexx Movie Ticket Selectitron Wizard"
font1 = self~createFontEx("Verdana", 12, "BOLD") -- From the Wizard97 specification.
st1 = self~newStatic(IDC_ST_INTRO_MSG)
st1~setFont(font1)
st1~setText(msg)
info = "This wizard will help you select a ticket, or tickets, for the movie(s) of your choice. For each" -
"ticket you will specify the theater and time for the movie you wish to see." || .endOfLine~copies(2) || -
"Tickets for any movies playing in the upcoming week are available. Select as many" -
"movies as you wish to see."
self~newStatic(IDC_ST_INTRO_INFO)~setText(info)
msg = "Select the Next button to continue"
self~newStatic(IDC_ST_INTRO_LAST_MSG)~setText(msg)
::method initAutoDetection
self~noAutoDetection
-- MoviesDlg
-- Dialog for second page (interior page, movie selection.)
::class 'MoviesDlg' subclass UserPSPDialog
::method defineDialog
x = 21 -- From the Wizard97 specification.
y = 1 -- From the Wizard97 specification, the Wizard
-- automatically adds a 7 dlu marging on all sides.
self~createGroupBox(-1, x, y, 113, 125, , "The upcoming movies")
self~createListBox(31, x + 10, y + 15, 93, 105, "MULTI NOTIFY GROUP", "MovieList")
x += 125 + 10
self~createStaticText(-1, x, y, 60, 8, , "Produced by:")
self~createEdit(32, x, y + 12, 84, 12, "READONLY GROUP", "Produced")
y += 15 * 2
self~createStaticText(-1, x, y, 60, 8, , "Starring:")
self~createEdit(33, x, y + 12, 84, 12, "READONLY GROUP", "Star")
y += 15 * 2
self~createStaticText(-1, x, y, 60, 8, , "Director:")
self~createEdit(34, x, y + 12, 84, 12, "READONLY GROUP", "Director")
y += 15 * 2
self~createStaticText(-1, x, y, 60, 8, , "With:")
self~createComboBox(35, x, y + 12, 84, 33, "LIST GROUP", "COMBOBOX")
self~connectListBoxEvent(31, "SELCHANGE", "onMovieClick")
::method pageCreate unguarded
self~setMovieData
return .true
::method setMovieData private
expose movieData films lastSelected
films = .array~of("Vertigo", "Taxi Driver", "Superman", "Larger than Life", -
"Hair", "Cinderella", "True Lies", "E.T.", "Twister", "Lawnmower Duel")
movieData = .table~new
do i = 1 to films~items
d = .directory~new
movieData[films[i]] = d
end
d = movieData[films[1]]
d~produced = "Paramount"; d~star = "Kim Novak"; d~director = "Alfred Hitchcock"
d~with = .array~of("James Stewart")
d = movieData[films[2]]
d~produced = "Universal"; d~star = "Robert De Niro"; d~director = "Martin Scorsese"
d~with = .array~of("Jodie Foster", 'Albert Brooks', 'Harvey Keitel', 'Cybill Shepherd')
d = movieData[films[3]]
d~produced = "Warner Bros"; d~star = "Christopher Reeves"; d~director = "Richard Donner"
d~with = .array~of('Marlon Brando', 'Gene Hackman', 'Margot Kidder')
d = movieData[films[4]]
d~produced = "United Artists"; d~star = "The Elephant"; d~director = "Howard Franklin"
d~with = .array~of("Bill Murray")
d = movieData[films[5]]
d~produced = "Hippies"; d~star = "John Savage"; d~director = "Milos Forman"
d~with = .array~of("Beverly D'Angelo", 'Dorsey Wright', 'Cheryl Barnes', 'Treat Williams', 'Annie Golden')
d = movieData[films[6]]
d~produced = "Disney"; d~star = "Cinderella"; d~director = "Walt"
d~with = .array~of('Step mother', 'Witch', 'Prince', 'King')
d = movieData[films[7]]
d~produced = "20. Century Fox"; d~star = "Arnold Schwarzenegger"; d~director = "James Cameron"
d~with = .array~of('Jamie Lee Curtis', 'Tom Arnold', 'Richard Harris')
d = movieData[films[8]]
d~produced = "United Artists"; d~star = "The Extra-Terrestrial"; d~director = "Steven Spielberg"
d~with = .array~of('Henry Thomas', 'Drew Barrymore', 'Dee Wallace', 'Peter Coyote')
d = movieData[films[9]]
d~produced = "Warner Bros"; d~star = "Helen Hunt"; d~director = "Jan De Bont"
d~with = .array~of("Bill Paxten")
d = movieData[films[10]]
d~produced= "Sunset Mowers"; d~star = "The Lawn Mower"; d~director = "Mower Pusher"
d~with = .array~of('Lawn', 'Garden hose', 'Sprinkler', 'Shredder')
self~movieList = 0
::method setActive unguarded
use arg propSheet
propSheet~setWizButtons("BACK NEXT")
return 0
-- wizNext()
-- The user clicked the next button. If the user does not pick a movie, we
-- don't let her proceed to the next page. There is no point in using the
-- wizard without selecting a movie. We use wizNext() rather than
-- killActive() because killActive is invoked both when the user clicks the
-- Back and the Next buttons. If the user wants to go back to the intor page,
-- we don't want to put up an annoying message box.
::method wizNext
expose lb
use arg propSheet
count = lb~selectedItems
if count < 1 then do
msg = "To purchase a ticket, you must select at".endOfLine"least one movie."
j = MessageDialog(msg, propSheet~hwnd, "ooRexx Movie Ticket Selectitron", "OK", "INFORMATION")
return -1
end
return 0
::method initDialog
expose films lb
lb = self~newListBox(31)
do i = 1 to films~items
lb~add(films[i])
end
lb~deselectIndex
::method onMovieClick unguarded
expose movieData
use arg , , id, nCode, listBox
movieName = listBox~selected
combo = self~newComboBox(35)
combo~deleteAll
-- If no movie in the list box is selected, set eveything blank, otherwise,
-- set everything to match the selected movie.
if movieName == "" then do
self~newEdit(32)~setText("")
self~newEdit(33)~setText("")
self~newEdit(34)~setText("")
combo~add("")
end
else do
d = movieData[movieName]
self~newEdit(32)~setText(d~produced)
self~newEdit(33)~setText(d~star)
self~newEdit(34)~setText(d~director)
do n over d~with
combo~add(n)
end
combo~selectIndex(1)
end
return 0
::method queryFromSibling unguarded
expose lb films
use arg arg1, arg2, propSheet
select
when arg2 == "FILMS" then do
-- arg1 is an array that we fill in with all the movies
arg1~empty
do i = 1 to films~items
arg1[i] = films[i]
end
end
when arg2 == "SELECTED" then do
-- arg1 is a table, we set an index for each selected movie. Note that
-- the item for the
arg1~empty
currentSelectedMovies = self~getSelectedMovies
do i = 1 to currentSelectedMovies~items
arg1[currentSelectedMovies[i]] = .true
end
end
when arg2 == "DATA" then do
-- arg1 is a table whose indexes are the films. Each item is a directory
-- indexes are theater, date, and time. The other pages fill in the
-- directory. We just make sure only the selected movies are in the
-- table.
arg1~empty
currentSelectedMovies = self~getSelectedMovies
do movie over currentSelectedMovies
d = .directory~new
arg1[movie] = d
end
end
otherwise do
-- We do not handle any other queries.
nop
end
end
-- End select
return 0
::method getSelectedMovies unguarded
expose lb
count = lb~selectedItems
if count < 1 then return .array~new
a = .array~new(count)
indexes = lb~selectedIndexes
do i over indexes~makeArray(" ")
a~append(lb~getText(i))
end
return a
-- CinemasDlg
-- Dialog for the third page (interior page, theater selection.)
::class 'CinemasDlg' subclass UserPSPdialog
::method defineDialog
expose buttonTable
x = 21; y = 1
self~createStaticText(-1, x, y, 100, 8, , "Selected movies:")
self~createComboBox(IDC_COMBO_CINEMAS, x, y + 12, 170, 75, "LIST SORT", "COMBOBOX")
y += 15 * 2
self~createGroupBox(-1, x, y, 170, 105, "", "Theaters")
y += 10; x += 10
self~createRadioButton(IDC_RB_CINEMAS_UPTOWN, x, y, 145, 12, "TABSTOP", "&Uptown San Jose Cinemas")
y += 15
self~createRadioButton(IDC_RB_CINEMAS_PALO, x, y, 145, 12, "", "&Palo Alto News Scene")
y += 15
self~createRadioButton(IDC_RB_CINEMAS_CHARLIES, x, y, 145, 12, "", "&Charlie's Suburban Barn Theater")
y += 15
self~createRadioButton(IDC_RB_CINEMAS_DRIVEIN, x, y, 145, 12, "", "&Drive-in above Highway 101")
y += 15
self~createRadioButton(IDC_RB_CINEMAS_GRAND, x, y, 145, 12, "", "&Grand Black n White Movies Monterey")
y += 15
self~createRadioButton(IDC_RB_CINEMAS_BROADWAY, x, y, 145, 12, "", "&Broadway Cinema San Francisco")
first = self~resolveSymbolicID(IDC_RB_CINEMAS_FIRST)
last = self~resolveSymbolicID(IDC_RB_CINEMAS_LAST)
self~connectComboBoxEvent(IDC_COMBO_CINEMAS, "SELENDOK", "onComboUpdate")
do i = first to last
self~connectButtonEvent(i, "CLICKED", onRBClick)
end
buttonTable = .table~new
buttonTable["Uptown San Jose Cinemas"] = IDC_RB_CINEMAS_UPTOWN
buttonTable["Palo Alto News Scene"] = IDC_RB_CINEMAS_PALO
buttonTable["Charlie's Suburban Barn Theater"] = IDC_RB_CINEMAS_CHARLIES
buttonTable["Drive-in above Highway 101"] = IDC_RB_CINEMAS_DRIVEIN
buttonTable["Grand Black n White Movies Monterey"] = IDC_RB_CINEMAS_GRAND
buttonTable["Broadway Cinema San Francisco"] = IDC_RB_CINEMAS_BROADWAY
::method initDialog
expose filmArray movieTheaters selectedMovies movieCombo
filmArray = .array~new(20)
self~propSheet~querySiblings(filmArray, "FILMS")
movieTheaters = .table~new
do movie over filmArray
movieTheaters[movie] = .nil
end
selectedMovies = .array~new
movieCombo = self~newComboBox(IDC_COMBO_CINEMAS)
::method setActive unguarded
expose filmArray movieTheaters selectedMovies movieCombo
use arg propSheet
propSheet~setWizButtons("BACK NEXT")
selected = .table~new
selectedMovies~empty
propSheet~querySiblings(selected, "SELECTED")
movieCombo~deleteAll
-- For every movie, check if it is now selected. If it is, we add it to the
-- selected moveies combo box. If it isn't, we mark that movie as not having
-- a movie theater selected. We don't care what the previous setting was.
do movie over filmArray
if selected~hasIndex(movie) then do
movieCombo~add(movie)
selectedMovies~append(movie)
end
else do
movieTheaters[movie] = .nil
end
end
if selected~items > 0 then do
movieCombo~selectIndex(1)
movie = movieCombo~selected
self~setRadioButtons(movie)
end
return 0
-- wizNext()
-- The user clicked the next button. If there is not a theater selected for
-- each selected movie, we warn the user. We use wizNext() rather than
-- killActive() because killActive is invoked both when the user clicks the
-- Back and the Next buttons. If the user is going back, we don't want to put
-- up an annoying message box.
::method wizNext unguarded
expose selectedMovies movieTheaters movieCombo
use arg propSheet
do movie over selectedMovies
if movieTheaters[movie] == .nil then do
msg = "Warning. You have not selected a movie theater for all".endOfLine"selected movies." || -
.endOfLine~copies(2) || "Are you sure you want to go to the next page?"
title = "Theater Selection is not Complete"
buttons = "YESNO"
icon = "WARNING"
style = "DEFBUTTON2 TASKMODAL"
ans = MessageDialog(msg, propSheet~dlgHandle, title, buttons, icon, style)
if ans == .PlainBaseDialog~IDYES then return 0
movieCombo~select(movie)
self~setRadioButtons(movie)
return -1
end
end
return 0
::method queryFromSibling unguarded
expose movieTheaters
use arg arg1, arg2, propSheet
select
when arg2 == "DATA" then do
-- arg1 is a table whose indexes are the films. Each item is a directory
-- indexes are theater, date, and time. We only fill in the theater index
-- for any movie in the table. We do not care what our status is for the
-- theater, we just fill it in.
do movie over arg1
d = arg1[movie]
d~theater = movieTheaters[movie]
end
end
otherwise do
-- We do not handle any of the other queries.
nop
end
end
-- End select
return 0
::method onComboUpdate
expose movieTheaters movieCombo
movie = movieCombo~selected
self~setRadioButtons(movie)
::method onRBClick
expose movieTheaters movieCombo
use arg id, hwnd
movie = movieCombo~selected
movieTheaters[movie] = self~newRadioButton(id)~getText~changestr("&", "")
::method setRadioButtons private
expose movieTheaters buttonTable
use arg movie
movieTheater = movieTheaters[movie]
if movieTheater == .nil then id = 0
else id = buttonTable[movieTheater]
.RadioButton~checkInGroup(self, IDC_RB_CINEMAS_FIRST, IDC_RB_CINEMAS_LAST, id)
-- DaysDlg
-- Dialog for the fourth page (interior page, date selection.)
::class 'DaysDlg' subclass UserPSPdialog
::method defineDialog
expose buttonTable
dayNames = .array~of('&Monday', '&Tuesday', '&Wednesday', 'T&hursday', '&Friday', '&Saturday', 'S&unday')
x = 21; y = 1
self~createStaticText(-1, x, y, 100, 8, , "Selected movies:")
self~createComboBox(IDC_COMBO_DAYS, x, y + 12, 170, 75, "LIST SORT", "COMBOBOX")
-- The space on this page is rather tight, so we try to make the group box as
-- narrow as possible without clipping any of the radio buttons. I like a
-- margin of 10 within the group box.
y += 15 * 2
cx = self~calcWidthRadioButtons(dayNames)
cy = self~sizeY - y
self~createGroupBox(-1, x, y, cx + 20, cy, "", "Day for Movie")
-- We create the radio buttons in a loop, so we take advantage of that to do
-- the button event connections and other related tasks.
buttonTable = .table~new
first = self~resolveSymbolicID(IDC_RB_DAYS_FIRST)
last = self~resolveSymbolicID(IDC_RB_DAYS_LAST)
y += 10; x += 10
do id = first to last
day = dayNames[id - first + 1]
self~createRadioButton(id, x, y, cx, 12, "", day)
self~connectButtonEvent(id, "CLICKED", onRBClick)
buttonTable[day~changestr("&", "")] = id
y += 14
end
-- The movie bitmap is 238 X 178, convert that to dialog units and place at
-- the lower right corner.
s = .Size~new(238, 178)
self~pixel2dlgUnit(s)
x = self~sizeX - s~width
y = self~sizeY - s~height
self~createStaticImage(IDC_ST_MOVIE_BMP, x, y, s~width, s~height, "BITMAP SIZEIMAGE CENTERIMAGE")
self~connectComboBoxEvent(IDC_COMBO_DAYS, "SELENDOK", "onComboUpdate")
-- calcWidthRadioButtons()
-- Given an array of the labels for a group of radio buttons, calculates the
-- smallest width necessary for the buttons so that the widest label is not
-- clipped.
::method calcWidthRadioButtons private
use strict arg labels
width = 0
do l over labels
size = self~getTextSizeDu(l)
if size~width > width then width = size~width
end
-- There doesn't seem to be any direct way to find out the width of the radio
-- button bitmap, the little round circle. But, some of the MSDN doc
-- *suggests* that it is 10 x 10 in dlus.
width += 10
return width
::method initDialog
expose filmArray movieDays selectedMovies movieCombo
sd = locate()
staticImage = self~newStatic(IDC_ST_MOVIE_BMP)
size = staticImage~getRealSize
image = .Image~getImage(sd'rc\ticketWizardMovie.bmp', BITMAP, size)
staticImage~setImage(image)
filmArray = .array~new(20)
self~propSheet~querySiblings(filmArray, "FILMS")
movieDays = .table~new
do movie over filmArray
movieDays[movie] = .nil
end
selectedMovies = .array~new
movieCombo = self~newComboBox(IDC_COMBO_DAYS)
::method setActive unguarded
expose movieCombo selectedMovies filmArray movieDays
use arg propSheet
propSheet~setWizButtons("BACK NEXT")
selected = .table~new
selectedMovies~empty
propSheet~querySiblings(selected, "SELECTED")
movieCombo~deleteAll
do movie over filmArray
if selected~hasIndex(movie) then do
selectedMovies~append(movie)
movieCombo~add(movie)
end
else do
movieDays[movie] = .nil
end
end
if selected~items > 0 then do
movieCombo~selectIndex(1)
movie = movieCombo~selected
self~setRadioButtons(movie)
end
return 0
-- wizNext()
-- We check if the user has set the day for each selected movie. If not, we
-- warn the user, let the user decide if he wants to continue or not.
::method wizNext unguarded
expose selectedMovies movieDays movieCombo
use arg propSheet
do movie over selectedMovies
if movieDays[movie] == .nil then do
msg = "Warning. You have not selected a day to attend the" || .endOfLine || -
"movie for all selected movies." || .endOfLine~copies(2) || -
"Are you sure you want to go to the next page?"
title = "Date Selection is not Complete"
buttons = "YESNO"
icon = "WARNING"
style = "DEFBUTTON2 TASKMODAL"
ans = MessageDialog(msg, propSheet~dlgHandle, title, buttons, icon, style)
if ans == .PlainBaseDialog~IDYES then return 0
movieCombo~select(movie)
self~setRadioButtons(movie)
return -1
end
end
return 0
::method queryFromSibling unguarded
expose movieDays
use arg arg1, arg2, propSheet
select
when arg2 == "DATA" then do
-- arg1 is a table whose indexes are the films. Each item is a directory
-- indexes are theater, date, and time. We only fill in the date index
-- for any movie in the table. We do not care what our status is for the
-- theater, we just fill it in.
do movie over arg1
d = arg1[movie]
d~date = movieDays[movie]
end
end
otherwise do
-- We do not handle any of the other queries.
nop
end
end
-- End select
return 0
::method onComboUpdate
expose movieCombo
movie = movieCombo~selected
self~setRadioButtons(movie)
::method onRBClick
expose movieDays movieCombo
use arg id, hwnd
movie = movieCombo~selected
movieDays[movie] = self~newRadioButton(id)~getText~changestr("&", "")
::method setRadioButtons private
expose movieDays buttonTable
use arg movie
movieDay = movieDays[movie]
if movieDay == .nil then id = 0
else id = buttonTable[movieDay]
.RadioButton~checkInGroup(self, IDC_RB_DAYS_FIRST, IDC_RB_DAYS_LAST, id)
-- TicketDlg
-- Dialog for the fifth page (interior page, time selection and review.)
::class 'TicketDlg' subclass UserPSPdialog
::method defineDialog
expose buttonTable
x = 21; y = 1
self~createStaticText(-1, x, y, 100, 8, , "Selected movies:")
self~createComboBox(IDC_COMBO_TIMES, x, y + 12, 170, 75, "LIST SORT", "COMBOBOX")
label = "Theater:"
size = self~getTextSizeDu(label)
y += 15 *2
x1 = x + size~width + 1
cx1 = 170 - size~width - 1
self~createStaticText(-1, x, y + 2, size~width, size~height, "RIGHT", label)
self~createBlackFrame(-1, x1, y, cx1, size~height + 6, "")
self~createStaticText(IDC_ST_TIMES_THEATER, x1 + 4, y + 2, cx1 - 8, size~height, "", "")
y += 20
self~createStaticText(-1, x, y + 2, size~width, size~height, "RIGHT", "Date:")
self~createBlackFrame(-1, x1, y, cx1, size~height + 6, "")
self~createStaticText(IDC_ST_TIMES_DAY, x1 + 4, y + 2, cx1 - 8, size~height, "", "")
y += size~height + 6 + 4
cy = self~sizeY - y
self~createGroupBox(-1, x, y, 60, cy, "", "Time:")
times = .array~of("11:00", "17:00", "20:00", "22:00")
buttonTable = .table~new
first = self~resolveSymbolicID(IDC_RB_TIMES_FIRST)
last = self~resolveSymbolicID(IDC_RB_TIMES_LAST)
x += 10; y += 10; cx = 40; cy = 12
do id = first to last
time = times[id - first + 1]
self~createRadioButton(id, x, y, cx, cy, "", time)
self~connectButtonEvent(id, "CLICKED", onRBClick)
buttonTable[time] = id
y +=15
end
self~connectComboBoxEvent(IDC_COMBO_TIMES, "SELENDOK", "onComboUpdate")
::method initDialog
expose filmArray selectedMovies movieTimes movieData movieCombo staticTheater staticDay
filmArray = .array~new(20)
self~propSheet~querySiblings(filmArray, "FILMS")
movieTimes = .table~new
do movie over filmArray
movieTimes[movie] = .nil
end
-- We also need a table to keep track of the selected theaters and days sent
-- to us from the Cinemas and Days pages.
movieData = .table~new
selectedMovies = .array~new
movieCombo = self~newComboBox(IDC_COMBO_TIMES)
staticTheater = self~newStatic(IDC_ST_TIMES_THEATER)
staticDay = self~newStatic(IDC_ST_TIMES_DAY)
::method setActive unguarded
expose filmArray selectedMovies movieCombo movieTimes movieData
use arg propSheet
propSheet~setWizButtons("BACK NEXT")
propSheet~querySiblings(movieData, "DATA")
selected = .table~new
selectedMovies~empty
movieCombo~deleteAll
propSheet~querySiblings(selected, "SELECTED")
do movie over filmArray
if selected~hasIndex(movie) then do
movieCombo~add(movie)
selectedMovies~append(movie)
end
else do
movieTimes[movie] = .nil
end
end
if selected~items > 0 then do
movieCombo~selectIndex(1)
movie = movieCombo~selected
self~setMovieData(movie)
end
return 0
-- wizNext()
-- This is the last page before completion. Here we do not let the user
-- proceed unless every selected movie has each item (theater, day, and time)
-- specified.
::method wizNext unguarded
expose selectedMovies movieTimes movieData movieCombo
use arg propSheet
-- We make two loops over the selected movies. The first is to force the
-- user to select a time for very selected movie. Once that passes, we then
-- loop over the movie data and check that the day and theater is specified
-- for each selected movie. If we find a piece of information missing in the
-- second loop, we return the user to the proper page to fill in the info.
do movie over selectedMovies
if movieTimes[movie] == .nil then do
msg = "You have not selected a time to attend the" || .endOfLine || -
"movie:" movie || .endOfLine~copies(2) || -
"You must specify a time to attend each movie."
title = "Time Selection is not Complete"
buttons = "OK"
icon = "EXCLAMATION"
ans = MessageDialog(msg, propSheet~dlgHandle, title, buttons, icon)
movieCombo~select(movie)
self~setMovieData(movie)
return -1
end
end
do movie over selectedMovies
d = movieData[movie]
if d~theater == .nil then do
msg = "You have not selected a theater for the" || .endOfLine || -
"movie:" movie || .endOfLine~copies(2) || -
"You must specify a theater, day, and time" || .endOfLine || -
"for each movie ticket."
title = "Ticket Information is not Complete"
buttons = "OK"
icon = "EXCLAMATION"
ans = MessageDialog(msg, propSheet~dlgHandle, title, buttons, icon)
-- Return the page index of the Cinemas page to switch to that page
return 3
end
if d~date == .nil then do
msg = "You have not selected a day to attend the" || .endOfLine || -
"movie:" movie || .endOfLine~copies(2) || -
"You must specify a theater, day, and time" || .endOfLine || -
"for each movie ticket."
title = "Ticket Information is not Complete"
buttons = "OK"
icon = "EXCLAMATION"
ans = MessageDialog(msg, propSheet~dlgHandle, title, buttons, icon)
-- Return the page index of the Days page to switch to that page
return 4
end
end
return 0
::method queryFromSibling unguarded
expose movieTimes
use arg arg1, arg2, propSheet
select
when arg2 == "DATA" then do
do movie over arg1
d = arg1[movie]
d~time = movieTimes[movie]
end
end
otherwise do
nop
end
end
-- End select
return 0
::method onComboUpdate
expose movieCombo
movie = movieCombo~selected
self~setMovieData(movie)
::method onRBClick
expose movieTimes movieCombo
use arg id, hwnd
movie = movieCombo~selected
movieTimes[movie] = self~newRadioButton(id)~getText~changestr("&", "")
::method setMovieData private
expose movieTimes buttonTable movieData staticTheater staticDay
use arg movie
movieTime = movieTimes[movie]
if movieTime == .nil then id = 0
else id = buttonTable[movieTime]
.RadioButton~checkInGroup(self, IDC_RB_TIMES_FIRST, IDC_RB_TIMES_LAST, id)
d = movieData[movie]
if d~theater == .nil then text = "==> No theater was selected"
else text = d~theater
staticTheater~setText(text)
if d~date == .nil then text = "==> No day selected"
else text = d~date
staticDay~setText(text)
-- CompletionDlg
-- Dialog for the sixth page (exterior page, review and finish.)
::class 'CompletionDlg' subclass UserPSPDialog
::method defineDialog
expose sd
sd = locate()
-- Watermark bitmap is 164 x 316. The wizard does not stretch the bitmap,
-- its size remains constant. So, the width of the bitmap, in dialog units,
-- changes as the font changes. pixel2dlgUnit() will convert the pixel size
-- of the bitmap to the correct dialog units for the font in use by this
-- dialog.
s = .Size~new(164, 314)
self~pixel2dlgUnit(s)
x = s~width + 6 -- 6 dlus right of the edge of the watermark bitmap.
y = 8 -- From the Wizard97 specification.
cx = self~sizeX - x -- To the right side of the template, the wizard automatically adds 14 dlus.
cy = 3 * 12 -- Using 12 point font, takes 3 lines for the msg.
self~createStaticText(IDC_ST_COMPLETE_MSG, x, y, cx, cy, "", "")
-- Things are a little crowded on this page, so only add 4 dlus of space
-- between the top message and the next control. (Contrast this to the
-- IntroDlg.)
y += cy + 4
self~createStaticText(-1, x, y, 165, 8, , "Ticket information for your selected movie(s):")
self~createComboBox(IDC_COMBO_COMPLETE, x, y + 12, 165, 63, "LIST SORT PARTIAL", "COMBOBOX")
label = "Theater:"
size = self~getTextSizeDu(label)
y += 15 * 2
x1 = x + size~width + 1
cx1 = 165 - size~width - 1
self~createStaticText(-1, x, y + 2, size~width, size~height, "", label)
self~createBlackFrame(-1, x1, y, cx1, size~height + 6)
self~createStaticText(IDC_ST_COMPLETE_THEATER, x1 + 4, y + 2, cx1 - 8, size~height)
y += 20
self~createStaticText(-1, x, y + 2, size~width, size~height, "", "Date:")
self~createBlackFrame(-1, x1, y, cx1, size~height + 6)
self~createStaticText(IDC_ST_COMPLETE_DAY, x1 + 4, y + 2, cx1 - 8, size~height)
y += 20
self~createStaticText(-1, x, y + 2, size~width, size~height, "", "Time:")
self~createBlackFrame(-1, x1, y, cx1, size~height + 6)
self~createStaticText(IDC_ST_COMPLETE_TIME, x1 + 4, y + 2, cx1 - 8, size~height)
-- ticket.bmp is 204 x 80 pixels, convert to dialog units and place it in
-- the lower left corner. At the x margin.
s = .Size~new(204, 80)
self~pixel2dlgUnit(s)
y = self~sizeY - s~height - 4
if .DlgUtil~comCtl32Version < 6 then do
self~createBitmapButton(IDC_PB_TICKET_BMP, x, y, s~width, s~height, "FRAME USEPAL STRETCH GROUP", "Get the Ticket", -
'onGetTicket', sd"rc\ticketWizardTicket.bmp")
end
else do
self~createPushButton(IDC_PB_TICKET_BMP, x, y, s~width, s~height, "GROUP", "", 'onGetTicket')
end
self~connectComboBoxEvent(IDC_COMBO_COMPLETE, "SELENDOK", "onComboUpdate")
::method initDialog
expose movieCombo staticTheater staticDay staticTime sd
msg = "Thank You For Using the ooRexx Movie Ticket Selectitron Wizard"
font1 = self~createFontEx("Verdana", 12, "BOLD")
st1 = self~newStatic(IDC_ST_COMPLETE_MSG)
st1~setFont(font1)
st1~setText(msg)
movieCombo = self~newComboBox(IDC_COMBO_COMPLETE)
staticTheater = self~newStatic(IDC_ST_COMPLETE_THEATER)
staticDay = self~newStatic(IDC_ST_COMPLETE_DAY)
staticTime = self~newStatic(IDC_ST_COMPLETE_TIME)
if .DlgUtil~comCtl32Version < 6 then return
bmpButton = self~newPushButton(IDC_PB_TICKET_BMP)
size = bmpButton~getRealSize
size~width -= 10;
size~height -= 10;
sd = locate()
image = .Image~getImage(sd'rc\ticketWizardTicket.bmp', BITMAP, size)
imageList = .ImageList~create(size, COLOR8, 1, 0)
imageList~add(image)
align = CENTER
margin = .Rect~new(5)
bmpButton~setImageList(imageList, margin, align)
::method setActive unguarded
expose movieCombo staticTheater staticDay staticTime info
use arg propSheet
propSheet~setWizButtons("BACK FINISH")
info = .table~new
movieCombo~deleteAll
ret = propSheet~querySiblings(info, "DATA")
do movie over info
movieCombo~add(movie)
end
movieCombo~selectIndex(1)
movie = movieCombo~selected
self~setMovieData(movie)
return 0
-- onGetTicket()
-- This method is invoked when the user pushes the fancy bitmap button. We
-- simply, programmatically, press the Finish button because the action to
-- take is the same.
::method onGetTicket unguarded
self~propSheet~pressButton("FINISH")
-- wizFinish()
-- Invoked when the user presses the Finish button. We use the ticket
-- information to display a, (slightly,) fancy message to the user telling her
-- where and when she can get her ticket(s).
::method wizFinish unguarded
expose info
use arg propSheet
indexes = info~allIndexes
count = indexes~items
theaterFirst = info[indexes[1]]~theater
smallTab = " "~copies(4)
doubleSpace = .endOfLine~copies(2)
if count == 1 then ticketWord = "ticket"
else ticketWord = count "tickets"
msg = "You can pick your" ticketWord "up now at the" || doubleSpace || -
smallTab || theaterFirst || doubleSpace || -
"box office. Or at"
if count > 1 then do
theaterList = ""
do i = 2 to count
index = indexes[i]
theaterList ||= smallTab || info[index]~theater || .endOfLine
end
msg ||= " one of the following" || .endOfLine || -
"theaters:" || doubleSpace || -
theaterList || .endOfLine || -
"within an hour from now." || doubleSpace || doubleSpace
cost = "$" || (count * 15) "dollars."
end
else do
msg ||= " any other convenient time." || doubleSpace || doubleSpace
cost = "$15 dollars."
end
msg ||= "Your bank account is debited" cost
title = "ooRexx Movie Ticket Selectitron"
buttons = "OK"
icon = "INFORMATION"
ans = MessageDialog(msg, propSheet~dlgHandle, title, buttons, icon)
return 0
::method onComboUpdate
expose movieCombo
movie = movieCombo~selected
self~setMovieData(movie)
::method setMovieData private
expose staticTheater staticDay staticTime info
use arg movie
d = info[movie]
staticTheater~setText(d~theater)
staticDay~setText(d~date)
staticTime~setText(d~time)
-- FontPicker
-- Dialog that allows the user to pick different fonts for the example program.
-- This lets the user see how defineDialog() works with different fonts.
::class 'FontPicker' subclass RcDialog
::method initAutoDetection
self~noAutoDetection
::method initDialog
expose nameCB sizeCB
nameCB = self~newComboBox(IDC_COMBO_NAME)
sizeCB = self~newComboBox(IDC_COMBO_SIZE)
names = .array~of("Default", "Tahoma", "Courier", "MS Sans Serif")
sizes = .array~of("Default", '8 point', '10 point', '12 point', '16 point')
do name over names
nameCB~add(name)
end
nameCB~select("Default")
do size over sizes
sizeCB~add(size)
end
sizeCB~select("Default")
::method ok
expose nameCB sizeCB
fontName = nameCB~selected
if fontName == "Default" then fontName = .PlainBaseDialog~getFontName
fontSize = sizeCB~selected~word(1)
if fontSize == "Default" then fontSize = .PlainBaseDialog~getFontSize
.PlainBaseDialog~setDefaultFont(fontName, fontSize)
return self~ok:super
::routine setFont
oldFont = .directory~new
oldFont~name = .PlainBaseDialog~getFontName
oldFont~size = .PlainBaseDialog~getFontSize
sd = locate()
dlg = .FontPicker~new(sd"rc\ticketWizard.rc", IDD_FONT_PICKER, , , , 6)
if dlg~initCode == 0 then do
dlg~execute("SHOWTOP", IDI_DLG_OOREXX)
end
return oldFont
::routine restoreFont
use strict arg oldFont
.PlainBaseDialog~setDefaultFont(oldFont~name, oldFont~size)
return oldFont