]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/calendar.py
style tweaked
[wxWidgets.git] / wxPython / wx / lib / calendar.py
1 #----------------------------------------------------------------------------
2 # Name: calendar.py
3 # Purpose: Calendar display control
4 #
5 # Author: Lorne White (email: lorne.white@telusplanet.net)
6 #
7 # Created:
8 # Version 0.92
9 # Date: Nov 26, 2001
10 # Licence: wxWindows license
11 #----------------------------------------------------------------------------
12 # 12/01/2003 - Jeff Grimmett (grimmtooth@softhome.net)
13 #
14 # o Updated for wx namespace
15 # o Tested with updated demo
16 # o Added new event type EVT_CALENDAR. The reason for this is that the original
17 # library used a hardcoded ID of 2100 for generating events. This makes it
18 # very difficult to fathom when trying to decode the code since there's no
19 # published API. Creating the new event binder might seem like overkill -
20 # after all, you might ask, why not just use a new event ID and be done with
21 # it? However, a consistent interface is very useful at times; also it makes
22 # it clear that we're not just hunting for mouse clicks -- we're hunting
23 # wabbit^H^H^H^H (sorry bout that) for calender-driven mouse clicks. So
24 # that's my sad story. Shoot me if you must :-)
25 # o There's still one deprecation warning buried in here somewhere, but I
26 # haven't been able to find it yet. It only occurs when displaying a
27 # print preview, and only the first time. It *could* be an error in the
28 # demo, I suppose.
29 #
30 # Here's the traceback:
31 #
32 # C:\Python\lib\site-packages\wx\core.py:949: DeprecationWarning:
33 # integer argument expected, got float
34 # newobj = _core.new_Rect(*args, **kwargs)
35 #
36 # 12/17/2003 - Jeff Grimmett (grimmtooth@softhome.net)
37 #
38 # o A few style-guide nips and tucks
39 # o Renamed wxCalendar to Calendar
40 # o Couple of bugfixes
41 #
42 # 06/02/2004 - Joerg "Adi" Sieker adi@sieker.info
43 #
44 # o Changed color handling, use dictionary instead of members.
45 # This causes all color changes to be ignored if they manipluate the members directly.
46 # SetWeekColor and other method color methods were adapted to use the new dictionary.
47 # o Added COLOR_* constants
48 # o Added SetColor method for Calendar class
49 # o Added 3D look of week header
50 # o Added colors for 3D look of header
51 # o Fixed width calculation.
52 # Because of rounding difference the total width and height of the
53 # calendar could be up to 6 pixels to small. The last column and row
54 # are now wider/taller by the missing amount.
55 # o Added SetTextAlign method to wxCalendar. This exposes logic
56 # which was already there.
57 # o Fixed CalDraw.SetMarg which set set_x_st and set_y_st which don't get used anywhere.
58 # Instead set set_x_mrg and set_y_mrg
59 # o Changed default X and Y Margin to 0.
60 # o Added wxCalendar.SetMargin.
61 #
62 # 17/03/2004 - Joerg "Adi" Sieker adi@sieker.info
63 # o Added keyboard navigation to the control.
64 # Use the cursor keys to navigate through the ages. :)
65 # The Home key function as go to today
66 # o select day is now a filled rect instead of just an outline
67
68 import wx
69
70 from CDate import *
71
72 CalDays = [6, 0, 1, 2, 3, 4, 5]
73 AbrWeekday = {6:"Sun", 0:"Mon", 1:"Tue", 2:"Wed", 3:"Thu", 4:"Fri", 5:"Sat"}
74 _MIDSIZE = 180
75
76 COLOR_GRID_LINES = "grid_lines"
77 COLOR_BACKGROUND = "background"
78 COLOR_SELECTION_FONT = "selection_font"
79 COLOR_SELECTION_BACKGROUND = "selection_background"
80 COLOR_BORDER = "border"
81 COLOR_HEADER_BACKGROUND = "header_background"
82 COLOR_HEADER_FONT = "header_font"
83 COLOR_WEEKEND_BACKGROUND = "weekend_background"
84 COLOR_WEEKEND_FONT = "weekend_font"
85 COLOR_FONT = "font"
86 COLOR_3D_LIGHT = "3d_light"
87 COLOR_3D_DARK = "3d_dark"
88 COLOR_HIGHLIGHT_FONT = "highlight_font"
89 COLOR_HIGHLIGHT_BACKGROUND = "highlight_background"
90
91 BusCalDays = [0, 1, 2, 3, 4, 5, 6]
92
93 # Calendar click event - added 12/1/03 by jmg (see above)
94 wxEVT_COMMAND_PYCALENDAR_DAY_CLICKED = wx.NewEventType()
95 EVT_CALENDAR = wx.PyEventBinder(wxEVT_COMMAND_PYCALENDAR_DAY_CLICKED, 1)
96
97 def GetMonthList():
98 monthlist = []
99 for i in range(13):
100 name = Month[i]
101 if name != None:
102 monthlist.append(name)
103 return monthlist
104
105 def MakeColor(in_color):
106 try:
107 color = wxNamedColour(in_color)
108 except:
109 color = in_color
110 return color
111
112 def DefaultColors():
113 colors = {}
114 colors[COLOR_GRID_LINES] = 'BLACK'
115 colors[COLOR_BACKGROUND] = 'WHITE'
116 colors[COLOR_SELECTION_FONT] = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)
117 colors[COLOR_SELECTION_BACKGROUND] =wx.Colour(255,255,225)
118 colors[COLOR_BORDER] = 'BLACK'
119 colors[COLOR_HEADER_BACKGROUND] = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
120 colors[COLOR_HEADER_FONT] = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)
121 colors[COLOR_WEEKEND_BACKGROUND] = 'LIGHT GREY'
122 colors[COLOR_WEEKEND_FONT] = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)
123 colors[COLOR_FONT] = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)
124 colors[COLOR_3D_LIGHT] = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNHIGHLIGHT)
125 colors[COLOR_3D_DARK] = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
126 colors[COLOR_HIGHLIGHT_FONT] = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
127 colors[COLOR_HIGHLIGHT_BACKGROUND] = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)
128 return colors
129 # calendar drawing routing
130
131 class CalDraw:
132 def __init__(self, parent):
133 self.pwidth = 1
134 self.pheight = 1
135 try:
136 self.scale = parent.scale
137 except:
138 self.scale = 1
139
140 self.gridx = []
141 self.gridy = []
142
143 self.DefParms()
144
145 def DefParms(self):
146 self.num_auto = True # auto scale of the cal number day size
147 self.num_size = 12 # default size of calendar if no auto size
148 self.max_num_size = 12 # maximum size for calendar number
149
150 self.num_align_horz = wx.ALIGN_CENTRE # alignment of numbers
151 self.num_align_vert = wx.ALIGN_CENTRE
152 self.num_indent_horz = 0 # points indent from position, used to offset if not centered
153 self.num_indent_vert = 0
154
155 self.week_auto = True # auto scale of week font text
156 self.week_size = 10
157 self.max_week_size = 12
158
159 self.colors = DefaultColors()
160
161 self.font = wx.SWISS
162 self.bold = wx.NORMAL
163
164 self.hide_title = False
165 self.hide_grid = False
166 self.outer_border = True
167
168 self.title_offset = 0
169 self.cal_week_scale = 0.7
170 self.show_weekend = False
171 self.cal_type = "NORMAL"
172
173 def SetWeekColor(self, font_color, week_color):
174 # set font and background color for week title
175 self.colors[COLOR_HEADER_FONT] = MakeColor(font_color)
176 self.colors[COLOR_HEADER_BACKGROUND] = MakeColor(week_color)
177 self.colors[COLOR_3D_LIGHT] = MakeColor(week_color)
178 self.colors[COLOR_3D_DARK] = MakeColor(week_color)
179
180 def SetSize(self, size):
181 self.set_sizew = size[0]
182 self.set_sizeh = size[1]
183
184 def InitValues(self): # default dimensions of various elements of the calendar
185 self.rg = {}
186 self.cal_sel = {}
187 self.set_cy_st = 0 # start position
188 self.set_cx_st = 0
189
190 self.set_y_mrg = 1 # start of vertical draw default
191 self.set_x_mrg = 1
192 self.set_y_end = 1
193 def SetPos(self, xpos, ypos):
194 self.set_cx_st = xpos
195 self.set_cy_st = ypos
196
197 def SetMarg(self, xmarg, ymarg):
198 self.set_x_mrg = xmarg
199 self.set_y_mrg = ymarg
200 self.set_y_end = ymarg
201
202 def InitScale(self): # scale position values
203 self.sizew = int(self.set_sizew * self.pwidth)
204 self.sizeh = int(self.set_sizeh * self.pheight)
205
206 self.cx_st = int(self.set_cx_st * self.pwidth) # draw start position
207 self.cy_st = int(self.set_cy_st * self.pheight)
208
209 self.x_mrg = int(self.set_x_mrg * self.pwidth) # calendar draw margins
210 self.y_mrg = int(self.set_y_mrg * self.pheight)
211 self.y_end = int(self.set_y_end * self.pheight)
212
213 def DrawCal(self, DC, sel_lst=[]):
214 self.InitScale()
215
216 self.DrawBorder(DC)
217
218 if self.hide_title is False:
219 self.DrawMonth(DC)
220
221 self.Center()
222
223 self.DrawGrid(DC)
224 self.GetRect()
225 if self.show_weekend is True: # highlight weekend dates
226 self.SetWeekEnd()
227
228 self.AddSelect(sel_lst) # overrides the weekend highlight
229
230 self.DrawSel(DC) # highlighted days
231 self.DrawWeek(DC)
232 self.DrawNum(DC)
233
234 def AddSelect(self, list, cfont=None, cbackgrd = None):
235 if cfont is None:
236 cfont = self.colors[COLOR_SELECTION_FONT] # font digit color
237 if cbackgrd is None:
238 cbackgrd = self.colors[COLOR_SELECTION_BACKGROUND] # select background color
239
240 for val in list:
241 self.cal_sel[val] = (cfont, cbackgrd)
242
243 # draw border around the outside of the main display rectangle
244 def DrawBorder(self, DC, transparent = False):
245 if self.outer_border is True:
246 if transparent == False:
247 brush = wx.Brush(MakeColor(self.colors[COLOR_BACKGROUND]), wx.SOLID)
248 else:
249 brush = wx.TRANSPARENT_BRUSH
250 DC.SetBrush(brush)
251 DC.SetPen(wx.Pen(MakeColor(self.colors[COLOR_BORDER])))
252 # full display window area
253 rect = wx.Rect(self.cx_st, self.cy_st, self.sizew, self.sizeh)
254 DC.DrawRectangleRect(rect)
255
256 def DrawFocusIndicator(self, DC):
257 if self.outer_border is True:
258 DC.SetBrush(wx.TRANSPARENT_BRUSH)
259 DC.SetPen(wx.Pen(MakeColor(self.colors[COLOR_HIGHLIGHT_BACKGROUND]), style=wx.DOT))
260 # full display window area
261 rect = wx.Rect(self.cx_st, self.cy_st, self.sizew, self.sizeh)
262 DC.DrawRectangleRect(rect)
263
264 def DrawNumVal(self):
265 self.DrawNum()
266
267 # calculate the calendar days and offset position
268 def SetCal(self, year, month):
269 self.InitValues() # reset initial values
270
271 self.year = year
272 self.month = month
273
274 day = 1
275 t = Date(year, month, day)
276 dow = self.dow = t.day_of_week # start day in month
277 dim = self.dim = t.days_in_month # number of days in month
278
279 if self.cal_type == "NORMAL":
280 start_pos = dow+1
281 else:
282 start_pos = dow
283
284 self.st_pos = start_pos
285
286 self.cal_days = []
287 for i in range(start_pos):
288 self.cal_days.append('')
289
290 i = 1
291 while i <= dim:
292 self.cal_days.append(str(i))
293 i = i + 1
294
295 return start_pos
296
297 def SetWeekEnd(self, font_color=None, backgrd = None):
298 if font_color != None:
299 self.SetColor(COLOR_WEEKEND_FONT, MakeColor(font_color))
300 if backgrd != None:
301 self.SetColor(COLOR_WEEKEND_BACKGROUND, MakeColor(backgrd))
302
303 date = 6 - int(self.dow) # start day of first saturday
304
305 while date <= self.dim:
306 self.cal_sel[date] = (self.GetColor(COLOR_WEEKEND_FONT), self.GetColor(COLOR_WEEKEND_BACKGROUND)) # Saturday
307 date = date + 1
308
309 if date <= self.dim:
310 self.cal_sel[date] = (self.GetColor(COLOR_WEEKEND_FONT), self.GetColor(COLOR_WEEKEND_BACKGROUND)) # Sunday
311 date = date + 6
312 else:
313 date = date + 7
314
315 # get the display rectange list of the day grid
316 def GetRect(self):
317 cnt = 0
318 h = 0
319 w = 0
320 for y in self.gridy[1:-1]:
321 if y == self.gridy[-2]:
322 h = h + self.restH
323
324 for x in self.gridx[:-1]:
325 assert type(y) == int
326 assert type(x) == int
327
328 w = self.cellW
329 h = self.cellH
330
331 if x == self.gridx[-2]:
332 w = w + self.restW
333
334 rect = wx.Rect(x, y, w+1, h+1) # create rect region
335
336 self.rg[cnt] = rect
337 cnt = cnt + 1
338
339 return self.rg
340
341 def GetCal(self):
342 return self.cal_days
343
344 def GetOffset(self):
345 return self.st_pos
346
347 # month and year title
348 def DrawMonth(self, DC):
349 month = Month[self.month]
350
351 sizef = 11
352 if self.sizeh < _MIDSIZE:
353 sizef = 10
354
355 f = wx.Font(sizef, self.font, wx.NORMAL, self.bold)
356 DC.SetFont(f)
357
358 tw,th = DC.GetTextExtent(month)
359 adjust = self.cx_st + (self.sizew-tw)/2
360 DC.DrawText(month, (adjust, self.cy_st + th))
361
362 year = str(self.year)
363 tw,th = DC.GetTextExtent(year)
364 adjust = self.sizew - tw - self.x_mrg
365
366 self.title_offset = th * 2
367
368 f = wx.Font(sizef, self.font, wx.NORMAL, self.bold)
369 DC.SetFont(f)
370 DC.DrawText(year, (self.cx_st + adjust, self.cy_st + th))
371
372 def DrawWeek(self, DC): # draw the week days
373 # increase by 1 to include all gridlines
374 width = self.gridx[1] - self.gridx[0] + 1
375 height = self.gridy[1] - self.gridy[0] + 1
376 rect_w = self.gridx[-1] - self.gridx[0]
377
378 f = wx.Font(10, self.font, wx.NORMAL, self.bold) # initial font setting
379
380 if self.week_auto == True:
381 test_size = self.max_week_size # max size
382 test_day = ' Sun '
383 while test_size > 2:
384 f.SetPointSize(test_size)
385 DC.SetFont(f)
386 tw,th = DC.GetTextExtent(test_day)
387
388 if tw < width and th < height:
389 break
390
391 test_size = test_size - 1
392 else:
393 f.SetPointSize(self.week_size) # set fixed size
394 DC.SetFont(f)
395
396 DC.SetTextForeground(MakeColor(self.colors[COLOR_HEADER_FONT]))
397
398 cnt_x = 0
399 cnt_y = 0
400
401 brush = wx.Brush(MakeColor(self.colors[COLOR_HEADER_BACKGROUND]), wx.SOLID)
402 DC.SetBrush(brush)
403
404 if self.cal_type == "NORMAL":
405 cal_days = CalDays
406 else:
407 cal_days = BusCalDays
408
409 for val in cal_days:
410 if val == cal_days[-1]:
411 width = width + self.restW
412
413 day = AbrWeekday[val]
414
415 if self.sizew < 200:
416 day = day[0]
417
418 dw,dh = DC.GetTextExtent(day)
419
420 diffx = (width-dw)/2
421 diffy = (height-dh)/2
422
423 x = self.gridx[cnt_x]
424 y = self.gridy[cnt_y]
425 pointXY = (x, y)
426 pointWH = (width, height)
427 if self.hide_grid == False:
428 pen = wx.Pen(MakeColor(self.GetColor(COLOR_GRID_LINES)), 1, wx.SOLID)
429 else:
430 pen = wx.Pen(MakeColor(self.GetColor(COLOR_BACKGROUND)), 1, wx.SOLID)
431 DC.SetPen(pen)
432 DC.DrawRectangle( pointXY, pointWH)
433
434 old_pen = DC.GetPen()
435
436 pen = wx.Pen(MakeColor(self.colors[COLOR_3D_LIGHT]), 1, wx.SOLID)
437 DC.SetPen(pen)
438 # draw the horizontal hilight
439 startPoint = wx.Point(x + 1 , y + 1)
440 endPoint = wx.Point(x + width - 1, y + 1)
441 DC.DrawLine(startPoint, endPoint )
442
443 # draw the vertical hilight
444 startPoint = wx.Point(x + 1 , y + 1)
445 endPoint = wx.Point(x + 1, y + height - 2)
446 DC.DrawLine(startPoint, endPoint )
447
448 pen = wx.Pen(MakeColor(self.colors[COLOR_3D_DARK]), 1, wx.SOLID)
449 DC.SetPen(pen)
450
451 # draw the horizontal lowlight
452 startPoint = wx.Point(x + 1, y + height - 2)
453 endPoint = wx.Point(x + width - 1, y + height - 2)
454 DC.DrawLine(startPoint, endPoint )
455
456 # draw the vertical lowlight
457 startPoint = wx.Point(x + width - 2 , y + 2)
458 endPoint = wx.Point(x + width - 2, y + height - 2)
459 DC.DrawLine(startPoint, endPoint )
460
461 pen = wx.Pen(MakeColor(self.colors[COLOR_FONT]), 1, wx.SOLID)
462
463 DC.SetPen(pen)
464
465 point = (x+diffx, y+diffy)
466 DC.DrawText(day, point)
467 cnt_x = cnt_x + 1
468
469 def _CalcFontSize(self, DC, f):
470 if self.num_auto == True:
471 test_size = self.max_num_size # max size
472 test_day = ' 99 '
473
474 while test_size > 2:
475 f.SetPointSize(test_size)
476 DC.SetFont(f)
477 tw,th = DC.GetTextExtent(test_day)
478
479 if tw < self.cellW and th < self.cellH:
480 sizef = test_size
481 break
482 test_size = test_size - 1
483 else:
484 f.SetPointSize(self.num_size) # set fixed size
485 DC.SetFont(f)
486
487 # draw the day numbers
488 def DrawNum(self, DC):
489 f = wx.Font(10, self.font, wx.NORMAL, self.bold) # initial font setting
490 self._CalcFontSize(DC, f)
491
492 cnt_x = 0
493 cnt_y = 1
494 for val in self.cal_days:
495 x = self.gridx[cnt_x]
496 y = self.gridy[cnt_y]
497
498 self._DrawDayText(x, y, val, f, DC)
499
500 if cnt_x < 6:
501 cnt_x = cnt_x + 1
502 else:
503 cnt_x = 0
504 cnt_y = cnt_y + 1
505
506 def _DrawDayText(self, x, y, text, font, DC):
507
508 try:
509 num_val = int(text)
510 num_color = self.cal_sel[num_val][0]
511 except:
512 num_color = self.colors[COLOR_FONT]
513
514 DC.SetTextForeground(MakeColor(num_color))
515 DC.SetFont(font)
516
517 tw,th = DC.GetTextExtent(text)
518
519 if self.num_align_horz == wx.ALIGN_CENTRE:
520 adj_h = (self.cellW - tw)/2
521 elif self.num_align_horz == wx.ALIGN_RIGHT:
522 adj_h = self.cellW - tw
523 else:
524 adj_h = 0 # left alignment
525
526 adj_h = adj_h + self.num_indent_horz
527
528 if self.num_align_vert == wx.ALIGN_CENTRE:
529 adj_v = (self.cellH - th)/2
530 elif self.num_align_vert == wx.ALIGN_BOTTOM:
531 adj_v = self.cellH - th
532 else:
533 adj_v = 0 # left alignment
534
535 adj_v = adj_v + self.num_indent_vert
536
537 DC.DrawText(text, (x+adj_h, y+adj_v))
538
539 def DrawDayText(self, DC, key):
540 f = wx.Font(10, self.font, wx.NORMAL, self.bold) # initial font setting
541 self._CalcFontSize(DC, f)
542
543 val = self.cal_days[key]
544 cnt_x = key % 7
545 cnt_y = int(key / 7)+1
546 x = self.gridx[cnt_x]
547 y = self.gridy[cnt_y]
548 self._DrawDayText(x, y, val, f, DC)
549
550
551 # calculate the dimensions in the center of the drawing area
552 def Center(self):
553 borderW = self.x_mrg * 2
554 borderH = self.y_mrg + self.y_end + self.title_offset
555
556 self.cellW = int((self.sizew - borderW)/7)
557 self.cellH = int((self.sizeh - borderH)/7)
558
559 self.restW = ((self.sizew - borderW)%7 ) - 1
560
561 # week title adjustment
562 self.weekHdrCellH = int(self.cellH * self.cal_week_scale)
563 # recalculate the cell height exkl. the week header and
564 # subtracting the size
565 self.cellH = int((self.sizeh - borderH - self.weekHdrCellH)/6)
566
567 self.restH = ((self.sizeh - borderH - self.weekHdrCellH)%6 ) - 1
568 self.calW = self.cellW * 7
569 self.calH = self.cellH * 6 + self.weekHdrCellH
570
571 # highlighted selected days
572 def DrawSel(self, DC):
573
574 for key in self.cal_sel.keys():
575 sel_color = self.cal_sel[key][1]
576 brush = wx.Brush(MakeColor(sel_color), wx.SOLID)
577 DC.SetBrush(brush)
578
579 if self.hide_grid is False:
580 DC.SetPen(wx.Pen(MakeColor(self.colors[COLOR_GRID_LINES]), 0))
581 else:
582 DC.SetPen(wx.Pen(MakeColor(self.colors[COLOR_BACKGROUND]), 0))
583
584 nkey = key + self.st_pos -1
585 rect = self.rg[nkey]
586
587 DC.DrawRectangle((rect.x, rect.y), (rect.width, rect.height))
588
589 # calculate and draw the grid lines
590 def DrawGrid(self, DC):
591 DC.SetPen(wx.Pen(MakeColor(self.colors[COLOR_GRID_LINES]), 0))
592
593 self.gridx = []
594 self.gridy = []
595
596 self.x_st = self.cx_st + self.x_mrg
597 # start postion of draw
598 self.y_st = self.cy_st + self.y_mrg + self.title_offset
599
600 x1 = self.x_st
601 y1 = self.y_st
602 y2 = y1 + self.calH + self.restH
603
604 for i in range(8):
605 if i == 7:
606 x1 = x1 + self.restW
607
608 if self.hide_grid is False:
609 DC.DrawLine((x1, y1), (x1, y2))
610
611 self.gridx.append(x1)
612
613 x1 = x1 + self.cellW
614
615 x1 = self.x_st
616 y1 = self.y_st
617 x2 = x1 + self.calW + self.restW
618
619 for i in range(8):
620 if i == 7:
621 y1 = y1 + self.restH
622
623 if self.hide_grid is False:
624 DC.DrawLine((x1, y1), (x2, y1))
625
626 self.gridy.append(y1)
627
628 if i == 0:
629 y1 = y1 + self.weekHdrCellH
630 else:
631 y1 = y1 + self.cellH
632
633 def GetColor(self, name):
634 return MakeColor(self.colors[name])
635
636 def SetColor(self, name, value):
637 self.colors[name] = MakeColor(value)
638
639 class PrtCalDraw(CalDraw):
640 def InitValues(self):
641 self.rg = {}
642 self.cal_sel = {}
643 # start draw border location
644 self.set_cx_st = 1.0
645 self.set_cy_st = 1.0
646
647 # draw offset position
648 self.set_y_mrg = 0.2
649 self.set_x_mrg = 0.2
650 self.set_y_end = 0.2
651
652 # calculate the dimensions in the center of the drawing area
653 def SetPSize(self, pwidth, pheight):
654 self.pwidth = int(pwidth)/self.scale
655 self.pheight = int(pheight)/self.scale
656
657 def SetPreview(self, preview):
658 self.preview = preview
659
660 class Calendar( wx.PyControl ):
661 def __init__(self, parent, id, pos=wx.DefaultPosition, size=wx.Size(200,200),
662 style= 0, validator=wx.DefaultValidator,
663 name= "calendar"):
664 wx.PyControl.__init__(self, parent, id, pos, size, style | wx.WANTS_CHARS, validator, name)
665
666 self.hasFocus = False
667 # set the calendar control attributes
668
669 self.hide_grid = False
670 self.hide_title = False
671 self.show_weekend = False
672 self.cal_type = "NORMAL"
673 self.outer_border = True
674 self.num_align_horz = wx.ALIGN_CENTRE
675 self.num_align_vert = wx.ALIGN_CENTRE
676 self.colors = DefaultColors()
677 self.set_x_mrg = 1
678 self.set_y_mrg = 1
679 self.set_y_end = 1
680
681 self.select_list = []
682
683 self.SetBackgroundColour(MakeColor(self.colors[COLOR_BACKGROUND]))
684 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftEvent)
685 self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDEvent)
686 self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightEvent)
687 self.Bind(wx.EVT_RIGHT_DCLICK, self.OnRightDEvent)
688 self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
689 self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
690 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
691
692 self.sel_key = None # last used by
693 self.sel_lst = [] # highlighted selected days
694
695 # default calendar for current month
696 self.SetNow()
697
698 self.size = None
699 self.set_day = None
700
701 self.Bind(wx.EVT_PAINT, self.OnPaint)
702 self.Bind(wx.EVT_SIZE, self.OnSize)
703
704 def AcceptsFocus(self):
705 return self.IsShown() and self.IsEnabled()
706
707 def GetColor(self, name):
708 return MakeColor(self.colors[name])
709
710 def SetColor(self, name, value):
711 self.colors[name] = MakeColor(value)
712
713 # control some of the main calendar attributes
714
715 def HideTitle(self):
716 self.hide_title = True
717
718 def HideGrid(self):
719 self.hide_grid = True
720
721 # determine the calendar rectangle click area and draw a selection
722
723 def ProcessClick(self, event):
724 self.x, self.y = event.GetX(), event.GetY()
725 key = self.GetDayHit(self.x, self.y)
726 self.SelectDay(key)
727
728 # tab mouse click events and process
729
730 def OnLeftEvent(self, event):
731 self.click = 'LEFT'
732 self.shiftkey = event.ShiftDown()
733 self.ctrlkey = event.ControlDown()
734 self.ProcessClick(event)
735
736 def OnLeftDEvent(self, event):
737 self.click = 'DLEFT'
738 self.ProcessClick(event)
739
740 def OnRightEvent(self, event):
741 self.click = 'RIGHT'
742 self.ProcessClick(event)
743
744 def OnRightDEvent(self, event):
745 self.click = 'DRIGHT'
746 self.ProcessClick(event)
747
748 def OnSetFocus(self, event):
749 self.hasFocus = True
750 self.DrawFocusIndicator(True)
751
752 def OnKillFocus(self, event):
753 self.hasFocus = False
754 self.DrawFocusIndicator(False)
755
756 def OnKeyDown(self, event):
757 if not self.hasFocus:
758 event.Skip()
759 return
760
761 key_code = event.KeyCode()
762
763 if key_code == wx.WXK_TAB:
764 forward = not event.ShiftDown()
765 ne = wx.NavigationKeyEvent()
766 ne.SetDirection(forward)
767 ne.SetCurrentFocus(self)
768 ne.SetEventObject(self)
769 self.GetParent().GetEventHandler().ProcessEvent(ne)
770 event.Skip()
771 return
772
773 delta = None
774
775 if key_code == wx.WXK_UP:
776 delta = -7
777 elif key_code == wx.WXK_DOWN:
778 delta = 7
779 elif key_code == wx.WXK_LEFT:
780 delta = -1
781 elif key_code == wx.WXK_RIGHT:
782 delta = 1
783 elif key_code == wx.WXK_HOME:
784 curDate = wx.DateTimeFromDMY(int(self.cal_days[self.sel_key]),self.month - 1,self.year)
785 newDate = wx.DateTime_Now()
786 ts = newDate - curDate
787 delta = ts.GetDays()
788
789 if delta <> None:
790 curDate = wx.DateTimeFromDMY(int(self.cal_days[self.sel_key]),self.month - 1,self.year)
791 timeSpan = wx.TimeSpan_Days(delta)
792 newDate = curDate + timeSpan
793
794 if curDate.GetMonth() == newDate.GetMonth():
795 self.set_day = newDate.GetDay()
796 key = self.sel_key + delta
797 self.SelectDay(key)
798 else:
799 self.month = newDate.GetMonth() + 1
800 self.year = newDate.GetYear()
801 self.set_day = newDate.GetDay()
802 self.sel_key = None
803 self.DoDrawing(wx.ClientDC(self))
804
805 event.Skip()
806
807 def SetSize(self, set_size):
808 self.size = set_size
809
810 def SetSelDay(self, sel):
811 # list of highlighted days
812 self.sel_lst = sel
813
814 # get the current date
815 def SetNow(self):
816 dt = now()
817 self.month = dt.month
818 self.year = dt.year
819 self.day = dt.day
820
821 # set the current day
822 def SetCurrentDay(self):
823 self.SetNow()
824 self.set_day = self.day
825
826 # get the date, day, month, year set in calendar
827
828 def GetDate(self):
829 return self.day, self.month, self.year
830
831 def GetDay(self):
832 return self.day
833
834 def GetMonth(self):
835 return self.month
836
837 def GetYear(self):
838 return self.year
839
840 # set the day, month, and year
841
842 def SetDayValue(self, day):
843 self.set_day = day
844
845 def SetMonth(self, month):
846 if month >= 1 and month <= 12:
847 self.month = month
848 else:
849 self.month = 1
850 self.set_day = None
851
852 def SetYear(self, year):
853 self.year = year
854
855 # increment year and month
856
857 def IncYear(self):
858 self.year = self.year + 1
859 self.set_day = None
860
861 def DecYear(self):
862 self.year = self.year - 1
863 self.set_day = None
864
865 def IncMonth(self):
866 self.month = self.month + 1
867 if self.month > 12:
868 self.month = 1
869 self.year = self.year + 1
870 self.set_day = None
871
872 def DecMonth(self):
873 self.month = self.month - 1
874 if self.month < 1:
875 self.month = 12
876 self.year = self.year - 1
877 self.set_day = None
878
879 # test to see if the selection has a date and create event
880
881 def TestDay(self, key):
882 try:
883 self.day = int(self.cal_days[key])
884 except:
885 return None
886
887 if self.day == "":
888 return None
889 else:
890 # Changed 12/1/03 by jmg (see above) to support 2.5 event binding
891 evt = wx.PyCommandEvent(wxEVT_COMMAND_PYCALENDAR_DAY_CLICKED, self.GetId())
892 evt.click, evt.day, evt.month, evt.year = self.click, self.day, self.month, self.year
893 evt.shiftkey = self.shiftkey
894 evt.ctrlkey = self.ctrlkey
895 self.GetEventHandler().ProcessEvent(evt)
896
897 self.set_day = self.day
898 return key
899
900 # find the clicked area rectangle
901
902 def GetDayHit(self, mx, my):
903 for key in self.rg.keys():
904 val = self.rg[key]
905 ms_rect = wx.Rect(mx, my, 1, 1)
906 if wx.IntersectRect(ms_rect, val) is not None:
907 result = self.TestDay(key)
908 return result
909
910 return None
911
912 # calendar drawing
913
914 def SetWeekColor(self, font_color, week_color):
915 # set font and background color for week title
916 self.colors[COLOR_HEADER_FONT] = MakeColor(font_color)
917 self.colors[COLOR_HEADER_BACKGROUND] = MakeColor(week_color)
918 self.colors[COLOR_3D_LIGHT] = MakeColor(week_color)
919 self.colors[COLOR_3D_DARK] = MakeColor(week_color)
920
921 def SetTextAlign(self, vert, horz):
922 self.num_align_horz = horz
923 self.num_align_vert = vert
924
925 def AddSelect(self, list, font_color, back_color):
926 list_val = [list, font_color, back_color]
927 self.select_list.append(list_val)
928
929 def ShowWeekEnd(self):
930 # highlight weekend
931 self.show_weekend = True
932
933 def SetBusType(self):
934 self.cal_type = "BUS"
935
936 def OnSize(self, evt):
937 self.Refresh(False)
938 evt.Skip()
939
940 def OnPaint(self, event):
941 DC = wx.PaintDC(self)
942 self.DoDrawing(DC)
943
944 def DoDrawing(self, DC):
945 #DC = wx.PaintDC(self)
946 DC.BeginDrawing()
947
948 try:
949 cal = self.caldraw
950 except:
951 self.caldraw = CalDraw(self)
952 cal = self.caldraw
953
954 cal.hide_grid = self.hide_grid
955 cal.hide_title = self.hide_title
956 cal.show_weekend = self.show_weekend
957 cal.cal_type = self.cal_type
958 cal.outer_border = self.outer_border
959 cal.num_align_horz = self.num_align_horz
960 cal.num_align_vert = self.num_align_vert
961 cal.colors = self.colors
962
963 if self.size is None:
964 size = self.GetClientSize()
965 else:
966 size = self.size
967
968 # drawing attributes
969
970 cal.SetSize(size)
971 cal.SetCal(self.year, self.month)
972
973 # these have to set after SetCal as SetCal would overwrite them again.
974 cal.set_x_mrg = self.set_x_mrg
975 cal.set_y_mrg = self.set_y_mrg
976 cal.set_y_end = self.set_y_end
977
978 for val in self.select_list:
979 cal.AddSelect(val[0], val[1], val[2])
980
981 cal.DrawCal(DC, self.sel_lst)
982
983 self.rg = cal.GetRect()
984 self.cal_days = cal.GetCal()
985 self.st_pos = cal.GetOffset()
986 self.ymax = DC.MaxY()
987
988 if self.set_day != None:
989 self.SetDay(self.set_day)
990
991 DC.EndDrawing()
992
993 # draw the selection rectangle
994 def DrawFocusIndicator(self, draw):
995 DC = wx.ClientDC(self)
996 try:
997 if draw == True:
998 self.caldraw.DrawFocusIndicator(DC)
999 else:
1000 self.caldraw.DrawBorder(DC,True)
1001 except:
1002 pass
1003
1004 def DrawRect(self, key, bgcolor = 'WHITE', fgcolor= 'PINK',width = 0):
1005 if key == None:
1006 return
1007
1008 DC = wx.ClientDC(self)
1009 DC.BeginDrawing()
1010
1011 brush = wx.Brush(MakeColor(bgcolor))
1012 DC.SetBrush(brush)
1013
1014 DC.SetPen(wx.TRANSPARENT_PEN)
1015
1016 rect = self.rg[key]
1017 DC.DrawRectangle((rect.x+1, rect.y+1), (rect.width-2, rect.height-2))
1018
1019 self.caldraw.DrawDayText(DC,key)
1020
1021 DC.EndDrawing()
1022
1023 def DrawRectOrg(self, key, fgcolor = 'BLACK', width = 0):
1024 if key == None:
1025 return
1026
1027 DC = wx.ClientDC(self)
1028 DC.BeginDrawing()
1029
1030 brush = wx.Brush(wx.Colour(0, 0xFF, 0x80), wx.TRANSPARENT)
1031 DC.SetBrush(brush)
1032
1033 try:
1034 DC.SetPen(wx.Pen(MakeColor(fgcolor), width))
1035 except:
1036 DC.SetPen(wx.Pen(MakeColor(self.GetColor(COLOR_GRID_LINES)), width))
1037
1038 rect = self.rg[key]
1039 DC.DrawRectangle((rect.x, rect.y), (rect.width, rect.height))
1040
1041 DC.EndDrawing()
1042
1043 # set the day selection
1044
1045 def SetDay(self, day):
1046 d = day + self.st_pos - 1
1047 self.SelectDay(d)
1048
1049 def IsDayInWeekend(self, key):
1050 try:
1051 t = Date(self.year, self.month, 1)
1052
1053 day = self.cal_days[key]
1054 day = int(day) + t.day_of_week
1055
1056 if day % 7 == 6 or day % 7 == 0:
1057 return True
1058 except:
1059 return False
1060
1061 def SelectDay(self, key):
1062 sel_size = 1
1063 # clear large selection
1064
1065 if self.sel_key != None:
1066 (cfont, bgcolor) = self.__GetColorsForDay(self.sel_key)
1067 self.DrawRect(self.sel_key, bgcolor,cfont, sel_size)
1068
1069 self.DrawRect(key, self.GetColor(COLOR_HIGHLIGHT_BACKGROUND), self.GetColor(COLOR_HIGHLIGHT_FONT), sel_size)
1070
1071 # store last used by
1072 self.sel_key = key
1073 self.select_day = None
1074
1075 def ClearDsp(self):
1076 self.Clear()
1077 def SetMargin(self, xmarg, ymarg):
1078 self.set_x_mrg = xmarg
1079 self.set_y_mrg = ymarg
1080 self.set_y_end = ymarg
1081 def __GetColorsForDay(self, key):
1082 cfont = self.GetColor(COLOR_FONT)
1083 bgcolor = self.GetColor(COLOR_BACKGROUND)
1084
1085 if self.IsDayInWeekend(key) is True and self.show_weekend is True:
1086 cfont = self.GetColor(COLOR_WEEKEND_FONT)
1087 bgcolor = self.GetColor(COLOR_WEEKEND_BACKGROUND)
1088
1089 try:
1090 dayIdx = int(self.cal_days[key])
1091 (cfont, bgcolor) = self.caldraw.cal_sel[dayIdx]
1092 except:
1093 pass
1094
1095 return (cfont, bgcolor)
1096
1097 class CalenDlg(wx.Dialog):
1098 def __init__(self, parent, month=None, day = None, year=None):
1099 wx.Dialog.__init__(self, parent, -1, "Event Calendar", wx.DefaultPosition, (280, 360))
1100
1101 # set the calendar and attributes
1102 self.calend = Calendar(self, -1, (20, 60), (240, 200))
1103
1104 if month == None:
1105 self.calend.SetCurrentDay()
1106 start_month = self.calend.GetMonth()
1107 start_year = self.calend.GetYear()
1108 else:
1109 self.calend.month = start_month = month
1110 self.calend.year = start_year = year
1111 self.calend.SetDayValue(day)
1112
1113 self.calend.HideTitle()
1114 self.ResetDisplay()
1115
1116 # get month list from DateTime
1117 monthlist = GetMonthList()
1118
1119 # select the month
1120 self.date = wx.ComboBox(self, -1, Month[start_month], (20, 20), (90, -1),
1121 monthlist, wx.CB_DROPDOWN)
1122 self.Bind(wx.EVT_COMBOBOX, self.EvtComboBox, self.date)
1123
1124 # alternate spin button to control the month
1125 h = self.date.GetSize().height
1126 self.m_spin = wx.SpinButton(self, -1, (130, 20), (h*2, h), wx.SP_VERTICAL)
1127 self.m_spin.SetRange(1, 12)
1128 self.m_spin.SetValue(start_month)
1129 self.Bind(wx.EVT_SPIN, self.OnMonthSpin, self.m_spin)
1130
1131 # spin button to control the year
1132 self.dtext = wx.TextCtrl(self, -1, str(start_year), (160, 20), (60, -1))
1133 h = self.dtext.GetSize().height
1134
1135 self.y_spin = wx.SpinButton(self, -1, (220, 20), (h*2, h), wx.SP_VERTICAL)
1136 self.y_spin.SetRange(1980, 2010)
1137 self.y_spin.SetValue(start_year)
1138
1139 self.Bind(wx.EVT_SPIN, self.OnYrSpin, self.y_spin)
1140 self.Bind(EVT_CALENDAR, self.MouseClick, self.calend)
1141
1142 x_pos = 50
1143 y_pos = 280
1144 but_size = (60, 25)
1145
1146 btn = wx.Button(self, -1, ' Ok ', (x_pos, y_pos), but_size)
1147 self.Bind(wx.EVT_BUTTON, self.OnOk, btn)
1148
1149 btn = wx.Button(self, -1, ' Close ', (x_pos + 120, y_pos), but_size)
1150 self.Bind(wx.EVT_BUTTON, self.OnCancel, btn)
1151
1152 def OnOk(self, event):
1153 self.EndModal(wx.ID_OK)
1154
1155 def OnCancel(self, event):
1156 self.EndModal(wx.ID_CANCEL)
1157
1158 # log the mouse clicks
1159 def MouseClick(self, evt):
1160 self.month = evt.month
1161 # result click type and date
1162 self.result = [evt.click, str(evt.day), Month[evt.month], str(evt.year)]
1163
1164 if evt.click == 'DLEFT':
1165 self.EndModal(wx.ID_OK)
1166
1167 # month and year spin selection routines
1168 def OnMonthSpin(self, event):
1169 month = event.GetPosition()
1170 self.date.SetValue(Month[month])
1171 self.calend.SetMonth(month)
1172 self.calend.Refresh()
1173
1174 def OnYrSpin(self, event):
1175 year = event.GetPosition()
1176 self.dtext.SetValue(str(year))
1177 self.calend.SetYear(year)
1178 self.calend.Refresh()
1179
1180 def EvtComboBox(self, event):
1181 name = event.GetString()
1182 monthval = self.date.FindString(name)
1183 self.m_spin.SetValue(monthval+1)
1184
1185 self.calend.SetMonth(monthval+1)
1186 self.ResetDisplay()
1187
1188 # set the calendar for highlighted days
1189
1190 def ResetDisplay(self):
1191 month = self.calend.GetMonth()
1192 self.calend.Refresh()
1193
1194
1195