home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Total C++ 2
/
TOTALCTWO.iso
/
vb5.0
/
tools
/
unsupprt
/
calendar
/
calendar.ctl
< prev
next >
Wrap
Text File
|
1997-01-16
|
75KB
|
1,937 lines
VERSION 5.00
Begin VB.UserControl Calendar
ClientHeight = 2745
ClientLeft = 0
ClientTop = 0
ClientWidth = 3480
EditAtDesignTime= -1 'True
KeyPreview = -1 'True
PropertyPages = "Calendar.ctx":0000
ScaleHeight = 183
ScaleMode = 3 'Pixel
ScaleWidth = 232
ToolboxBitmap = "Calendar.ctx":0032
Begin VB.TextBox ctlFocus
Height = 285
Left = -300
TabIndex = 0
Top = 900
Width = 150
End
Begin VB.TextBox txtYear
Height = 285
Left = 2280
MaxLength = 4
TabIndex = 3
ToolTipText = "Year"
Top = 120
Width = 495
End
Begin VB.ComboBox cbxMonth
Height = 315
Left = 480
Style = 2 'Dropdown List
TabIndex = 2
ToolTipText = "Month"
Top = 120
Width = 1695
End
Begin VB.CommandButton btnNext
Height = 255
Left = 3060
MaskColor = &H000000FF&
Picture = "Calendar.ctx":012C
Style = 1 'Graphical
TabIndex = 4
ToolTipText = "Go To Next Month"
Top = 120
UseMaskColor = -1 'True
Width = 255
End
Begin VB.CommandButton btnPrev
Height = 255
Left = 60
MaskColor = &H000000FF&
Picture = "Calendar.ctx":020E
Style = 1 'Graphical
TabIndex = 1
ToolTipText = "Go To Previous Month"
Top = 120
UseMaskColor = -1 'True
Width = 255
End
End
Attribute VB_Name = "Calendar"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Attribute VB_Description = "VB Calendar Control Sample"
'----------------------------------------------------------------------
' Calendar.ctl
'----------------------------------------------------------------------
' Implementation file for the VB Calendar control sample.
' This control displays a month-at-a-time view calendar that the
' developer can use to let users view and adjust date values
'----------------------------------------------------------------------
' Copyright (c) 1996, Microsoft Corporation
' All Rights Reserved
'
' Information Contained Herin is Proprietary and Confidential
'----------------------------------------------------------------------
Option Explicit
'======================================================================
' Public Event Declarations
'======================================================================
Public Event DateChange(ByVal OldDate As Date, ByVal NewDate As Date)
Public Event WillChangeDate(ByVal NewDate As Date, Cancel As Boolean)
Public Event DblClick()
Public Event Click()
'======================================================================
' Public Enumerations
'======================================================================
Public Enum CalendarMonths 'months of the year
calJanuary = 1
calFebruary
calMarch
calApril
calMay
calJune
calJuly
calAugust
calSeptember
calOctober
calNovember
calDecember
End Enum 'CalendarMonths
Public Enum DaysOfTheWeek
calUseSystem = 0
calSunday
calMonday
calTuesday
calWednesday
calThursday
calFriday
calSaturday
End Enum 'DaysOfTheWeek
Public Enum CalendarAreas
calNavigationArea
calDayNameArea
calDateArea
calUnknownArea
End Enum 'CalendarAreas
'Short = "F"
'Medium = "Fri"
'Long = "Friday"
Public Enum DayNameFormats
calShortName = 0
calMediumName
calLongName
End Enum 'DayNameFormats
'======================================================================
' Private Constants
'======================================================================
Private Const NUMCOLS As Long = 7 'number of cols in grid
Private Const NUMROWS As Long = 6 'number of rows in grid
Private Const NUMMONTHS As Long = 12 'number of months in a year
Private Const NUMDAYS As Long = 7 'number of days in a week
Private Const BORDER3D As Long = 2 'num pixels for good 3d border
Private Const FOCUSBORDER As Long = 1 'num pixels for focus border
Private Enum DaySets
PrevMonthDays
CurMonthDays
NextMonthDays
End Enum 'DaySets
Private Enum DayEffectFlags
calEffectOff = 1
calEffectOn = -1
calEffectDefault = 0
End Enum 'DayEffectFlags
'======================================================================
' Private Data Members
'======================================================================
'Current Date
Private mnDay As Long 'current day number
Private mnYear As Long 'current year number
Private mnMonth As Long 'currnet month number
'Formatting and Appearance Settings
Private mnFirstDayOfWeek As VbDayOfWeek 'first day of the week
Private mnDayNameFormat As DayNameFormats
Private mfntDayNames As StdFont 'font to use for painting day names
Private mclrDayNames As OLE_COLOR 'color for the day names
Private mfShowIterrators As Boolean 'determines if iterrator buttons
'should be shown or not
Private mfMonthReadOnly As Boolean 'month selector or none
Private mfYearReadOnly As Boolean 'month selector or none
'Behavior settings
Private mfLocked As Boolean 'read-only or not
'String Arrays For Month and Day Names
Private masMonthNames(NUMMONTHS - 1) As String 'string array of month names
Private masDayNames(NUMDAYS - 1) As String 'string array of day names
'this should be replaced with day styles eventually
Private mfntDayFont As StdFont 'font to use for painting dates in
'the current month
Private mclrDay As OLE_COLOR 'color for the day numbers
Private mafDayBold(1 To 31) As DayEffectFlags 'array of flags for day being bold
Private mafDayItalic(1 To 31) As DayEffectFlags 'array of flags for day being italic
'Current Column Width and Row Height For Calendar Grid
Private mcxColWidth As Long 'width of each column in the grid
Private mcyRowHeight As Long 'height of each row in the grid
'RECTs For Different Calendar Areas
Private mrcNavArea As RECT 'rect bounding the navigation area
Private mrcDayNameArea As RECT 'rect bounding the day name area
Private mrcCalArea As RECT 'area bounding the calendar days
Private mrcFocusArea As RECT 'current focus area
'General Utility Members
Private mobjRes As ResLoader 'resource loading object (localization)
Private mfIgnoreMonthYearChange As Boolean 'HACKY flag for ignoring the programatic
'change of the month and year navigation
'controls.
Private maRepaintDays(1) As Long 'array of day numbers to repaint
Private mfFastRepaint As Boolean 'boolean flag used to do fast repaint
'when only the day selected is changing
'======================================================================
' Public Property Procedures
'======================================================================
'----------------------------------------------------------------------
' Version Get
'----------------------------------------------------------------------
' Purpose: Gets the version number of the control
'----------------------------------------------------------------------
Public Property Get Version() As String
Attribute Version.VB_Description = "Returns the version number of this control."
Attribute Version.VB_ProcData.VB_Invoke_Property = ";Misc"
Version = App.Major & "." & App.Minor & "." & App.Revision
End Property 'Get Version()
'----------------------------------------------------------------------
' Day Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and lets the current day value
'----------------------------------------------------------------------
Public Property Get Day() As Long
Attribute Day.VB_Description = "Returns/Sets the Day number of the selected date."
Attribute Day.VB_ProcData.VB_Invoke_Property = ";Data"
Day = mnDay
End Property 'Get Day()
Public Property Let Day(nNewVal As Long)
'validate our inputs
If nNewVal > 0 And nNewVal <= MaxDayInMonth(mnMonth, mnYear) Then
ChangeValue nNewVal, mnMonth, mnYear
Else
mobjRes.RaiseUserError errPropValueRange, Array("Day", "0", CStr(MaxDayInMonth(mnMonth, mnYear)))
End If
End Property 'Let Day()
'----------------------------------------------------------------------
' Month Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and lets the current month value
'----------------------------------------------------------------------
Public Property Get Month() As CalendarMonths
Attribute Month.VB_Description = "Returns/Sets the month number of the currently selected date."
Attribute Month.VB_ProcData.VB_Invoke_Property = ";Data"
Month = mnMonth
End Property 'Get Month()
Public Property Let Month(nNewVal As CalendarMonths)
'validate our inputs
'note we still need to do this even though we're using
'an enumeration since VB only treats this as a long value
If nNewVal > 0 And nNewVal <= 12 Then
ChangeValue mnDay, nNewVal, mnYear
Else
mobjRes.RaiseUserError errPropValueRange, Array("Month", "0", "12")
End If
End Property 'Let Month()
'----------------------------------------------------------------------
' Year Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and lets the current year value
'----------------------------------------------------------------------
Public Property Get Year() As Long
Attribute Year.VB_Description = "Returns/Sets the year number of the currently selected date."
Attribute Year.VB_ProcData.VB_Invoke_Property = ";Data"
Year = mnYear
End Property 'Get Year()
Public Property Let Year(nNewVal As Long)
'validate our inputs
'year must be between 100 and 9999 due to the restrictions
'of the date data type in basic
If nNewVal >= 100 And nNewVal <= 9999 Then
ChangeValue mnDay, mnMonth, nNewVal
Else
mobjRes.RaiseUserError errPropValueRange, Array("Year", "100", "9999")
End If
End Property 'Let Year()
'----------------------------------------------------------------------
' Value Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and lets the current date value
'----------------------------------------------------------------------
Public Property Get Value() As Date
Attribute Value.VB_Description = "Returns/Sets the currently selected date in the control."
Attribute Value.VB_ProcData.VB_Invoke_Property = ";Data"
Attribute Value.VB_MemberFlags = "3c"
Value = DateSerial(mnYear, mnMonth, mnDay)
End Property 'Get Value()
Public Property Let Value(dtNew As Date)
ChangeValue VBA.Day(dtNew), VBA.Month(dtNew), VBA.Year(dtNew)
End Property 'Let Value()
'----------------------------------------------------------------------
' DayFont Get/Set
'----------------------------------------------------------------------
' Purpose: Gets or sets the font to use for date numbers
'----------------------------------------------------------------------
Public Property Get DayFont() As Font
Attribute DayFont.VB_Description = "Returns/Sets the font used for the day numbers."
Attribute DayFont.VB_ProcData.VB_Invoke_Property = ";Appearance"
Attribute DayFont.VB_UserMemId = -512
Set DayFont = mfntDayFont
End Property 'Get DayFont()
'*** VB BUG Workaround ***
'The fntNew argument is passed in ByVal in order to
'get this property to show in the built-in Font
'property page. When the bug is fixed, change this
'back to ByRef (remove ByVal)
Public Property Set DayFont(ByVal fntNew As Font)
Set mfntDayFont = fntNew
UserControl.Refresh
End Property 'Set DayFont()
'----------------------------------------------------------------------
' DayNameFont Get/Set
'----------------------------------------------------------------------
' Purpose: Gets or sets the font to use for day names
'----------------------------------------------------------------------
Public Property Get DayNameFont() As Font
Attribute DayNameFont.VB_Description = "Returns/Sets the font used for the day names."
Attribute DayNameFont.VB_ProcData.VB_Invoke_Property = ";Appearance"
Set DayNameFont = mfntDayNames
End Property 'Get DayFont()
'*** VB BUG Workaround ***
'The fntNew argument is passed in ByVal in order to
'get this property to show in the built-in Font
'property page. When the bug is fixed, change this
'back to ByRef (remove ByVal)
Public Property Set DayNameFont(ByVal fntNew As Font)
Set mfntDayNames = fntNew
UserControl.Refresh
End Property 'Set DayFont()
'----------------------------------------------------------------------
' DayBold() Get/Let
'----------------------------------------------------------------------
' Purpose: This property allows the user to set a particular day to bold
' or not so as to give the effect of a 'special' day
' Inputs: day number (1 to max day in current month)
' Outputs: True if it's Bold, False if not
'----------------------------------------------------------------------
Public Property Get DayBold(DayNumber As Long) As Boolean
Attribute DayBold.VB_Description = "Returns/Sets the Bold state for a day in the current month."
'if the setting for this day is "default" then the
'value returned depends on the bold state of the
'DayFont property
If mafDayBold(DayNumber) = calEffectDefault Then
DayBold = mfntDayFont.Bold
Else
DayBold = (mafDayBold(DayNumber) = calEffectOn)
End If
End Property 'Get DayBold()
Public Property Let DayBold(DayNumber As Long, NewVal As Boolean)
If NewVal = True Then
mafDayBold(DayNumber) = calEffectOn
Else
mafDayBold(DayNumber) = calEffectOff
End If
End Property 'Let DayBold()
'----------------------------------------------------------------------
' DayItalic() Get/Let
'----------------------------------------------------------------------
' Purpose: This property allows the user to set a particular day italic
' or not so as to give the effect of a 'special' day
' Inputs: day number (1 to max day in current month)
' Outputs: True if it's Italic, False if not
'----------------------------------------------------------------------
Public Property Get DayItalic(DayNumber As Long) As Boolean
Attribute DayItalic.VB_Description = "Returns/Sets the Italic state for a day in the current month."
'if the setting for this day is "default" then the
'value returned depends on the italic state of the
'DayFont property
If mafDayItalic(DayNumber) = calEffectDefault Then
DayItalic = mfntDayFont.Italic
Else
DayItalic = (mafDayItalic(DayNumber) = calEffectOn)
End If
End Property 'Get DayItalic()
'**Let
Public Property Let DayItalic(DayNumber As Long, NewVal As Boolean)
If NewVal = True Then
mafDayItalic(DayNumber) = calEffectOn
Else
mafDayItalic(DayNumber) = calEffectOff
End If
End Property 'Let DayItalic()
'----------------------------------------------------------------------
' StartOfWeek Get/Let
'----------------------------------------------------------------------
' Purpose: Gets or lets the first day to display in a week
'----------------------------------------------------------------------
Public Property Get StartOfWeek() As DaysOfTheWeek
Attribute StartOfWeek.VB_Description = "Returns/Sets the first day of the week which will be displayed in the left-most column."
Attribute StartOfWeek.VB_ProcData.VB_Invoke_Property = ";Appearance"
StartOfWeek = mnFirstDayOfWeek
End Property 'Get StartOfWeek()
Public Property Let StartOfWeek(nNewVal As DaysOfTheWeek)
'validate our inputs
If nNewVal >= calUseSystem And nNewVal <= calSaturday Then
mnFirstDayOfWeek = nNewVal
'do a Refresh to make the control repaint
UserControl.Refresh
Else
mobjRes.RaiseUserError errPropValueRange, Array("StartOfWeek", calUseSystem, calSaturday)
End If 'valid inputs
End Property 'Let StartOfWeek()
'----------------------------------------------------------------------
' DayNameFormat Get/Let
'----------------------------------------------------------------------
' Purpose: Gets or lets the format to use for day names
' (short, medium, long)
'----------------------------------------------------------------------
Public Property Get DayNameFormat() As DayNameFormats
Attribute DayNameFormat.VB_Description = "Returns/Sets the format to use for the day names (Short = ""M"", Medium = ""Mon"", Long = ""Monday"")."
Attribute DayNameFormat.VB_ProcData.VB_Invoke_Property = ";Appearance"
DayNameFormat = mnDayNameFormat
End Property 'Get DayNameFormat
Public Property Let DayNameFormat(nNewFormat As DayNameFormats)
'validate the input
If nNewFormat >= calShortName And nNewFormat <= calLongName Then
'set the new format and re-load the day names
mnDayNameFormat = nNewFormat
LoadDayNames
UserControl.Refresh
Else
mobjRes.RaiseUserError errPropValueRange, Array("DayNameFormat", calShortName, calLongName)
End If 'valid inputs
End Property 'Let DayNameFormat
'----------------------------------------------------------------------
' ShowIterratorButtons Get/Let
'----------------------------------------------------------------------
' Purpose: Gets or lets the option for showing or hiding the month
' iterrator buttons
'----------------------------------------------------------------------
Public Property Get ShowIterrationButtons() As Boolean
Attribute ShowIterrationButtons.VB_Description = "Returns/Sets the visible state of the previous and next month navigation buttons."
Attribute ShowIterrationButtons.VB_ProcData.VB_Invoke_Property = ";Appearance"
ShowIterrationButtons = mfShowIterrators
End Property 'Get ShowIterrationButtons()
Public Property Let ShowIterrationButtons(fNew As Boolean)
'if it's not changing, don't bother
If fNew = mfShowIterrators Then Exit Property
'assign the new value
mfShowIterrators = fNew
'and adjust the visible state of the buttons
btnPrev.Visible = mfShowIterrators
btnNext.Visible = mfShowIterrators
'trigger the resize event to recalc the widths
'of the other navigation controls
UserControl_Resize
End Property 'Let ShowIterrationButtons()
'----------------------------------------------------------------------
' MonthReadOnly Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and lets the option of making the month selector
' read-only or not
'----------------------------------------------------------------------
Public Property Get MonthReadOnly() As Boolean
Attribute MonthReadOnly.VB_Description = "Returns/Sets the read-only state of the month navigation combo box."
Attribute MonthReadOnly.VB_ProcData.VB_Invoke_Property = ";Appearance"
MonthReadOnly = mfMonthReadOnly
End Property 'Get MonthReadOnly()
Public Property Let MonthReadOnly(fNew As Boolean)
'if it's not changing, don't bother
If fNew = mfMonthReadOnly Then Exit Property
'set the new value and hide or show the month selector
mfMonthReadOnly = fNew
cbxMonth.Visible = Not mfMonthReadOnly
End Property 'Let MonthReadOnly()
'----------------------------------------------------------------------
' YearReadOnly Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and lets the option of making the year selector
' read-only or not
'----------------------------------------------------------------------
Public Property Get YearReadOnly() As Boolean
Attribute YearReadOnly.VB_Description = "Returns/Sets the read-only state of the year navigation text box."
Attribute YearReadOnly.VB_ProcData.VB_Invoke_Property = ";Appearance"
YearReadOnly = mfYearReadOnly
End Property 'Get YearReadOnly()
Public Property Let YearReadOnly(fNew As Boolean)
'if it's not changing, don't bother
If fNew = mfYearReadOnly Then Exit Property
'set the new value and hide or show the month selector
mfYearReadOnly = fNew
txtYear.Visible = Not mfYearReadOnly
End Property 'Let YearReadOnly()
'----------------------------------------------------------------------
' Locked Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and sets the Locked option which makes the whole thing
' read-only or not
'----------------------------------------------------------------------
Public Property Get Locked() As Boolean
Attribute Locked.VB_Description = "Returns/Sets the locked state of the control. When locked, the user cannot change the selected date."
Attribute Locked.VB_ProcData.VB_Invoke_Property = ";Behavior"
Locked = mfLocked
End Property 'Get Locked()
Public Property Let Locked(fNew As Boolean)
'set the private variable
mfLocked = fNew
'set the locked state of contained controls
'we'll disable the buttons if locked since
'there is no locked state for buttons
cbxMonth.Locked = fNew
txtYear.Locked = fNew
btnNext.Enabled = Not fNew
btnPrev.Enabled = Not fNew
End Property 'Let Locked()
'----------------------------------------------------------------------
' DayColor Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and sets the color used for the day numbers
'----------------------------------------------------------------------
Public Property Get DayColor() As OLE_COLOR
Attribute DayColor.VB_Description = "Returns/Sets the color used for the day numbers."
Attribute DayColor.VB_ProcData.VB_Invoke_Property = ";Appearance"
Attribute DayColor.VB_UserMemId = -513
DayColor = mclrDay
End Property 'Get DayColor()
Public Property Let DayColor(NewVal As OLE_COLOR)
mclrDay = NewVal
UserControl.Refresh
End Property 'Let DayColor()
'----------------------------------------------------------------------
' DayNameColor Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and sets the color used for the day numbers
'----------------------------------------------------------------------
Public Property Get DayNameColor() As OLE_COLOR
Attribute DayNameColor.VB_Description = "Returns/Sets the color used for the day names (i.e. days of the week)."
Attribute DayNameColor.VB_ProcData.VB_Invoke_Property = ";Appearance"
DayColor = mclrDayNames
End Property 'Get DayNameColor()
Public Property Let DayNameColor(NewVal As OLE_COLOR)
mclrDayNames = NewVal
UserControl.Refresh
End Property 'Let DayNameColor()
'======================================================================
' Public Methods
'======================================================================
'----------------------------------------------------------------------
' HitTest()
'----------------------------------------------------------------------
' Purpose: Does a hit test based on x,y coordinates
' Inputs: x and y coordinates
' Outputs: Area of the control and specific date if over one
'----------------------------------------------------------------------
Public Sub HitTest(ByVal X As Long, ByVal Y As Long, Area As Long, HitDate As Date)
Attribute HitTest.VB_Description = "Returns the area and day number (if any) that corresponds to a given X,Y position."
Dim nRow As Long
Dim nCol As Long
'assert that the x and y are indeed in our coordinate system
Debug.Assert (X <= UserControl.ScaleWidth)
Debug.Assert (Y <= UserControl.ScaleHeight)
'determine the area of the control that x and y are over
If X > mrcNavArea.Right Then
Area = calUnknownArea
Else
If Y >= mrcNavArea.Top And Y <= mrcNavArea.Bottom Then
Area = calNavigationArea
ElseIf Y >= mrcDayNameArea.Top And Y <= mrcDayNameArea.Bottom Then
Area = calDayNameArea
ElseIf Y >= mrcCalArea.Top And Y <= mrcCalArea.Bottom Then
Area = calDateArea
Else
Area = calUnknownArea
End If 'determine area by y
End If 'x is past right of all areas
'if we are in the date area, calculate the hit date
If Area = calDateArea Then
'determine the row and column and make them 0-based
nRow = ((Y - mrcCalArea.Top) \ mcyRowHeight) - 1
If (Y - mrcCalArea.Top) Mod mcyRowHeight > 0 Then
nRow = nRow + 1
End If
nCol = ((X - mrcCalArea.Left) \ mcxColWidth) - 1
If (X - mrcCalArea.Left) Mod mcxColWidth > 0 Then
nCol = nCol + 1
End If
'given the row and column, determine the date
HitDate = DateForRowCol(nRow, nCol)
End If 'in date area
End Sub 'HitTest
'----------------------------------------------------------------------
' Refresh()
'----------------------------------------------------------------------
' Purpose: Refreshes/repaints the entire control
' Inputs: none
' Outputs: none
'----------------------------------------------------------------------
Public Sub Refresh()
Attribute Refresh.VB_Description = "Refreshes the control by causing a complete repaint."
'just pass it on...
UserControl.Refresh
End Sub 'Refresh()
'----------------------------------------------------------------------
' About()
'----------------------------------------------------------------------
' Purpose: Opens the About box for the control--this is marked hidden
' so that it doesn't show up in the statement completion
' but we do mark this with the DispID of AboutBox so that it
' shows in the property sheet with an elipsis button
' Inputs: none
' Outputs: none
'----------------------------------------------------------------------
Public Sub About()
Attribute About.VB_Description = "Shows the about box for the control."
Attribute About.VB_UserMemId = -552
Attribute About.VB_MemberFlags = "40"
frmAbout.Show vbModal
End Sub 'About()
'======================================================================
' Initialize and Terminate Events
'======================================================================
Private Sub UserControl_Initialize()
On Error GoTo Err_Init
'set the resource loader
'daveste -- 7/31/96
'TODO: put in code to load a satellite resource DLL based on the
'locale ID of the ambient host
Set mobjRes = New ResLoader
'load the month names into the combo box
LoadMonthNames
'initialize the area rects that don't depend on the
'size of the control (which are left and top and sometimes bottom)
'doing this here lets us reduce the code needed to execute
'when the control is resized which will happen more often
'than the control being initialized.
mrcNavArea.Left = 1
mrcNavArea.Top = 1
'height of navigation area is the height of the month combo
'plus 4, since we will draw a 3d box around the controls
mrcNavArea.Bottom = cbxMonth.Height + (2 * BORDER3D)
mrcDayNameArea.Left = 1
mrcDayNameArea.Top = mrcNavArea.Bottom
'height of the day name area should be the height of
'the day name font plus 6 pixels for 3d effects
mrcDayNameArea.Bottom = mrcDayNameArea.Top + UserControl.TextHeight("A") + 6
mrcCalArea.Left = 1
mrcCalArea.Top = mrcDayNameArea.Bottom
'set the position and sizes of the navigation controls that
'don't depend on the size of the control (like left and top
'values).
btnPrev.Move mrcNavArea.Left, mrcNavArea.Top, btnPrev.Width, mrcNavArea.Bottom - mrcNavArea.Top
btnNext.Top = mrcNavArea.Top
btnNext.Height = mrcNavArea.Bottom - mrcNavArea.Top
cbxMonth.Move mrcNavArea.Left + btnPrev.Width + BORDER3D, mrcNavArea.Top + BORDER3D
txtYear.Height = cbxMonth.Height
txtYear.Top = mrcNavArea.Top + BORDER3D
'set the disabled picture for the prev and next buttons
'to be the same as the regular picture--this will let us
'give a locked effect by disabling the prev and next buttons
btnPrev.DisabledPicture = btnPrev.Picture
btnNext.DisabledPicture = btnNext.Picture
Exit Sub
Err_Init:
Debug.Assert False
Exit Sub
End Sub 'UserControl_Initialize()
'======================================================================
' Private Event Handles
'======================================================================
'----------------------------------------------------------------------
' InitProperties Event
'----------------------------------------------------------------------
' Purpose: Called when the control is first put on a form
' One-time initialization of data members
' Inputs: None
' Outputs: None
'----------------------------------------------------------------------
Private Sub UserControl_InitProperties()
Dim dt As Date
On Error GoTo Err_InitProps
'initialize the day, month and year to the current system date
dt = Date
mnDay = VBA.Day(dt)
mnMonth = VBA.Month(dt)
mnYear = VBA.Year(dt)
mfIgnoreMonthYearChange = True
cbxMonth.ListIndex = mnMonth - 1
txtYear.Text = mnYear
mfIgnoreMonthYearChange = False
'create new font objects for the day and day name
'fonts and copy the font attributes from the
'user control's ambient font into them
Set mfntDayFont = New StdFont
CopyFont UserControl.Ambient.Font, mfntDayFont
Set mfntDayNames = New StdFont
CopyFont UserControl.Ambient.Font, mfntDayNames
mfntDayNames.Bold = True
'initialize the day and dayname colors to the ambient's
'fore color value
mclrDay = vbBlack
mclrDayNames = vbBlack
'initialize the day name format to medium
mnDayNameFormat = calMediumName
LoadDayNames
'init various appearance options
mfShowIterrators = True
mfMonthReadOnly = False
mfYearReadOnly = False
mfLocked = False
Exit Sub
Err_InitProps:
Debug.Assert False
Exit Sub
End Sub 'UserControl_InitProperties()
'----------------------------------------------------------------------
' ReadProperties Event
'----------------------------------------------------------------------
' Purpose: Called when we need to read property settings back in
' Inputs: the property bag class for reading
' Outputs: None
'----------------------------------------------------------------------
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
Dim dtCurrent As Date
dtCurrent = Date
On Error Resume Next
'read in the properties from the property bag
mnFirstDayOfWeek = PropBag.ReadProperty("StartOfWeek", vbUseSystemDayOfWeek)
ChangeValue PropBag.ReadProperty("Day", VBA.Day(dtCurrent)), _
PropBag.ReadProperty("Month", VBA.Month(dtCurrent)), _
PropBag.ReadProperty("Year", VBA.Year(dtCurrent))
Set mfntDayNames = PropBag.ReadProperty("DayNameFont", UserControl.Font)
Set mfntDayFont = PropBag.ReadProperty("DayFont", UserControl.Font)
mclrDay = PropBag.ReadProperty("DayColor", vbBlack)
mclrDayNames = PropBag.ReadProperty("DayNameColor", vbBlack)
mnDayNameFormat = PropBag.ReadProperty("DayNameFormat", calMediumName)
LoadDayNames
Me.ShowIterrationButtons = PropBag.ReadProperty("ShowIterrationButtons", True)
Me.MonthReadOnly = PropBag.ReadProperty("MonthReadOnly", False)
Me.YearReadOnly = PropBag.ReadProperty("YearReadOnly", False)
Me.Locked = PropBag.ReadProperty("Locked", False)
'trigger a resize since this event happens after the initial
'resize when going to run mode
UserControl_Resize
End Sub 'UserControl_ReadProperties()
'----------------------------------------------------------------------
' WriteProperties Event
'----------------------------------------------------------------------
' Purpose: Called when we need to write property settings out to disk
' Inputs: the property bag class for writing
' Outputs: None
'----------------------------------------------------------------------
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
On Error Resume Next
'write the current property values to the property bag
PropBag.WriteProperty "Day", mnDay
PropBag.WriteProperty "Month", mnMonth
PropBag.WriteProperty "Year", mnYear
PropBag.WriteProperty "StartOfWeek", mnFirstDayOfWeek, vbUseSystemDayOfWeek
PropBag.WriteProperty "DayNameFont", mfntDayNames, UserControl.Font
PropBag.WriteProperty "DayFont", mfntDayFont, UserControl.Font
PropBag.WriteProperty "DayNameFormat", mnDayNameFormat, calMediumName
PropBag.WriteProperty "DayColor", mclrDay, vbBlack
PropBag.WriteProperty "DayNameColor", mclrDayNames, vbBlack
PropBag.WriteProperty "ShowIterrationButtons", mfShowIterrators, True
PropBag.WriteProperty "MonthReadOnly", mfMonthReadOnly, False
PropBag.WriteProperty "YearReadOnly", mfYearReadOnly, False
PropBag.WriteProperty "Locked", mfLocked, False
End Sub 'UserControl_WriteProperties()
'----------------------------------------------------------------------
' Paint Event
'----------------------------------------------------------------------
' Purpose: Called when the control needs to be repainted
' Inputs: None
' Outputs: None
'----------------------------------------------------------------------
Private Sub UserControl_Paint()
Dim dcWork As OffScreenDC
Dim nTop As Long
Dim nLeft As Long
Dim nWidth As Long
Dim nHeight As Long
Dim nDay As Long
Dim nRow As Long
Dim nCol As Long
Dim nLastDay As Long
Dim eDaySet As DaySets
Dim rgbColor As Long
Dim fDefBold As Boolean
Dim fDefItalic As Boolean
On Error GoTo Err_Paint
'save the initial bold and italic state of our day font
fDefBold = mfntDayFont.Bold
fDefItalic = mfntDayFont.Italic
Set dcWork = New OffScreenDC
dcWork.Initialize UserControl.hdc, UserControl.ScaleWidth, UserControl.ScaleHeight
'set the text color to be the color chosen for
'the days of the week names
OleTranslateColor mclrDayNames, 0, rgbColor
dcWork.TextColor = rgbColor
If mfFastRepaint Then
FastRepaint dcWork
Exit Sub
End If
'fill the background of the control with the ambient's
'background color
nLeft = 0
nTop = 0
nWidth = UserControl.ScaleWidth
nHeight = UserControl.ScaleHeight
'I use the OLE API OleTranslateColor here to translate
'an OLE color to an RGB value. VB will return an OLE color
'value for the ambient's back color and this API will convert
'it to an RGB value for painting.
OleTranslateColor UserControl.Ambient.BackColor, 0, rgbColor
dcWork.FillRect nLeft, nTop, nWidth, nHeight, rgbColor
'next fill a black rect that will serve as a thin back outline
'around the painted part of the control
nWidth = mrcNavArea.Right + 1
nHeight = mrcDayNameArea.Bottom + (mcyRowHeight * NUMROWS) + 1
dcWork.FillRect 0, 0, nWidth, nHeight, vbBlack
'draw a 3d rect around the navigation controls
nTop = mrcNavArea.Top
nHeight = mrcNavArea.Bottom - mrcNavArea.Top
If mfShowIterrators Then
nLeft = mrcNavArea.Left + btnPrev.Width
nWidth = btnNext.Left - nLeft
Else
nLeft = mrcNavArea.Left
nWidth = mrcNavArea.Right - mrcNavArea.Left
End If 'mfShowIterrators
dcWork.Draw3DRect nLeft, nTop, nWidth, nHeight
'if the month is read only, draw the month name
If mfMonthReadOnly Then
Set dcWork.Font = cbxMonth.Font
'squeeze the width in by one to make a better 3d effect
dcWork.Draw3DRect cbxMonth.Left, cbxMonth.Top, _
cbxMonth.Width - 1, cbxMonth.Height, _
cbxMonth.List(cbxMonth.ListIndex), _
caCenterCenter, Sunken
End If 'month is read only
'if the year is read only, draw the year number
If mfYearReadOnly Then
Set dcWork.Font = txtYear.Font
dcWork.Draw3DRect txtYear.Left, txtYear.Top, _
txtYear.Width, txtYear.Height, _
txtYear.Text, caCenterCenter, Sunken
End If 'year is read only
'paint the day names
PaintDayNames dcWork
'change the text color to dark gray to paint the previous month days
'daveste -- 7/31/96
'TODO: this should be replaced with day styles or at least with
'a property the control the font and color of these other dates
dcWork.TextColor = RGB(128, 128, 128)
'get the first and last days of the previous month to paint
GetPrevMonthDays mnMonth, mnYear, nDay, nLastDay
eDaySet = PrevMonthDays
Set dcWork.Font = mfntDayFont
'draw a grid of date numbers for the current month
For nRow = 0 To NUMROWS - 1
For nCol = 0 To NUMCOLS - 1
'if we've done painting the current set of days
'switch to the next set
If nDay > nLastDay Then
If eDaySet = PrevMonthDays Then
OleTranslateColor mclrDay, 0, rgbColor
dcWork.TextColor = rgbColor
nDay = 1
nLastDay = MaxDayInMonth(mnMonth, mnYear)
eDaySet = CurMonthDays
Else
dcWork.TextColor = RGB(128, 128, 128)
nDay = 1
nLastDay = 100 'no need to calc the last
'day since the for loops
'will govern when to stop
eDaySet = NextMonthDays
End If 'day set was previous month
End If 'done painting this day set
'paint the day
'set the font attributes for the day being painted
If eDaySet = CurMonthDays Then
If mafDayBold(nDay) = calEffectDefault Then
'optimize for the case where no days are bold
If mfntDayFont.Bold <> fDefBold Then
mfntDayFont.Bold = fDefBold
Set dcWork.Font = mfntDayFont
End If
Else
mfntDayFont.Bold = (mafDayBold(nDay) = calEffectOn)
Set dcWork.Font = mfntDayFont
End If 'DayBold setting is default
If mafDayItalic(nDay) = calEffectDefault Then
'optimize for the case where no days are italic
If mfntDayFont.Italic <> fDefItalic Then
mfntDayFont.Italic = fDefItalic
Set dcWork.Font = mfntDayFont
End If
Else
mfntDayFont.Italic = (mafDayItalic(nDay) = calEffectOn)
Set dcWork.Font = mfntDayFont
End If
End If 'we're in the current month day set
'if it's the current day, draw it selected
If nDay = mnDay And eDaySet = CurMonthDays Then
dcWork.Draw3DRect mrcCalArea.Left + (nCol * mcxColWidth), _
mrcCalArea.Top + (nRow * mcyRowHeight), _
mcxColWidth, mcyRowHeight, CStr(nDay), _
caCenterCenter, Selected
Else
dcWork.Draw3DRect mrcCalArea.Left + (nCol * mcxColWidth), _
mrcCalArea.Top + (nRow * mcyRowHeight), _
mcxColWidth, mcyRowHeight, CStr(nDay)
End If 'current day
'increment the day number
nDay = nDay + 1
Next nCol
Next nRow
'blast the control to the screen
dcWork.BlastToScreen
'if the dummy control has focus, and we are in run-mode,
'draw a focus rect around the current focus area
If UserControl.ActiveControl Is ctlFocus Then
DrawFocusRect UserControl.hdc, mrcFocusArea
End If
'restore the initial settings for bold and italic
'in our day font
mfntDayFont.Bold = fDefBold
mfntDayFont.Italic = fDefItalic
Exit Sub
Err_Paint:
Debug.Assert False
Exit Sub
End Sub 'UserControl_Paint()
'----------------------------------------------------------------------
' Resize Event
'----------------------------------------------------------------------
' Purpose: Called when the control is resized by the developer
' Inputs: None
' Outputs: None
'----------------------------------------------------------------------
Private Sub UserControl_Resize()
Dim nNewWidth As Long 'new scale width
Dim nNewHeight As Long 'new scale height
Dim nUsableWidth As Long 'actual width we can use
On Error GoTo Err_Resize
nNewWidth = UserControl.ScaleWidth
nNewHeight = UserControl.ScaleHeight
'since all the grid cells need to be the same width
'the usable width is the width we will consume and there
'maybe unused pixels due to left-overs from division
nUsableWidth = ((nNewWidth - (2 * mrcCalArea.Left)) \ NUMCOLS) * NUMCOLS
'recalculate the bounding rectangles for the various areas
'of the control (navigation, day names, and calendar days)
mrcNavArea.Right = mrcNavArea.Left + nUsableWidth
mrcDayNameArea.Right = mrcDayNameArea.Left + nUsableWidth
mrcCalArea.Right = mrcCalArea.Left + nUsableWidth
mrcCalArea.Bottom = nNewHeight
'Recalculate the width and heights of the grid rows and columns
mcxColWidth = (nNewWidth - (2 * mrcCalArea.Left)) \ NUMCOLS
mcyRowHeight = (mrcCalArea.Bottom - mrcCalArea.Top) \ NUMROWS
'resize the month and year selection controls
btnNext.Left = mrcNavArea.Right - btnNext.Width
'if there's not enough room, just display the buttons
If (mrcNavArea.Right - mrcNavArea.Left) <= _
(btnNext.Width + btnPrev.Width + txtYear.Width + 10) _
And mfShowIterrators Then
cbxMonth.Visible = False
txtYear.Visible = False
Else
If Not mfMonthReadOnly Then cbxMonth.Visible = True
If Not mfYearReadOnly Then txtYear.Visible = True
If mfShowIterrators Then
cbxMonth.Left = mrcNavArea.Left + btnPrev.Width + BORDER3D
txtYear.Left = btnNext.Left - txtYear.Width - BORDER3D
Else
cbxMonth.Left = mrcNavArea.Left + BORDER3D
txtYear.Left = mrcNavArea.Right - txtYear.Width - BORDER3D
End If
cbxMonth.Width = txtYear.Left - cbxMonth.Left
End If 'not enough horizontal room
Exit Sub
Err_Resize:
Debug.Assert False
Exit Sub
End Sub 'UserControl_Resize()
'----------------------------------------------------------------------
' MouseDown Event
'----------------------------------------------------------------------
' Purpose: Called when the mouse button is pushed down while over
' the control's area
' Inputs: Which mouse button, shift state and x and y position
' Outputs: None
'----------------------------------------------------------------------
Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim Area As CalendarAreas
Dim dtOld As Date
Dim dtNew As Date
On Error GoTo Err_MouseDown
'keep the old date to see if it's changed
dtOld = Me.Value
'Do a hit test to determine where the user clicked
Me.HitTest X, Y, Area, dtNew
'if the area was in the date area and the control is not locked,
'switch to the hit date
If (Area = calDateArea) And (Not mfLocked) Then
If dtNew <> dtOld Then
ChangeValue VBA.Day(dtNew), VBA.Month(dtNew), VBA.Year(dtNew)
End If 'date did change
End If 'clicked in date area
'grab focus back if needed
If Not (UserControl.ActiveControl Is ctlFocus) Then
ctlFocus.SetFocus
End If
Exit Sub
Err_MouseDown:
Debug.Assert False
Exit Sub
End Sub 'UserControl_MouseDown()
'----------------------------------------------------------------------
' DblClick Event
'----------------------------------------------------------------------
' Purpose: Called when the user double-clicks on the main control area
' Inputs: None
' Outputs: None
'----------------------------------------------------------------------
Private Sub UserControl_DblClick()
On Error GoTo Err_DblClick
'pass this event to the host
RaiseEvent DblClick
Exit Sub
Err_DblClick:
Exit Sub
End Sub 'UserControl_DblClick()
'----------------------------------------------------------------------
' Click Event
'----------------------------------------------------------------------
' Purpose: Called when the user clicks on the main control area
' Inputs: None
' Outputs: None
'----------------------------------------------------------------------
Private Sub UserControl_Click()
On Error GoTo Err_Click
'raise our click event to the user
RaiseEvent Click
Exit Sub
Err_Click:
Exit Sub
End Sub 'UserControl_Click()
'----------------------------------------------------------------------
' ctlFocus_GotFocus Event
'----------------------------------------------------------------------
' Purpose: Called when the main calendar area is to get focus.
' We use a dummy control to capture focus since we are
' just painting the calendar days and cannot set focus
' to the entire user control.
' Inputs: None
' Outputs: None
'----------------------------------------------------------------------
Private Sub ctlFocus_GotFocus()
'draw a focus rect to signify that the calendar
'area now has focus
DrawFocusRect UserControl.hdc, mrcFocusArea
End Sub 'ctlFocus_GotFocus()
'----------------------------------------------------------------------
' ctlFocus_LostFocus Event
'----------------------------------------------------------------------
' Purpose: Called when the main calendar area has lost focus.
' We use a dummy control to capture focus since we are
' just painting the calendar days and cannot set focus
' to the entire user control.
' Inputs: None
' Outputs: None
'----------------------------------------------------------------------
Private Sub ctlFocus_LostFocus()
'draw a focus rect where the last focus area was
'drawing a focus rect twice removes it
DrawFocusRect UserControl.hdc, mrcFocusArea
End Sub 'ctlFocus_LostFocus()
'----------------------------------------------------------------------
' ctlFocus_KeyDown Event
'----------------------------------------------------------------------
' Purpose: Called when the user presses a key while the dummy control
' has focus
' Inputs: Which key, shift state
' Outputs: None
'----------------------------------------------------------------------
Private Sub ctlFocus_KeyDown(KeyCode As Integer, Shift As Integer)
Dim dtTemp As Date 'temp date for date arithmetic
Select Case KeyCode
Case vbKeyLeft
dtTemp = DateSerial(mnYear, mnMonth, mnDay)
'if shift is down, move by month
If (Shift And vbShiftMask) > 0 Then
dtTemp = DateAdd("m", -1, dtTemp)
ElseIf (Shift And vbCtrlMask) > 0 Then
'else if control is down, move by year
dtTemp = DateAdd("yyyy", -1, dtTemp)
Else
'go back on day
dtTemp = DateAdd("d", -1, dtTemp)
End If
ChangeValue VBA.Day(dtTemp), VBA.Month(dtTemp), _
VBA.Year(dtTemp)
Case vbKeyRight
dtTemp = DateSerial(mnYear, mnMonth, mnDay)
If (Shift And vbShiftMask) > 0 Then
dtTemp = DateAdd("m", 1, dtTemp)
ElseIf (Shift And vbCtrlMask) > 0 Then
'else if control is down, move by year
dtTemp = DateAdd("yyyy", 1, dtTemp)
Else
'go forward one day
dtTemp = DateAdd("d", 1, dtTemp)
End If
ChangeValue VBA.Day(dtTemp), VBA.Month(dtTemp), _
VBA.Year(dtTemp)
Case vbKeyUp
'go one week back
dtTemp = DateSerial(mnYear, mnMonth, mnDay)
dtTemp = DateAdd("ww", -1, dtTemp)
ChangeValue VBA.Day(dtTemp), VBA.Month(dtTemp), _
VBA.Year(dtTemp)
Case vbKeyDown
'go one week forwad
dtTemp = DateSerial(mnYear, mnMonth, mnDay)
dtTemp = DateAdd("ww", 1, dtTemp)
ChangeValue VBA.Day(dtTemp), VBA.Month(dtTemp), _
VBA.Year(dtTemp)
Case vbKeyHome
'if control is down, go to first day of the year
If (Shift And vbCtrlMask) > 0 Then
ChangeValue 1, 1, mnYear
Else
'go to the first day of the current month
ChangeValue 1, mnMonth, mnYear
End If
Case vbKeyEnd
'if control is down, go to last day of the year
If (Shift And vbCtrlMask) > 0 Then
ChangeValue 31, 12, mnYear
Else
'go to the last day of the current month
ChangeValue MaxDayInMonth(mnMonth, mnYear), _
mnMonth, mnYear
End If
End Select
End Sub 'ctlFocus_KeyDown()
'----------------------------------------------------------------------
' cbxMonth_Click Event
'----------------------------------------------------------------------
' Purpose: Called when the user changes the item selected in the moth
' navigation combo box
' Inputs: none
' Outputs: None
'----------------------------------------------------------------------
Private Sub cbxMonth_Click()
If mfIgnoreMonthYearChange Then Exit Sub
'if we are locked, just reset the list index
'to the current month
If mfLocked Then
mfIgnoreMonthYearChange = True
cbxMonth.ListIndex = mnMonth - 1
mfIgnoreMonthYearChange = False
End If
'change the date
ChangeValue mnDay, cbxMonth.ListIndex + 1, mnYear
RaiseEvent Click
End Sub 'cbxMonth_Click()
'----------------------------------------------------------------------
' txtYear_KeyPress Event
'----------------------------------------------------------------------
' Purpose: Called when the user presses a key in the year
' navigation text box
' Inputs: Key Pressed
' Outputs: None
'----------------------------------------------------------------------
Private Sub txtYear_KeyPress(KeyAscii As Integer)
If mfIgnoreMonthYearChange Then Exit Sub
'if they pressed return, process the date change
If KeyAscii = vbKeyReturn Then
'change the date
ChangeValue mnDay, mnMonth, Val(txtYear)
KeyAscii = 0
End If
End Sub 'txtYear_KeyPress
'----------------------------------------------------------------------
' txtYear_Click Event
'----------------------------------------------------------------------
' Purpose: Called when the user clicks the year
' navigation text box
' Inputs: None
' Outputs: None
'----------------------------------------------------------------------
Private Sub txtYear_Click()
RaiseEvent Click
End Sub 'txtYear_Click()
'----------------------------------------------------------------------
' txtYear_GotFocus Event
'----------------------------------------------------------------------
' Purpose: Called when the user moved into the year text box
' Inputs: None
' Outputs: None
'----------------------------------------------------------------------
Private Sub txtYear_GotFocus()
'select all the text that is there
txtYear.SelStart = 0
txtYear.SelLength = Len(txtYear.Text)
End Sub
'----------------------------------------------------------------------
' txtYear_LostFocus Event
'----------------------------------------------------------------------
' Purpose: Called when the user moved out of the year text box
' Inputs: None
' Outputs: None
'----------------------------------------------------------------------
Private Sub txtYear_LostFocus()
If mnYear <> Val(txtYear.Text) Then
ChangeValue mnDay, mnMonth, Val(txtYear.Text)
End If
End Sub 'txtYear_LostFocus()
'----------------------------------------------------------------------
' btnNext_Click Event
'----------------------------------------------------------------------
' Purpose: Called when the user clicks the next month button
' Inputs: none
' Outputs: None
'----------------------------------------------------------------------
Private Sub btnNext_Click()
Dim dtTemp As Date
dtTemp = DateSerial(mnYear, mnMonth, mnDay)
dtTemp = DateAdd("m", 1, dtTemp)
ChangeValue VBA.Day(dtTemp), VBA.Month(dtTemp), VBA.Year(dtTemp)
ctlFocus.SetFocus
RaiseEvent Click
End Sub 'btnNext_Click()
'----------------------------------------------------------------------
' btnPrev_Click Event
'----------------------------------------------------------------------
' Purpose: Called when the user clicks the previous month button
' Inputs: none
' Outputs: None
'----------------------------------------------------------------------
Private Sub btnPrev_Click()
Dim dtTemp As Date
dtTemp = DateSerial(mnYear, mnMonth, mnDay)
dtTemp = DateAdd("m", -1, dtTemp)
ChangeValue VBA.Day(dtTemp), VBA.Month(dtTemp), VBA.Year(dtTemp)
ctlFocus.SetFocus
RaiseEvent Click
End Sub 'btnPrev_Click()
'======================================================================
' Private Helper Methods
'======================================================================
'----------------------------------------------------------------------
' PaintDayNames()
'----------------------------------------------------------------------
' Purpose: Paints names of the week days above the main date grid
' Inputs: reference to the offscreen dc object
' Outputs: none
'----------------------------------------------------------------------
Private Sub PaintDayNames(dc As OffScreenDC)
Dim rc As RECT
Dim nCol As Long
Dim fntOld As StdFont
Dim idx As Long
'make a copy of the day name area rect
rc.Left = mrcDayNameArea.Left
rc.Top = mrcDayNameArea.Top
rc.Right = mrcDayNameArea.Right
rc.Bottom = mrcDayNameArea.Bottom
'set the current font to use
Set fntOld = dc.Font
Set dc.Font = mfntDayNames
'fill a black rect as a border
dc.FillRect rc.Left, rc.Top, rc.Right - rc.Left, _
rc.Bottom - rc.Top, vbBlack
'now draw 3d rects for each day name
rc.Top = rc.Top + 1
rc.Bottom = rc.Bottom - 1
'initialize idx to be the setting for first day of week
'and if that setting is "use system", determine what the
'system is using
If mnFirstDayOfWeek = vbUseSystemDayOfWeek Then
'8/4/96 is a Sunday, so if the system says the day
'of week is other than 1, we'll figure that out
idx = WeekDay(DateSerial(1996, 8, 4), mnFirstDayOfWeek)
Else
idx = mnFirstDayOfWeek
End If 'first day of week was "use system"
For nCol = 0 To NUMCOLS - 1
dc.Draw3DRect (nCol * mcxColWidth) + rc.Left, rc.Top, mcxColWidth, _
rc.Bottom - rc.Top, masDayNames(idx - 1)
'increment the indexer and if it's past the end
'wrap it back around to zero
idx = idx + 1
If idx > NUMCOLS Then idx = 1
Next nCol
'reset the old font
Set dc.Font = fntOld
End Sub 'PaintDayNames()
'----------------------------------------------------------------------
' FastRepaint()
'----------------------------------------------------------------------
' Purpose: Fast repaint routine for painting when only the day number
' changes and not the month or year.
' Inputs: work off screen DC
' Outputs: none
'----------------------------------------------------------------------
Private Sub FastRepaint(dcWork As OffScreenDC)
Dim nLeft As Long
Dim nTop As Long
Dim rgbColor As Long
Dim ct As Long
Dim eAppearance As Appearances
Dim fDefBold As Boolean
Dim fDefItalic As Boolean
'save the initial states of bold and italic in our day font
fDefBold = mfntDayFont.Bold
fDefItalic = mfntDayFont.Italic
'set the font as the day font and the text
'color as black
Set dcWork.Font = mfntDayFont
OleTranslateColor mclrDay, 0, rgbColor
dcWork.TextColor = rgbColor
For ct = 0 To 1
If mafDayBold(maRepaintDays(ct)) = calEffectDefault Then
'optimize for the case where no days are bold
If mfntDayFont.Bold <> fDefBold Then
mfntDayFont.Bold = fDefBold
Set dcWork.Font = mfntDayFont
End If
Else
mfntDayFont.Bold = (mafDayBold(maRepaintDays(ct)) = calEffectOn)
Set dcWork.Font = mfntDayFont
End If 'DayBold setting is default
If mafDayItalic(maRepaintDays(ct)) = calEffectDefault Then
'optimize for the case where no days are italic
If mfntDayFont.Italic <> fDefItalic Then
mfntDayFont.Italic = fDefItalic
Set dcWork.Font = mfntDayFont
End If
Else
mfntDayFont.Italic = (mafDayItalic(maRepaintDays(ct)) = calEffectOn)
Set dcWork.Font = mfntDayFont
End If
'repaint the old day as normal
nLeft = LeftForDay(maRepaintDays(ct))
nTop = TopForDay(maRepaintDays(ct))
If ct = 0 Then
eAppearance = Raised
Else
eAppearance = Selected
End If
dcWork.Draw3DRect nLeft, nTop, _
mcxColWidth, mcyRowHeight, _
CStr(maRepaintDays(ct)), _
caCenterCenter, eAppearance
'blast just this day to the screen
dcWork.BlastToScreen nLeft, nTop, mcxColWidth, mcyRowHeight
Next ct
' 'repaint the newly selected day as selected
' nLeft = LeftForDay(maRepaintDays(1))
' nTop = TopForDay(maRepaintDays(1))
' dcWork.Draw3DRect nLeft, nTop, _
' mcxColWidth, mcyRowHeight, _
' CStr(maRepaintDays(1)), _
' caCenterCenter, Selected
'
' 'blast just this day to the screen
' dcWork.BlastToScreen nLeft, nTop, mcxColWidth, mcyRowHeight
'draw the focus rect on the selected day if
'the dummy focus control has focus
If UserControl.ActiveControl Is ctlFocus Then
DrawFocusRect UserControl.hdc, mrcFocusArea
End If
'restore the initial states of bold and italic in our day font
mfntDayFont.Bold = fDefBold
mfntDayFont.Italic = fDefItalic
'reset the fast repaint flag to False
mfFastRepaint = False
End Sub 'FastRepaint()
'----------------------------------------------------------------------
' MaxDayInMonth()
'----------------------------------------------------------------------
' Purpose: Returns the max day number for a given month number and year
' Inputs: month number
' Outputs: max day number
'----------------------------------------------------------------------
Private Function MaxDayInMonth(nMonth As Long, Optional nYear As Long = 0) As Long
Select Case nMonth
Case 9, 4, 6, 11 '30 days hath September,
'April, June, and November
MaxDayInMonth = 30
Case 2 'February -- check for leapyear
'The full rule for leap years is that they occur in
'every year divisible by four, except that they don't
'occur in years divisible by 100, except that they
'*do* in years divisible by 400.
If (nYear Mod 4) = 0 Then
If nYear Mod 100 = 0 Then
If nYear Mod 400 = 0 Then
MaxDayInMonth = 29
Else
MaxDayInMonth = 28
End If 'divisible by 400
Else
MaxDayInMonth = 29
End If 'divisible by 100
Else
MaxDayInMonth = 28
End If 'divisible by 4
Case Else 'All the rest have 31
MaxDayInMonth = 31
End Select
End Function 'MaxDayInMonth()
'----------------------------------------------------------------------
' ChangeValue()
'----------------------------------------------------------------------
' Purpose: Changes the control's current value, checking if it's OK
' and doing the necessary notifications that it's changed
' Inputs: new day, month and year
' Outputs: none
'----------------------------------------------------------------------
Private Sub ChangeValue(nDay As Long, nMonth As Long, nYear As Long)
Dim rc As RECT 'used to invalidate smaller rects
'if only the day number changed
Dim fCancel As Boolean 'used in the WillChangeDate event
Dim dtOld As Date 'old date for raising in event
'give the developer a chance to cancel the date change
fCancel = False
RaiseEvent WillChangeDate(DateSerial(nYear, nMonth, nDay), fCancel)
If fCancel Then Exit Sub
'build a date using the current values
dtOld = DateSerial(mnYear, mnMonth, mnDay)
'check to see if it's OK to change the value
If UserControl.CanPropertyChange("Value") Then
'changing the month or year can make the day number
'invalid, so check the new combination and adjust the day
'if necessary.
If nDay > MaxDayInMonth(nMonth, nYear) Then
nDay = MaxDayInMonth(nMonth, nYear)
End If
'to avoid unecessary repainting, if only the day number changed
'just invalidate the two rects where the old and new dates are
If mnMonth = nMonth And mnYear = nYear Then
'setup a rect for the old day
rc.Left = LeftForDay(mnDay)
rc.Top = TopForDay(mnDay)
rc.Right = rc.Left + mcxColWidth
rc.Bottom = rc.Top + mcyRowHeight
'invalidate it
InvalidateRect UserControl.hwnd, rc, 0
'setup a rect for the new day
rc.Left = LeftForDay(nDay)
rc.Top = TopForDay(nDay)
rc.Right = rc.Left + mcxColWidth
rc.Bottom = rc.Top + mcyRowHeight
'invalidate it
InvalidateRect UserControl.hwnd, rc, 0
'since we are only changing the current day
'and not the current month or year, store off
'the specific days to repaint and set the
'fast repaint flag to true. This will cause the
'paint routing to just repaint these two days
'which makes the repaint considerably faster.
'The fast repaint is reset to False automatically.
maRepaintDays(0) = mnDay
maRepaintDays(1) = nDay
mfFastRepaint = True
'change the value and notify those interested
mnDay = nDay
Else
'reset the month and year navigators if they need to be
mfIgnoreMonthYearChange = True
If cbxMonth.ListIndex <> (nMonth - 1) Then cbxMonth.ListIndex = (nMonth - 1)
If Val(txtYear.Text) <> nYear Then txtYear.Text = nYear
mfIgnoreMonthYearChange = False
'change the value and notify those interested
mnDay = nDay
mnMonth = nMonth
mnYear = nYear
'refresh the entire calendar area since we have to
're-layout the days
InvalidateRect UserControl.hwnd, mrcCalArea, 0
End If 'just changing the day
'update the new focus area based on the new day selected
mrcFocusArea.Left = LeftForDay(mnDay) + FOCUSBORDER
mrcFocusArea.Top = TopForDay(mnDay) + FOCUSBORDER
mrcFocusArea.Right = mrcFocusArea.Left + mcxColWidth - (2 * FOCUSBORDER)
mrcFocusArea.Bottom = mrcFocusArea.Top + mcyRowHeight - (2 * FOCUSBORDER)
'update the window (usercontrol.refresh will invalidate
'everything so call UpdateWindow directly)
UpdateWindow UserControl.hwnd
'notify of the date change
UserControl.PropertyChanged "Value"
RaiseEvent DateChange(dtOld, DateSerial(mnYear, mnMonth, mnDay))
Else 'can't change prop
mobjRes.RaiseUserError errCantChange, Array("Value")
End If 'can change prop
End Sub 'ChangeValue()
'----------------------------------------------------------------------
' LeftForDay()
'----------------------------------------------------------------------
' Purpose: Returns the left (X) coodinate for a given day in the
' current month and year
' Inputs: day number
' Outputs: left coordinate
'----------------------------------------------------------------------
Private Function LeftForDay(nDay As Long) As Long
'the left coordinate for a given day is a function of the
'weekday (column number) of the day, the column width and
'the grid's left border
LeftForDay = ((WeekDay(DateSerial(mnYear, mnMonth, nDay), mnFirstDayOfWeek) - 1) _
* mcxColWidth) + mrcCalArea.Left
End Function 'LeftForDay()
'----------------------------------------------------------------------
' TopForDay()
'----------------------------------------------------------------------
' Purpose: Returns the top (Y) coodinate for a given day in the
' current month and year
' Inputs: day number
' Outputs: top coordinate
'----------------------------------------------------------------------
Private Function TopForDay(nDay As Long) As Long
Dim nRow As Long
'the top coordinate for a given day is a function of the
'row number of the day (day + column number of first day of month
'divided by number of columns), the row height, and the top of the
'entire grid
'we subtract 2 from the left side of the division since the
'weekday function is 1-based and since we need to subtract an
'additional one to make zero-base the day
nRow = (nDay + WeekDay(DateSerial(mnYear, mnMonth, 1), mnFirstDayOfWeek) - 2) \ NUMCOLS
TopForDay = (nRow * mcyRowHeight) + mrcCalArea.Top
End Function 'TopForDay()
'----------------------------------------------------------------------
' DateForRowCol()
'----------------------------------------------------------------------
' Purpose: Returns the Date for a given row and column in the
' current calendar grid
' Inputs: row and column number (zero-based)
' Outputs: corresponding date
'----------------------------------------------------------------------
Private Function DateForRowCol(nRow As Long, nCol As Long) As Date
Dim dtFirstDay As Date
Dim nColFirstDay As Long
Dim ctDaysDiff As Long
Debug.Assert (nRow < NUMROWS)
Debug.Assert (nCol < NUMCOLS)
'get the column for the first day of the current month
'first day is always in row 1
dtFirstDay = DateSerial(mnYear, mnMonth, 1)
nColFirstDay = WeekDay(dtFirstDay, mnFirstDayOfWeek) - 1
'how many days away is the current row and column?
ctDaysDiff = (nCol - nColFirstDay) + (NUMDAYS * nRow)
'calc the hit date by using date arithmetic
DateForRowCol = DateAdd("d", ctDaysDiff, dtFirstDay)
End Function 'DateForRowCol()
'----------------------------------------------------------------------
' GetPrevMonthDays()
'----------------------------------------------------------------------
' Purpose: Calculates the first and last day of the previous month
' that should be displayed before the first day of the
' of the given month and year
' Inputs: current month and year
' Outputs: first and last day of prev month to display
'----------------------------------------------------------------------
Private Sub GetPrevMonthDays(ByVal nCurMonth As Long, ByVal nCurYear As Long, nFirst As Long, nLast As Long)
Dim dtTemp As Date 'temp date
Dim nColDayOne As Long 'column of 1st day of cur month
'construct a date to do date math
dtTemp = DateSerial(nCurYear, nCurMonth, 1)
'determine the column of the first day of the current month
nColDayOne = WeekDay(dtTemp, mnFirstDayOfWeek)
'if the first day of the current month is in column 1, we
'don't need to paint any days from the prev month, so return
'zeros and -1 for the first and last value
If nColDayOne = 1 Then
nFirst = 0
nLast = -1
Else
'if there are days to paint, calculate the last and
'first day using date math
dtTemp = DateAdd("d", -1, dtTemp)
nLast = VBA.Day(dtTemp)
dtTemp = DateAdd("d", -(nColDayOne - 2), dtTemp)
nFirst = VBA.Day(dtTemp)
End If 'no days to paint
End Sub 'GetPrevMonthDays()
'----------------------------------------------------------------------
' LoadMonthNames()
'----------------------------------------------------------------------
' Purpose: Loads the names of the months into the month selector
' combo box
' Inputs: none
' Outputs: none
'----------------------------------------------------------------------
Private Sub LoadMonthNames()
Dim nMonth As Long
'use the format function to return the system specified
'long month name for each month
For nMonth = 1 To 12
masMonthNames(nMonth - 1) = Format(DateSerial(100, nMonth, 1), "mmmm")
cbxMonth.AddItem masMonthNames(nMonth - 1)
Next nMonth
End Sub 'LoadMonthNames()
'----------------------------------------------------------------------
' LoadDayNames()
'----------------------------------------------------------------------
' Purpose: Loads the names of the days into the day name string array
' Inputs: none
' Outputs: none
'----------------------------------------------------------------------
Private Sub LoadDayNames()
Dim nDay As Long
Dim sFormat As String
Select Case mnDayNameFormat
Case calShortName, calMediumName
sFormat = "ddd"
Case calLongName
sFormat = "dddd"
End Select
For nDay = 1 To 7
'if they want the short format, just take the first char
If mnDayNameFormat = calShortName Then
masDayNames(nDay - 1) = Left$(Format(DateSerial(1996, 8, 3 + nDay), sFormat), 1)
Else
masDayNames(nDay - 1) = Format(DateSerial(1996, 8, 3 + nDay), sFormat)
End If
Next nDay
End Sub 'LoadDayNames()
'----------------------------------------------------------------------
' CopyFont
'----------------------------------------------------------------------
' Purpose: Copies the contents of one StdFont object to another
' Inputs: source and destination StdFont object
' Outputs: none
'----------------------------------------------------------------------
Private Sub CopyFont(fntSource As StdFont, fntDest As StdFont)
'daveste -- 8/14/96
'REVIEW: Is there a better way to do this???!!!
'if the destination is nothing, create a new font object
If fntDest Is Nothing Then Set fntDest = New StdFont
fntDest.Bold = fntSource.Bold
fntDest.Charset = fntSource.Charset
fntDest.Italic = fntSource.Italic
fntDest.Name = fntSource.Name
fntDest.Size = fntSource.Size
fntDest.Strikethrough = fntSource.Strikethrough
fntDest.Underline = fntSource.Underline
fntDest.Weight = fntSource.Weight
End Sub 'CopyFont()