1 #----------------------------------------------------------------------------
3 # Purpose: Calendar display control
5 # Author: Lorne White (email: lorne.white@telusplanet.net)
10 # Licence: wxWindows license
11 #----------------------------------------------------------------------------
13 from wxPython
.wx
import *
19 CalDays
= [6, 0, 1, 2, 3, 4, 5]
20 AbrWeekday
= {6:"Sun", 0:"Mon", 1:"Tue", 2:"Wed", 3:"Thu", 4:"Fri", 5:"Sat"}
23 BusCalDays
= [0, 1, 2, 3, 4, 5, 6]
25 # calendar drawing routing
32 monthlist
.append(name
)
36 def __init__(self
, parent
):
40 self
.scale
= parent
.scale
47 self
.grid_color
= 'BLACK' # grid and selection colors
48 self
.back_color
= 'WHITE'
49 self
.sel_color
= 'RED'
51 self
.high_color
= 'LIGHT BLUE'
52 self
.border_color
= 'BLACK'
53 self
.week_color
= 'LIGHT GREY'
55 self
.week_font_color
= 'BLACK' # font colors
56 self
.day_font_color
= 'BLACK'
61 self
.hide_title
= FALSE
62 self
.hide_grid
= FALSE
63 self
.outer_border
= TRUE
66 self
.cal_week_scale
= 0.7
67 self
.show_weekend
= FALSE
68 self
.cal_type
= "NORMAL"
70 def SetWeekColor(self
, font_color
, week_color
): # set font and background color for week title
71 self
.week_font_color
= font_color
72 self
.week_color
= week_color
74 def SetSize(self
, size
):
75 self
.set_sizew
= size
.width
76 self
.set_sizeh
= size
.height
78 def InitValues(self
): # default dimensions of various elements of the calendar
81 self
.set_cy_st
= 0 # start position
84 self
.set_y_mrg
= 15 # start of vertical draw default
88 def SetPos(self
, xpos
, ypos
):
92 def SetMarg(self
, xmarg
, ymarg
):
95 self
.set_y_end
= ymarg
97 def InitScale(self
): # scale position values
98 self
.sizew
= self
.set_sizew
* self
.pwidth
99 self
.sizeh
= self
.set_sizeh
* self
.pheight
101 self
.cx_st
= self
.set_cx_st
* self
.pwidth
# draw start position
102 self
.cy_st
= self
.set_cy_st
* self
.pheight
104 self
.x_mrg
= self
.set_x_mrg
* self
.pwidth
# calendar draw margins
105 self
.y_mrg
= self
.set_y_mrg
* self
.pheight
106 self
.y_end
= self
.set_y_end
* self
.pheight
108 def DrawCal(self
, DC
, sel_lst
=[]):
113 if self
.hide_title
is FALSE
:
121 if self
.show_weekend
is TRUE
: # highlight weekend dates
124 self
.AddSelect(sel_lst
) # overrides the weekend highlight
126 self
.DrawSel() # highlighted days
130 def AddSelect(self
, list, cfont
=None, cbackgrd
= None):
132 cfont
= self
.sel_color
# font digit color
134 cbackgrd
= self
.high_color
# select background color
137 self
.cal_sel
[val
] = (cfont
, cbackgrd
)
139 def DrawBorder(self
): # draw border around the outside of the main display rectangle
140 brush
= wxBrush(wxNamedColour(self
.back_color
), wxSOLID
)
141 self
.DC
.SetBrush(brush
)
142 self
.DC
.SetPen(wxPen(wxNamedColour(self
.border_color
), 1))
144 if self
.outer_border
is TRUE
:
145 rect
= wxRect(self
.cx_st
, self
.cy_st
, self
.sizew
, self
.sizeh
) # full display window area
146 self
.DC
.DrawRectangle(rect
.x
, rect
.y
, rect
.width
, rect
.height
)
148 def DrawNumVal(self
):
151 # calculate the calendar days and offset position
153 def SetCal(self
, year
, month
):
154 self
.InitValues() # reset initial values
160 t
= Date(year
, month
, day
)
161 dow
= self
.dow
= t
.day_of_week
# start day in month
162 dim
= self
.dim
= t
.days_in_month
# number of days in month
163 if self
.cal_type
== "NORMAL":
168 self
.st_pos
= start_pos
171 for i
in range(start_pos
):
175 self
.cal
.append(str(i
))
179 def SetWeekEnd(self
, font_color
='BLACK', backgrd
= 'LIGHT GREY'):
180 date
= 6 - int(self
.dow
) # start day of first saturday
181 while date
<= self
.dim
:
182 self
.cal_sel
[date
] = (font_color
, backgrd
) # Saturday
185 self
.cal_sel
[date
] = (font_color
, backgrd
) # Sunday
190 def GetRect(self
): # get the display rectange list of the day grid
192 for y
in self
.gridy
[1:-1]:
193 for x
in self
.gridx
[:-1]:
194 rect
= wxRect(x
, y
, self
.dl_w
, self
.dl_h
) # create rect region
205 def DrawMonth(self
): # month and year title
206 month
= Month
[self
.month
]
209 if self
.sizeh
< _MIDSIZE
:
212 f
= wxFont(sizef
, self
.font
, wxNORMAL
, self
.bold
)
215 tw
,th
= self
.DC
.GetTextExtent(month
)
216 adjust
= self
.cx_st
+ (self
.sizew
-tw
)/2
217 self
.DC
.DrawText(month
, adjust
, self
.cy_st
+ th
)
219 year
= str(self
.year
)
220 tw
,th
= self
.DC
.GetTextExtent(year
)
221 adjust
= self
.sizew
- tw
- self
.x_mrg
223 self
.title_offset
= th
* 2
225 f
= wxFont(sizef
, self
.font
, wxNORMAL
, self
.bold
)
227 self
.DC
.DrawText(year
, self
.cx_st
+ adjust
, self
.cy_st
+ th
)
229 def DrawWeek(self
): # draw the week days
231 if self
.sizeh
< _MIDSIZE
:
234 f
= wxFont(sizef
, self
.font
, wxNORMAL
, self
.bold
)
236 self
.DC
.SetTextForeground(wxNamedColour(self
.week_font_color
))
240 width
= self
.gridx
[1]-self
.gridx
[0]
241 height
= self
.gridy
[1] - self
.gridy
[0]
243 rect_w
= self
.gridx
[7]-self
.gridx
[0]
245 brush
= wxBrush(wxNamedColour(self
.week_color
), wxSOLID
)
246 self
.DC
.SetBrush(brush
)
247 # self.DC.DrawRectangle(self.gridx[0], self.gridy[0], rect_w+1, height)
249 if self
.cal_type
== "NORMAL":
252 cal_days
= BusCalDays
255 day
= AbrWeekday
[val
]
258 dw
,dh
= self
.DC
.GetTextExtent(day
)
260 diffy
= (height
-dh
)/2
262 x
= self
.gridx
[cnt_x
]
263 y
= self
.gridy
[cnt_y
]
264 self
.DC
.DrawRectangle(self
.gridx
[cnt_x
], self
.gridy
[0], width
+1, height
)
265 self
.DC
.DrawText(day
, x
+diffx
, y
+diffy
)
269 def DrawNum(self
): # draw the day numbers
271 if self
.sizeh
< _MIDSIZE
:
273 f
= wxFont(sizef
, self
.font
, wxNORMAL
, self
.bold
)
278 x
= self
.gridx
[cnt_x
]
279 y
= self
.gridy
[cnt_y
]
283 num_color
= self
.cal_sel
[num_val
][0]
285 num_color
= self
.day_font_color
287 self
.DC
.SetTextForeground(wxNamedColour(num_color
))
290 self
.DC
.DrawText(val
, x
+5, y
+5)
297 def Center(self
): # calculate the dimensions in the center of the drawing area
299 bdh
= self
.y_mrg
+ self
.y_end
+ self
.title_offset
301 self
.dl_w
= int((self
.sizew
-bdw
)/7)
302 self
.dl_h
= int((self
.sizeh
-bdh
)/7)
304 self
.dl_th
= int(self
.dl_h
*self
.cal_week_scale
) # week title adjustment
305 self
.cwidth
= self
.dl_w
* 7
306 self
.cheight
= self
.dl_h
* 6 + self
.dl_th
308 def DrawSel(self
): # highlighted selected days
309 for key
in self
.cal_sel
.keys():
310 sel_color
= self
.cal_sel
[key
][1]
311 brush
= wxBrush(wxNamedColour(sel_color
), wxSOLID
)
312 self
.DC
.SetBrush(brush
)
314 if self
.hide_grid
is FALSE
:
315 self
.DC
.SetPen(wxPen(wxNamedColour(self
.grid_color
), 0))
317 self
.DC
.SetPen(wxPen(wxNamedColour(self
.back_color
), 0))
318 nkey
= key
+ self
.st_pos
-1
320 self
.DC
.DrawRectangle(rect
.x
, rect
.y
, rect
.width
+1, rect
.height
+1)
322 def DrawGrid(self
): # calculate and draw the grid lines
323 self
.DC
.SetPen(wxPen(wxNamedColour(self
.grid_color
), 0))
328 self
.x_st
= self
.cx_st
+ self
.x_mrg
329 self
.y_st
= self
.cy_st
+ self
.y_mrg
+ self
.title_offset
# start postion of draw
334 y2
= y1
+ self
.cheight
336 if self
.hide_grid
is FALSE
:
337 self
.DC
.DrawLine(x1
, y1
, x1
, y2
)
338 self
.gridx
.append(x1
)
344 x2
= x1
+ self
.cwidth
346 if self
.hide_grid
is FALSE
:
347 self
.DC
.DrawLine(x1
, y1
, x2
, y1
)
348 self
.gridy
.append(y1
)
355 class PrtCalDraw(CalDraw
):
356 def InitValues(self
):
359 self
.set_cx_st
= 1.0 # start draw border location
362 self
.set_y_mrg
= 0.2 # draw offset position
366 def SetPSize(self
, pwidth
, pheight
): # calculate the dimensions in the center of the drawing area
367 self
.pwidth
= int(pwidth
)/self
.scale
368 self
.pheight
= int(pheight
)/self
.scale
370 def SetPreview(self
, preview
):
371 self
.preview
= preview
373 class wxCalendar(wxWindow
):
374 def __init__(self
, parent
, id, pos
=wxDefaultPosition
, size
=wxDefaultSize
):
375 wxWindow
.__init
__(self
, parent
, id, pos
, size
)
377 # set the calendar control attributes
379 self
.grid_color
= 'BLACK'
380 self
.back_color
= 'WHITE'
381 self
.hide_grid
= FALSE
382 self
.sel_color
= 'RED'
383 self
.hide_title
= FALSE
384 self
.show_weekend
= FALSE
385 self
.cal_type
= "NORMAL"
387 self
.week_color
= 'LIGHT GREY'
388 self
.week_font_color
= 'BLACK' # font colors
390 self
.select_list
= []
392 self
.SetBackgroundColour(wxNamedColor(self
.back_color
))
393 self
.Connect(-1, -1, wxEVT_LEFT_DOWN
, self
.OnLeftEvent
)
394 self
.Connect(-1, -1, wxEVT_LEFT_DCLICK
, self
.OnLeftDEvent
)
395 self
.Connect(-1, -1, wxEVT_RIGHT_DOWN
, self
.OnRightEvent
)
396 self
.Connect(-1, -1, wxEVT_RIGHT_DCLICK
, self
.OnRightDEvent
)
398 self
.sel_key
= None # last used by
399 self
.sel_lst
= [] # highlighted selected days
401 self
.SetNow() # default calendar for current month
406 EVT_PAINT(self
, self
.OnPaint
)
409 # control some of the main calendar attributes
412 self
.hide_title
= TRUE
415 self
.hide_grid
= TRUE
417 # determine the calendar rectangle click area and draw a selection
419 def ProcessClick(self
, event
):
420 self
.x
, self
.y
= event
.GetX(), event
.GetY()
421 key
= self
.GetDayHit(self
.x
, self
.y
)
424 # tab mouse click events and process
426 def OnLeftEvent(self
, event
):
428 self
.ProcessClick(event
)
430 def OnLeftDEvent(self
, event
):
432 self
.ProcessClick(event
)
434 def OnRightEvent(self
, event
):
436 self
.ProcessClick(event
)
438 def OnRightDEvent(self
, event
):
439 self
.click
= 'DRIGHT'
440 self
.ProcessClick(event
)
442 def SetSize(self
, set_size
):
445 def SetSelDay(self
, sel
):
446 self
.sel_lst
= sel
# list of highlighted days
448 # get the current date
452 self
.month
= dt
.month
456 # set the current day
458 def SetCurrentDay(self
):
460 self
.set_day
= self
.day
462 # get the date, day, month, year set in calendar
465 return self
.day
, self
.month
, self
.year
476 # set the day, month, and year
478 def SetDayValue(self
, day
):
481 def SetMonth(self
, month
):
482 if month
>= 1 and month
<= 12:
488 def SetYear(self
, year
):
491 # increment year and month
494 self
.year
= self
.year
+ 1
498 self
.year
= self
.year
- 1
502 self
.month
= self
.month
+ 1
505 self
.year
= self
.year
+ 1
509 self
.month
= self
.month
- 1
512 self
.year
= self
.year
- 1
515 # test to see if the selection has a date and create event
517 def TestDay(self
, key
):
519 self
.day
= int(self
.cal
[key
])
525 evt
= wxPyCommandEvent(2100, self
.GetId())
526 evt
.click
, evt
.day
, evt
.month
, evt
.year
= self
.click
, self
.day
, self
.month
, self
.year
527 self
.GetEventHandler().ProcessEvent(evt
)
529 self
.set_day
= self
.day
532 # find the clicked area rectangle
534 def GetDayHit(self
, mx
, my
):
535 for key
in self
.rg
.keys():
537 ms_rect
= wxRect(mx
, my
, 1, 1)
538 if wxIntersectRect(ms_rect
, val
) is not None:
539 result
= self
.TestDay(key
)
545 def SetWeekColor(self
, font_color
, week_color
): # set font and background color for week title
546 self
.week_font_color
= font_color
547 self
.week_color
= week_color
549 def AddSelect(self
, list, font_color
, back_color
):
550 list_val
= [list, font_color
, back_color
]
551 self
.select_list
.append(list_val
)
553 def ShowWeekEnd(self
):
554 self
.show_weekend
= TRUE
# highlight weekend
556 def SetBusType(self
):
557 self
.cal_type
= "BUS"
559 def OnPaint(self
, event
):
563 def DoDrawing(self
, DC
):
567 self
.cal
= cal
= CalDraw(self
)
569 cal
.grid_color
= self
.grid_color
570 cal
.back_color
= self
.back_color
571 cal
.hide_grid
= self
.hide_grid
572 cal
.grid_color
= self
.grid_color
573 cal
.hide_title
= self
.hide_title
574 cal
.show_weekend
= self
.show_weekend
575 cal
.cal_type
= self
.cal_type
577 if self
.size
is None:
578 size
= self
.GetClientSize()
584 cal
.week_font_color
= self
.week_font_color
585 cal
.week_color
= self
.week_color
588 cal
.SetCal(self
.year
, self
.month
)
589 for val
in self
.select_list
:
590 cal
.AddSelect(val
[0], val
[1], val
[2])
592 cal
.DrawCal(DC
, self
.sel_lst
)
594 self
.rg
= cal
.GetRect()
595 self
.cal
= cal
.GetCal()
596 self
.st_pos
= cal
.GetOffset()
597 self
.ymax
= DC
.MaxY()
599 if self
.set_day
!= None:
600 self
.SetDay(self
.set_day
)
603 # draw the selection rectangle
605 def DrawRect(self
, key
, color
= 'BLACK', width
= 0):
608 DC
= wxClientDC(self
)
611 brush
= wxBrush(wxColour(0, 0xFF, 0x80), wxTRANSPARENT
)
613 DC
.SetPen(wxPen(wxNamedColour(color
), width
))
616 DC
.DrawRectangle(rect
.x
, rect
.y
, rect
.width
+1, rect
.height
+1)
620 # set the day selection
622 def SetDay(self
, day
):
623 day
= day
+ self
.st_pos
- 1
626 def SelectDay(self
, key
):
628 self
.DrawRect(self
.sel_key
, self
.back_color
, sel_size
) # clear large selection
629 if self
.hide_grid
is FALSE
:
630 self
.DrawRect(self
.sel_key
, self
.grid_color
)
632 self
.DrawRect(key
, self
.sel_color
, sel_size
)
633 self
.sel_key
= key
# store last used by
634 self
.select_day
= None
639 class CalenDlg(wxDialog
):
640 def __init__(self
, parent
, month
=None, day
= None, year
=None):
641 wxDialog
.__init
__(self
, parent
, -1, "Event Calendar", wxPyDefaultPosition
, wxSize(280, 360))
643 # set the calendar and attributes
644 self
.calend
= wxCalendar(self
, -1, wxPoint(20, 60), wxSize(240, 200))
646 self
.calend
.SetCurrentDay()
647 start_month
= self
.calend
.GetMonth()
648 start_year
= self
.calend
.GetYear()
650 self
.calend
.month
= start_month
= month
651 self
.calend
.year
= start_year
= year
652 self
.calend
.SetDayValue(day
)
654 self
.calend
.HideTitle()
657 # get month list from DateTime
658 monthlist
= GetMonthList()
662 self
.date
= wxComboBox(self
, mID
, Month
[start_month
], wxPoint(20, 20), wxSize(90, -1), monthlist
, wxCB_DROPDOWN
)
663 EVT_COMBOBOX(self
, mID
, self
.EvtComboBox
)
665 # alternate spin button to control the month
667 h
= self
.date
.GetSize().height
668 self
.m_spin
= wxSpinButton(self
, mID
, wxPoint(130, 20), wxSize(h
*2, h
), wxSP_VERTICAL
)
669 self
.m_spin
.SetRange(1, 12)
670 self
.m_spin
.SetValue(start_month
)
672 EVT_SPIN(self
, mID
, self
.OnMonthSpin
)
674 # spin button to control the year
676 self
.dtext
= wxTextCtrl(self
, -1, str(start_year
), wxPoint(160, 20), wxSize(60, -1))
677 h
= self
.dtext
.GetSize().height
679 self
.y_spin
= wxSpinButton(self
, mID
, wxPoint(220, 20), wxSize(h
*2, h
), wxSP_VERTICAL
)
680 self
.y_spin
.SetRange(1980, 2010)
681 self
.y_spin
.SetValue(start_year
)
683 EVT_SPIN(self
, mID
, self
.OnYrSpin
)
685 self
.Connect(self
.calend
.GetId(), -1, 2100, self
.MouseClick
)
689 but_size
= wxSize(60, 25)
692 wxButton(self
, mID
, ' Ok ', wxPoint(x_pos
, y_pos
), but_size
)
693 EVT_BUTTON(self
, mID
, self
.OnOk
)
696 wxButton(self
, mID
, ' Close ', wxPoint(x_pos
+ 120, y_pos
), but_size
)
697 EVT_BUTTON(self
, mID
, self
.OnCancel
)
699 def OnOk(self
, event
):
700 self
.EndModal(wxID_OK
)
702 def OnCancel(self
, event
):
703 self
.EndModal(wxID_CANCEL
)
705 # log the mouse clicks
706 def MouseClick(self
, evt
):
707 self
.month
= evt
.month
708 self
.result
= [evt
.click
, str(evt
.day
), Month
[evt
.month
], str(evt
.year
)] # result click type and date
710 if evt
.click
== 'DLEFT':
711 self
.EndModal(wxID_OK
)
713 # month and year spin selection routines
714 def OnMonthSpin(self
, event
):
715 month
= event
.GetPosition()
716 self
.date
.SetValue(Month
[month
])
717 self
.calend
.SetMonth(month
)
718 self
.calend
.Refresh()
720 def OnYrSpin(self
, event
):
721 year
= event
.GetPosition()
722 self
.dtext
.SetValue(str(year
))
723 self
.calend
.SetYear(year
)
724 self
.calend
.Refresh()
726 def EvtComboBox(self
, event
):
727 name
= event
.GetString()
728 monthval
= self
.date
.FindString(name
)
729 self
.m_spin
.SetValue(monthval
+1)
731 self
.calend
.SetMonth(monthval
+1)
734 # set the calendar for highlighted days
736 def ResetDisplay(self
):
737 month
= self
.calend
.GetMonth()
738 self
.calend
.Refresh()