Skip to content
Snippets Groups Projects
Commit 05eba381 authored by Antoine Smolders's avatar Antoine Smolders
Browse files

Timeline height and day captions have a minimal sizes depending on GTK font-size

parent 521a9d6f
No related branches found
No related tags found
No related merge requests found
......@@ -51,9 +51,9 @@
self.connect('size-allocate', self.on_size_allocate)
self.connect('key-press-event', self.on_key_press_event)
# Initialize background and days and add them to canvas
# Initialize background, timeline and days and add them to canvas
root = self.get_root_item()
style = self.get_style()
color = util.color_to_string(style.bg[gtk.STATE_PRELIGHT])
self.bg_rect = goocanvas.Rect(parent=root, x=0, y=0, \
stroke_color=color, fill_color=color)
......@@ -55,8 +55,10 @@
root = self.get_root_item()
style = self.get_style()
color = util.color_to_string(style.bg[gtk.STATE_PRELIGHT])
self.bg_rect = goocanvas.Rect(parent=root, x=0, y=0, \
stroke_color=color, fill_color=color)
self.timeline = TimelineItem(self)
root.add_child(self.timeline)
self.days = []
while len(self.days) < 42: # 6 rows of 7 days
box = DayItem(self)
......@@ -182,6 +184,7 @@
Draws the currently selected week.
"""
style = self.get_style()
pango_size = style.font_desc.get_size()
text_color = util.color_to_string(style.fg[gtk.STATE_NORMAL])
border_color = util.color_to_string(style.mid[gtk.STATE_NORMAL])
body_color = util.color_to_string(style.light[gtk.STATE_ACTIVE])
......@@ -189,8 +192,12 @@
style.mid[gtk.STATE_SELECTED])
today_body_color = 'ivory'
x, y, w, h = self.get_bounds()
timeline_w = w / 12
day_width = (w - timeline_w) / 7
timeline_w = self.timeline.width
caption_size = max(len(day_name) for day_name in calendar.day_name)
caption_size += 3 # The needed space for the date before the day_name
day_width_min = caption_size * pango_size / pango.SCALE
day_width_max = (w - timeline_w) / 7
day_width = max(day_width_min, day_width_max)
day_height = h
# Redraw all days.
......@@ -243,7 +250,12 @@
"""
style = self.get_style()
x1, y1, w, h = self.get_bounds()
day_width = w / 7
pango_size = style.font_desc.get_size()
caption_size = max(len(day_name) for day_name in calendar.day_name)
caption_size += 3 # The needed space for the date before the day_name
day_width_min = caption_size * pango_size / pango.SCALE
day_width_max = w / 7
day_width = max(day_width_min, day_width_max)
day_height = (h - self.line_height) / 6
text_height = max(day_height / 12, 10)
font_descr = style.font_desc.copy()
......@@ -247,7 +259,6 @@
day_height = (h - self.line_height) / 6
text_height = max(day_height / 12, 10)
font_descr = style.font_desc.copy()
font_descr.set_absolute_size(text_height * pango.SCALE)
text_color = util.color_to_string(style.fg[gtk.STATE_NORMAL])
inactive_text_color = util.color_to_string(
style.fg[gtk.STATE_INSENSITIVE])
......@@ -401,7 +412,10 @@
continue
max_line_height = max(x.line_height for x in days)
max_y = max((free_line + 2) * max_line_height + 2, max_y)
all_day_events_height = (free_line + 2) * max_line_height
all_day_events_height += (free_line + 1) * 2 #2px margin per line
all_day_events_height += 1 # 1px padding-top
max_y = max(all_day_events_height, max_y)
for day in days:
day.lines[free_line] = 1
......@@ -415,7 +429,6 @@
week_end = week_start + (7 - weekday)
week = days[week_start:week_end]
weeks.append(week)
#print "Week:", weekday, [d.date for d in week], start, end
week_start = week_end
for week in weeks:
......@@ -427,7 +440,9 @@
self.event_items.append(event_item)
self.get_root_item().add_child(event_item)
event_item.x = day.x
event_item.y = day.y + (free_line + 1) * day.line_height + 2
event_item.y = day.y + (free_line + 1) * day.line_height
event_item.y += free_line * 2 # 2px of margin per line
event_item.y += 1 # 1px padding-top
event_item.width = (day.width + 2) * len(week)
event_item.height = day.line_height
week_start = week[0].date
......@@ -457,10 +472,7 @@
text_color = util.color_to_string(style.fg[gtk.STATE_NORMAL])
border_color = util.color_to_string(style.mid[gtk.STATE_NORMAL])
body_color = util.color_to_string(style.light[gtk.STATE_ACTIVE])
if self.timeline is None:
self.timeline = TimelineItem(self)
self.get_root_item().add_child(self.timeline)
self.timeline.set_property('visibility', goocanvas.ITEM_VISIBLE)
x, y, w, h = self.get_bounds()
self.timeline.x = x
self.timeline.y = max_y
......@@ -463,8 +475,7 @@
self.timeline.set_property('visibility', goocanvas.ITEM_VISIBLE)
x, y, w, h = self.get_bounds()
self.timeline.x = x
self.timeline.y = max_y
self.timeline.width = w / 12 - 2
self.timeline.height = h - max_y - 2
self.timeline.line_color = body_color
self.timeline.bg_color = border_color
......@@ -515,7 +526,7 @@
self.on_event_item_button_press_event)
self.event_items.append(event_item)
self.get_root_item().add_child(event_item)
minute_height = self.timeline.height / 24 / 60
minute_height = self.timeline.line_height / 60
y_off1 = top_offset_mins * minute_height
y_off2 = bottom_offset_mins * minute_height
column_width = day.width / parallel
......@@ -523,7 +534,6 @@
event_item.y = max_y + y_off1
event_item.width = column_width - 4
event_item.height = y_off2
event_item.font_size = day.font_size
if event.start < event1_start and event.end > event1_end:
event_item.type = 'mid'
elif event.start < event1_start:
......
......@@ -4,9 +4,10 @@
import goocanvas
import pango
import math
class DayItem(goocanvas.Group):
"""
A canvas item representing a day.
"""
......@@ -7,9 +8,10 @@
class DayItem(goocanvas.Group):
"""
A canvas item representing a day.
"""
def __init__(self, cal, **kwargs):
super(DayItem, self).__init__()
......@@ -24,8 +26,6 @@
self.date = kwargs.get('date')
self.type = kwargs.get('type', 'month')
self.show_indic = False
self.line_height = 0
self.font_size = 0
self.lines = {}
self.n_lines = 0
self.title_text_color = ""
......@@ -37,11 +37,12 @@
self.indic = goocanvas.Rect(parent=self)
def update(self):
if self.type == 'month':
self.font_size = max(self.height / 12, 10)
else:
self.font_size = max(self.height / 65, 10)
text_padding = max(self.font_size / 2.5, 4)
self.line_height = self.font_size + 2 * text_padding
if not self.date:
return
date_tuple = self.date.timetuple()[:3]
week_day = calendar.weekday(*date_tuple)
day_name = calendar.day_name[week_day]
caption = '%s %s' % (date_tuple[2], day_name)
style = self.cal.get_style()
font_descr = style.font_desc.copy()
......@@ -46,14 +47,12 @@
style = self.cal.get_style()
font_descr = style.font_desc.copy()
font_descr.set_absolute_size(self.font_size * pango.SCALE)
self.font = font_descr.to_string()
if self.date:
date_tuple = self.date.timetuple()[:3]
week_day = calendar.weekday(*date_tuple)
day_name = calendar.day_name[week_day]
caption = '%s %s' % (date_tuple[2], day_name)
else:
caption = ""
font = font_descr.to_string()
pango_size = font_descr.get_size()
self.text.set_property('font', font)
self.text.set_property('text', caption)
logical_height = self.text.get_natural_extents()[1][3]
line_height = int(math.ceil(float(logical_height) / pango.SCALE))
self.line_height = line_height
# Draw the border.
self.border.set_property('x', self.x)
......@@ -64,13 +63,11 @@
self.border.set_property('fill_color', self.border_color)
# Draw the title text.
x = self.x + text_padding
self.text.set_property('x', x)
self.text.set_property('y', self.y + text_padding)
self.text.set_property('font', self.font)
self.text.set_property('text', caption)
padding_left = 2
self.text.set_property('x', self.x + padding_left)
self.text.set_property('y', self.y)
self.text.set_property('fill_color', self.title_text_color)
# Print the "body" of the day.
if self.full_border:
box_x = self.x + 2
......@@ -72,7 +69,7 @@
self.text.set_property('fill_color', self.title_text_color)
# Print the "body" of the day.
if self.full_border:
box_x = self.x + 2
box_y = self.y + self.line_height
box_y = self.y + line_height
box_width = max(self.width - 4, 0)
......@@ -78,4 +75,4 @@
box_width = max(self.width - 4, 0)
box_height = max(self.height - self.line_height - 3, 0)
box_height = max(self.height - line_height - 3, 0)
else:
box_x = self.x + 1
......@@ -80,4 +77,4 @@
else:
box_x = self.x + 1
box_y = self.y + self.line_height
box_y = self.y + line_height
box_width = max(self.width - 2, 0)
......@@ -83,5 +80,5 @@
box_width = max(self.width - 2, 0)
box_height = max(self.height - self.line_height, 0)
box_height = max(self.height - line_height, 0)
self.box.set_property('x', box_x)
self.box.set_property('y', box_y)
self.box.set_property('width', box_width)
......@@ -89,7 +86,7 @@
self.box.set_property('stroke_color', self.body_color)
self.box.set_property('fill_color', self.body_color)
self.n_lines = int(box_height / self.line_height)
self.n_lines = int(box_height / line_height)
# Show an indicator in the title, if requested.
if not self.show_indic:
......@@ -98,11 +95,11 @@
self.indic.set_property('visibility', goocanvas.ITEM_VISIBLE)
self.indic.set_property('x',
self.x + self.width - self.line_height / 1.5)
self.indic.set_property('y', self.y + self.line_height / 3)
self.indic.set_property('width', self.line_height / 3)
self.indic.set_property('height', self.line_height / 3)
self.x + self.width - line_height / 1.5)
self.indic.set_property('y', self.y + line_height / 3)
self.indic.set_property('width', line_height / 3)
self.indic.set_property('height', line_height / 3)
self.indic.set_property('stroke_color', self.title_text_color)
self.indic.set_property('fill_color', self.title_text_color)
# Draw a triangle.
......@@ -105,12 +102,12 @@
self.indic.set_property('stroke_color', self.title_text_color)
self.indic.set_property('fill_color', self.title_text_color)
# Draw a triangle.
x1 = self.x + self.width - self.line_height / 1.5
y1 = self.y + self.line_height / 3
x2 = x1 + self.line_height / 6
y2 = y1 + self.line_height / 3
x3 = x1 + self.line_height / 3
x1 = self.x + self.width - line_height / 1.5
y1 = self.y + line_height / 3
x2 = x1 + line_height / 6
y2 = y1 + line_height / 3
x3 = x1 + line_height / 3
y3 = y1
path = 'M%s,%s L%s,%s L%s,%s Z' % (x1, y1, x2, y2, x3, y3)
self.indic.set_property('clip_path', path)
......@@ -8,6 +8,7 @@
"""
A canvas item representing an event.
"""
def __init__(self, cal, **kwargs):
super(EventItem, self).__init__()
......@@ -18,7 +19,6 @@
self.height = kwargs.get('height')
self.bg_color = kwargs.get('bg_color')
self.text_color = kwargs.get('text_color')
self.font_size = kwargs.get('font_size')
self.event = kwargs.get('event')
self.type = kwargs.get('type', 'leftright')
......@@ -39,8 +39,7 @@
def update_event(self):
style = self.cal.get_style()
font_descr = style.font_desc.copy()
if self.font_size is not None:
font_descr.set_absolute_size(self.font_size * pango.SCALE)
self.width = max(self.width, 0)
self.font = font_descr.to_string()
caption = self.event.caption
the_event_bg_color = self.event.bg_color
......@@ -83,11 +82,11 @@
self.box2.set_property('fill_color', the_event_bg_color)
# Print the event name into the title box.
self.text.set_property('x', self.x + 6)
self.text.set_property('y', self.y + 2)
self.text.set_property('font', self.font)
self.text.set_property('text', caption)
self.text.set_property('x', self.x + 2)
self.text.set_property('y', self.y)
self.text.set_property('font', self.font)
self.text.set_property('text', caption)
self.text.set_property('fill_color', the_event_text_color)
# Clip the text.
x2, y2 = self.x + self.width, self.y + self.height,
......@@ -90,11 +89,9 @@
self.text.set_property('fill_color', the_event_text_color)
# Clip the text.
x2, y2 = self.x + self.width, self.y + self.height,
path = 'M%s,%s L%s,%s L%s,%s L%s,%s Z' % (self.x, self.y,
self.x, y2,
x2, y2,
x2, self.y)
self.text.set_property('clip_path', path)
path = 'M%s,%s L%s,%s L%s,%s L%s,%s Z' % (self.x, self.y, self.x, y2,
x2, y2, x2, self.y)
self.text.set_property('clip_path', path)
def update_all_day_event(self):
......@@ -99,6 +96,5 @@
def update_all_day_event(self):
text_padding = max(self.height / 4.5, 4)
text_height = max(self.height - 2 * text_padding, 10)
self.width = max(self.width, 0)
style = self.cal.get_style()
font_descr = style.font_desc.copy()
......@@ -103,6 +99,5 @@
style = self.cal.get_style()
font_descr = style.font_desc.copy()
font_descr.set_absolute_size(text_height * pango.SCALE)
self.font = font_descr.to_string()
caption = self.event.caption
the_event_bg_color = self.event.bg_color
......@@ -106,6 +101,10 @@
self.font = font_descr.to_string()
caption = self.event.caption
the_event_bg_color = self.event.bg_color
self.text.set_property('font', self.font)
self.text.set_property('text', caption)
logical_height = self.text.get_natural_extents()[1][3]
self.height = logical_height / pango.SCALE
# Choose text color.
if self.event.text_color is None:
......@@ -131,7 +130,7 @@
self.box.set_property('x', self.x)
self.box.set_property('y', self.y)
self.box.set_property('width', self.width)
self.box.set_property('height', self.height - 4)
self.box.set_property('height', self.height)
self.box.set_property('radius_x', radius)
self.box.set_property('radius_y', radius)
self.box.set_property('stroke_color', the_event_bg_color)
......@@ -140,8 +139,8 @@
# Box 2 hides the rounded corners of box1.
self.box2.set_property('y', self.y)
self.box2.set_property('width', radius)
self.box2.set_property('height', self.height - 4)
self.box2.set_property('height', self.height)
self.box2.set_property('stroke_color', the_event_bg_color)
self.box2.set_property('fill_color', the_event_bg_color)
# Print the event name into the title box.
......@@ -144,14 +143,12 @@
self.box2.set_property('stroke_color', the_event_bg_color)
self.box2.set_property('fill_color', the_event_bg_color)
# Print the event name into the title box.
self.text.set_property('x', self.x + 6)
self.text.set_property('y', self.y + 2)
self.text.set_property('font', self.font)
self.text.set_property('text', caption)
self.text.set_property('x', self.x + 2)
self.text.set_property('y', self.y)
self.text.set_property('fill_color', the_event_text_color)
# Clip the text.
x2, y2 = self.x + self.width, self.y + self.height,
path = 'M%s,%s L%s,%s L%s,%s L%s,%s Z' % (
self.x, self.y, self.x, y2, x2, y2, x2, self.y)
......@@ -152,7 +149,7 @@
self.text.set_property('fill_color', the_event_text_color)
# Clip the text.
x2, y2 = self.x + self.width, self.y + self.height,
path = 'M%s,%s L%s,%s L%s,%s L%s,%s Z' % (
self.x, self.y, self.x, y2, x2, y2, x2, self.y)
self.text.set_property('clip_path', path)
self.text.set_property('clip_path', path)
......@@ -2,9 +2,10 @@
#this repository contains the full copyright notices and license terms.
import goocanvas
import pango
import math
class TimelineItem(goocanvas.Group):
"""
A canvas item representing a timeline.
"""
......@@ -5,12 +6,13 @@
class TimelineItem(goocanvas.Group):
"""
A canvas item representing a timeline.
"""
def __init__(self, cal, **kwargs):
super(TimelineItem, self).__init__()
self.cal = cal
self.x = kwargs.get('x')
self.y = kwargs.get('y')
......@@ -11,11 +13,9 @@
def __init__(self, cal, **kwargs):
super(TimelineItem, self).__init__()
self.cal = cal
self.x = kwargs.get('x')
self.y = kwargs.get('y')
self.width = kwargs.get('width')
self.height = kwargs.get('height')
self.line_color = kwargs.get('line_color')
self.bg_color = kwargs.get('bg_color')
self.text_color = kwargs.get('text_color')
......@@ -23,11 +23,12 @@
# Create canvas items.
self.timeline_rect = {}
self.timeline_text = {}
for n in range(0, 24):
caption = '%s:00' % n
for n in range(24):
hour = str(n).zfill(2)
caption = hour + ':00'
self.timeline_rect[n] = goocanvas.Rect(parent=self)
self.timeline_text[n] = goocanvas.Text(parent=self, text=caption)
if self.x is not None:
self.update()
......@@ -28,13 +29,28 @@
self.timeline_rect[n] = goocanvas.Rect(parent=self)
self.timeline_text[n] = goocanvas.Text(parent=self, text=caption)
if self.x is not None:
self.update()
def update(self):
text_padding = max(self.width / 20, 4)
text_width = self.width - 2 * text_padding
text_height = text_width / 5
line_height = self.height / 24
@property
def width(self):
style = self.cal.get_style()
font = style.font_desc
# Find the maximal padding and width of texts
ink_padding_left = 0
ink_max_width = 0
for n in range(24):
self.timeline_text[n].set_property('font', font)
natural_extents = self.timeline_text[n].get_natural_extents()
ink_rect = natural_extents[0]
ink_padding_left = max(ink_padding_left, ink_rect[0])
ink_max_width = max(ink_max_width, ink_rect[2])
self._width = int(math.ceil(float(ink_padding_left + ink_max_width)
/ pango.SCALE))
return self._width
@property
def line_height(self):
style = self.cal.get_style()
font_descr = style.font_desc.copy()
......@@ -39,6 +55,27 @@
style = self.cal.get_style()
font_descr = style.font_desc.copy()
font_descr.set_absolute_size(text_height * pango.SCALE)
font = font_descr.to_string()
pango_size = font_descr.get_size()
logical_height = 0
ink_padding_top = 0
for n in range(24):
natural_extents = self.timeline_text[n].get_natural_extents()
logical_rect = natural_extents[1]
logical_height = max(logical_height, logical_rect[3])
ink_rect = natural_extents[0]
ink_padding_top = max(ink_padding_top, ink_rect[0])
line_height = int(math.ceil(float(logical_height) / pango.SCALE))
# If we have more vertical space, use it and center the text
self.padding_top = 0
if line_height < self.height / 24:
line_height = self.height / 24
pango_size = self.cal.get_style().font_desc.get_size()
padding_top = (line_height - pango_size / pango.SCALE) / 2
padding_top -= int(math.ceil(float(ink_padding_top) / pango.SCALE))
self.padding_top = padding_top
return line_height
def update(self):
line_height = self.line_height
# Draw the timeline.
......@@ -44,5 +81,5 @@
# Draw the timeline.
for n in range(0, 24):
for n in range(24):
rect = self.timeline_rect[n]
text = self.timeline_text[n]
y = self.y + n * line_height
......@@ -54,7 +91,6 @@
rect.set_property('stroke_color', self.line_color)
rect.set_property('fill_color', self.bg_color)
text.set_property('x', self.x + text_padding)
text.set_property('y', y + text_padding)
text.set_property('font', font)
text.set_property('x', self.x)
text.set_property('y', y + self.padding_top)
text.set_property('fill_color', self.text_color)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment