// Metric: 6 - Pixels only
/*
File: kmDateWithCal.cc
Author: Ken Mayer
Date: January 30, 2017
Updated: February 7, 2017 -- moved the language property to
the kmDateWithCalendar class (with code to assign the value
to the subform in the onClick for the pushbutton); and
added the autoTab property -- if set to true, will tab to
next control on the form (default is false) when the calendar
closes.
March 19, 2018 -- added some improvements -- clicking on
a date, the "Today" button, or the "Cancel" button, and the
subform closes, rather than leaving it open, with no apparent
way to close it.
In dBASE Plus 11 the controls look better on the subform, but this should
work for earlier versions of dBASE as well. In Plus 11, we use the
new pushbutton property "themeBackground", in earlier versions we use
"systemTheme" ...
There are two primary classes here:
kmDateWithCalendar
kmDTWithCalendar
The first is an entryfield/pushbutton combination designed to be dataLinked
to a date field in a table. The pushbutton opens and closes a calendar,
which interacts directly with the entryfield (changing the date on the
calendar updates the entryfield as you go).
The second is the same but for a DateTime (or Timestamp) field. The biggest
difference is that the DateTime version (kmDTWithCalendar) is that it has
an option to handle the time part of the field on the calendar.
The calendar itself is customizable through the use of a header
file (kmDateWithCal.h). See notes below and in the header file
itself.
This file contains a lot of code just to handle entryfields with a
calendar attached, but that is because the calendar itself takes a lot
of code to handle what needs to be done. The code for the entryfield
also takes a bit of work, although most of that is associated with
the pushbutton.
Usage:
set procedure to :dUFLP:kmDateWithCal.cc
Two items will appear on the Component Palette (if you have
not run the setup for the dUFLP, on the "Custom" tab, otherwise
on the "dUFLP Misc. Controls" tab). The instructions below are for
both controls -- drag the one you want (kmDateWithCalendar or
kmDTWithCalendar) to the form, making sure to manipulate the
position by dragging the underlying container, not the controls
*on* the container. You may see some other controls appear on the
Component Palette ("Custom" tab), ignore them -- these will be:
CalPushbutton and WeekDayText --
these are not useful as independent controls, but I can't keep
them off the Component Palette ...
Set the dataLink for the entryfield to the field in the table you
wish to link it to.
Modifications:
There are two properties of the control you may wish to change:
language -- change the language -- see details in documentation
below, and in the file :dUFLP:DateEx.cc.
Details on the language strings can be found in the code at
the beginning of :dUFLP:DateEx.cc, in the definition code
for the associative array: asLang -- this is a long list,
but you have to have the correct language definition as there
needs to be an exact match on the text. Example: there are
quite a few variations of "Arabic" in the list, you
couldn't just use "Arabic", you would need to use
the specific version: "Arabic (Saudi Arabia)" or
"Arabic (Qatar)".
Default: "English (United States)"
***NOTE***
This property only affects the month and day of week
headings of the subform /calendar -- for any other language
changes you would need to modify the file kmDateWithCal.h.
autoTab -- tab from the DateEF (entryfield) when the calendar
subform closes, the default is to place focus on the
entryfield. (This is at the request of Mervyn Bick.)
Default: false
To change either of these, in the form's onOpen event handler:
function form_onOpen()
form.kmDateWithCalendar1.language := "German (Standard)"
form.kmDateWithCalendar1.autoTab := true
return
Note: the form sets the form's doubleBufferred property to true,
due to display issues of controls on containers.
In addition, when the user clicks the CalendarButton, focus is
set (briefly) to the DateEF control (the entryfield), which means
if you wish to add some code for validation or an onLostFocus
event handler, as soon as the Subform with the calendar appears,
that code will fire. This allows you to hook in and add your own
customized code. When the Subform is closed (by clicking the
CalendarButton again), the entryfield regains focus, again
allowing any additional code you may add to fire.
There is (as noted above) an autoTab property you can set that
will fire right after setting focus back on the entryfield,
and tab to the next control on the form. The default setting
is false.
CONSTANTS:
The constants used throughout the two primary controls
are stored in "kmDateWithCal.cc" in the dUFLP, a copy is copied
when you run the setup routine to whereever it is copied to
for your version of dBASE and Windows. However, you should consider
keeping a copy in the folder for your own application, if you wish
to modify the values in the constants (language appropriate text
for speedtips and the "Today" button, images for buttons, fontSize ...).
Descriptions of the constants are noted here and in the pKenCalendar
header comments below.
When you compile the kmDateWithCal.cc class, then the constants
in the header are included and accessible.
CHANGING ENTRYFIELD COLORS / SPEEDTIP / IMAGES
These constants are defined in kmDateWithCal.h
EFNormalColor -- assigned to the Entryfield's colorNormal property
Default: "WindowText/Window"
EFColorHighlight -- assigned to the Entryfield's colorHighlight
property, the color when it has focus:
Default: "WindowText/0x80ffff"
CalButton1 -- the Calendar Button when the calendar is not
displayed.
Default: "RESOURCE PNG/calendar :resources:dFugue_24.dll"
CalButton2 -- the Calendar Button when the calendar *is* displayed.
Default: "RESOURCE PNG/calendarexport :resources:dFugue_24.dll"
CalBtnSpeedTip1 -- the screenTip for when the calendar is NOT
displayed
Default:
CalBtnSpeedTip2 -- the screenTip for when the calendar *is*
displayed.
Default: "Click to close the calendar"
When the form is run and the pushbutton is clicked, the entryfield
will be linked to the calendar, and updating the date in the calendar
will automatically update the value property of the entryfield. The "cancel"
button will set the value property back to what it was to start with
(if it wasn't empty). If the field is empty (a new record for example),
the calendar will assign the current date to the value. If the user
wishes the field to be left empty they would need to empty the
entryfield (delete what is there). One could, of course, add a "delete"
button next to the calendar button to empty the value property if one
wanted to. The code would be simply:
this.parent.DateEF.value := {}
to provide a blank date.
ENTRYFIELD CONCERNS:
This code is set to set focus to the entryfield when the pushbutton
is clicked, either direction (it needs to be clicked two different
times, once to open the calendar, once to close it). The reason for
this is based on something Mervyn Bick pointed out in the newsgroups,
if you want to fire code like an onLostFocus event handler for the
entryfield, it won't fire unless the entryfield has focus in the
first place. This ensures that it has focus first. This could
also be used to effect field-level validation (perhaps a date range,
etc.). See information about the autoTab property above.
IMPORTANT DESIGN NOTE:
You will need to experiment to be sure your form is tall/wide enough for
the calendar to display, as it becomes part of the form while it is open.
Once you get the control on the form, try running it, click the
pushbutton, and check to see if the whole calendar displays or not.
This means it will be cut off at the bottom (or right) of the form if
you do not plan for it. It may be possible to add a new property for
where to display the calendar (right/bottom as options for example),
but for the moment, this is the issue. The larger the font,
the bigger the calendar, the more space needed ...
WHAT IS INCLUDED:
The following is a short breakdown of what is here.
--------------------------------------------------
kmDateWithCalendar:
This is a container with an entryfield designed to be dataLinked
to a date field in a table, and a pushbutton that will open
a calendar control under the container.
kmDTWithCalendar:
As above but for datetime (timestamp) fields, rather than
pure date-only fields.
DateEF:
Contained inside kmDateWithCalendar, this is the entryfield object
used to dataLink to the table, etc.
CalendarButton:
The pushbutton used to do the work. Clicking this will set the
calendar's currentDate property to the value in the DateEF entryfield,
set a reference that the calendar control understands to the entryfield,
so that when clicking dates, the value changes ... the calendar
will open on top of anything else on the form, and when closed (clicking
the button again, using polymorphism to do this -- changing the appearance
and the code just a bit) will close the calendar. All of the calendar
code below has a HUGE amount of documentation.
--------------------------------------------------
Calendar Code:
pKenCalendarWithDate
The container for the calendar. There are a ton of buttons and some
text objects, as well as the code to deal with things.
See the documentation for this class for details on customization
(including colors, fontSize, fontName, language, images and text for
speedTips, and so on ...)
CalPushbutton
A base pushbutton class with some shared properties for all pushbuttons
on the container.
DayPushbutton
The pushbutton class used to define the days.
WeekDayText
The text controls above the days (S for Sunday, M for Monday, etc.).
--------------------------------------------------
Code not associated with classes directly:
Points2Pixels() -- a function that does a basic calculation to convert
fontSize (points) to pixels -- helps determine the size of the buttons
and other controls as well as the calendar itself.
--------------------------------------------------
DEPENDENCIES:
If you choose to use this set of code with your own application,
there are a lot of dependences you need to be aware of.
For the images:
Note that the default images are using the .DLLs provided by dBASE in the
:resources: source code alias. To find the exact path to these, check
the Properties dialog in the IDE, find the "Source Aliases" tab, and
the "resources" source alias. Click it, and the path will appear
in the dialog. Example, for dBASE Plus 11, on my Windows 10 computer:
C:\Users\Public\Documents\dBASE\Plus11\media\Resources
This is important if you wish to deploy this application and wish to use
the images provided. You would need to deploy:
dFugue_16_1.dll
dFugue_24.dll
See below as well for other files needed.
DEPENDENCIES (Important for deploying an application that uses this
control):
:dUFLP:DATEEX.CC
:dUFLP:HOLIDAY.CC
:dUFLP:TIME.CC
:dUFLP:HEBREW.CC
DUFLP.H *shouldn't need to be deployed, as it would be compiled
into the file needing it (DateEx.cc, etc.)*
:dUFLP:kmDateWithCal.h -- same as dUFLP.H ... shouldn't need
to be deployed
If using the default images, if you change the images
(which is an option) you would need to deploy those images
in whatever fashion is appropriate:
:resources:dFugue_24.dll
:resources:dFugue_16_1.dll
*/
// Don't remove this -- it's vital:
#INCLUDE kmDateWithCal.h
class kmDateWithCalendar( oParent ) of container( oParent ) custom
// NOTE: constants (for images and speedTips) defined in kmDateWithCal.h
with (this)
metric = 6 // Pixels
borderStyle = 3 // None
transparent = true
width = 110.0
height = 30.0
onDesignOpen = class::onDesignOpen
onOpen = class::Container_onOpen
endwith
// Language -- for use with the API calls in DateEx.cc, so we can
// get the correct info for the month and day of the week --
// see documentation in :dUFLP:DateEx.cc for details:
this.language = "English (United States)"
this.autoTab = false // can be modified in code, used to
// tab off the entryfield when
// calendar closes
this.type = "Date" // don't change this
this.DateEF = new ENTRYFIELD( this )
with ( this.DATEEF )
height = 22.0
left = 2.0
top = 3.0
width = 79.0
value = { / / }
pageno = 0
colorNormal = EFNormalColor
colorHighlight = EFColorHighlight
endwith
this.CalendarButton = new PUSHBUTTON( this )
with ( this.CALENDARBUTTON )
onClick = class::CALENDARBUTTON_ONCLICK
height = 26.0
left = 83.0
top = 1.0
width = 26.0
text = ""
speedBar = true
upBitmap = CalButton1
scaleBitmaps = true
pageno = 0
speedtip = CalBtnSpeedTip1
endwith
function onDesignOpen
// called from container's onDesignOpen:
if form.metric # 6
msgbox( "Form's metric property is not '6 - Pixels', "+;
"this will not display properly.", ;
"Bad Form Metric!", 16 )
return
endif
return
function Container_onOpen
// force this so any display issues
// are minimized:
form.doubleBuffered := true
return
function CALENDARBUTTON_onClick()
// a polymorphing button: meaning that it basically has
// two states -- if the calendar is not displayed,
// the button will display it when clicked, if the button
// is displayed, the button will close it when clicked
local oParent, oEF
if type( "this.CalendarOn" ) == "U"
this.CalendarOn = false
endif
// if it's not 'on', then display it ... ('this' is the pushbutton)
if not this.CalendarOn
this.CalendarOn := true // set it to true now
// modify display:
this.speedtip := CalBtnSpeedTip2
this.upBitmap := CalButton2
oParent = this.parent // container ...
oEF = oParent.DateEF // entryfield with date
// instantiate the calendar:
this.oCalendar = new pKenCalendar( form ) // setting parent to the form
// Pass the entryfield object to a custom
// property of the calendar:
this.oCalendar.EF = oEF
// set reference to this button for subform:
this.oCalendar.Btn = this
// set language property of the subform:
this.oCalendar.language := this.parent.language
// if the date entryfield value is empty, set
// it to the current date:
if empty( oEF.value )
if oParent.type == "Date"
oEF.value := date()
else
oEF.value := datetime()
endif
endif
// set the calendar's currentDate property to the
// value of the entryfield:
this.oCalendar.currentDate = oEF.value
// determine whether date or datetime
this.oCalendar.type = oParent.type
oEF.setFocus() // this would fire any onLostFocus or
// similar events
// set the position
this.oCalendar.top := oParent.height+oParent.top
this.oCalendar.left := oParent.left
// open the subform which fires off the code for
// the subform's onOpen event handler:
this.oCalendar.open()
else
// reset flag:
this.CalendarOn := false
// reset display:
this.speedtip := CalBtnSpeedTip1
this.upBitmap := CalButton1
// set focus back to the entryfield:
this.parent.DateEF.setFocus()
// autotab (put focus on next control of form)?
if this.parent.autoTab
keyboard( "{Tab}" )
endif
// release calendar and cleanup:
this.oCalendar.close()
release object this.oCalendar
this.oCalendar = null
endif // not this.CalendarOn
return // from CALENDARBUTTON_onClick
endclass
/*
kmDTWithCalendar -- a copy of the above but designed for
DateTime (or Timestamp) fields, rather than just date.
This is a subclass of the kmDateWithCalendar class above.
*/
class kmDTWithCalendar( oParent ) of kmDateWithCalendar( oParent ) custom
// NOTE: constants (for images and speedTips) defined in kmDateWithCal.h
// the Container:
with (this)
width = 160.0
endwith
this.type = "DateTime" // don't change this
// modify the value and width only of the entryfield:
with ( this.DATEEF )
width = 130.0
value = {00/00/0000 00:00:00.00}
endwith
// the calendar button, modify the position
with ( this.CALENDARBUTTON )
left = 134.0
endwith
endclass
/*
pKenCalendar -- calendar class used by kmDateWithCalendar
entryfield/button combination, based on pKenCal3.cc in the
dUFLP and massively modified ...
Author : Ken Mayer
January, 2017 in an attempt to make a more flexible
calendar by allowing the developer using it to determine
font, fontSize, and so on I ended up creating a whole new
"thing". While very similar to some other calendars,
this one is meant to be more flexible, with an updated
appearance.
I have given this one the ability to define (see below)
text for language specific items in the code more easily
(except for holidays -- that's trickier) ... See also
comments for kmDateWithCalendar class above which provides
more detail.
Usage -- called from above, this is not designed as an independant control,
although you could probably do something with it to make it useful
for your own app without the kmDateWithCalendar class above.
Modifying Constants and Properties:
Open a local copy (one in the working folder for your development
environment) of kmDateWithCal.h, and you can change the constants
there. When you recompile kmDateWithCal.cc, the changes will take
effect. The following are the various constants defined that affect
the calendar itself. The ones that affect the Entryfield and
Pushbutton parts of the control are explained in the header for
that control above.
CALENDAR TITLE TEXT:
CalendarTitleText
As this is a subform, the you can change the text
in the title of the form.
Default: "Calendar"
COLOR CONSTANTS:
The following custom color constants can be used
to change the appearance of the calendar.
You can change them in the file "kmDateWithCal.h". Below is
a description of what they are used for.
NormalColor
This can be used to set the color of the non-selected
days. Default: black/white
SelectedColor
This is used to set the selected day (current
date) to a specific color so that it stands out.
Default: white/blue
SundayColor
As above, this is used to display the first column
in a specific color.
NOTE: In this version, holidays that
are defined in the "LoadHolidays" method of the
container will appear in the "SundayColor"
unless they are also the "selected" day ...
Default: maroon/white
HolidayColor
As above, used specifically for Holidays, will
override a sundaycolor setting ...
Default: green/white
MouseOverColor
When the mouse is over a day, the color of the button
changes to this color.
Default: red/white
Note: The colors used here are basic named colors, but you could
use hexidecimal colors, such as: "0XA00000", but you would need to
spend some time figuring out which values to use. For more details
on colors, see the Appendices of The dBASE Book, by Ken Mayer.
MONTH/YEAR INCREMENT/DECREMENT BUTTONS:
These two values (also defined the same way as above, as constants)
can be used to change the defaults for the buttons for adding
or subtracting 'n' number of months/years -- the speedtip is
updated as well as the actual calculation:
MonthIncrement -- add/subtract 'n' months
Default: 3
YearIncrement -- add/subtract 'n' years
Default: 10
LANGUAGE Properties:
The kmDateWithCalendar container has a "language" property that defaults to
"English (United States)",
used to format dates and deal with the months/day headings ...
It can be changed either in the code here, or in a running
form with:
fMyForm.kmDateWithCalendar1.language := "German (Standard)"
Details on these can be found in the code at the beginning
of :dUFLP:DateEx.cc, in the definition code for the
associative array: asLang -- this is a long list, but you have to have
the correct language definition as there needs to be an exact match
on the text. Example: there are quite a few variations of "Arabic"
in the list, you couldn't just use "Arabic", you would need to use
the specific version: "Arabic (Saudi Arabia)" or "Arabic (Qatar)".
If you are using the subform on its own, then you would need to reference
the subform to set the language appropriately:
form.pKenCalendar1.language := ...
LANGUAGE CONSTANTS:
TodayText -- text of "Today" button
Default: "Today"
TodaySpeedTip -- text of speedtip for Today Button
Default: "Go to Today's Date"
CancelSpeedTip -- text of speedTip for the Cancel
button in the lower right corner of the calendar.
Default: "Cancel Changes"
// these are all used in the speedtips for the
// next/prev 'n' months, etc. buttons:
MonthText -- singular (Next Month, Previous Month)
Default: "Month"
MonthsText -- multiple (n Months Ahead ...)
Default: "Months"
YearText -- singular (Next Year)
Default: "Year"
YearsText -- multiple (n Years Ahead ...)
Default: "Years"
BackText -- text used for "n Months Back"
Default: "Back"
PreviousText -- text used for "Previous Month"
Default: "Previous"
AheadText -- "n Months Ahead"
Default: "Ahead"
NextText -- "Next Month"
Default: "Next"
BUTTON IMAGES:
NextButtonImg -- next month/year:
Default: "RESOURCE PNG/control :resources:dFugue_16_1.dll"
Next10BtnImg -- next 'n' months/years:
Default: "RESOURCE PNG/controldouble :resources:dFugue_16_1.dll"
PrevButtonImg -- previous month/year:
Default: "RESOURCE PNG/control180 :resources:dFugue_16_1.dll"
Prev10BtnImg -- back n months/years:
Default: "RESOURCE PNG/controldouble180 :resources:dFugue_16_1.dll"
TodayBtnImg -- Today Button:
Default: "RESOURCE PNG/calendarselect :resources:dFugue_16_1.dll"
UndoButtonImg -- Cancel/Undo Changes Button
Default: "RESOURCE PNG/arrowcircle225left :resources:dFugue_16_1.dll"
TimeButtonImg -- Change Time Button:
Default: "RESOURCE PNG/alarmclockblue :resources:dFugue_24.dll"
TimeBackImg -- time button back to calendar:
Default: "RESOURCE PNG/calendarimport :resources:dFugue_16_1.dll"
Note that these images are using the .DLLs provided by dBASE in the
:resources: source code alias. To find the exact path to these, check
the Properties dialog in the IDE, find the "Source Aliases" tab, and
the "resources" source alias. Click it, and the path will appear
in the dialog. Example, for dBASE Plus 11, on my Windows 10 computer:
C:\Users\Public\Documents\dBASE\Plus11\media\Resources
This is important if you wish to deploy this application and wish to use
the images provided. You would need to deploy:
dFugue_16_1.dll
dFugue_24.dll
See below as well for other files needed.
HOLIDAYS: see code in method LoadHolidays -- you can change the
holidays used, the ones that are automatically loaded are
standard United States Holidays. You may want to add
your own, see the code examples. You may not want all
the U.S. holidays if you aren't in the US. In a case like
that, comment out the ones you don't want on the calendar,
and again add your own. You may want to change the text
for the buttons. Note that at least currently the
software only handles one holiday per date ... not sure
how standard speedTips would handle a line break to deal
with multiple lines of text. :)
** Note that this cc file uses Source Aliasing, specifically the
** dUFLP source Alias. If you do not know how to set up
** a Source Alias, see the instructions in WHATS.NEW at
** the top of the file, or in README.TXT.
** Any files referenced by :dUFLP:filename must be
** included in an executable if you are building
** one ... make sure that your project includes these
** files.
**
** This particular program uses:
** dateex.cc
** holiday.cc
** time.cc
** hebrew.cc
** duflp.h <== not referred to by source alias, used
** in DateEx.cc, etc.
** kmDateWithCal.h
** Images are from:
** :resources:dFugue_24.dll
** :resources:dFugue_16_1.dll
** You would either need to change the images, or
** deploy these two .dll files
DEPENDENCIES (Important for deploying an application
that uses this control):
DATEEX.CC
HOLIDAY.CC
TIME.CC
HEBREW.CC
dFugue_24.dll
dFugue_16_1.dll
*/
/*
-------------------------------------------------------
The subform class here is what does all the work ...
There are some custom button/text control definitions
after the subform definition.
-------------------------------------------------------
*/
class pKenCalendar(parentObj) of subform(parentObj)
set procedure to :dUFLP:dateex.cc additive
set procedure to :dUFLP:holiday.cc additive
// Note that size and position are determined based
// on calculations ...
with (this)
metric := 6 // Pixels
onOpen := class::CONTAINEROPEN
onClose := class::CONTAINERCLOSE
systemTheme := false
doubleBufferred := true
colorNormal := "white"
text := CalendarTitleText
smallTitle := true
showTaskBarButton := false
mdi := false
topMost := true
escExit := false
sizeable := false
maximize := false
minimize := false
escExit := false
sysMenu := false
endwith
// default, but the calendarButton in kmDateWithCalendar will set this
// if it is changed in the form's onOpen event handler:
this.language = "English (United States)"
// NOTE: other constants (not below) are defined in kmDateWithCal.h
// From here down, don't mess with these ...
#define ButtonHeight Points2Pixels( ButtonFontSize ) + (PaddingSize * 2) // pixels
#define ButtonWidth Points2Pixels( ButtonFontSize ) + (PaddingSize * 2) // pixels
// need to define these here, but then need the column
// positions below ...
#define YearRow 4 // pixels from top of container
// YMBtnHeight is the height of the Year and Month buttons
// at the top of the calendar:
#define YMBtnHeight ButtonHeight + PaddingSize // additional room for descenders
#define MonthRow YearRow+YMBtnHeight // from top
// Define rows based on button heights:
#define TITLEROW MonthRow+YMBtnHeight+2
#define ROW1 (TitleRow-PaddingSize)+YMBtnHeight
#define ROW2 ROW1+ButtonHeight
#define ROW3 ROW2+ButtonHeight
#define ROW4 ROW3+ButtonHeight
#define ROW5 ROW4+ButtonHeight
#define ROW6 Row5+ButtonHeight
#define TodayButtonTop Row6+ButtonHeight
// define columns based on button widths:
#define COL1 7 // pixels from left of container
#define COL2 COL1+ButtonWidth
#define COL3 COL2+ButtonWidth
#define COL4 Col3+ButtonWidth
#define COL5 Col4+ButtonWidth
#define COL6 Col5+ButtonWidth
#define COL7 Col6+ButtonWidth
// Year and Month rows, we need to define
// where everything is, the calcs will be a bit more
// complex than some of the above.
#define PrevBtnLeft COL1+23
// go to the right side of the buttons at COL7,
// subtract width of Next10 button, and width of
// Next button:
#define NextBtnLeft (COL7+ButtonWidth) - (23+18)
// same as above but without the 'next' button
#define Next10BtnLeft (COL7+ButtonWidth) - 23
// then we deal with the left and widths of the Month and Year
// text controls:
#define YMTextleft 23+18+8
#define YMTextWidth (COL7+ButtonWidth) - (2*(23+18)) - 8
// width and height of the subform will
// vary based on width/height of buttons:
#if __version__ < 11
#define ContainerWidth COL7+ButtonWidth+15
#else
#define ContainerWidth COL7+ButtonWidth+5
#endif
// once we add more buttons at the bottom, this will
// need to be modified:
#if __version__ < 11
#define ContainerHeight TodayButtonTop+ButtonHeight+PaddingSize+10
#else
#define ContainerHeight TodayButtonTop+ButtonHeight+PaddingSize
#endif
this.width := ContainerWidth
this.height := ContainerHeight
// set left of TodayButton based on width of container
// and width of TodayButton ...
// left = (ContainerWidth - TodayButtonWidth) / 2
// width: image width + text: "Today"
#define TodayButtonWidth ( 23 + ( Points2Pixels( ButtonFontSize ) * 4 ) )
#define TodayButtonLeft (ContainerWidth - TodayButtonWidth) / 2
// instance of dateex class and holiday class:
this.DateEx = new DateEx()
this.Holiday = new Holiday()
// used to set speedtips ...
this.cSpeedTip = ""
// currentDate and beginDate:
this.currentDate = {}
this.beginDate = {}
// constructor for calendar begins here ... don't mess with this!
this.YEARMINUS10 = new CalPushbutton(this)
with (this.YEARMINUS10)
onClick := class::YEARMINUS10_ONCLICK
height := YMBtnHeight
left := COL1
top := YearRow
width := 23
text := ""
upBitmap := Prev10BtnImg
speedBar := true
speedTip := YearIncrement+" " + YearsText + " " + BackText
colorNormal := NormalColor
pageNo := 1
endwith
this.PREVYEARPUSHBUTTON = new CalPushbutton(this)
with (this.PREVYEARPUSHBUTTON)
onClick := CLASS::PREVYEARPUSHBUTTON_OnClick
upBitmap := PrevButtonImg
text := ""
height := YMBtnHeight
width := 18
left := PrevBtnLeft
top := YearRow
speedTip := PreviousText + " " + YearText
colorNormal := NormalColor
pageNo := 1
endwith
this.TEXTYEAR = new TEXT(this)
with (this.TEXTYEAR)
fontSize := ButtonFontSize
text := "9999"
alignHorizontal := 1 // center
alignVertical := 1 // middle
height := YMBtnHeight-1 // odd discrepency, possibly border?
left := YMTextleft
top := YearRow+1 // compensate for -1 in height above
width := YMTextWidth
border := true
#if __version__ < 11
borderStyle := 1 // raised
#else
borderStyle := 9 // etched in
#endif
colorNormal := NormalColor
pageNo := 1
endwith
this.NEXTYEARPUSHBUTTON = new CalPushbutton(this)
with (this.NEXTYEARPUSHBUTTON)
onClick := CLASS::NEXTYEARPUSHBUTTON_OnClick
upBitmap := NextButtonImg
text := ""
height := YMBtnHeight
width := 18
left := NextBtnLeft
top := YearRow
speedTip := NextText +" " +YearText
colorNormal := NormalColor
pageNo := 1
endwith
this.YEARPLUS10 = new CalPushbutton(this)
with (this.YEARPLUS10)
onClick := class::YEARPLUS10_ONCLICK
upBitmap := Next10BtnImg
height := YMBtnHeight
left := Next10BtnLeft
top := YearRow
width := 23
text := ""
speedTip := YearIncrement + " " + YearsText + " " + AheadText
colorNormal := NormalColor
pageNo := 1
endwith
this.MONTHMINUS3 = new CalPushbutton(this)
with (this.MONTHMINUS3)
onClick := class::MONTHMINUS3_ONCLICK
height := YMBtnHeight
left := COL1
top := MonthRow
width := 23
text := ""
speedTip := MonthIncrement + " " + MonthsText + " " + BackText
colorNormal := NormalColor
upBitmap := Prev10BtnImg
pageNo := 1
endwith
this.PREVMONTHPUSHBUTTON = new CalPushbutton(this)
with (this.PREVMONTHPUSHBUTTON)
onClick := CLASS::PREVMONTHPUSHBUTTON_OnClick
upBitmap := PrevButtonImg
text := ""
height := YMBtnHeight
width := 18
left := PrevBtnLeft
top := MonthRow
speedTip := PreviousText + " " + MonthText
colorNormal := NormalColor
pageNo := 1
endwith
this.TEXTMONTH = new TEXT(this)
with (this.TEXTMONTH)
fontSize := ButtonFontSize
text := "Month"
alignHorizontal := 1 // center
alignVertical := 1 // middle
height := YMBtnHeight-1
left := YMTextleft
width := YMTextWidth
top := MonthRow+1
border := true
#if __version__ < 11
borderStyle := 1 // raised
#else
borderStyle := 9 // etched in
#endif
colorNormal := NormalColor
pageNo := 1
endwith
this.NEXTMONTHPUSHBUTTON = new CalPushbutton(this)
with (this.NEXTMONTHPUSHBUTTON)
onClick := CLASS::NEXTMONTHPUSHBUTTON_OnClick
height := YMBtnHeight
width := 18
left := NextBtnLeft
top := MonthRow
upBitmap := NextButtonImg
text := ""
speedTip := NextText + " " + MonthText
colorNormal := NormalColor
pageNo := 1
endwith
this.MONTHPLUS3 = new CalPushbutton(this)
with (this.MONTHPLUS3)
onClick := class::MONTHPLUS3_ONCLICK
height := YMBtnHeight
left := Next10BtnLeft
top := MonthRow
width := 23
text := ""
upBitmap := Next10BtnImg
speedTip := MonthIncrement + " " + MonthsText + " " + AheadText
colorNormal := NormalColor
pageNo := 1
endwith
this.TITLESUNDAY = new WeekDayText(this)
with (this.TITLESUNDAY)
left := COL1
top := TITLEROW
endwith
this.TITLEMONDAY = new WeekDayText(this)
with (this.TITLEMONDAY)
left := COL2
top := TITLEROW
text := "M"
endwith
this.TITLETUESDAY = new WeekDayText(this)
with (this.TITLETUESDAY)
left := COL3
top := TITLEROW
text := "T"
endwith
this.TITLEWEDNESDAY = new WeekDayText(this)
with (this.TITLEWEDNESDAY)
left := COL4
top := TITLEROW
text := "W"
endwith
this.TITLETHURSDAY = new WeekDayText(this)
with (this.TITLETHURSDAY)
left := COL5
top := TITLEROW
text := "T"
endwith
this.TITLEFRIDAY = new WeekDayText(this)
with (this.TITLEFRIDAY)
left := COL6
top := TITLEROW
text := "F"
endwith
this.TITLESATURDAY = new WeekDayText(this)
with (this.TITLESATURDAY)
left := COL7
top := TITLEROW
endwith
this.ROW1COL1 = new DayPushButton(this)
with (this.ROW1COL1)
left = COL1
top = ROW1
endwith
this.ROW1COL2 = new DayPushButton(this)
with (this.ROW1COL2)
left = COL2
top = ROW1
endwith
this.ROW1COL3 = new DayPushButton(this)
with (this.ROW1COL3)
left = COL3
top = ROW1
endwith
this.ROW1COL4 = new DayPushButton(this)
with (this.ROW1COL4)
left = COL4
top = ROW1
endwith
this.ROW1COL5 = new DayPushButton(this)
with (this.ROW1COL5)
left = COL5
top = ROW1
endwith
this.ROW1COL6 = new DayPushButton(this)
with (this.ROW1COL6)
left = COL6
top = ROW1
endwith
this.ROW1COL7 = new DayPushButton(this)
with (this.ROW1COL7)
left = COL7
top = ROW1
endwith
this.ROW2COL1 = new DayPushButton(this)
with (this.ROW2COL1)
left = COL1
top = ROW2
endwith
this.ROW2COL2 = new DayPushButton(this)
with (this.ROW2COL2)
left = COL2
top = ROW2
endwith
this.ROW2COL3 = new DayPushButton(this)
with (this.ROW2COL3)
left = COL3
top = ROW2
endwith
this.ROW2COL4 = new DayPushButton(this)
with (this.ROW2COL4)
left = COL4
top = ROW2
endwith
this.ROW2COL5 = new DayPushButton(this)
with (this.ROW2COL5)
left = COL5
top = ROW2
endwith
this.ROW2COL6 = new DayPushButton(this)
with (this.ROW2COL6)
left = COL6
top = ROW2
endwith
this.ROW2COL7 = new DayPushButton(this)
with (this.ROW2COL7)
left = COL7
top = ROW2
endwith
this.ROW3COL1 = new DayPushButton(this)
with (this.ROW3COL1)
left = COL1
top = ROW3
endwith
this.ROW3COL2 = new DayPushButton(this)
with (this.ROW3COL2)
left = COL2
top = ROW3
endwith
this.ROW3COL3 = new DayPushButton(this)
with (this.ROW3COL3)
left = COL3
top = ROW3
endwith
this.ROW3COL4 = new DayPushButton(this)
with (this.ROW3COL4)
left = COL4
top = ROW3
endwith
this.ROW3COL5 = new DayPushButton(this)
with (this.ROW3COL5)
left = COL5
top = ROW3
endwith
this.ROW3COL6 = new DayPushButton(this)
with (this.ROW3COL6)
left = COL6
top = ROW3
endwith
this.ROW3COL7 = new DayPushButton(this)
with (this.ROW3COL7)
left = COL7
top = ROW3
endwith
this.ROW4COL1 = new DayPushButton(this)
with (this.ROW4COL1)
left = COL1
top = ROW4
endwith
this.ROW4COL2 = new DayPushButton(this)
with (this.ROW4COL2)
left = COL2
top = ROW4
endwith
this.ROW4COL3 = new DayPushButton(this)
with (this.ROW4COL3)
left = COL3
top = ROW4
endwith
this.ROW4COL4 = new DayPushButton(this)
with (this.ROW4COL4)
left = COL4
top = ROW4
endwith
this.ROW4COL5 = new DayPushButton(this)
with (this.ROW4COL5)
left = COL5
top = ROW4
endwith
this.ROW4COL6 = new DayPushButton(this)
with (this.ROW4COL6)
left = COL6
top = ROW4
endwith
this.ROW4COL7 = new DayPushButton(this)
with (this.ROW4COL7)
left = COL7
top = ROW4
endwith
this.ROW5COL1 = new DayPushButton(this)
with (this.ROW5COL1)
left = COL1
top = ROW5
endwith
this.ROW5COL2 = new DayPushButton(this)
with (this.ROW5COL2)
left = COL2
top = ROW5
endwith
this.ROW5COL3 = new DayPushButton(this)
with (this.ROW5COL3)
left = COL3
top = ROW5
endwith
this.ROW5COL4 = new DayPushButton(this)
with (this.ROW5COL4)
left = COL4
top = ROW5
endwith
this.ROW5COL5 = new DayPushButton(this)
with (this.ROW5COL5)
left = COL5
top = ROW5
endwith
this.ROW5COL6 = new DayPushButton(this)
with (this.ROW5COL6)
left = COL6
top = ROW5
endwith
this.ROW5COL7 = new DayPushButton(this)
with (this.ROW5COL7)
left = COL7
top = ROW5
endwith
this.ROW6COL1 = new DayPushButton(this)
with (this.ROW6COL1)
left = COL1
top = ROW6
endwith
this.ROW6COL2 = new DayPushButton(this)
with (this.ROW6COL2)
left = COl2
top = ROW6
endwith
this.ROW6COL3 = new DayPushButton(this)
with (this.ROW6COL3)
left = COL3
top = ROW6
endwith
this.ROW6COL4 = new DayPushButton(this)
with (this.ROW6COL4)
left = COL4
top = ROW6
endwith
this.ROW6COL5 = new DayPushButton(this)
with (this.ROW6COL5)
left = COL5
top = ROW6
endwith
this.ROW6COL6 = new DayPushButton(this)
with (this.ROW6COL6)
left = COL6
top = ROW6
endwith
this.ROW6COL7 = new DayPushButton(this)
with (this.ROW6COL7)
left = COL7
top = ROW6
endwith
this.TimeButton = new CalPushbutton(this)
with (this.TimeButton)
onClick = class::TimeButton_OnClick
height = ButtonHeight
width = ButtonWidth
text = ""
left = COL1
top = TodayButtonTop
speedTip = TimeSpeedTip1
colorNormal = NormalColor
upBitmap = TimeButtonImg
visible = false
pageNo = 0
endwith
this.TodayPushButton = new CalPushbutton(this)
with (this.TodayPushButton)
onClick = CLASS::TodayPushButton_OnClick
height = ButtonHeight
left = TodayButtonLeft
top = TodayButtonTop
width = TodayButtonWidth
text = TodayText
fontSize = ButtonFontSize
speedTip = TodaySpeedTip
colorNormal = NormalColor
upBitmap = TodayBtnImg
pageNo = 1
endwith
this.CancelButton = new CalPushbutton(this)
with (this.CancelButton)
onClick = CLASS::CancelButton_OnClick
height = ButtonHeight
width = ButtonWidth
text = ""
left = COL7
top = TodayButtonTop
speedTip = CancelSpeedTip
colorNormal = NormalColor
upBitmap = UndoButtonImg
pageNo = 1
endwith
/*
Define controls for the time part of the calendar ...
Look at controls in the dUFLP for handling time values
*/
this.TimeTitle = new text( this )
with( this.TimeTitle )
fontSize := ButtonFontSize
text := TimeTitleText
alignHorizontal := 1 // center
alignVertical := 1 // middle
height := YMBtnHeight-1 // odd discrepency, possibly border?
left := YMTextleft-10
top := YearRow+1 // compensate for -1 in height above
width := YMTextWidth+20
border := true
#if __version__ < 11
borderStyle := 1 // raised
#else
borderStyle := 9 // etched in
#endif
colorNormal := NormalColor
pageNo := 2
endwith
this.HOURLabel = new TEXT(this)
with (this.HOURLabel)
height = 16.0
left = COL2
top = ROW1
width = 18.0
fontBold = true
text = HoursText
pageNo = 2
endwith
this.HOURSB = new SPINBOX(this)
with (this.HOURSB)
height = 22.0
left = COL2
top = ROW2
width = 47.0
speedTip = HoursSpeedTip
picture = "99"
function = "@L"
rangeMax = 24
rangeMin = 1
value = 1
rangeRequired = true
colorNormal = EFNormalColor
colorHighlight = EFColorHighlight
pageNo = 2
onChange = class::HoursSB_OnChange
endwith
this.MINUTESLabel = new TEXT(this)
with (this.MINUTESLabel)
height = 22.0
left = COL4
top = ROW1
width = 18.0
fontBold = true
text = MinutesText
pageNo = 2
endwith
this.MINUTESSB = new SPINBOX(this)
with (this.MINUTESSB)
height = 22.0
left = COL4
top = ROW2
width = 47.0
speedTip = MinutesSpeedTip
picture = "99"
function = "@L"
rangeMax = 59
rangeMin = 0
value = 1
rangeRequired = true
colorNormal = EFNormalColor
colorHighlight = EFColorHighlight
pageNo = 2
onChange = class::MinutesSB_OnChange
endwith
this.SecondsLabel = new TEXT(this)
with (this.SecondsLabel)
height = 22.0
left = COL6
top = ROW1
width = 20.0
fontBold = true
text = SecondsText
pageNo = 2
endwith
this.SECONDSSB = new SPINBOX(this)
with (this.SECONDSSB)
height = 22.0
left = COL6
top = ROW2
width = 47.0
speedTip = "Seconds"
picture = "99"
function = "@L"
rangeMax = 59
rangeMin = 0
value = 1
rangeRequired = true
colorNormal = EFNormalColor
colorHighlight = EFColorHighlight
pageNo = 2
onChange = class::SecondsSB_OnChange
endwith
function CheckMetric
// called from container's onDesignOpen:
if form.metric # 6
msgbox( "Form's metric property is not '6 - Pixels', "+;
"this will not display properly.", ;
"Bad Form Metric!", 16 )
endif
return
function containerOpen
// if we have a custom property of "EF":
if type( "this.EF" ) == "O" // object
this.currentDate = this.EF.value
endif
// default date if needed:
if type( 'this.currentDate' ) # "D" or empty( this.currentDate )
if this.type == "Date"
this.currentDate = date()
else // datetime
this.currentDate = datetime()
endif
endif
// Set color of "sunday" title button
this.titleSunday.colorNormal := SundayColor
// store starting date value, in
// case there's a cancel option,
// the user can return to the 'beginDate':
this.beginDate = this.currentDate
// update day-of-week headings
class::DayHeadings()
// if we are working with a datetime field:
if this.type == "DateTime"
this.TimeButton.visible := true
endif
// newMonth routine -- ensures all the
// buttons are the 'correct' colors, and
// speedTips added for holidays, etc.
class::NewMonth()
return
function ContainerClose
// the Calendar button is a toggle, so we need to
// reset it when the subform closes. We added a
// reference (this.Btn) in the button's onClick
// event handler for when we first click the button,
// now we're just calling the code that causes
// the polymorphism to occur and change the image
// and code that fires for the button (allowing
// the calendar to open properly again if necessary,
// without multiple mouse clicks).
this.Btn.onclick()
return
function DayHeadings
// deal with language stuff for the
// day of the week:
local cDay, dTemp
// Set the language for the DateEx object:
this.dateEx.Language := this.Language
// we need a day known to be a Sunday:
dTemp = new date( 2004, 1, 1 ) // February 1, 2004
// remember date object
// is zero-based, hence
// the second month of
// the year is 1
// Get Sunday
cDay = this.dateEx.intlcdow( dTemp )
// Assign first letter ...:
this.TitleSunday.text := left( cDay, 1 )
// Get Monday
cDay = this.dateEx.intlcdow( dTemp+1 )
// Assign first letter ...:
this.TitleMonday.text := left( cDay, 1 )
// Get Tuesday
cDay = this.dateEx.intlcdow( dTemp+2 )
// Assign first letter ...:
this.TitleTuesday.text := left( cDay, 1 )
// Get Wednesday
cDay = this.dateEx.intlcdow( dTemp+3 )
// Assign first letter ...:
this.TitleWednesday.text := left( cDay, 1 )
// Get Thursday
cDay = this.dateEx.intlcdow( dTemp+4 )
// Assign first letter ...:
this.TitleThursday.text := left( cDay, 1 )
// Get Friday
cDay = this.dateEx.intlcdow( dTemp+5 )
// Assign first letter ...:
this.TitleFriday.text := left( cDay, 1 )
// Get Saturday
cDay = this.dateEx.intlcdow( dTemp+6 )
// Assign first letter ...:
this.TitleSaturday.text := left( cDay, 1 )
return
function newMonth
// this function deals with setting values based
// on changes to month/year -- determine where
// first day is, last day is, everything in
// between: set button texts, colors ...
// First: need to determine what level we're at --
// are we working from subform, or control
// on subform (cRef needs to point to the subform):
if "SUBFORM" $ upper( this.className ) or;
"SUBFORM" $ upper( this.baseClassName )
// we're on the subform
oRef = this
else
// we're on a pushbutton _on_ the subform
oRef = this.parent
endif
// Make sure holiday list is current ...
class::LoadHolidays()
// now to get first day of month and last day of
// month from 'currentDate'
dDate = oRef.currentDate
dFirst = oRef.dateEx.fdom( dDate )
dLast = oRef.dateEx.ldom( dDate )
nDay = day( dDate ) // current day of month
bDateTime = ( oRef.type == "DateTime" )
if bDateTime
// we need to deal with the time portion
// of the value ...
cTime = oRef.currentDate.hour+":"+;
oRef.currentDate.minute+":"+;
oRef.currentDate.second
endif
// character values for month and year:
oRef.textMonth.text := oRef.dateEx.intlCMon( dDate )
oRef.textYear.text := ltrim( str( year( dDate ) ) )
// now the fun part ... assigning values, based
// on where we start:
nStart = dow( oRef.currentDate )
// Clear out any outstanding speedTips
for nRows = 1 to 6
for nColumns = 1 to 7
cObject = "oRef.Row1Col"+nColumns
cSpeedTip = cObject+".speedTip"
&cSpeedTip. := ""
next
next
// We need to loop through everything, and set
// visible properties as well as text if it's going
// to display:
nCurrent = 0
for nRows = 1 to 6
for nColumns = 1 to 7
nCurrent++
// start at day 1, but ...
// for first row, loop through until we find
// the first one (and make everything before
// the first day of month invisible):
if nCurrent == 1
do while nCurrent <= nColumns
if dow( dFirst ) == nColumns
// set the text:
cObject = "oRef.Row1Col"+nColumns
cText = cObject+".text"
&cText. := "1"
// Set colors:
cColor = cObject+".colorNormal"
// if the day we're setting is the
// selected/current date:
dTestDate = new date(year(dDate), ;
month(dDate)-1, nCurrent)
// Make it a real date
dTestDate = ctod( left( dTestDate.toLocaleString(), ;
iif( set("CENTURY") == "ON", 10, 8 ) ) )
if nDay == nCurrent
&cColor. := SelectedColor //oRef.SELECTEDCOLOR
oRef.currentButton = &cObject.
cSpeedTip = cObject+".speedTip"
if class::isHoliday( dtestDate )
&cSpeedTip. = oRef.cSpeedTip
endif
else
// is it a sunday or a holiday?
cSpeedTip = cObject+".speedTip"
if nColumns == 1
&cColor. := SundayColor //oRef.SUNDAYCOLOR
if class::IsHoliday( dTestDate )
&cColor. := HolidayColor //oRef.HOLIDAYCOLOR
&cSpeedTip. := oRef.cSpeedTip
endif
elseif class::IsHoliday( dTestDate )
&cColor. := HolidayColor //oRef.HOLIDAYCOLOR
&cSpeedTip. := oRef.cSpeedTip
else
// it's any other day of week ...
&cColor. := NormalColor //oRef.NORMALCOLOR
endif
endif // nDay == nCurrent
// set visible property
cVisible = cObject+".visible"
&cVisible. := true
// finish the row
for i = nColumns to 7
cObject = "oRef.Row1Col"+i
cText = cObject+".text"
&cText. := "1"
// set visible property
cVisible = cObject+".visible"
&cVisible. := true
next
exit // out of this loop, we're done
else
if nColumns > 7
nColumns = 7
exit
endif
cObject = "oRef.Row1Col"+nColumns
cVisible = cObject+".visible"
&cVisible. := false
endif // dow( dFirst ) = nColumns
nColumns++ // increment column counter
loop // top of _this_ loop
enddo // while nCurrent <= nColumns
loop // back to columns for/next loop
endif // nCurrent = 1
// now to attempt to handle setting
// text and colors ...
cObject = "oRef.Row"+nRows+"Col"+nColumns
cSpeedTip = cObject+".speedTip"
&cSpeedTip := "" // clear out whatever's there
// if we're inside the month's dates:
if nCurrent > 1 and nCurrent <= day( dLast )
// set the text property:
cText = cObject+".text"
&cText. := ""+nCurrent
// set the button to visible:
cVisible = cObject+".visible"
&cVisible. := true
// deal with colors:
cColor = cObject+".colorNormal"
// if the day we're setting is the
// selected/current date:
dTestDate = new date(year(dDate), ;
month(dDate)-1, nCurrent)
// Make it a real date
dTestDate = ctod( left( dTestDate.toLocaleString(), ;
iif( set("CENTURY") == "ON", 10, 8 ) ) )
if nDay == nCurrent
&cColor. := SelectedColor
oRef.currentButton = &cObject.
cSpeedTip = cObject+".speedTip"
if class::isHoliday( dtestDate )
&cSpeedTip. = oRef.cSpeedTip
endif
else
// is it a sunday or a holiday?
cSpeedTip = cObject+".speedTip"
if nColumns == 1
&cColor. := SundayColor
if class::IsHoliday( dTestDate )
&cColor. := HolidayColor
&cSpeedTip. := oRef.cSpeedTip
endif
elseif class::IsHoliday( dTestDate )
&cColor. := HolidayColor
&cSpeedTip. := oRef.cSpeedTip
else
// it's any other day of week ...
&cColor. := NormalColor
endif
endif // nDay == nCurrent
else
// we want to make it invisible
cVisible = cObject+".visible"
&cVisible. := false
endif // nCurrent > 1 and nCurrent <= day( dLast )
next // nColumns
next // nRows
// deal with DateTime:
if oRef.type == "DateTime"
cDate = dtoc( oRef.currentDate )
cDate += " " + cTime
oRef.currentDate = ctodt( cDate )
endif
// if it exists, refresh the entryfield:
if type( "oRef.EF" ) == "O" // object
oRef.EF.value = oRef.currentDate
endif
return
function TodayPushButton_onClick
// set today's date
this.parent.currentDate = date()
// refresh display
class::NewMonth()
// close the subform:
this.parent.close()
return
function CancelButton_OnClick
// reset date to the starting date:
this.parent.currentDate = this.parent.beginDate
// refresh display
class::NewMonth()
return
function TimeButton_OnClick
// need to change display of the subform to handle
// time and morph the button back to point back to
// the main calendar
if this.parent.PageNo == 1
this.parent.PageNo := 2 // change pages
// morph the button
this.speedTip := TimeSpeedTip2
this.upBitMap := TimeBackImg
// break up values for H/M/S and place in
// controls. Need to get value from
// this.parent.currentDate:
this.parent.HourSB.value := this.parent.currentDate.hour
this.parent.MinutesSB.value := this.parent.currentDate.minute
this.parent.SecondsSB.value := this.parent.currentDate.second
// set focus to Hours spinbox:
this.parent.HourSB.setFocus()
else
this.parent.PageNo := 1
// morph the button:
this.speedTip := TimeSpeedTip1
this.upBitMap := TimeButtonImg
endif
return
function NEXTYEARPUSHBUTTON_onClick
// code to add year to date,
// and call newMonth routine
// if dateTime we need to catch the time and add it back in
if this.parent.type == "DateTime"
cTime = this.parent.currentDate.hour+":"+;
this.parent.currentDate.minute+":"+;
this.parent.currentDate.second
endif
// increment year:
this.parent.currentDate = ;
this.parent.dateEx.addYears( this.parent.currentDate, 1 )
// if needed put the time back in
if this.parent.type == "DateTime"
this.parent.currentDate := ;
ctodt( dtoc( this.parent.currentDate ) + " " + cTime )
endif
// update the whole thing
class::NewMonth()
return
function YEARPLUS10_onClick
// code to add 10 years to date,
// and call newMonth routine
// if dateTime we need to catch the time and add it back in
if this.parent.type == "DateTime"
cTime = this.parent.currentDate.hour+":"+;
this.parent.currentDate.minute+":"+;
this.parent.currentDate.second
endif
// increment year 'n' years:
this.parent.currentDate = ;
this.parent.dateEx.addYears( this.parent.currentDate, YearIncrement )
// if needed put the time back in
if this.parent.type == "DateTime"
this.parent.currentDate := ;
ctodt( dtoc( this.parent.currentDate ) + " " + cTime )
endif
// update the calendar
class::NewMonth()
return
function PREVYEARPUSHBUTTON_onClick
// code to subtract year from date,
// and call newMonth routine
// if dateTime we need to catch the time and add it back in
if this.parent.type == "DateTime"
cTime = this.parent.currentDate.hour+":"+;
this.parent.currentDate.minute+":"+;
this.parent.currentDate.second
endif
// decrement year
this.parent.currentDate = ;
this.parent.dateEx.addYears( this.parent.currentDate, -1 )
// if needed put the time back in
if this.parent.type == "DateTime"
this.parent.currentDate := ;
ctodt( dtoc( this.parent.currentDate ) + " " + cTime )
endif
// update the calendar
class::NewMonth()
return
function YEARMINUS10_onClick
// code to subtract 10 years from date,
// and call newMonth routine
// if dateTime we need to catch the time and add it back in
if this.parent.type == "DateTime"
cTime = this.parent.currentDate.hour+":"+;
this.parent.currentDate.minute+":"+;
this.parent.currentDate.second
endif
// decrement 'n' years
this.parent.currentDate = ;
this.parent.dateEx.addYears( this.parent.currentDate, -YearIncrement )
// if needed put the time back in
if this.parent.type == "DateTime"
this.parent.currentDate := ;
ctodt( dtoc( this.parent.currentDate ) + " " + cTime )
endif
// update the calendar
class::NewMonth()
return
function NEXTMONTHPUSHBUTTON_onClick
// code to add month to date,
// and call newMonth routine
// if dateTime we need to catch the time and add it back in
if this.parent.type == "DateTime"
cTime = this.parent.currentDate.hour+":"+;
this.parent.currentDate.minute+":"+;
this.parent.currentDate.second
endif
// increment month
this.parent.currentDate = ;
this.parent.dateEx.addMonths( this.parent.currentDate, 1 )
// if needed put the time back in
if this.parent.type == "DateTime"
this.parent.currentDate := ;
ctodt( dtoc( this.parent.currentDate ) + " " + cTime )
endif
// update the calendar
class::NewMonth()
return
function MONTHPLUS3_onClick
// code to add 3 months to date,
// and call newMonth routine
// if dateTime we need to catch the time and add it back in
if this.parent.type == "DateTime"
cTime = this.parent.currentDate.hour+":"+;
this.parent.currentDate.minute+":"+;
this.parent.currentDate.second
endif
// increment 'n' months
this.parent.currentDate = ;
this.parent.dateEx.addMonths( this.parent.currentDate, MonthIncrement )
// if needed put the time back in
if this.parent.type == "DateTime"
this.parent.currentDate := ;
ctodt( dtoc( this.parent.currentDate ) + " " + cTime )
endif
// update the calendar
class::NewMonth()
return
function PREVMONTHPUSHBUTTON_onClick
// code to subtract month from date,
// and call newMonth routine
// if dateTime we need to catch the time and add it back in
if this.parent.type == "DateTime"
cTime = this.parent.currentDate.hour+":"+;
this.parent.currentDate.minute+":"+;
this.parent.currentDate.second
endif
// decrement month
this.parent.currentDate = ;
this.parent.dateEx.addMonths( this.parent.currentDate, -1 )
// if needed put the time back in
if this.parent.type == "DateTime"
this.parent.currentDate := ;
ctodt( dtoc( this.parent.currentDate ) + " " + cTime )
endif
// update the calendar
class::NewMonth()
return
function MONTHMINUS3_onClick
// code to subtract 3 months from date,
// and call newMonth routine
// if dateTime we need to catch the time and add it back in
if this.parent.type == "DateTime"
cTime = this.parent.currentDate.hour+":"+;
this.parent.currentDate.minute+":"+;
this.parent.currentDate.second
endif
// decrement 'n' months
this.parent.currentDate = ;
this.parent.dateEx.addMonths( this.parent.currentDate, -MonthIncrement )
// if needed put the time back in
if this.parent.type == "DateTime"
this.parent.currentDate := ;
ctodt( dtoc( this.parent.currentDate ) + " " + cTime )
endif
// update the calendar
class::NewMonth()
return
function HoursSB_OnChange
// from the HoursSB (Spinbox), change the hours for the current date:
oRef = this.parent
// build datetime string:
cDTString = oRef.currentDate.month+;
"/"+;
oRef.currentDate.date+;
"/"+;
oRef.currentDate.year+;
" "+;
this.value+;
":"+;
oRef.currentDate.minute+;
":"+;
oRef.currentDate.second
// call method to update:
class::UpdateTime( cDTString )
return
function MinutesSB_OnChange
// from the MinutesSB (Spinbox), change the minutes for the current date:
oRef = this.parent
// build datetime string:
cDTString = oRef.currentDate.month+;
"/"+;
oRef.currentDate.date+;
"/"+;
oRef.currentDate.year+;
" "+;
oRef.currentDate.hour+;
":"+;
this.value+;
":"+;
oRef.currentDate.second
// call method to update:
class::UpdateTime( cDTString )
return
function SecondsSB_OnChange
// from the SecondsSB (Spinbox), change the seconds for the current date:
oRef = this.parent
// build datetime string:
cDTString = oRef.currentDate.month+;
"/"+;
oRef.currentDate.date+;
"/"+;
oRef.currentDate.year+;
" "+;
oRef.currentDate.hour+;
":"+;
oRef.currentDate.minute+;
":"+;
this.value
// call method to update:
class::UpdateTime( cDTString )
return
procedure UpdateTime( cDTString )
// called from HoursSP, MinutesSB or SecondsSB
oRef = this.parent
// save old date setting in case not MDY:
cOldDate = set( "date" )
// set to MDY format:
set date MDY
// assign and convert string to currentDate property:
oRef.currentDate = ctodt( cDTString )
// reset date format
set date &cOldDate.
// update the entryfield:
oRef.EF.value := oRef.currentDate
return
procedure LoadHolidays
// Creates/re-creates array used to determine
// a holiday ... NOTE: It adds an array
// to the form ...
local nYear, oRef, nHoliday, d
local cMarkSet
private cCmd, cDateSet
// Have to determine if being called from container
// or from a button call ...
if "CALENDAR" $ this.className
nYear = year( this.currentDate )
oRef = this
else
nYear = year( this.parent.currentDate )
oRef = this.parent
endif
// Create array
oRef.Holidays = new Array(1,2) // 1 row, 2 columns
// Load holidays using holidaydate method below:
// floating holidays (most of these are US Holidays --
// *********************************************
// you may wish to modify if not in the US ...):
// *********************************************
// President's Day
i = 0
i++
oRef.Holidays[i,1] = oRef.Holiday.HolidayDate( nYear, "P" )
oRef.Holidays[i,2] = "President's Day"
// Daylight Savings time -- always a Sunday
// Memorial Day
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = oRef.Holiday.HolidayDate( nYear, "M" )
oRef.Holidays[i,2] = "Memorial Day"
// Labor Day
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = oRef.Holiday.HolidayDate( nYear, "L" )
oRef.Holidays[i,2] = "Labor Day"
// Columbus Day
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = oRef.Holiday.HolidayDate( nYear, "C" )
oRef.Holidays[i,2] = "Columbus Day"
// Standard Time -- always a Sunday
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = oRef.Holiday.HolidayDate( nYear, "S" )
oRef.Holidays[i,2] = "Standard Time"
// Daylight Savings Time
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = oRef.Holiday.HolidayDate( nYear, "D" )
oRef.Holidays[i,2] = "Daylight Savings Time"
// Election Day
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = oRef.Holiday.HolidayDate( nYear, "E" )
oRef.Holidays[i,2] = "Election Day"
// Thanksgiving
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = oRef.Holiday.HolidayDate( nYear, "T" )
oRef.Holidays[i,2] = "Thanksgiving"
// Advent -- always a Sunday
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = oRef.Holiday.HolidayDate( nYear, "A" )
oRef.Holidays[i,2] = "Advent"
// Easter requires special code ...:
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = oRef.Holiday.EasterDay( nYear )
oRef.Holidays[i,2] = "Easter"
// fixed dates:
// deal with date format, so we don't
// mess up international users ...
cDateSet = set("DATE")
cMarkSet = set("MARK")
set date MDY
// New Year's Day
d = ctod( "01/01/"+nYear )
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = d
oRef.Holidays[i,2] = "New Year's Day"
// Lincoln's Birthday
d = ctod( "02/12/"+nYear)
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = d
oRef.Holidays[i,2] = "Lincoln's Birthday"
// Valentine's Day
d = ctod( "02/14/"+nYear )
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = d
oRef.Holidays[i,2] = "Valentine's Day"
// Washington's Birthday
d = ctod( "02/22/"+nYear)
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = d
oRef.Holidays[i,2] = "Washington's Birthday"
// St. Patrick's Day
d = ctod( "03/17/"+nYear)
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = d
oRef.Holidays[i,2] = "St. Patrick's Day"
// April Fool's Day
d = ctod( "04/01/"+nYear)
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = d
oRef.Holidays[i,2] = "April Fool's Day"
// Fourth of July
d = ctod( "07/04/"+nYear )
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = d
oRef.Holidays[i,2] = "Independance Day"
// Halloween (All Hallows Eve)
d = ctod( "10/31/"+nYear )
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = d
oRef.Holidays[i,2] = "Halloween"
// Christmas
d = ctod( "12/25/"+nYear )
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = d
oRef.Holidays[i,2] = "Christmas"
// New Year's Eve
d = ctod( "12/31/"+nYear )
i++
oRef.Holidays.grow(1)
oRef.Holidays[i,1] = d
oRef.Holidays[i,2] = "New Year's Eve"
// You can add more here if you wish ...
// make sure you add a row to the array,
// and add the name of the holiday or memorable
// date ... Basically, copy the code as shown
// above, and make appropriate changes
// reset date format to whatever it was
// before we changed to American
set date &cDateSet.
cCmd = "set mark to '"+cMarkSet+"'"
&cCmd.
// one last thing:
oRef.Holidays.sort(1) // sort on first column
return
Function IsHoliday
parameter dCheckIt
// this routine reads the array "this.Holidays"
// and checks the date to see if the date in
// dCheck parameter is in the list, and returns
// a logical value ...
if "CALENDAR" $ upper( this.className )
oRef = this
else
oRef = this.parent
endif
lHoliday = false
oRef.cSpeedTip = ""
for i = 1 to oRef.Holidays.size/2
if oRef.Holidays[ i, 1 ] == dCheckIt
lHoliday := true
oRef.cSpeedTip = oRef.Holidays[ i, 2 ]
endif
next
return ( lHoliday )
endclass
// end of class pKenCalendarContainer
/*
----------------------------------------------------------
Pushbutton class definitions
CalPushButton -- default button definition used for all
buttons on form
DayPushButton -- used to display the days on the calendar
----------------------------------------------------------
*/
class CalPushbutton( oParent ) of Pushbutton( oParent )
this.fontName := ButtonFontName
this.speedBar := true // so they don't keep focus
#if __version__ < 11
this.systemTheme := false
#else
// dBASE Plus 11 new property,
// allows us to keep general pushbutton
// appearance of theme, but change
// the color of the button:
this.themeBackground := false
#endif
this.visible := true // unless turned off
this.metric := 6 // Pixels
endclass
class DayPushButton( oParent ) of CalPushbutton( oParent )
with (this)
fontSize := ButtonFontSize
height := ButtonHeight
width := ButtonWidth
text := "30" // set to this for layout purposes
visible := false
pageNo := 1
endwith
function onClick
// deal with whether or not this is date or dateTime
if this.parent.type == "DateTime"
cTime = this.parent.currentDate.hour+":"+;
this.parent.currentDate.minute+":"+;
this.parent.currentDate.second
endif
/*
The tricky part of this little routine is
resetting colors -- in order to do that,
we need to store a reference to the 'current'
button, so we can reset that, before we change
the now current button's color ...
*/
dCurrentDate = new date(year(this.parent.currentDate), ;
month(this.parent.currentDate)-1, ;
VAL(this.parent.currentButton.text))
dCurrentDate = ctod( left( dCurrentDate.toLocaleString(), ;
iif( set("CENTURY") == "ON", 10, 8 ) ) )
if type( "this.parent.currentbutton" ) # "U"
// if it's in Column 1, it's a "sunday" ...
if "COL1" $ this.parent.currentButton.Name
this.parent.currentButton.colorNormal := ;
SundayColor // this.parent.SUNDAYCOLOR
// set holiday color if needed:
elseif this.parent.isHoliday( dCurrentDate )
this.parent.currentButton.colorNormal := ;
HolidayColor // this.parent.HOLIDAYCOLOR
// otherwise, we have a "normal" day ...
else
this.parent.currentButton.colorNormal := ;
NormalColor // this.parent.NORMALCOLOR
endif
endif
// Assign currentButton property of container
this.parent.currentButton = this
// Assign color ...
this.colorNormal := SelectedColor // this.parent.SELECTEDCOLOR
// set current date to this one:
this.parent.currentDate := ;
new date( year(this.parent.currentDate), ;
month(this.parent.currentDate)-1, ;
VAL(this.text) )
this.parent.currentDate := ;
ctod( left( this.parent.currentDate.toLocaleString(), ;
iif( set("CENTURY") == "ON", 10, 8 ) ) )
// and we need the darn time ...
if this.parent.type == "DateTime"
cDate = this.parent.currentDate + " " + cTime
this.parent.currentDate = ctoDT( cDate )
endif
// because of adding the onMouseOver event, we
// are having an issue here ... sequence
// of event processing is throwing things
// off (which makes sense, moving the mouse over
// the control would happen before the onClick
// event):
this.oldColorNormal := this.colorNormal
// deal with entryfield update:
if type( "this.parent.EF" ) == "O" // object
this.parent.EF.value := this.parent.currentDate
endif
// close the subform:
this.parent.close()
return
function onMouseOver
// save current color setting
this.oldColorNormal = this.colorNormal
// make it readable ...:
this.colorNormal := MouseOverColor //this.parent.MouseOverColor
return
function onMouseOut
this.colorNormal := this.oldColorNormal // revert to previous setting
return
endclass
// custom class the "title" text so we have something nearly
// identical to the pushbuttons used for the days for the titles
class WeekDayText( oParent ) of Text( oParent )
with (this)
fontName := ButtonFontName
fontSize := ButtonFontSize
height := ButtonHeight
width := ButtonWidth
metric := 6 // Pixels
text := "S"
border := true
#if __version__ < 11
borderStyle := 1 // raised
#else
borderStyle := 9 // etched in
#endif
alignHorizontal := 1 // center
alignVertical := 1 // middle
colorNormal := normalColor
pageNo := 1
endwith
endclass
// for conversion from fontSize (points) to Pixels (form metric):
function Points2Pixels( nPoints )
return round( nPoints * 1.3333333333333333, 0 )
/* END OF FILE -- kmDateWithCal.cc */
Warning: Unknown: write failed: No space left on device (28) in Unknown on line 0
Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct () in Unknown on line 0