class Header(Gtk.DrawingArea): def __init__(self, cols=7): super(Header, self).__init__() self.labels = [] self.background = Background(1, cols) self.sidebar = 0 self.font = "Courier" self.font_size = 12 self.font_color = (0.35, 0.31, 0.24) self.highlight_cell = (None, None) self.connect("draw", self.draw) def set_sidebar_size(self, size): self.sidebar = size def set_labels(self, labels): self.labels = labels def set_font(self, font): self.font = font def set_font_size(self, size): self.font_size = size def set_font_color(self, color): self.font_color = color def set_line_color(self, color): self.background.set_line_color(color) def set_background_color(self, color): self.background.set_background_color(color) def get_height(self): try: line_height = self.get_allocation().height / len(self.labels[0]) except ZeroDivisionError: print("List of labels in object Header not initialized!") raise else: return line_height def get_col_width(self): try: col_width = (self.get_allocation().width - self.sidebar) \ / float(len(self.labels)) except ZeroDivisionError: print("List of labels in object Header not initialized!") raise else: return col_width def set_highlight_cell(self, row, col): if row == 0 and 0 <= col < len(self.labels): self.highlight_cell = (row, col) else: self.highlight_cell = (None, None) def draw(self, widget, ctx): """ Draws the header according to the labels. @param ctx: a Cairo context """ alloc = self.get_allocation() alloc.width -= self.sidebar # FIXME: look deeper into why x=5 and y=35 - both should start at 0 # Whathever is happening has to do with spacing in vbox (glade file) # temporary fix: alloc.x = 0 alloc.y = 0 ctx.set_line_width(0.8) row, col = self.highlight_cell if row is not None and col is not None: # print "header", alloc.x, alloc.y, alloc.width, alloc.height self.background.highlight_cell(ctx, row, col, alloc) self.background.draw(ctx, alloc, vgrid=False, hgrid=True) color = self.font_color ctx.set_source_rgb(color[0], color[1], color[2]) ctx.set_font_size(self.font_size) ctx.select_font_face(self.font, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) # print labels: use multiple lines if necessary col_width = self.get_col_width() line_height = self.get_height() for i in range(0, len(self.labels)): for j in range(0, len(self.labels[i])): label, base_x, base_y = utils.center_text_on_rect( ctx, self.labels[i][j], (i * col_width), (j * line_height), col_width, line_height) ctx.move_to(base_x, base_y) ctx.text_path(label) ctx.stroke()
class AllDayTasks(Gtk.DrawingArea): def __init__(self, parent, rows=1, cols=7): super(Gtk.DrawingArea, self).__init__() self.par = parent self.num_rows = rows self.num_columns = cols self.background = Background(rows, cols) self.padding = 1.5 self.font = "Courier" self.font_size = 12 self.font_color = (0.35, 0.31, 0.24) self.link_color = (0, 0, 255, 0.5) # default blue link color self.today_cell = (None, None) self.selected_task = None self.faded_cells = [] self.cells = [] self.labels = None self.label_height = self.font_size self.overflow_links = [] self.connect("draw", self.draw) # drag-and-drop signals and events self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.BUTTON1_MOTION_MASK | Gdk.EventMask.POINTER_MOTION_MASK) def get_label_height(self): if self.labels: return self.label_height return 0 def set_labels(self, labels): self.labels = labels def set_num_rows(self, rows): self.num_rows = rows self.background.set_num_rows(rows) def set_font(self, font): self.font = font def set_font_size(self, size): self.font_size = size def set_font_color(self, color): self.font_color = color def set_line_color(self, color): self.background.set_line_color(color) def set_background_color(self, color): self.background.set_background_color(color) def get_day_width(self): return self.get_allocation().width / float(self.num_columns) def get_week_height(self): return self.get_allocation().height / float(self.num_rows) def set_tasks_to_draw(self, drawtasks): self.drawtasks = drawtasks def highlight_cells(self, ctx, cells, color, alpha=0.5): alloc = self.get_allocation() for cell in cells: row, col = cell if 0 <= row < self.num_rows and 0 <= col < self.num_columns: ctx.save() self.background.highlight_cell(ctx, row, col, alloc, color, alpha) ctx.restore() def set_today_cell(self, row, col): if 0 <= row < self.num_rows and 0 <= col < self.num_columns: self.today_cell = (row, col) else: self.today_cell = (None, None) def draw(self, widget, ctx): ctx.set_line_width(0.8) ctx.set_font_size(self.font_size) ctx.select_font_face(self.font, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) # first draw background ctx.save() alloc = self.get_allocation() self.set_line_color(color=(0.35, 0.31, 0.24, 0.15)) row, col = self.today_cell if row is not None and col is not None and row >= 0 and col >= 0: self.background.highlight_cell(ctx, row, col, alloc) self.background.draw(ctx, alloc, vgrid=True, hgrid=True) ctx.restore() # then draw labels, if any (used only on month_view) if self.labels: ctx.save() color = self.font_color ctx.set_source_rgb(color[0], color[1], color[2]) for j, week in enumerate(self.labels): for i, day in enumerate(week): base_x = i * self.get_day_width() + self.padding base_y = j * self.get_week_height() + self.label_height ctx.move_to(base_x, base_y) ctx.text_path(day) ctx.stroke() ctx.restore() # fade days not in current month if self.faded_cells: self.highlight_cells(ctx, self.faded_cells, color=(0.8, 0.8, 0.8)) # then draw links when there is overflowing tasks (only in month_view) if self.overflow_links: ctx.save() color = self.link_color ctx.set_source_rgba(color[0], color[1], color[2], color[3]) for link in self.overflow_links: (text, row, col) = link w = ctx.text_extents(text)[2] base_x = (col+1) * self.get_day_width() - w - 3*self.padding base_y = row * self.get_week_height() + self.label_height ctx.move_to(base_x, base_y) ctx.text_path(text) # underline y = base_y + 2 ctx.move_to(base_x, y) ctx.line_to(base_x + w, y) ctx.stroke() ctx.restore() # then draw all tasks for dtask in self.drawtasks: selected = self.selected_task and \ (dtask.get_id() == self.selected_task) ctx.save() dtask.draw(ctx, self.get_day_width(), self.padding, selected, self.get_week_height()) ctx.restore() # if dragging cells to create new task, highlight them now if self.cells: self.highlight_cells(ctx, self.cells, color=(0.8, 0.8, 0), alpha=0.1) def identify_pointed_object(self, event, clicked=False): """ Identify the object inside drawing area that is being pointed by the mouse. Also points out which mouse cursor should be used in result. @param event: a Gdk event @param clicked: bool, indicates whether or not the user clicked on the object being pointed """ expand_border = 10 cursor = Gdk.Cursor.new(Gdk.CursorType.ARROW) drag_action = None if clicked: cursor = Gdk.Cursor.new(Gdk.CursorType.HAND1) if self.overflow_links: for link in self.overflow_links: (text, row, col) = link # h, w = ctx.text_extents(text)[1:3] # FIXME: more generic values for h and w h = self.font_size w = self.font_size/2 * len(text) base_x = (col+1) * self.get_day_width() - w - 3*self.padding base_y = row * self.get_week_height() + self.label_height if base_x <= event.x <= base_x + w and \ base_y - h <= event.y <= base_y: drag_action = "click_link" cursor = Gdk.Cursor.new(Gdk.CursorType.HAND1) for task in self.drawtasks: (x, y, w, h) = utils.convert_grid_to_screen_coord( self.get_day_width(), TASK_HEIGHT, *task.get_position(), padding=self.padding) # calculating week position when in month view if task.get_week_num() is not None: y += task.get_week_num() * self.get_week_height() + 15 if not y < event.y < (y + h): continue if x <= event.x <= x + expand_border: drag_action = "expand_left" cursor = Gdk.Cursor.new(Gdk.CursorType.LEFT_SIDE) elif (x + w) - expand_border <= event.x <= (x + w): drag_action = "expand_right" cursor = Gdk.Cursor.new(Gdk.CursorType.RIGHT_SIDE) elif x <= event.x <= (x + w): drag_action = "move" if clicked: cursor = Gdk.Cursor.new(Gdk.CursorType.FLEUR) else: continue return task.get_id(), drag_action, cursor return None, drag_action, cursor