VBCommons/ui/Calendar/CSE_Calendar.frm

484 lines
13 KiB
Plaintext
Raw Normal View History

2024-06-07 20:46:40 +03:00
VERSION 5.00
Begin {C62A69F0-16DC-11CE-9E98-00AA00574A4F} CSE_Calendar
Caption = "Calendar"
ClientHeight = 4455
ClientLeft = 30
ClientTop = 390
ClientWidth = 4440
OleObjectBlob = "CSE_Calendar.frx":0000
StartUpPosition = 2 'CenterScreen
End
Attribute VB_Name = "CSE_Calendar"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
' =========== Calendar picker native VBA ================
' Shared module version: 20210502
' Dependencies: z_CalendarUI, CSE_CallbackCalendar
Option Explicit
Private Const GWL_STYLE = -16
Private Const WS_CAPTION = &HC00000
Private Const MOUSE_LEFT_BTN = 1
Private Const CALENDAR_DAYS_COUNT = 42
Private Const CALENDAR_WEEKDAY_COUNT = 7
Private Const CALENDAR_MONTH_COUNT = 12
Private Const CALENDAR_YEARS_PER_PAGE = 12
Private Type CalendarThemeColors
background_ As Long
foreground_ As Long
curDateBG_ As Long
curDateFG_ As Long
inactiveDates_ As Long
End Type
Private Enum CalendarMode
CAL_MODE_DAY = 0
CAL_MODE_MONTH = 1
CAL_MODE_YEAR = 2
End Enum
Private Declare PtrSafe Function FindWindow Lib "user32" _
Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function GetWindowLong Lib "user32" _
Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Declare PtrSafe Function SetWindowLong Lib "user32" _
Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare PtrSafe Function DrawMenuBar Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Public isCancelled_ As Boolean
Private curDate_ As Long
Private month_ As Long
Private year_ As Long
Private mode_ As CalendarMode
Private theme_ As TCalendarTheme
Private colors_ As CalendarThemeColors
Private firstYear_ As Long
Private lastYear_ As Long
Private xPos_ As Double
Private yPos_ As Double
Private callbacks_ As Collection
Private Sub UserForm_Initialize()
Call ResetBorders
Call HideTitleBar
Call InitLabelCallbacks
isCancelled_ = True
mode_ = CAL_MODE_DAY
Call PositionInMiddle
Call SetCurrentDateInternal(Int(Now))
Call SetTheme(T_CT_LIGHT)
End Sub
Public Function Init(theDate&, aTheme As TCalendarTheme)
isCancelled_ = True
Call SetCurrentDateInternal(theDate)
Call ChangeMode(CAL_MODE_DAY)
Call UpdateTitle
Call SetTheme(aTheme)
Call ResetBorders
End Function
Public Property Get SelectedDate() As Long
SelectedDate = curDate_
End Property
Public Property Get Theme() As TCalendarTheme
Theme = theme_
End Property
Public Function SetTheme(newValue As TCalendarTheme)
theme_ = newValue
Call UpdateThemeColors
Call RepaintAllColors
End Function
' ==== Events handlings ======
Public Function OnDayClicked(cLabel As MSForms.Label)
Call ReturnResult(cLabel.Tag)
End Function
Public Function OnMonthClicked(cLabel As MSForms.Label)
month_ = TagToMonth(cLabel.Caption)
Call ChangeMode(CAL_MODE_DAY)
End Function
Public Function OnYearClicked(cLabel As MSForms.Label)
If Len(Trim(cLabel.Caption)) = 0 Then _
Exit Function
year_ = val(cLabel.Caption)
Call ChangeMode(CAL_MODE_MONTH)
End Function
Private Sub lblToday_Click()
If mode_ <> CAL_MODE_DAY Then
Call SetCurrentDateInternal(Int(Now))
Call ChangeMode(CAL_MODE_DAY)
Else
Call ReturnResult(Int(Now))
End If
End Sub
Private Sub lblThemes_Click()
If theme_ < TCalendarTheme.[_Last] Then
Call SetTheme(theme_ + 1)
Else
Call SetTheme(TCalendarTheme.[_First])
End If
End Sub
Private Sub lblUnload_Click()
isCancelled_ = True
Call Me.Hide
End Sub
Private Sub btnClose_Click()
If mode_ <> CAL_MODE_DAY Then
Call ChangeMode(mode_ - 1)
Else
isCancelled_ = True
Call Me.Hide
End If
End Sub
Private Sub lblUP_Click()
Select Case mode_
Case CAL_MODE_DAY
Call IncrementMonth(-1)
Case CAL_MODE_MONTH
Case CAL_MODE_YEAR
lastYear_ = firstYear_ - 1
firstYear_ = firstYear_ - CALENDAR_YEARS_PER_PAGE
Call RepaintYearsColor
End Select
End Sub
Private Sub lblDOWN_Click()
Select Case mode_
Case CAL_MODE_DAY
Call IncrementMonth(1)
Case CAL_MODE_MONTH
Case CAL_MODE_YEAR
firstYear_ = lastYear_ + 1
lastYear_ = lastYear_ + CALENDAR_YEARS_PER_PAGE
Call RepaintYearsColor
End Select
End Sub
Private Sub UserForm_MouseDown(ByVal nBtn As Integer, ByVal nShift As Integer, ByVal mvX As Single, ByVal mvY As Single)
If nBtn = MOUSE_LEFT_BTN Then
xPos_ = mvX
yPos_ = mvY
End If
End Sub
Private Sub UserForm_MouseMove(ByVal nBtn As Integer, ByVal nShift As Integer, ByVal mvX As Single, ByVal mvY As Single)
If nBtn And MOUSE_LEFT_BTN Then
Me.Left = Me.Left + (mvX - xPos_)
Me.Top = Me.Top + (mvY - yPos_)
End If
End Sub
Private Sub Frame1_MouseDown(ByVal nBtn As Integer, ByVal nShift As Integer, ByVal mvX As Single, ByVal mvY As Single)
If nBtn = MOUSE_LEFT_BTN Then
xPos_ = mvX
yPos_ = mvY
End If
End Sub
Private Sub lblTitleCurMY_Click()
'--> Handles the month to year multipage display
If mode_ = CAL_MODE_YEAR Then _
Exit Sub
Call ChangeMode(mode_ + 1)
End Sub
' =========
Private Function ReturnResult(theDate&)
curDate_ = theDate
isCancelled_ = False
Call Me.Hide
End Function
Private Function PositionInMiddle()
Dim nTopOffset&: nTopOffset = (Application.UsableHeight / 2) - (Me.Height / 2)
Dim nLeftOffset&: nLeftOffset = (Application.UsableWidth / 2) - (Me.Width / 2)
Me.StartUpPosition = 0
Me.Top = Application.Top + IIf(nTopOffset > 0, nTopOffset, 0)
Me.Left = Application.Left + IIf(nLeftOffset > 0, nLeftOffset, 0)
End Function
Private Function HideTitleBar()
Dim frameHandle As Long: frameHandle = FindWindow(vbNullString, Me.Caption)
Dim windowHandle As Long: windowHandle = GetWindowLong(frameHandle, GWL_STYLE)
windowHandle = windowHandle And (Not WS_CAPTION)
Call SetWindowLong(frameHandle, GWL_STYLE, windowHandle)
Call DrawMenuBar(frameHandle)
End Function
Private Function ResetBorders()
Dim aLabel As control
For Each aLabel In Me.Controls
If TypeOf aLabel Is MSForms.Label Then _
aLabel.BorderStyle = fmBorderStyleNone
Next
End Function
Private Function InitLabelCallbacks()
Dim aControl As control
Dim controlType$
Set callbacks_ = New Collection
For Each aControl In Me.Controls
If Not TypeOf aControl Is MSForms.Label Then _
GoTo NEXT_CONTROL
controlType = Left(aControl.Name, 1)
If Not controlType Like "[DMY]" Then _
GoTo NEXT_CONTROL
Call AddCallback(aControl)
NEXT_CONTROL:
Next aControl
Call AddCallback(lblUP)
Call AddCallback(lblDOWN)
Call AddCallback(lblThemes)
Call AddCallback(lblUnload)
Call AddCallback(lblTitleCurMY, bUnderline:=True)
Call AddCallback(lblToday, bUnderline:=True)
End Function
Private Function AddCallback(target As control, Optional bUnderline As Boolean = False)
Dim newCallback As New CSE_CallbackCalendar
Call newCallback.Init(target, bUnderline)
Call callbacks_.Add(newCallback)
End Function
Private Function SetCurrentDateInternal(theDate&)
curDate_ = theDate
month_ = Month(curDate_)
year_ = Year(curDate_)
Call UpdateDays
End Function
Private Function IncrementMonth(inc&)
year_ = year_ + ((month_ + inc + CALENDAR_MONTH_COUNT - 1) \ CALENDAR_MONTH_COUNT - 1)
month_ = 1 + ((CALENDAR_MONTH_COUNT + (month_ + inc - 1) Mod CALENDAR_MONTH_COUNT) Mod CALENDAR_MONTH_COUNT)
Call UpdateTitle
Call UpdateDays
End Function
Private Function ChangeMode(newMode As CalendarMode)
If newMode = mode_ Then _
Exit Function
Me.MPmainDisplay.Value = newMode
Call SetArrowsVisibility(newMode <> CAL_MODE_MONTH)
mode_ = newMode
Select Case mode_
Case CAL_MODE_DAY
Call UpdateDays
Case CAL_MODE_MONTH
Call RepaintMonthsColors
Case CAL_MODE_YEAR
lastYear_ = year_ + 1
firstYear_ = lastYear_ - CALENDAR_YEARS_PER_PAGE + 1
Call RepaintYearsColor
End Select
Call UpdateTitle
End Function
Private Function UpdateDays()
'--> Populate the calendar
Dim firstDay&: firstDay = DateSerial(year_, month_, 1)
firstDay = firstDay - Weekday(firstDay, vbMonday) + 1
Dim lastDay&: lastDay = firstDay + CALENDAR_DAYS_COUNT - 1
Dim nItem&
For nItem = 1 To CALENDAR_DAYS_COUNT
With Me.Controls("D" & nItem)
.Caption = Day(firstDay + nItem - 1)
.Tag = firstDay + nItem - 1
End With
Next nItem
Call RepaintDaysColors
End Function
Private Function UpdateTitle()
Select Case mode_
Case CAL_MODE_DAY
lblTitleCurMY.Caption = Format(DateSerial(year_, month_, 1), "MMMM yyyy")
Case CAL_MODE_MONTH
lblTitleCurMY.Caption = year_
Case CAL_MODE_YEAR
lblTitleCurMY.Caption = firstYear_ & " - " & lastYear_
End Select
End Function
Private Function UpdateThemeColors()
With colors_
Select Case theme_
Case TCalendarTheme.T_CT_DARK
.background_ = RGB(69, 69, 69)
.foreground_ = RGB(252, 248, 248)
.curDateBG_ = RGB(246, 127, 8)
.curDateFG_ = RGB(0, 0, 0)
.inactiveDates_ = RGB(120, 120, 120)
Case TCalendarTheme.T_CT_RED
.background_ = RGB(87, 0, 0)
.foreground_ = RGB(203, 146, 146)
.curDateBG_ = RGB(122, 185, 247)
.curDateFG_ = RGB(0, 0, 0)
.inactiveDates_ = RGB(144, 70, 70)
Case TCalendarTheme.T_CT_BLUE
.background_ = RGB(42, 48, 92)
.foreground_ = RGB(179, 179, 179)
.curDateBG_ = RGB(122, 185, 247)
.curDateFG_ = RGB(0, 0, 0)
.inactiveDates_ = RGB(80, 80, 166)
Case TCalendarTheme.T_CT_LIGHT
.background_ = RGB(240, 240, 240)
.foreground_ = RGB(0, 0, 0)
.curDateBG_ = RGB(246, 127, 8)
.curDateFG_ = RGB(0, 0, 0)
.inactiveDates_ = RGB(200, 200, 200)
End Select
End With
End Function
Private Function SetArrowsVisibility(isVisible As Boolean)
lblDOWN.Visible = isVisible
lblUP.Visible = isVisible
End Function
Private Function TagToMonth(sTag$) As Long
Select Case sTag
Case "JAN": TagToMonth = 1
Case "FEB": TagToMonth = 2
Case "MAR": TagToMonth = 3
Case "APR": TagToMonth = 4
Case "MAY": TagToMonth = 5
Case "JUN": TagToMonth = 6
Case "JUL": TagToMonth = 7
Case "AUG": TagToMonth = 8
Case "SEP": TagToMonth = 9
Case "OCT": TagToMonth = 10
Case "NOV": TagToMonth = 11
Case "DEC": TagToMonth = 12
End Select
End Function
Private Function RepaintAllColors()
Me.BackColor = colors_.background_
FrameDay.BackColor = colors_.background_
FrameMonth.BackColor = colors_.background_
FrameYr.BackColor = colors_.background_
lblToday.ForeColor = colors_.foreground_
lblToday.BorderColor = colors_.foreground_
lblTitleCurMY.ForeColor = colors_.foreground_
lblTitleCurMY.BorderColor = colors_.foreground_
lblUnload.ForeColor = colors_.foreground_
lblThemes.ForeColor = colors_.foreground_
lblUP.ForeColor = colors_.foreground_
lblDOWN.ForeColor = colors_.foreground_
Dim nItem&
For nItem = 1 To CALENDAR_WEEKDAY_COUNT Step 1
Me.Controls("WD" & nItem).ForeColor = colors_.foreground_
Next nItem
Call RepaintDaysColors
Call RepaintMonthsColors
Call RepaintYearsColor
End Function
Private Function RepaintDaysColors()
Dim nItem&
Dim theDate&
For nItem = 1 To CALENDAR_DAYS_COUNT Step 1
With Me.Controls("D" & nItem)
theDate = .Tag
.BorderStyle = fmBorderStyleNone
If .Tag = curDate_ Then
.BackStyle = fmBackStyleOpaque
.BackColor = colors_.curDateBG_
.ForeColor = colors_.curDateFG_
ElseIf Month(.Tag) = month_ Then
.BackStyle = fmBackStyleTransparent
.BackColor = colors_.background_
.ForeColor = colors_.foreground_
Else
.BackStyle = fmBackStyleTransparent
.BackColor = colors_.background_
.ForeColor = colors_.inactiveDates_
End If
End With
Next nItem
End Function
Private Function RepaintMonthsColors()
Dim nMonth&
For nMonth = 1 To CALENDAR_MONTH_COUNT Step 1
With Me.Controls("M" & nMonth)
.BorderStyle = fmBorderStyleNone
If nMonth = month_ Then
.BackStyle = fmBackStyleOpaque
.BackColor = colors_.curDateBG_
.ForeColor = colors_.curDateFG_
Else
.BackStyle = fmBackStyleTransparent
.BackColor = colors_.background_
.ForeColor = colors_.foreground_
End If
End With
Next nMonth
End Function
Private Function RepaintYearsColor()
Dim nYear&
For nYear = 1 To CALENDAR_YEARS_PER_PAGE Step 1
With Me.Controls("Y" & nYear)
.BorderStyle = fmBorderStyleNone
.Caption = CStr(firstYear_ + nYear - 1)
If nYear + firstYear_ - 1 = year_ Then
.BackStyle = fmBackStyleOpaque
.BackColor = colors_.curDateBG_
.ForeColor = colors_.curDateFG_
Else
.BackStyle = fmBackStyleTransparent
.BackColor = colors_.background_
.ForeColor = colors_.foreground_
End If
End With
Next nYear
End Function