Package Gnumed :: Package timelinelib :: Package wxgui :: Package components :: Module wxdatetimepicker
[frames] | no frames]

Source Code for Module Gnumed.timelinelib.wxgui.components.wxdatetimepicker

  1  # Copyright (C) 2009, 2010, 2011  Rickard Lindberg, Roger Lindberg 
  2  # 
  3  # This file is part of Timeline. 
  4  # 
  5  # Timeline is free software: you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation, either version 3 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # Timeline is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License 
 16  # along with Timeline.  If not, see <http://www.gnu.org/licenses/>. 
 17   
 18   
 19  import os.path 
 20   
 21  import wx.calendar 
 22   
 23  from timelinelib.config.paths import ICONS_DIR 
 24  from timelinelib.time import try_to_create_wx_date_time_from_dmy 
 25  from timelinelib.time import WxTimeType 
 26  from timelinelib.wxgui.utils import _display_error_message 
 27   
 28   
29 -class WxDateTimePicker(wx.Panel):
30
31 - def __init__(self, parent, show_time=True, config=None):
32 wx.Panel.__init__(self, parent) 33 self.config = config 34 self._create_gui() 35 self.controller = WxDateTimePickerController( 36 self.date_picker, self.time_picker, wx.DateTime.Now) 37 self.show_time(show_time)
38
39 - def show_time(self, show=True):
40 self.time_picker.Show(show) 41 self.GetSizer().Layout()
42
43 - def set_value(self, value):
44 self.controller.set_value(value)
45
46 - def get_value(self):
47 return self.controller.get_value()
48
49 - def _create_gui(self):
50 self.date_picker = WxDatePicker(self) 51 self.date_button = self._create_date_button() 52 self.time_picker = WxTimePicker(self) 53 self._layout_controls()
54
55 - def _create_date_button(self):
56 image = wx.Bitmap(os.path.join(ICONS_DIR, "calendar.png")) 57 date_button = wx.BitmapButton(self, bitmap=image) 58 self.Bind(wx.EVT_BUTTON, self._date_button_on_click, date_button) 59 return date_button
60
61 - def _layout_controls(self):
62 sizer = wx.BoxSizer(wx.HORIZONTAL) 63 flags = wx.ALIGN_CENTER_VERTICAL 64 sizer.Add(self.date_picker, proportion=1, flag=flags) 65 sizer.Add(self.date_button, proportion=0, flag=flags) 66 sizer.Add(self.time_picker, proportion=0, flag=flags) 67 self.SetSizerAndFit(sizer)
68
69 - def _date_button_on_click(self, evt):
70 try: 71 self.calendar_popup = self._create_calendar_popup() 72 self._position_calendar_popup(evt) 73 self.calendar_popup.Popup() 74 except: 75 _display_error_message(_("Invalid date"))
76
77 - def _create_calendar_popup(self):
78 wx_date = self.controller.get_value() 79 calendar_popup = CalendarPopup(self, wx_date, self.config) 80 calendar_popup.Bind(wx.calendar.EVT_CALENDAR_SEL_CHANGED, 81 self._calendar_on_date_changed) 82 calendar_popup.Bind(wx.calendar.EVT_CALENDAR, 83 self._calendar_on_date_changed_dclick) 84 return calendar_popup
85
86 - def _position_calendar_popup(self, evt):
87 btn = evt.GetEventObject() 88 pos = btn.ClientToScreen((0,0)) 89 size = btn.GetSize() 90 self.calendar_popup.Position(pos, (0, size[1]))
91
92 - def _calendar_on_date_changed(self, evt):
93 wx_date = evt.GetEventObject().GetDate() 94 self.date_picker.set_date(wx_date)
95
96 - def _calendar_on_date_changed_dclick(self, evt):
97 self.time_picker.SetFocus() 98 self.calendar_popup.Dismiss()
99 100
101 -class WxDateTimePickerController(object):
102
103 - def __init__(self, date_picker, time_picker, now_fn):
104 self.date_picker = date_picker 105 self.time_picker = time_picker 106 self.now_fn = now_fn
107
108 - def set_value(self, date_time):
109 if date_time == None: 110 date_time = self.now_fn() 111 self.date_picker.set_date(date_time) 112 self.time_picker.set_time(date_time)
113
114 - def get_value(self):
115 wx_date = self.date_picker.get_date() 116 if self.time_picker.IsShown(): 117 wx_time = self.time_picker.get_time() 118 wx_date.SetHour(wx_time.GetHour()) 119 wx_date.SetMinute(wx_time.GetMinute()) 120 return wx_date
121 122
123 -class CalendarPopup(wx.PopupTransientWindow):
124
125 - def __init__(self, parent, wx_date, config):
126 self.config = config 127 self.controller = CalendarPopupController(self) 128 wx.PopupTransientWindow.__init__(self, parent, style=wx.BORDER_NONE) 129 border = 2 130 style = self._get_cal_style() 131 self.cal = wx.calendar.CalendarCtrl(self, -1, wx_date, 132 pos=(border,border), style=style) 133 self._set_cal_range() 134 self._set_size(border) 135 self._bind_events()
136
137 - def _get_cal_style(self):
138 style = (wx.calendar.CAL_SHOW_HOLIDAYS | 139 wx.calendar.CAL_SEQUENTIAL_MONTH_SELECTION) 140 if self.config.week_start == "monday": 141 style |= wx.calendar.CAL_MONDAY_FIRST 142 else: 143 style |= wx.calendar.CAL_SUNDAY_FIRST 144 return style
145
146 - def _set_cal_range(self):
147 min_date, msg = WxTimeType().get_min_time() 148 max_date, msg = WxTimeType().get_max_time() 149 max_date -= wx.DateSpan.Day() 150 self.cal.SetDateRange(min_date, max_date)
151
152 - def _set_size(self, border):
153 size = self.cal.GetBestSize() 154 self.SetSize((size.width + border * 2, size.height + border * 2))
155
156 - def _bind_events(self):
157 def on_month(evt): 158 self.controller.on_month()
159 def on_day(evt): 160 self.controller.on_day()
161 self.cal.Bind(wx.calendar.EVT_CALENDAR_MONTH, on_month) 162 self.cal.Bind(wx.calendar.EVT_CALENDAR_DAY, on_day) 163
164 - def OnDismiss(self):
165 self.controller.on_dismiss()
166 167
168 -class CalendarPopupController(object):
169
170 - def __init__(self, calendar_popup):
171 self.calendar_popup = calendar_popup 172 self.repop = False 173 self.repoped = False
174
175 - def on_month(self):
176 self.repop = True
177
178 - def on_day(self):
179 self.repop = True
180
181 - def on_dismiss(self):
182 # This funny code makes the calender control stay open when you change 183 # month or day. The control is closed on a double-click on a day or 184 # a single click outside of the control 185 if self.repop and not self.repoped: 186 self.calendar_popup.Popup() 187 self.repoped = True
188 189
190 -class WxDatePicker(wx.TextCtrl):
191
192 - def __init__(self, parent):
193 wx.TextCtrl.__init__(self, parent, style=wx.TE_PROCESS_ENTER) 194 self.controller = WxDatePickerController(self) 195 self._bind_events() 196 self._resize_to_fit_text()
197
198 - def get_date(self):
199 return self.controller.get_date()
200
201 - def set_date(self, wx_date):
202 self.controller.set_date(wx_date)
203
204 - def get_date_string(self):
205 return self.GetValue()
206
207 - def set_date_string(self, date_string):
208 return self.SetValue(date_string)
209
210 - def _bind_events(self):
211 self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus) 212 self.Bind(wx.EVT_KILL_FOCUS, self._on_kill_focus) 213 self.Bind(wx.EVT_CHAR, self._on_char) 214 self.Bind(wx.EVT_TEXT, self._on_text) 215 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
216
217 - def _on_set_focus(self, evt):
218 # CallAfter is a trick to prevent default behavior of selecting all 219 # text when a TextCtrl is given focus 220 wx.CallAfter(self.controller.on_set_focus)
221
222 - def _on_kill_focus(self, evt):
223 # Trick to not make selection text disappear when focus is lost (we 224 # remove the selection instead) 225 self.controller.on_kill_focus() 226 self.SetSelection(0, 0)
227
228 - def _on_char(self, evt):
229 if evt.GetKeyCode() == wx.WXK_TAB: 230 if evt.ShiftDown(): 231 skip = self.controller.on_shift_tab() 232 else: 233 skip = self.controller.on_tab() 234 else: 235 skip = True 236 evt.Skip(skip)
237
238 - def _on_text(self, evt):
239 self.controller.on_text_changed()
240
241 - def _on_key_down(self, evt):
242 if evt.GetKeyCode() == wx.WXK_UP: 243 self.controller.on_up() 244 elif evt.GetKeyCode() == wx.WXK_DOWN: 245 self.controller.on_down() 246 else: 247 evt.Skip()
248
249 - def _resize_to_fit_text(self):
250 w, h = self.GetTextExtent("0000-00-00") 251 width = w + 20 252 self.SetMinSize((width, -1))
253 254
255 -class WxDatePickerController(object):
256
257 - def __init__(self, py_date_picker, error_bg="pink"):
258 self.wx_date_picker = py_date_picker 259 self.error_bg = error_bg 260 self.original_bg = self.wx_date_picker.GetBackgroundColour() 261 self.separator = WxTimeType().event_date_string(WxTimeType().now())[4] 262 self.region_year = 0 263 self.region_month = 1 264 self.region_day = 2 265 self.region_siblings = ((self.region_year, self.region_month), 266 (self.region_month, self.region_day)) 267 self.preferred_day = None 268 self.save_preferred_day = True 269 self.last_selection = None
270
271 - def get_date(self):
272 try: 273 (year, month, day) = self._parse_year_month_day() 274 if year == 0: 275 raise ValueError("Invalid date.") 276 if year < 0: 277 year +=1 278 wx_date = try_to_create_wx_date_time_from_dmy(day, month - 1, year) 279 self._ensure_date_within_allowed_period(wx_date) 280 return wx_date 281 except ValueError: 282 raise ValueError("Invalid date.")
283
284 - def set_date(self, wx_date):
285 bc_year = wx.DateTime.ConvertYearToBC(wx_date.Year) 286 tmp_date = wx.DateTimeFromDMY(wx_date.Day, wx_date.Month, bc_year) 287 date_string = WxTimeType().event_date_string(tmp_date) 288 self.wx_date_picker.set_date_string(date_string)
289
290 - def on_set_focus(self):
291 if self.last_selection: 292 start, end = self.last_selection 293 self.wx_date_picker.SetSelection(start, end) 294 else: 295 self._select_region_if_possible(self.region_year) 296 self.last_selection = self.wx_date_picker.GetSelection()
297
298 - def on_kill_focus(self):
299 if self.last_selection: 300 self.last_selection = self.wx_date_picker.GetSelection()
301
302 - def on_tab(self):
303 for (left_region, right_region) in self.region_siblings: 304 if self._insertion_point_in_region(left_region): 305 self._select_region_if_possible(right_region) 306 return False 307 return True
308
309 - def on_shift_tab(self):
310 for (left_region, right_region) in self.region_siblings: 311 if self._insertion_point_in_region(right_region): 312 self._select_region_if_possible(left_region) 313 return False 314 return True
315
316 - def on_text_changed(self):
317 self._change_background_depending_on_date_validity() 318 if self._current_date_is_valid(): 319 current_date = self.get_date() 320 # To prevent saving of preferred day when year or month is changed 321 # in on_up() and on_down()... 322 # Save preferred day only when text is entered in the date text 323 # control and not when up or down keys has been used. 324 # When up and down keys are used, the preferred day is saved in 325 # on_up() and on_down() only when day is changed. 326 if self.save_preferred_day: 327 self._save_preferred_day(current_date)
328
329 - def on_up(self):
330 if not self._current_date_is_valid(): 331 return 332 if self._insertion_point_in_region(self.region_year): 333 new_date = self._increment_year() 334 elif self._insertion_point_in_region(self.region_month): 335 new_date = self._increment_month() 336 else: 337 new_date = self._increment_day() 338 self._save_preferred_day(new_date) 339 self._set_new_date_and_restore_selection(new_date)
340
341 - def on_down(self):
342 if not self._current_date_is_valid(): 343 return 344 if self._insertion_point_in_region(self.region_year): 345 new_date = self._decrement_year() 346 elif self._insertion_point_in_region(self.region_month): 347 new_date = self._decrement_month() 348 else: 349 new_date = self._decrement_day() 350 self._save_preferred_day(new_date) 351 self._set_new_date_and_restore_selection(new_date)
352
353 - def _increment_year(self):
354 date = self.get_date() 355 if date.Year < WxTimeType().get_max_time()[0].Year - 1: 356 date = self._set_valid_day(date.Year + 1, date.Month, date.Day) 357 return date
358
359 - def _increment_month(self):
360 date = self.get_date() 361 if date.Month < 11: 362 date = self._set_valid_day(date.Year, date.Month + 1, date.Day) 363 elif date.Year < WxTimeType().get_max_time()[0].Year - 1: 364 date = self._set_valid_day(date.Year + 1, 0, date.Day) 365 return date
366
367 - def _increment_day(self):
368 date = self.get_date() 369 if date < WxTimeType().get_max_time()[0] - wx.TimeSpan.Day(): 370 date = date + wx.DateSpan.Day() 371 return date
372
373 - def _decrement_year(self):
374 date = self.get_date() 375 if date.Year > WxTimeType().get_min_time()[0].Year: 376 date = self._set_valid_day(date.Year - 1, date.Month, date.Day) 377 return date
378
379 - def _decrement_month(self):
380 date = self.get_date() 381 if date.Month > 0: 382 date = self._set_valid_day(date.Year, date.Month - 1, date.Day) 383 elif date.Year > WxTimeType().get_min_time()[0].Year: 384 date = self._set_valid_day(date.Year - 1, 11, date.Day) 385 return date
386
387 - def _decrement_day(self):
388 date = self.get_date() 389 if date.Day > 1: 390 date.SetDay(date.Day - 1) 391 elif date.Month > 0: 392 date = self._set_valid_day(date.Year, date.Month - 1, 31) 393 elif date.Year > WxTimeType().get_min_time()[0].Year: 394 date = self._set_valid_day(date.Year - 1, 11, 31) 395 return date
396
398 if self._current_date_is_valid(): 399 color = self.original_bg 400 else: 401 color = self.error_bg 402 self.wx_date_picker.SetBackgroundColour(color) 403 self.wx_date_picker.SetFocus() 404 self.wx_date_picker.Refresh()
405
406 - def _parse_year_month_day(self):
407 date_string = self.wx_date_picker.get_date_string() 408 date_bc = False 409 if (date_string[0:1] == self.separator): 410 date_string = date_string[1:] 411 date_bc = True 412 components = date_string.split(self.separator) 413 if len(components) != 3: 414 raise ValueError() 415 year = int(components[self.region_year]) 416 if date_bc: 417 year = -year 418 month = int(components[self.region_month]) 419 day = int(components[self.region_day]) 420 return (year, month, day)
421
422 - def _ensure_date_within_allowed_period(self, wx_date):
423 if (wx_date >= WxTimeType().get_max_time()[0] or 424 wx_date < WxTimeType().get_min_time()[0]): 425 raise ValueError()
426
427 - def _set_new_date_and_restore_selection(self, new_date):
428 def restore_selection(selection): 429 self.wx_date_picker.SetSelection(selection[0], selection[1])
430 selection = self.wx_date_picker.GetSelection() 431 self.save_preferred_day = False 432 if self.preferred_day != None: 433 new_date = self._set_valid_day(new_date.Year, new_date.Month, 434 self.preferred_day) 435 self.set_date(new_date) 436 restore_selection(selection) 437 self.save_preferred_day = True
438
439 - def _set_valid_day(self, new_year, new_month, new_day):
440 while True: 441 try: 442 return try_to_create_wx_date_time_from_dmy(new_day, new_month, new_year) 443 except ValueError: 444 new_day -= 1
445
446 - def _save_preferred_day(self, date):
447 day = date.Day 448 if day > 28: 449 self.preferred_day = day 450 else: 451 self.preferred_day = None
452
453 - def _current_date_is_valid(self):
454 try: 455 self.get_date() 456 except ValueError: 457 return False 458 return True
459
460 - def _select_region_if_possible(self, region):
461 region_range = self._get_region_range(region) 462 if region_range: 463 self.wx_date_picker.SetSelection(region_range[0], region_range[-1])
464
465 - def _insertion_point_in_region(self, n):
466 region_range = self._get_region_range(n) 467 if region_range: 468 return self.wx_date_picker.GetInsertionPoint() in region_range
469
470 - def _get_region_range(self, n):
471 # Returns a range of valid cursor positions for a valid region year, 472 # month or day. 473 def region_is_not_valid(region): 474 return region not in (self.region_year, self.region_month, 475 self.region_day)
476 def date_has_exactly_two_seperators(datestring): 477 return len(datestring.split(self.separator)) == 3 478 def calculate_pos_range(region, datestring): 479 pos_of_separator1 = datestring.find(self.separator) 480 pos_of_separator2 = datestring.find(self.separator, 481 pos_of_separator1 + 1) 482 if region == self.region_year: 483 return range(0, pos_of_separator1 + 1) 484 elif region == self.region_month: 485 return range(pos_of_separator1 + 1, pos_of_separator2 + 1) 486 else: 487 return range(pos_of_separator2 + 1, len(datestring) + 1) 488 if region_is_not_valid(n): 489 return None 490 date = self.wx_date_picker.get_date_string() 491 if not date_has_exactly_two_seperators(date): 492 return None 493 pos_range = calculate_pos_range(n, date) 494 return pos_range 495 496
497 -class WxTimePicker(wx.TextCtrl):
498
499 - def __init__(self, parent):
500 wx.TextCtrl.__init__(self, parent, style=wx.TE_PROCESS_ENTER) 501 self.controller = WxTimePickerController(self) 502 self._bind_events() 503 self._resize_to_fit_text()
504
505 - def get_time(self):
506 return self.controller.get_time()
507
508 - def set_time(self, wx_time):
509 self.controller.set_time(wx_time)
510
511 - def get_time_string(self):
512 return self.GetValue()
513
514 - def set_time_string(self, time_string):
516
517 - def _bind_events(self):
518 self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus) 519 self.Bind(wx.EVT_KILL_FOCUS, self._on_kill_focus) 520 self.Bind(wx.EVT_CHAR, self._on_char) 521 self.Bind(wx.EVT_TEXT, self._on_text) 522 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
523
524 - def _on_set_focus(self, evt):
525 # CallAfter is a trick to prevent default behavior of selecting all 526 # text when a TextCtrl is given focus 527 wx.CallAfter(self.controller.on_set_focus)
528
529 - def _on_kill_focus(self, evt):
530 # Trick to not make selection text disappear when focus is lost (we 531 # remove the selection instead) 532 self.controller.on_kill_focus() 533 self.SetSelection(0, 0)
534
535 - def _on_char(self, evt):
536 if evt.GetKeyCode() == wx.WXK_TAB: 537 if evt.ShiftDown(): 538 skip = self.controller.on_shift_tab() 539 else: 540 skip = self.controller.on_tab() 541 else: 542 skip = True 543 evt.Skip(skip)
544
545 - def _on_text(self, evt):
546 self.controller.on_text_changed()
547
548 - def _on_key_down(self, evt):
549 if evt.GetKeyCode() == wx.WXK_UP: 550 self.controller.on_up() 551 elif evt.GetKeyCode() == wx.WXK_DOWN: 552 self.controller.on_down() 553 else: 554 evt.Skip()
555
556 - def _resize_to_fit_text(self):
557 w, h = self.GetTextExtent("00:00") 558 width = w + 20 559 self.SetMinSize((width, -1))
560 561
562 -class WxTimePickerController(object):
563
564 - def __init__(self, wx_time_picker):
565 self.wx_time_picker = wx_time_picker 566 self.original_bg = self.wx_time_picker.GetBackgroundColour() 567 self.separator = WxTimeType().event_time_string(WxTimeType().now())[2] 568 self.hour_part = 0 569 self.minute_part = 1 570 self.last_selection = None
571
572 - def get_time(self):
573 try: 574 split = self.wx_time_picker.get_time_string().split(self.separator) 575 if len(split) != 2: 576 raise ValueError() 577 hour_string, minute_string = split 578 hour = int(hour_string) 579 minute = int(minute_string) 580 return wx.DateTimeFromHMS(hour, minute, 0) 581 except ValueError: 582 raise ValueError("Invalid time.")
583
584 - def set_time(self, wx_time):
585 time_string = WxTimeType().event_time_string(wx_time) 586 self.wx_time_picker.set_time_string(time_string)
587
588 - def on_set_focus(self):
589 if self.last_selection: 590 start, end = self.last_selection 591 self.wx_time_picker.SetSelection(start, end) 592 else: 593 self._select_part(self.hour_part)
594
595 - def on_kill_focus(self):
596 self.last_selection = self.wx_time_picker.GetSelection()
597
598 - def on_tab(self):
599 if self._in_minute_part(): 600 return True 601 self._select_part(self.minute_part) 602 return False
603
604 - def on_shift_tab(self):
605 if self._in_hour_part(): 606 return True 607 self._select_part(self.hour_part) 608 return False
609
610 - def on_text_changed(self):
611 try: 612 self.get_time() 613 self.wx_time_picker.SetBackgroundColour(self.original_bg) 614 except ValueError: 615 self.wx_time_picker.SetBackgroundColour("pink") 616 self.wx_time_picker.Refresh()
617
618 - def on_up(self):
619 if not self._time_is_valid(): 620 return 621 if self._in_hour_part(): 622 new_time = self._increment_hour() 623 else: 624 new_time = self._increment_minutes() 625 self._set_new_time_and_restore_selection(new_time)
626
627 - def on_down(self):
628 if not self._time_is_valid(): 629 return 630 if self._in_hour_part(): 631 new_time = self._decrement_hour() 632 else: 633 new_time = self._decrement_minutes() 634 self._set_new_time_and_restore_selection(new_time)
635
636 - def _increment_hour(self):
637 time = self.get_time() 638 new_hour = time.Hour + 1 639 if new_hour > 23: 640 new_hour = 0 641 time.SetHour(new_hour) 642 return time
643
644 - def _increment_minutes(self):
645 time = self.get_time() 646 new_hour = time.Hour 647 new_minute = time.Minute + 1 648 if new_minute > 59: 649 new_minute = 0 650 new_hour = time.Hour + 1 651 if new_hour > 23: 652 new_hour = 0 653 time.SetHour(new_hour) 654 time.SetMinute(new_minute) 655 return time
656
657 - def _decrement_hour(self):
658 time = self.get_time() 659 new_hour = time.Hour - 1 660 if new_hour < 0: 661 new_hour = 23 662 time.SetHour(new_hour) 663 return time
664
665 - def _decrement_minutes(self):
666 time = self.get_time() 667 new_hour = time.Hour 668 new_minute = time.Minute - 1 669 if new_minute < 0: 670 new_minute = 59 671 new_hour = time.Hour - 1 672 if new_hour < 0: 673 new_hour = 23 674 time.SetHour(new_hour) 675 time.SetMinute(new_minute) 676 return time
677
678 - def _set_new_time_and_restore_selection(self, new_time):
679 def restore_selection(selection): 680 self.wx_time_picker.SetSelection(selection[0], selection[1])
681 selection = self.wx_time_picker.GetSelection() 682 self.set_time(new_time) 683 restore_selection(selection)
684
685 - def _time_is_valid(self):
686 try: 687 self.get_time() 688 except ValueError: 689 return False 690 return True
691
692 - def _select_part(self, part):
693 if self._separator_pos() == -1: 694 return 695 if part == self.hour_part: 696 self.wx_time_picker.SetSelection(0, self._separator_pos()) 697 else: 698 time_string_len = len(self.wx_time_picker.get_time_string()) 699 self.wx_time_picker.SetSelection(self._separator_pos() + 1, time_string_len) 700 self.preferred_part = part
701
702 - def _in_hour_part(self):
703 if self._separator_pos() == -1: 704 return 705 return self.wx_time_picker.GetInsertionPoint() <= self._separator_pos()
706
707 - def _in_minute_part(self):
708 if self._separator_pos() == -1: 709 return 710 return self.wx_time_picker.GetInsertionPoint() > self._separator_pos()
711
712 - def _separator_pos(self):
713 return self.wx_time_picker.get_time_string().find(self.separator)
714