COPY
      Option Explicit
'---------------------------------------
Dim shpHeight           As Long
Dim shpWidth            As Long
Dim TBT                 As Long
Dim YBT                 As Long
Dim DBT(1 To 6)         As Long
Dim BL(1 To 7)          As Long
Private Const ColorSunday = vbRed
Private Const ColorSaturday = vbBlue
Private Const ColorWeekday = vbBlack
Private Const ColorPreHome = 5288016
Private Enum IncFlg
    IncForward = 0
    IncBackward = -1
End Enum
Private Const FirstYobi = vbSunday
Private Const DayStr    As String = "d"
Private Const MonthStr  As String = "m"
Private Const YearStr   As String = "yyyy"
Private Const WeekStr   As String = "ww"
Private StartPosi       As Integer
Private MonthLen        As Variant
Private Yobi(1 To 7)    As Variant
Private DefYear         As Integer
Private DefMonth        As Integer
Private DefDay          As Integer
Private CurDate         As Date
Private CurYear         As Integer
Private CurMonth        As Integer
Private CurDay          As Integer
Private DefFirstYobi    As Integer
Private SelectShape      As String
'---------------------------------------
Public Sub OpenCalendar()
    Dim I               As Integer
    Dim J               As Long
    Dim BUF             As String
  
    Call DeleteCal
    
    '--------月の日数の配列 0はダミー値
    MonthLen = Array(0, 31, 28, 31, 30, 31, 30, _
        31, 31, 30, 31, 30, 31)
    
    '--------最初に来る曜日を日曜日に指定
    DefFirstYobi = FirstYobi
    For J = 1 To 7
        Yobi(J) = Left$(WeekdayName(J, FirstDayOfWeek:=DefFirstYobi), 1)
    Next J
    shpHeight = 15
    shpWidth = 35
    
    TBT = ActiveCell.OffSet(0, 1).Top
    BL(1) = ActiveCell.OffSet(0, 1).Left
    YBT = TBT + shpHeight
    
    DBT(1) = YBT + shpHeight
    For I = 2 To 6
        DBT(I) = DBT(I - 1) + shpHeight
    Next I
   
    For J = 2 To 7
        BL(J) = BL(J - 1) + shpWidth
    Next J
    Application.ScreenUpdating = False
    BUF = Replace(StrConv(ActiveCell.Value, vbNarrow), ".", "/")
    If IsDate(BUF) Then
        BUF = CDate(BUF)
    Else
        BUF = Date
    End If
    
    '--------年月日の要素を取り出す
    DefDay = DatePart(DayStr, BUF)
    DefMonth = DatePart(MonthStr, BUF)
    DefYear = DatePart(YearStr, BUF)
    Call UpShapes
    Call StartValues(BUF)
    Call CalendarDisp
    Application.ScreenUpdating = True
End Sub
'---------------------------------------
Private Sub UpShapes()
    Dim SHP             As Shape
    Dim I               As Integer
    Dim J               As Integer
    Dim intLogicalDay   As Integer
    '--------
    Set SHP = ActiveSheet.Shapes.AddShape(1, BL(1), _
        TBT, shpWidth, shpHeight)
    With SHP
        .Name = "SHP_PreviousYear"
        .OnAction = "ShapeCalendar.PreviousYearClick"
        .TextFrame.Characters.Text = "▼"
        .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(0, 0, 255)
        .Fill.ForeColor.RGB = RGB(252, 213, 181)
    End With
    Call ShapeHyozi(SHP)
    
    Set SHP = ActiveSheet.Shapes.AddShape(1, BL(2), _
        TBT, shpWidth * 2, shpHeight)
    With SHP
        .Name = "SHP_TextYaer"
        .OnAction = "ShapeCalendar.Dummy"
        .TextFrame.Characters.Text = ""
        .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(0, 0, 255)
        .Fill.ForeColor.RGB = RGB(221, 221, 221)
    End With
    Call ShapeHyozi(SHP)
    
    Set SHP = ActiveSheet.Shapes.AddShape(1, BL(4), _
        TBT, shpWidth, shpHeight)
    With SHP
        .Name = "SHP_NextYear"
        .OnAction = "ShapeCalendar.NextYearClick"
        .TextFrame.Characters.Text = "▲"
        .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(0, 0, 255)
        .Fill.ForeColor.RGB = RGB(146, 246, 166)
    End With
    Call ShapeHyozi(SHP)
    
    Set SHP = ActiveSheet.Shapes.AddShape(1, BL(5), _
        TBT, shpWidth, shpHeight)
    With SHP
        .Name = "SHP_PreviousMonth"
        .OnAction = "ShapeCalendar.PreviousMonthClick"
        .TextFrame.Characters.Text = "▼"
        .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(0, 0, 255)
        .Fill.ForeColor.RGB = RGB(252, 213, 181)
    End With
    Call ShapeHyozi(SHP)
    
    Set SHP = ActiveSheet.Shapes.AddShape(1, BL(6), TBT, shpWidth, shpHeight)
    With SHP
        .Name = "SHP_TextMonth"
        .OnAction = "ShapeCalendar.Dummy"
        .TextFrame.Characters.Text = ""
        .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(0, 0, 255)
        .Fill.ForeColor.RGB = RGB(221, 221, 221)
    End With
    Call ShapeHyozi(SHP)
    
    Set SHP = ActiveSheet.Shapes.AddShape(1, BL(7), _
        TBT, shpWidth, shpHeight)
    With SHP
        .Name = "SHP_NextMonth"
        .OnAction = "ShapeCalendar.NextMonthClick"
        .TextFrame.Characters.Text = "▲"
        .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(0, 0, 255)
        .Fill.ForeColor.RGB = RGB(146, 246, 166)
    End With
    Call ShapeHyozi(SHP)
    
    '--------
    For J = 1 To 7
        intLogicalDay = (((J - 1) + (DefFirstYobi - 1)) Mod 7) + 1
        Set SHP = ActiveSheet.Shapes.AddShape(1, BL(J), _
            YBT, shpWidth, shpHeight)
        With SHP
            .Name = "SHPY" & Format(J, "00")
            .OnAction = "ShapeCalendar.Dummy"
            .Fill.ForeColor.RGB = RGB(221, 221, 221)
            If ((intLogicalDay - 1) Mod 7) = 0 Then
                .TextFrame.Characters.Text = Yobi(intLogicalDay)
                .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 0, 0)
            ElseIf ((intLogicalDay - 1) Mod 7) = 6 Then
                .TextFrame.Characters.Text = Yobi(intLogicalDay)
                .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(0, 0, 255)
            Else
                .TextFrame.Characters.Text = Yobi(intLogicalDay)
                .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = ColorWeekday
            End If
        End With
        Call ShapeHyozi(SHP)
    Next J
    '--------
    For I = 1 To 6
        For J = 1 To 7
            Set SHP = ActiveSheet.Shapes.AddShape(1, BL(J), _
                DBT(I), shpWidth, shpHeight)
            With SHP
                .OnAction = "ShapeCalendar.DateClick"
                .Name = "SHPD" & I & J
                .TextFrame.Characters.Text = CStr((I - 1) * 7 + J)
                .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = ColorWeekday
                .Fill.ForeColor.RGB = RGB(221, 221, 221)
            End With
            Call ShapeHyozi(SHP)
        Next J
    Next I
    Set SHP = ActiveSheet.Shapes.AddShape(1, BL(1), _
        DBT(6) + shpHeight, shpWidth * 2, shpHeight)
    With SHP
        .Name = "SHP_HOME"
        .OnAction = "ShapeCalendar.GoHome"
        .Fill.ForeColor.RGB = RGB(221, 221, 221)
        .TextFrame.Characters.Text = "HOME"
        .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = ColorSaturday
    End With
    Call ShapeHyozi(SHP)
    
    Set SHP = ActiveSheet.Shapes.AddShape(1, BL(3), _
        DBT(6) + shpHeight, shpWidth * 2, shpHeight)
    With SHP
        .Name = "SHP_PREHOME"
        .OnAction = "ShapeCalendar.GoPreHome"
        .Fill.ForeColor.RGB = RGB(221, 221, 221)
        .TextFrame.Characters.Text = "preHOME"
        .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = ColorPreHome
    End With
    Call ShapeHyozi(SHP)
    Set SHP = ActiveSheet.Shapes.AddShape(1, BL(5), _
        DBT(6) + shpHeight, shpWidth * 3, shpHeight)
    With SHP
        .Name = "SHP_CANCEL"
        .OnAction = "ShapeCalendar.DeleteCal"
        .Fill.ForeColor.RGB = RGB(221, 221, 221)
        .TextFrame.Characters.Text = "CANCEL"
        .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = ColorSunday
    End With
    Call ShapeHyozi(SHP)
End Sub
'---------------------------------------
Private Sub ShapeHyozi(ByRef myShape As Shape)
    With myShape
        .Line.Visible = msoTrue
        .Line.ForeColor.RGB = RGB(166, 166, 166)
        .Line.Weight = 0.5
        .Fill.Visible = msoTrue
        .Fill.Solid
        .TextFrame2.TextRange.ParagraphFormat.Alignment = msoAlignCenter
        .TextFrame2.TextRange.Font.Size = 10
        .Placement = xlFreeFloating
        .Locked = msoTrue
    End With
    
End Sub
'---------------------------------------
Private Sub StartValues(ByVal OpenDate As Date)
    CurDate = OpenDate
    CurYear = DatePart(YearStr, CurDate)
    CurMonth = DatePart(MonthStr, CurDate)
    CurDay = DatePart(DayStr, CurDate)
    
    Call DispYearMonth
    
End Sub
'---------------------------------------
Private Sub DispYearMonth()
    With ActiveSheet.Shapes("SHP_TextYaer").DrawingObject
        .Caption = Format(DateSerial(CurYear, CurMonth, 1), "ggge年")
    End With
    
    With ActiveSheet.Shapes("SHP_TextMonth").DrawingObject
        .Caption = Format(DateSerial(CurYear, CurMonth, 1), "m月")
    End With
    
End Sub
'---------------------------------------
Private Sub DateClick()
    Dim strN            As String
    Dim FLG             As Boolean
    
    '-----マクロを呼び出したオブジェクトの名前
    strN = Application.Caller
   
    '-----シェイプにテキストデータがない
    If Len(ActiveSheet.Shapes(strN).TextFrame.Characters.Text) = 0 Then
        Exit Sub
    End If
    
    '-----2回連続でクリックされた場合、Tureで新たに押された場合Falseになる
    FLG = (SelectShape = strN)
    
    Call ClickShape(strN)
    
    '-----2回連続でクリックされた場合
    If FLG Then
        ActiveCell.Value = DateSerial(CurYear, CurMonth, CurDay)
        Call DeleteCal
    End If
End Sub
'---------------------------------------
Public Sub DeleteCal()
    Dim SHP()           As String
    Dim Sp              As Shape
    Dim objRange        As Object
    Dim iCount          As Long
    Dim I               As Integer
    
    '-----シェイプがなければ終了
    If ActiveSheet.Shapes.Count = 0 Then
        Exit Sub
    End If
    
    '-----名称がSHPから始まるシェイプの拾い上げ
    ReDim SHP(1 To ActiveSheet.Shapes.Count)
    iCount = 0
    For Each Sp In ActiveSheet.Shapes
        If InStr(1, Sp.Name, "SHP") > 0 Then
            iCount = iCount + 1
            SHP(iCount) = Sp.Name
        End If
    Next Sp
    
    '-----なければ終わり
    If iCount = 0 Then
        Exit Sub
    End If
    
    '-----シェイプの一括削除のため一括選択
    ReDim Preserve SHP(1 To iCount)
    Set objRange = ActiveSheet.Shapes.Range(SHP)
    objRange.Select
    
    '-----削除のためシート保護の解除
    ActiveSheet.Unprotect
    
    '----一括削除の実行
    objRange.Delete
End Sub
'---------------------------------------
Private Sub GoHome()
    Call MoveToToday(UseCurYear:=True)
End Sub
'---------------------------------------
Private Sub GoPreHome()
    Call MoveToToday(UseCurYear:=False)
End Sub
'---------------------------------------
Private Sub Dummy()
End Sub
'---------------------------------------DateCalendarの日付の描写
Private Sub CalendarDisp()
    Dim newSelected     As String
    Dim TsuBan          As Integer
    
    '--------1日の週日
    StartPosi = DatePart("w", _
        DateSerial(CurYear, CurMonth, 1), DefFirstYobi)
    
    '--------DateCalendarの日付の描写
    Call DaysInMonth(StartPosi)
    
    '--------選択された
    newSelected = "SHPD" & Grid(CurDay, StartPosi)
    Call ClickShape(newSelected)
End Sub
'---------------------------------------
Private Function Grid(intDay As Integer, _
                      intStart As Integer) As String
    Dim TsuBan          As Integer
    Dim Res             As String
    TsuBan = intDay + intStart - 1
    Res = CStr(((TsuBan - 1) \ 7) + 1) & CStr((TsuBan - 1) Mod 7 + 1)
    Grid = Res
End Function
'---------------------------------------
Private Sub DaysInMonth(intStartDay As Integer)
    Dim intRow              As Integer
    Dim intCol              As Integer
    Dim intDays             As Integer
    Dim intCount            As Integer
    Dim strTemp             As String
    Dim lngForeColor        As Long
    If CurMonth <> 2 Then
        '--------2月以外の場合
        intDays = MonthLen(CurMonth)
    Else
        '-------2月の場合(3月1日の1日前)
        intDays = DatePart(DayStr, DateSerial(CurYear, 3, 1) - 1)
    End If
    
    '--------月、年を更新した場合、1/31⇒2/28等の処理
    If CurDay > intDays Then
        CurDay = intDays
    End If
    
    '--------DateCalendarの日付の描写
    intCount = 0
    For intRow = 1 To 6
        For intCol = 1 To 7
            If (intRow = 1) And (intCol < intStartDay) Then
                ActiveSheet.Shapes("SHPD1" & intCol).TextFrame.Characters.Text = ""
            Else
                intCount = intCount + 1
                strTemp = "SHPD" & intRow & intCol
                With ActiveSheet.Shapes(strTemp)
                    If intCount <= intDays Then
                        .TextFrame.Characters.Text = intCount
                        '追加--------休日の赤色表示処理
                        Select Case Kyujitu(DateSerial(CurYear, CurMonth, intCount))
                        Case 1
                            .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = ColorSunday
                        Case 7
                            .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = ColorSaturday
                        Case Else
                            .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = ColorWeekday
                        End Select
                    Else
                        .TextFrame.Characters.Text = ""
                    End If
                End With
            End If
        Next intCol
    Next intRow
End Sub
'---------------------------------------
Private Function HandleSelected(strName As String)
    Call ClickShape(strName)
End Function
'---------------------------------------
Private Sub ClickShape(NewSelect As String)
    If Len(SelectShape) > 0 Then
        If SelectShape <> NewSelect Then
            With ActiveSheet.Shapes(SelectShape)
                .Fill.ForeColor.RGB = RGB(221, 221, 221)
            End With
            SelectShape = NewSelect
        End If
    Else
        SelectShape = NewSelect
    End If
    With ActiveSheet.Shapes(SelectShape)
        .Fill.ForeColor.RGB = RGB(255, 255, 0)
        CurDay = .TextFrame.Characters.Text
    End With
End Sub
'---------------------------------------
Private Sub NextYearClick()
    Call NextYear
End Sub
Private Sub PreviousYearClick()
    Call PreviousYear
End Sub
Private Sub NextMonthClick()
    Call NextMonth
End Sub
Private Sub PreviousMonthClick()
    Call PreviousMonth
End Sub
'---------------------------------------
Public Sub Today()
    Call MoveToToday(UseCurYear:=True)
End Sub
Public Sub NextMonth()
    Call ChageCalendar(MonthStr, IncForward)
End Sub
Public Sub NextYear()
    Call ChageCalendar(YearStr, IncForward)
End Sub
Public Sub PreviousMonth()
    Call ChageCalendar(MonthStr, IncBackward)
End Sub
Public Sub PreviousYear()
    Call ChageCalendar(YearStr, IncBackward)
End Sub
'---------------------------------------
Private Sub ChageCalendar(strMoveUnit As String, dt As IncFlg)
    Dim iMonth          As Integer
    Dim iYear           As Integer
    Dim iDay            As Integer
    Dim INCDate         As Date
    Dim OldDate         As Date
    Dim iInc            As Integer
    iYear = CurYear
    iMonth = CurMonth
    iDay = CurDay
    If dt = IncForward Then
        iInc = 1
    Else
        iInc = -1
    End If
    OldDate = DateSerial(iYear, iMonth, iDay)
    INCDate = DateAdd(strMoveUnit, iInc, OldDate)
    iMonth = DatePart(MonthStr, INCDate)
    iYear = DatePart(YearStr, INCDate)
    iDay = DatePart(DayStr, INCDate)
    If CurMonth = iMonth And CurYear = iYear Then
        Call ClickShape("SHPD" & Grid(iDay, StartPosi))
    Else
        CurDay = iDay
        CurMonth = iMonth
        CurYear = iYear
        
        Call DispYearMonth
        Call CalendarDisp
    End If
End Sub
'---------------------------------------
Private Sub MoveToToday(UseCurYear As Boolean)
    CurMonth = DefMonth
    If UseCurYear Then
        CurYear = DefYear
    End If
    
    CurDay = DefDay
    
    Call DispYearMonth
    Call CalendarDisp
    
End Sub