]>
Commit | Line | Data |
---|---|---|
1 | #! /usr/local/bin/python | |
2 | #---------------------------------------------------------------------------- | |
3 | # Name: calendar.py | |
4 | # Purpose: Calendar display control | |
5 | # | |
6 | # Author: Lorne White (email: lwhite1@planet.eon.net) | |
7 | # | |
8 | # Created: | |
9 | # Version 0.5 1999/11/03 | |
10 | # Licence: wxWindows license | |
11 | #---------------------------------------------------------------------------- | |
12 | ||
13 | from wxPython.wx import * | |
14 | ||
15 | from CDate import * | |
16 | import string, time | |
17 | ||
18 | ||
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"} | |
21 | _MIDSIZE = 100 | |
22 | ||
23 | ||
24 | # calendar drawing routing | |
25 | ||
26 | class CalDraw: | |
27 | def __init__(self): | |
28 | self.rg = {} | |
29 | self.y_st = 15 # start of vertical draw default | |
30 | ||
31 | def SetSize(self, size): | |
32 | self.sizew = size.width | |
33 | self.sizeh = size.height | |
34 | ||
35 | # draw the various elements of the calendar | |
36 | ||
37 | def DrawCal(self, DC, sel_lst): | |
38 | self.DC = DC | |
39 | ||
40 | self.DrawBorder() | |
41 | ||
42 | if self.hide_title is FALSE: | |
43 | self.DrawMonth() | |
44 | ||
45 | self.Center() | |
46 | ||
47 | self.DrawGrid() | |
48 | self.GetRect() | |
49 | ||
50 | self.DrawSel(sel_lst) # highlighted days | |
51 | self.DrawWeek() | |
52 | self.DrawNum() | |
53 | ||
54 | # draw border around the outside of the main display rectangle | |
55 | ||
56 | def DrawBorder(self): | |
57 | rect = wxRect(0, 0, self.sizew, self.sizeh) # full display window area | |
58 | self.DC.DrawRectangle(rect.x, rect.y, rect.width, rect.height) | |
59 | ||
60 | def DrawNumVal(self): | |
61 | self.DrawNum() | |
62 | ||
63 | # calculate the calendar days and offset position | |
64 | ||
65 | def SetCal(self, year, month): | |
66 | self.year = year | |
67 | self.month = month | |
68 | ||
69 | day = 1 | |
70 | t = Date(year, month, day) | |
71 | dow = t.day_of_week # start day in month | |
72 | dim = t.days_in_month # number of days in month | |
73 | start_pos = dow+1 | |
74 | self.st_pos = start_pos | |
75 | ||
76 | self.cal = [] | |
77 | for i in range(start_pos): | |
78 | self.cal.append('') | |
79 | i = 1 | |
80 | while i <= dim: | |
81 | self.cal.append(str(i)) | |
82 | i = i + 1 | |
83 | return start_pos | |
84 | ||
85 | # get the display rectange list of the day grid | |
86 | ||
87 | def GetRect(self): | |
88 | cnt = 0 | |
89 | for y in self.gridy[1:-1]: | |
90 | for x in self.gridx[:-1]: | |
91 | rect = wxRect(x, y, self.dl_w, self.dl_h) # create rect region | |
92 | self.rg[cnt] = rect | |
93 | cnt = cnt + 1 | |
94 | return self.rg | |
95 | ||
96 | def GetCal(self): | |
97 | return self.cal | |
98 | ||
99 | def GetOffset(self): | |
100 | return self.st_pos | |
101 | ||
102 | # month and year title | |
103 | ||
104 | def DrawMonth(self): | |
105 | month = Month[self.month] | |
106 | ||
107 | sizef = 12 | |
108 | if self.sizeh < _MIDSIZE: | |
109 | sizef = 10 | |
110 | ||
111 | f = wxFont(sizef, self.font, wxNORMAL, self.bold) | |
112 | self.DC.SetFont(f) | |
113 | ||
114 | tw,th = self.DC.GetTextExtent(month) | |
115 | adjust = (self.sizew-tw)/2 | |
116 | self.DC.DrawText(month, adjust, 10) | |
117 | ||
118 | year = str(self.year) | |
119 | tw,th = self.DC.GetTextExtent(year) | |
120 | adjust = self.sizew-tw-20 | |
121 | ||
122 | self.y_st = th * 3 | |
123 | ||
124 | f = wxFont(sizef, self.font, wxNORMAL, self.bold) | |
125 | self.DC.SetFont(f) | |
126 | self.DC.DrawText(year, adjust, 10) | |
127 | ||
128 | # draw the week days | |
129 | ||
130 | def DrawWeek(self): | |
131 | sizef = 10 | |
132 | if self.sizeh < _MIDSIZE: | |
133 | sizef = 8 | |
134 | ||
135 | f = wxFont(sizef, self.font, wxNORMAL, self.bold) | |
136 | self.DC.SetFont(f) | |
137 | ||
138 | cnt_x = 0 | |
139 | cnt_y = 0 | |
140 | width = self.gridx[1]-self.gridx[0] | |
141 | height = self.gridy[1] - self.gridy[0] | |
142 | ||
143 | for val in CalDays: | |
144 | day = AbrWeekday[val] | |
145 | if self.sizew < 200: | |
146 | day = day[0] | |
147 | dw,dh = self.DC.GetTextExtent(day) | |
148 | diffx = (width-dw)/2 | |
149 | diffy = (height-dh)/2 | |
150 | ||
151 | x = self.gridx[cnt_x] | |
152 | y = self.gridy[cnt_y] | |
153 | self.DC.DrawText(day, x+diffx, y+diffy) | |
154 | cnt_x = cnt_x + 1 | |
155 | ||
156 | # draw the day numbers | |
157 | ||
158 | def DrawNum(self): | |
159 | sizef = 10 | |
160 | if self.sizeh < _MIDSIZE: | |
161 | sizef = 8 | |
162 | f = wxFont(sizef, self.font, wxNORMAL, self.bold) | |
163 | self.DC.SetFont(f) | |
164 | ||
165 | cnt_x = 0 | |
166 | cnt_y = 1 | |
167 | for val in self.cal: | |
168 | x = self.gridx[cnt_x] | |
169 | y = self.gridy[cnt_y] | |
170 | self.DC.DrawText(val, x+5, y+5) | |
171 | if cnt_x < 6: | |
172 | cnt_x = cnt_x + 1 | |
173 | else: | |
174 | cnt_x = 0 | |
175 | cnt_y = cnt_y + 1 | |
176 | ||
177 | # calculate the dimensions in the center of the drawing area | |
178 | ||
179 | def Center(self): | |
180 | self.x_st = 10 | |
181 | self.y_end = 10 | |
182 | ||
183 | bdw = self.x_st * 2 | |
184 | bdh = self.y_st + self.y_end | |
185 | ||
186 | self.dl_w = (self.sizew-bdw)/7 | |
187 | self.dl_h = (self.sizeh-bdh)/7 | |
188 | ||
189 | self.cwidth = self.dl_w * 7 | |
190 | self.cheight = self.dl_h * 6 + self.dl_h/2 | |
191 | ||
192 | # highlighted selectioned days | |
193 | ||
194 | def DrawSel(self, sel_lst): | |
195 | for key in sel_lst: | |
196 | brush = wxBrush(wxNamedColour(self.high_color), wxSOLID) | |
197 | self.DC.SetBrush(brush) | |
198 | if self.hide_grid is FALSE: | |
199 | self.DC.SetPen(wxPen(wxNamedColour(self.grid_color), 0)) | |
200 | else: | |
201 | self.DC.SetPen(wxPen(wxNamedColour(self.back_color), 0)) | |
202 | nkey = key + self.st_pos -1 | |
203 | rect = self.rg[nkey] | |
204 | self.DC.DrawRectangle(rect.x, rect.y, rect.width+1, rect.height+1) | |
205 | ||
206 | # calculate and draw the grid lines | |
207 | ||
208 | def DrawGrid(self): | |
209 | self.DC.SetPen(wxPen(wxNamedColour(self.grid_color), 0)) | |
210 | ||
211 | self.gridx = [] | |
212 | self.gridy = [] | |
213 | ||
214 | x1 = self.x_st | |
215 | y1 = self.y_st | |
216 | y1 = self.y_st | |
217 | y2 = self.y_st + self.cheight | |
218 | for i in range(8): | |
219 | if self.hide_grid is FALSE: | |
220 | self.DC.DrawLine(x1, y1, x1, y2) | |
221 | self.gridx.append(x1) | |
222 | x1 = x1 + self.dl_w | |
223 | ||
224 | x1 = self.x_st | |
225 | y1 = self.y_st | |
226 | x2 = self.x_st + self.cwidth | |
227 | for i in range(8): | |
228 | if self.hide_grid is FALSE: | |
229 | self.DC.DrawLine(x1, y1, x2, y1) | |
230 | self.gridy.append(y1) | |
231 | if i == 0: | |
232 | y1 = y1 + self.dl_h/2 | |
233 | else: | |
234 | y1 = y1 + self.dl_h | |
235 | ||
236 | ||
237 | class wxCalendar(wxWindow): | |
238 | def __init__(self, parent, id, pos=wxDefaultPosition, size=wxDefaultSize): | |
239 | wxWindow.__init__(self, parent, id, pos, size) | |
240 | ||
241 | # set the calendar control attributes | |
242 | ||
243 | self.grid_color = 'BLACK' | |
244 | self.back_color = 'WHITE' | |
245 | self.sel_color = 'RED' | |
246 | self.high_color = 'LIGHT BLUE' | |
247 | self.font = wxSWISS | |
248 | self.bold = wxNORMAL | |
249 | ||
250 | self.SetBackgroundColour(wxNamedColor(self.back_color)) | |
251 | self.Connect(-1, -1, wxEVT_LEFT_DOWN, self.OnLeftEvent) | |
252 | self.Connect(-1, -1, wxEVT_LEFT_DCLICK, self.OnLeftDEvent) | |
253 | self.Connect(-1, -1, wxEVT_RIGHT_DOWN, self.OnRightEvent) | |
254 | self.Connect(-1, -1, wxEVT_RIGHT_DCLICK, self.OnRightDEvent) | |
255 | ||
256 | self.sel_key = None # last used by | |
257 | self.sel_lst = [] # highlighted selected days | |
258 | ||
259 | self.SetNow() # default calendar for current month | |
260 | ||
261 | self.size = None | |
262 | self.hide_title = FALSE | |
263 | self.hide_grid = FALSE | |
264 | self.set_day = None | |
265 | ||
266 | # control some of the main calendar attributes | |
267 | ||
268 | def HideTitle(self): | |
269 | self.hide_title = TRUE | |
270 | ||
271 | def HideGrid(self): | |
272 | self.hide_grid = TRUE | |
273 | ||
274 | # determine the calendar rectangle click area and draw a selection | |
275 | ||
276 | def ProcessClick(self, event): | |
277 | self.x, self.y = event.GetX(), event.GetY() | |
278 | key = self.GetDayHit(self.x, self.y) | |
279 | self.SelectDay(key) | |
280 | ||
281 | # tab mouse click events and process | |
282 | ||
283 | def OnLeftEvent(self, event): | |
284 | self.click = 'LEFT' | |
285 | self.ProcessClick(event) | |
286 | ||
287 | def OnLeftDEvent(self, event): | |
288 | self.click = 'DLEFT' | |
289 | self.ProcessClick(event) | |
290 | ||
291 | def OnRightEvent(self, event): | |
292 | self.click = 'RIGHT' | |
293 | self.ProcessClick(event) | |
294 | ||
295 | def OnRightDEvent(self, event): | |
296 | self.click = 'DRIGHT' | |
297 | self.ProcessClick(event) | |
298 | ||
299 | def SetSize(self, set_size): | |
300 | self.size = set_size | |
301 | ||
302 | def SetSelDay(self, sel): | |
303 | self.sel_lst = sel # list of highlighted days | |
304 | ||
305 | # get the current date | |
306 | ||
307 | def SetNow(self): | |
308 | dt = now() | |
309 | self.month = dt.month | |
310 | self.year = dt.year | |
311 | self.day = dt.day | |
312 | ||
313 | # set the current day | |
314 | ||
315 | def SetCurrentDay(self): | |
316 | self.SetNow() | |
317 | self.set_day = self.day | |
318 | ||
319 | # get the date, day, month, year set in calendar | |
320 | ||
321 | def GetDate(self): | |
322 | return self.day, self.month, self.year | |
323 | ||
324 | def GetDay(self): | |
325 | return self.day | |
326 | ||
327 | def GetMonth(self): | |
328 | return self.month | |
329 | ||
330 | def GetYear(self): | |
331 | return self.year | |
332 | ||
333 | # set the day, month, and year | |
334 | ||
335 | def SetDayValue(self, day): | |
336 | self.set_day = day | |
337 | ||
338 | def SetMonth(self, month): | |
339 | if month >= 1 and month <= 12: | |
340 | self.month = month | |
341 | else: | |
342 | self.month = 1 | |
343 | self.set_day = None | |
344 | ||
345 | def SetYear(self, year): | |
346 | self.year = year | |
347 | ||
348 | # increment year and month | |
349 | ||
350 | def IncYear(self): | |
351 | self.year = self.year + 1 | |
352 | self.set_day = None | |
353 | ||
354 | def DecYear(self): | |
355 | self.year = self.year - 1 | |
356 | self.set_day = None | |
357 | ||
358 | def IncMonth(self): | |
359 | self.month = self.month + 1 | |
360 | if self.month > 12: | |
361 | self.month = 1 | |
362 | self.year = self.year + 1 | |
363 | self.set_day = None | |
364 | ||
365 | def DecMonth(self): | |
366 | self.month = self.month - 1 | |
367 | if self.month < 1: | |
368 | self.month = 12 | |
369 | self.year = self.year - 1 | |
370 | self.set_day = None | |
371 | ||
372 | # test to see if the selection has a date and create event | |
373 | ||
374 | def TestDay(self, key): | |
375 | try: | |
376 | self.day = int(self.cal[key]) | |
377 | except: | |
378 | return None | |
379 | if self.day == "": | |
380 | return None | |
381 | else: | |
382 | evt = wxPyCommandEvent(2100, self.GetId()) | |
383 | evt.click, evt.day, evt.month, evt.year = self.click, self.day, self.month, self.year | |
384 | self.GetEventHandler().ProcessEvent(evt) | |
385 | ||
386 | self.set_day = self.day | |
387 | return key | |
388 | ||
389 | # find the clicked area rectangle | |
390 | ||
391 | def GetDayHit(self, mx, my): | |
392 | for key in self.rg.keys(): | |
393 | val = self.rg[key] | |
394 | rt = wxRegion() | |
395 | rt.UnionRect(val) | |
396 | if rt.Contains(mx, my) != 0: | |
397 | result = self.TestDay(key) | |
398 | return result | |
399 | return None | |
400 | ||
401 | # calendar drawing | |
402 | ||
403 | def OnPaint(self, event): | |
404 | DC = wxPaintDC(self) | |
405 | self.DoDrawing(DC) | |
406 | ||
407 | def DoDrawing(self, DC): | |
408 | DC = wxPaintDC(self) | |
409 | DC.BeginDrawing() | |
410 | ||
411 | self.cal = cal = CalDraw() | |
412 | if self.size is None: | |
413 | size = self.GetClientSize() | |
414 | else: | |
415 | size = self.size | |
416 | ||
417 | # drawing attributes | |
418 | ||
419 | cal.hide_title = self.hide_title | |
420 | cal.hide_grid = self.hide_grid | |
421 | ||
422 | cal.grid_color = self.grid_color | |
423 | cal.high_color = self.high_color | |
424 | cal.back_color = self.back_color | |
425 | cal.font = self.font | |
426 | cal.bold = self.bold | |
427 | ||
428 | cal.SetSize(size) | |
429 | cal.SetCal(self.year, self.month) | |
430 | cal.DrawCal(DC, self.sel_lst) | |
431 | ||
432 | self.rg = cal.GetRect() | |
433 | self.cal = cal.GetCal() | |
434 | self.st_pos = cal.GetOffset() | |
435 | self.ymax = DC.MaxY() | |
436 | ||
437 | if self.set_day != None: | |
438 | self.SetDay(self.set_day) | |
439 | DC.EndDrawing() | |
440 | ||
441 | # draw the selection rectangle | |
442 | ||
443 | def DrawRect(self, key, color = 'BLACK', width = 0): | |
444 | if key == None: | |
445 | return | |
446 | DC = wxClientDC(self) | |
447 | DC.BeginDrawing() | |
448 | ||
449 | brush = wxBrush(wxColour(0, 0xFF, 0x80), wxTRANSPARENT) | |
450 | DC.SetBrush(brush) | |
451 | DC.SetPen(wxPen(wxNamedColour(color), width)) | |
452 | ||
453 | rect = self.rg[key] | |
454 | DC.DrawRectangle(rect.x, rect.y, rect.width+1, rect.height+1) | |
455 | ||
456 | DC.EndDrawing() | |
457 | ||
458 | # set the day selection | |
459 | ||
460 | def SetDay(self, day): | |
461 | day = day + self.st_pos - 1 | |
462 | self.SelectDay(day) | |
463 | ||
464 | def SelectDay(self, key): | |
465 | sel_size = 1 | |
466 | self.DrawRect(self.sel_key, self.back_color, sel_size) # clear large selection | |
467 | if self.hide_grid is FALSE: | |
468 | self.DrawRect(self.sel_key, self.grid_color) | |
469 | ||
470 | self.DrawRect(key, self.sel_color, sel_size) | |
471 | self.sel_key = key # store last used by | |
472 | self.select_day = None | |
473 | ||
474 | def ClearDsp(self): | |
475 | self.Clear() | |
476 | ||
477 |