1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import wx
20
21 from timelinelib.canvas.events import create_divider_position_changed_event
22 from timelinelib.canvas.timelinecanvascontroller import TimelineCanvasController
23 from timelinelib.wxgui.keyboard import Keyboard
24 from timelinelib.wxgui.cursor import Cursor
25 from timelinelib.canvas.data import TimePeriod
26 from timelinelib.canvas.highlighttimer import HighlightTimer
27 import timelinelib.wxgui.utils as guiutils
28
29
30 MOVE_HANDLE = 0
31 LEFT_RESIZE_HANDLE = 1
32 RIGHT_RESIZE_HANDLE = 2
33
34 HIT_REGION_PX_WITH = 5
35 HSCROLL_STEP = 25
36
37
39
40 """
41 This is the surface on which a timeline is drawn. It is also the object that handles user
42 input events such as mouse and keyboard actions.
43 """
44
45 HORIZONTAL = 8
46 VERTICAL = 16
47 BOTH = 32
48
49 START = 0
50 DRAG = 1
51 STOP = 2
52
62
65
68
70 return self._divider_position
71
76
79
82
85
88
92
95
98
100 self._controller.increment_font_size()
101
103 self._controller.decrement_font_size()
104
107
108 - def Snap(self, time):
110
111 - def PostEvent(self, event):
112 wx.PostEvent(self, event)
113
117
120
123
126
129
132
135
137 selected_events = self.GetSelectedEvents()
138 if len(selected_events) == 1:
139 return selected_events[0]
140 return None
141
144
147
150
153
156
160
161 - def GetEventAt(self, cursor, prefer_container=False):
163
166
181
185
188
191
194
197
200
203
205 wx.ImageFromBitmap(self._surface_bitmap).SaveFile(path, wx.BITMAP_TYPE_PNG)
206
211
215
218
220 self._controller.navigate(navigation_fn)
221
224
227
229 width, height = self.GetSize()
230 self._surface_bitmap = wx.Bitmap(width, height)
231 memdc = wx.MemoryDC()
232 memdc.SelectObject(self._surface_bitmap)
233 memdc.SetBackground(wx.Brush(wx.WHITE, wx.BRUSHSTYLE_SOLID))
234 memdc.Clear()
235 fn_draw(memdc)
236 del memdc
237 self.Refresh()
238 self.Update()
239
241 self.SetCursor(wx.Cursor(wx.CURSOR_SIZEWE))
242
244 self.SetCursor(wx.Cursor(wx.CURSOR_SIZING))
245
248
250 self.Zoom(1, self._get_half_width())
251
253 self.Zoom(-1, self._get_half_width())
254
255 - def Zoom(self, direction, x):
256 """ zoom time line at position x """
257 width, _ = self.GetSize()
258 x_percent_of_width = float(x) / width
259 self.Navigate(lambda tp: tp.zoom(direction, x_percent_of_width))
260
263
266
272
279
280
281
283 self._start_time = self.GetTimeAt(evt.GetX())
284
286 rotation = evt.GetWheelRotation()
287 return 1 if rotation > 0 else -1 if rotation < 0 else 0
288
290 self.Zoom(self._direction(evt), evt.GetX())
291
297
300
303
306
308
309 def cursor_has_left_event():
310
311
312 if wx.GetMouseState().LeftIsDown():
313 return False
314 else:
315 return self.GetEventAtCursor() != self._last_balloon_event
316
317 def no_balloon_at_cursor():
318 return not self.GetBalloonAtCursor()
319
320 def update_last_seen_event():
321 if self._last_balloon_event is None:
322 self._last_balloon_event = self.GetEventAtCursor()
323 elif cursor_has_left_event() and no_balloon_at_cursor():
324 self._last_balloon_event = None
325 return self._last_balloon_event
326
327 def delayed_call():
328 if self.GetAppearance().get_balloons_visible():
329 self.SetHoveredEvent(self._last_balloon_event)
330 self._waiting = False
331
332
333
334 if not self._waiting:
335 update_last_seen_event()
336 self._wating = True
337 wx.CallLater(500, delayed_call)
338
339 - def GetTimelineInfoText(self, evt):
340
341 def format_current_pos_time_string(x):
342 tm = self.GetTimeAt(x)
343 return self.GetTimeType().format_period(TimePeriod(tm, tm))
344
345 event = self.GetEventAtCursor()
346 if event:
347 return event.get_label(self.GetTimeType())
348 else:
349 return format_current_pos_time_string(evt.GetX())
350
352
353 def get_cursor():
354 return Cursor(evt.GetX(), evt.GetY())
355
356 def get_keyboard():
357 return Keyboard(evt.ControlDown(), evt.ShiftDown(), evt.AltDown())
358
359 def hit_resize_handle():
360 try:
361 event, hit_info = self.GetEventWithHitInfoAt(get_cursor(), get_keyboard())
362 if event.get_locked():
363 return None
364 if event.is_milestone():
365 return None
366 if not self.IsEventSelected(event):
367 return None
368 if hit_info == LEFT_RESIZE_HANDLE:
369 return wx.LEFT
370 if hit_info == RIGHT_RESIZE_HANDLE:
371 return wx.RIGHT
372 return None
373 except:
374 return None
375
376 def hit_move_handle():
377 event_and_hit_info = self.GetEventWithHitInfoAt(get_cursor(), get_keyboard())
378 if event_and_hit_info is None:
379 return False
380 (event, hit_info) = event_and_hit_info
381 if event.get_locked():
382 return False
383 if not self.IsEventSelected(event):
384 return False
385 if event.get_ends_today():
386 return False
387 return hit_info == MOVE_HANDLE
388
389 def over_resize_handle():
390 return hit_resize_handle() is not None
391
392 def over_move_handle():
393 return hit_move_handle()
394
395 if over_resize_handle():
396 self.set_size_cursor()
397 elif over_move_handle():
398 self.set_move_cursor()
399 else:
400 self.set_default_cursor()
401
405
407
408 def get_cursor():
409 return Cursor(evt.GetX(), evt.GetY())
410
411 event = self.GetEventAt(get_cursor(), evt.AltDown())
412 if event:
413 self.SetEventSelected(event, not self.IsEventSelected(event))
414
418
424
434
437
439 self._selecting = False
440
442 self._selecting = True
443 self._cursor = self.GetCursor(evt)
444
450
452 return Cursor(evt.GetX(), evt.GetY())
453
459
461 self._zooming = False
462
464 self._zooming = True
465 self._start_time = self.GetTimeAt(evt.GetX())
466 self._end_time = self.GetTimeAt(evt.GetX())
467
472
477
479 self._period_select = False
480
482 self._period_select = True
483 self._start_time = self.GetTimeAt(evt.GetX())
484 self._end_time = self.GetTimeAt(evt.GetX())
485
490
492 self._period_select = False
493 self.SetPeriodSelection(None)
494 return self._start_time, self._end_time
495
496 - def InitDrag(self, scroll=None, zoom=None, period_select=None, event_select=None):
514
515 def init_zoom():
516 if zoom not in self._methods:
517 self.InitZoomSelect()
518 self._methods[zoom] = (self.StartZoomSelect,
519 self.DragZoom,
520 self.StopDragZoom)
521
522 def init_period_select():
523 if not period_select in self._methods:
524 self.InitDragPeriodSelect()
525 self._methods[period_select] = (self.StartDragPeriodSelect,
526 self.DragPeriodSelect,
527 self.StopDragPeriodSelect)
528
529 def init_event_select():
530 if not event_select in self._methods:
531 self.InitDragEventSelect()
532 self._methods[event_select] = (self.StartDragEventSelect,
533 self.DragEventSelect,
534 self.StopDragEventSelect)
535
536 self._drag_scroll = scroll
537 self._drag_zoom = zoom
538 self._drag_period_select = period_select
539 self._drag_event_select = event_select
540 self._methods = {}
541
542 if scroll:
543 init_scroll()
544 if zoom:
545 init_zoom()
546 if period_select:
547 init_period_select()
548 if event_select:
549 init_event_select()
550
552
553 def calc_cotrol_keys_value(evt):
554 combo = 0
555 if evt.ControlDown():
556 combo += Keyboard.CTRL
557 if evt.ShiftDown():
558 combo += Keyboard.SHIFT
559 if evt.AltDown():
560 combo += Keyboard.ALT
561 return combo
562
563 combo = calc_cotrol_keys_value(evt)
564 if combo in self._methods:
565 if index == self.STOP:
566 self._methods[combo][index]()
567 else:
568 self._methods[combo][index](evt)
569
572
573
574
577
580
583
585 self.Bind(wx.EVT_ERASE_BACKGROUND, self._on_erase_background)
586 self.Bind(wx.EVT_PAINT, self._on_paint)
587 self.Bind(wx.EVT_SIZE, self._on_size)
588
592
594 dc = wx.AutoBufferedPaintDC(self)
595 if self._surface_bitmap:
596 dc.DrawBitmap(self._surface_bitmap, 0, 0, True)
597 else:
598 pass
599
602
606
612