1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import os
20 import math
21
22 import wx
23
24 from timelinelib.canvas.drawing.utils import darken_color
25 from timelinelib.canvas.drawing.utils import get_colour
26 from timelinelib.config.paths import EVENT_ICONS_DIR
27 from timelinelib.features.experimental.experimentalfeatures import EXTENDED_CONTAINER_HEIGHT
28
29
30 HANDLE_SIZE = 4
31 HALF_HANDLE_SIZE = HANDLE_SIZE / 2
32 DATA_INDICATOR_SIZE = 10
33 INNER_PADDING = 3
34 GRAY = (200, 200, 200)
35
36
38
39 - def draw(self, dc, scene, rect, event, view_properties):
50
60
62 self._draw_background(dc, rect, event)
63 self._draw_fuzzy_edges(dc, rect, event)
64 self._draw_locked_edges(dc, rect, event)
65 self._draw_progress_box(dc, rect, event)
66 self._draw_text(dc, rect, event)
67 self._draw_contents_indicator(dc, event, rect)
68 self._draw_locked_edges(dc, rect, event)
69 self._draw_selection_handles(dc, event, rect, selected)
70 self._draw_hyperlink(dc, rect, event)
71
73 dc.SetBrush(wx.Brush(self._get_event_color(event), wx.BRUSHSTYLE_SOLID))
74 dc.SetPen(self._get_pen(dc, event))
75 dc.DrawRectangle(rect)
76
84
90
97
98 - def _draw_contents_indicator(self, dc, event, rect):
99 if event.has_balloon_data():
100 self._draw_balloon_indicator(dc, event, rect)
101
105
107 return self._get_border_pen(event)
108
110 return self._get_border_pen(event, thickness=8)
111
113 return wx.Pen(self._get_border_color(event), thickness, wx.PENSTYLE_SOLID)
114
116 base_color = self._get_event_color(event)
117 darker_color = darken_color(base_color, 0.6)
118 brush = wx.Brush(darker_color, wx.BRUSHSTYLE_SOLID)
119 return brush
120
123
129
131 self._inflate_clipping_region(dc, rect)
132 dc.DrawBitmap(self._get_fuzzy_bitmap(), rect.x - 4, rect.y + 4, True)
133
135 self._inflate_clipping_region(dc, rect)
136 dc.DrawBitmap(self._get_fuzzy_bitmap(), rect.x + rect.width - 8, rect.y + 4, True)
137
138 - def draw_fuzzy(self, dc, event, p1, p2, p3, p4, p5):
139 self._erase_outzide_fuzzy_box(dc, p1, p2, p3)
140 self._erase_outzide_fuzzy_box(dc, p3, p4, p5)
141 self._draw_fuzzy_border(dc, event, p2, p3, p5)
142
144 dc.SetBrush(wx.WHITE_BRUSH)
145 dc.SetPen(wx.WHITE_PEN)
146 dc.DrawPolygon((p1, p2, p3))
147
149 gc = wx.GraphicsContext.Create(dc)
150 path = gc.CreatePath()
151 path.MoveToPoint(p1.x, p1.y)
152 path.AddLineToPoint(p2.x, p2.y)
153 path.AddLineToPoint(p3.x, p3.y)
154 gc.SetPen(self._get_thin_border_pen(event))
155 gc.StrokePath(path)
156
158 self._inflate_clipping_region(dc, rect)
159 dc.DrawBitmap(self._get_lock_bitmap(), rect.x - 7, rect.y + 3, True)
160
162 self._inflate_clipping_region(dc, rect)
163 dc.DrawBitmap(self._get_lock_bitmap(), rect.x + rect.width - 8, rect.y + 3, True)
164
165 - def _draw_locked(self, dc, event, rect, x, start_angle, end_angle):
173
174 - def draw_segment(self, dc, event, x0, y0, r, start_angle, end_angle):
175 gc = wx.GraphicsContext.Create(dc)
176 path = gc.CreatePath()
177 segment_length = 2.0 * (end_angle - start_angle) * r
178 delta = (end_angle - start_angle) / segment_length
179 angle = start_angle
180 x1 = r * math.cos(angle) + x0
181 y1 = r * math.sin(angle) + y0
182 path.MoveToPoint(x1, y1)
183 while angle < end_angle:
184 angle += delta
185 if angle > end_angle:
186 angle = end_angle
187 x2 = r * math.cos(angle) + x0
188 y2 = r * math.sin(angle) + y0
189 path.AddLineToPoint(x2, y2)
190 x1 = x2
191 y1 = y2
192 gc.SetPen(self._get_thin_border_pen(event))
193 gc.StrokePath(path)
194
196 if event.get_data("progress"):
197 self._set_progress_color(dc, event)
198 progress_rect = self._get_progress_rect(rect, event)
199 dc.DrawRectangle(progress_rect)
200
204
213
215 """
216 The data contents indicator is a small triangle drawn in the upper
217 right corner of the event rectangle.
218 """
219 corner_x = rect.X + rect.Width
220 points = (
221 wx.Point(corner_x - DATA_INDICATOR_SIZE, rect.Y),
222 wx.Point(corner_x, rect.Y),
223 wx.Point(corner_x, rect.Y + DATA_INDICATOR_SIZE),
224 )
225 dc.SetBrush(self._get_balloon_indicator_brush(event))
226 dc.SetPen(wx.TRANSPARENT_PEN)
227 dc.DrawPolygon(points)
228
229 - def _draw_text(self, dc, rect, event):
230
231 if self._there_is_room_for_the_text(rect):
232 self._draw_the_text(dc, rect, event)
233
235 return self._get_inner_rect(rect).Width > 0
236
237 - def _draw_the_text(self, dc, rect, event):
238 self._set_text_foreground_color(dc, event)
239 if event.is_container() and EXTENDED_CONTAINER_HEIGHT.enabled():
240 EXTENDED_CONTAINER_HEIGHT.draw_container_text_top_adjusted(event.get_text(), dc, rect)
241 else:
242 self._draw_normal_text(dc, rect, event)
243 dc.DestroyClippingRegion()
244
245 - def _draw_normal_text(self, dc, rect, event):
246 self._set_clipping_rect(dc, rect)
247 dc.DrawText(self._get_text(event), self._calc_x_pos(dc, rect, event), self._calc_y_pos(rect))
248
249 - def _get_text(self, event):
250 if event.get_progress() == 100 and self.view_properties.get_display_checkmark_on_events_done():
251 return u"\u2714" + event.get_text()
252 else:
253 return event.get_text()
254
262
264 dc.SetClippingRegion(self._get_inner_rect(rect))
265
272
277
278 - def _adjust_x_for_centered_text(self, dc, event, inner_rect, text_x):
279 if self.center_text:
280 text_x = self._center_text(dc, event, inner_rect, text_x)
281 return text_x
282
285
287 return self._get_inner_rect(rect).Y
288
289 - def _center_text(self, dc, event, inner_rect, text_x):
290 width, _ = dc.GetTextExtent(self._get_text(event))
291 return max(text_x, text_x + (inner_rect.width - width) / 2)
292
293 - def _set_text_foreground_color(self, dc, event):
298
300
301 def draw_frame_around_event():
302 small_rect = wx.Rect(*rect)
303 small_rect.Deflate(1, 1)
304 border_color = self._get_border_color(event)
305 border_color = darken_color(border_color)
306 pen = wx.Pen(border_color, 1, wx.PENSTYLE_SOLID)
307 dc.SetBrush(wx.TRANSPARENT_BRUSH)
308 dc.SetPen(pen)
309 dc.DrawRectangle(small_rect)
310
311 dc.SetClippingRegion(rect)
312 draw_frame_around_event()
313 self._draw_all_handles(dc, rect, event)
314 dc.DestroyClippingRegion()
315
317
318 def inflate_clipping_region():
319 big_rect = wx.Rect(*rect)
320 big_rect.Inflate(HANDLE_SIZE, HANDLE_SIZE)
321 dc.DestroyClippingRegion()
322 dc.SetClippingRegion(big_rect)
323
324 def set_pen_and_brush():
325 dc.SetBrush(wx.BLACK_BRUSH)
326 dc.SetPen(wx.BLACK_PEN)
327
328 def create_handle_rect():
329 HALF_EVENT_HEIGHT = rect.Height / 2
330 y = rect.Y + HALF_EVENT_HEIGHT - HALF_HANDLE_SIZE
331 x = rect.X - HALF_HANDLE_SIZE + 1
332 return wx.Rect(x, y, HANDLE_SIZE, HANDLE_SIZE)
333
334 def draw_rect(handle_rect, offset):
335 handle_rect.Offset(offset, 0)
336 dc.DrawRectangle(handle_rect)
337
338 def draw_handle_rects(handle_rect):
339 HALF_EVENT_WIDTH = rect.Width / 2
340 EVENT_WIDTH = rect.Width
341 draw_rect(handle_rect, 0)
342 draw_rect(handle_rect, EVENT_WIDTH - 2)
343 if not event.ends_today:
344 draw_rect(handle_rect, -HALF_EVENT_WIDTH)
345
346 inflate_clipping_region()
347 set_pen_and_brush()
348 handle_rect = create_handle_rect()
349 draw_handle_rects(handle_rect)
350
354
356 copy = wx.Rect(*rect)
357 copy.Inflate(10, 0)
358 dc.DestroyClippingRegion()
359 dc.SetClippingRegion(copy)
360
363
366
369
372
380
381 def draw_shape():
382
383 draw_rectangle_shape()
384
385
386 def draw_rectangle_shape():
387 dc.DestroyClippingRegion()
388 dc.SetPen(self._black_solid_pen(1))
389 if event.get_category() is None:
390 dc.SetBrush(wx.Brush(wx.Colour(*event.get_default_color()), wx.BRUSHSTYLE_SOLID))
391 else:
392 dc.SetBrush(wx.Brush(wx.Colour(*event.get_category().get_color()), wx.BRUSHSTYLE_SOLID))
393 dc.DrawRectangle(rect)
394
395 def draw_circle_shape():
396 half_size = rect.width / 2
397 dc.DestroyClippingRegion()
398 dc.SetPen(self._black_solid_pen(1))
399 dc.SetBrush(wx.Brush(wx.Colour(*event.get_default_color()), wx.BRUSHSTYLE_SOLID))
400 dc.DrawCircle(rect.x + half_size, rect.y + half_size, 2 * rect.width / 3)
401
402 def draw_diamond_shape():
403 SIZE = 2
404 x = rect.x
405 y = rect.y
406 half_size = rect.width / 2
407 points = (wx.Point(x - SIZE, y + half_size),
408 wx.Point(x + half_size, y - SIZE),
409 wx.Point(x + rect.width + SIZE, y + half_size),
410 wx.Point(x + half_size, y + rect.width + SIZE))
411 dc.DestroyClippingRegion()
412 dc.SetPen(self._black_solid_pen(1))
413 dc.SetBrush(wx.Brush(wx.Colour(*event.get_default_color()), wx.BUSHSTYLE_SOLID))
414 dc.DrawPolygon(points)
415
416 def draw_label():
417 x_offset = 6
418 y_offset = 2
419 try:
420 label = event.get_text()[0]
421 except IndexError:
422 label = " "
423 dc.DrawText(label, rect.x + x_offset, rect.y + y_offset)
424
425 def draw_move_handle():
426 dc.SetBrush(self._black_solid_brush())
427 handle_rect = create_handle_rect()
428 handle_rect.Offset(rect.Width / 2, 0)
429 dc.DrawRectangle(handle_rect)
430
431 draw_shape()
432 draw_label()
433 if selected:
434 draw_move_handle()
435
437 return wx.Pen(wx.Colour(0, 0, 0), size, wx.PENSTYLE_SOLID)
438
440 return wx.Brush(wx.Colour(0, 0, 0), wx.BRUSHSTYLE_SOLID)
441