def category_render_cb(self, column, cell_renderer, model, iter, data): id = model.get_value(iter, 0) t = self.activity.transaction_map[id] category = t['category'] cell_renderer.set_property('text', category) if category: category_color = colors.get_category_color_str(category) cell_renderer.set_property('background', category_color) if not colors.is_too_light(category_color): cell_renderer.set_property('foreground', '#FFFFFF') else: cell_renderer.set_property('background', None)
def build(self): # Build the category totals. self.category_total = {} for t in self.activity.visible_transactions: cat = t['category'] amount = t['amount'] if t['type'] == 'debit': if cat not in self.category_total: self.category_total[cat] = amount else: self.category_total[cat] += amount # Generate a list of names sorted by total. self.sorted_categories = list(self.category_total.keys()) self.sorted_categories.sort() # Clear all widgets. for w in self.budgetbox.get_children(): self.budgetbox.remove(w) # Build header. catlabel = Gtk.Label() catlabel.set_markup( '<span size="x-large" foreground="white"><b>%s</b></span>' % _('Category')) spentlabel = Gtk.Label() spentlabel.set_markup( '<span size="x-large" foreground="white"><b>%s</b></span>' % _('Spent')) budgetlabel = Gtk.Label() budgetlabel.set_markup( '<span size="x-large" foreground="white"><b>%s</b></span>' % _('Budget')) header = Gtk.EventBox() header.modify_bg(Gtk.StateType.NORMAL, style.Color('#666666').get_gdk_color()) header.set_size_request(-1, style.GRID_CELL_SIZE) headerbox = Gtk.HBox() headerbox.pack_start(catlabel, False, True, 20) headerbox.pack_start(spentlabel, True, True, 10) headerbox.pack_start(budgetlabel, False, True, 20) header.add(headerbox) self.budgetbox.pack_start(header, False, False, 0) catgroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL) catgroup.add_widget(catlabel) spentgroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL) spentgroup.add_widget(spentlabel) budgetgroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL) budgetgroup.add_widget(budgetlabel) # Build categories. for c in self.sorted_categories: description = c # If there is no category, display as Unknown if c is '': description = _('Unknown') color = colors.get_category_color_str(c) if colors.is_too_light(color): font_color = '#000000' else: font_color = '#FFFFFF' catbox = Gtk.Label() catbox.set_markup('<span color="%s">%s</span>' % (font_color, description)) catbox.set_padding(10, 0) ebox = Gtk.EventBox() parse, color = Gdk.Color.parse(color) ebox.modify_bg(Gtk.StateType.NORMAL, color) ebox.add(catbox) catgroup.add_widget(ebox) bar = Gtk.DrawingArea() bar.connect('draw', self.bar_draw_cb, c) spentgroup.add_widget(bar) budgetentry = Gtk.Entry() budgetentry.connect('changed', self.budget_changed_cb, c) budgetentry.set_width_chars(10) if c in self.activity.data['budgets']: b = self.activity.data['budgets'][c] budgetentry.set_text(locale.currency(b['amount'], False)) budgetgroup.add_widget(budgetentry) # freqcombo = Gtk.ComboBoxText() # freqcombo.append_text(_('Daily')) # freqcombo.append_text(_('Weekly')) # freqcombo.append_text(_('Monthly')) # freqcombo.append_text(_('Annually')) # freqcombo.set_active(2) hbox = Gtk.HBox() hbox.pack_start(ebox, False, False, 20) hbox.pack_start(bar, True, True, 10) hbox.pack_start(budgetentry, False, False, 20) # hbox.pack_start(freqcombo, True, True, 0) self.budgetbox.pack_start(hbox, False, False, 5) self.show_all()
def _create_pie_chart(self, context, image_width, image_height): _set_screen_dpi() scale = image_width / 1600. context.rectangle(0, 0, image_width, image_height) logging.debug('canvas size %s x %s - scale %s', image_width, image_height, scale) context.set_source_rgb(1, 1, 1) context.fill() margin_left = (style.GRID_CELL_SIZE / 2) * scale margin_top = (style.GRID_CELL_SIZE / 2) * scale padding = 20 * scale title_font_size = self._calculate_title_font_size(scale) title_width, title_height = self._measure_text(self._title, title_font_size, max_width=image_width - margin_left * 2) logging.error('measure text pie %s %s', title_width, title_height) rectangles_width = 0 if self._show_labels: # measure the descriptions max_width_desc = 0 max_width_amount = 0 max_height = 0 label_font_size = 14 * scale for data in self._data: description = data['label'] # If there is no category, display as Unknown if description is '': description = _('Unknown') if len(description) > 30: description = description[:30] + '...' # need measure the description width to align the amounts width, height = self._measure_text(description, label_font_size) max_width_desc = max(max_width_desc, width) max_height = max(max_height, height) width, height = self._measure_text(str(data['value']), label_font_size) max_height = max(max_height, height) max_width_amount = max(max_width_amount, width) # draw the labels labels_height = (max_height * 2.5) * len(self._data) y = (image_height - labels_height) / 2 context.save() context.translate(margin_left, 0) rectangles_width = max_width_desc + max_width_amount + padding * 3 for data in self._data: description = data['label'] if description is '': description = _('Unknown') if len(description) > 30: description = description[:30] + '...' context.save() context.translate(0, y) draw_round_rect(context, 0, 0, rectangles_width, max_height * 2, 10) color = style.Color(data['color']) context.set_source_rgba(*color.get_rgba()) context.fill() if colors.is_too_light(data['color']): context.set_source_rgb(0, 0, 0) else: context.set_source_rgb(1, 1, 1) width, height = self._measure_text(description, label_font_size) self._print_text(context, padding, height * .5, description, label_font_size) text = str(data['value']) width, height = self._measure_text(text, label_font_size) self._print_text(context, rectangles_width - width - padding, height * .5, text, label_font_size) y += max_height * 2.5 context.restore() context.restore() self._print_text(context, 0, margin_top, self._title, title_font_size, max_width=image_width - margin_left * 2, alignment=Pango.Alignment.CENTER, color=self._title_color) margin_top += title_height + margin_top * 2 # draw the pie r = min(image_width - rectangles_width - margin_left * 3, image_height - margin_top - margin_left) / 2 y = max(r + margin_top, image_height / 2) if rectangles_width == 0: x = image_width / 2 else: x = image_width - margin_left - r total = 0 for data in self._data: total += data['value'] if total != 0: angle = 0.0 for data in self._data: value = data['value'] slice = 2 * math.pi * value / total color = style.Color(data['color']) context.move_to(x, y) context.arc(x, y, r, angle, angle + slice) context.close_path() context.set_source_rgba(*color.get_rgba()) context.fill() angle += slice
def create_chart(self, context, image_width, image_height): _set_screen_dpi() scale = image_width / 1600. context.rectangle(0, 0, image_width, image_height) logging.debug('canvas size %s x %s - scale %s', image_width, image_height, scale) context.set_source_rgb(1, 1, 1) context.fill() margin_left = (style.GRID_CELL_SIZE / 2) * scale margin_top = (style.GRID_CELL_SIZE / 2) * scale padding = 20 * scale # measure the descriptions max_width_desc = 0 max_width_amount = 0 max_height = 0 context.select_font_face('Sans', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) context.set_font_size(26 * scale) for c in self.sorted_categories: description = c # If there is no category, display as Unknown if c is '': description = _('Unknown') # need measure the description width to align the amounts x_bearing, y_bearing, width, height, x_advance, y_advance = \ context.text_extents(description) max_width_desc = max(max_width_desc, width) max_height = max(max_height, height) x_bearing, y_bearing, width, height, x_advance, y_advance = \ context.text_extents(locale.currency(self.category_total[c])) max_height = max(max_height, height) max_width_amount = max(max_width_amount, width) # draw the labels y = margin_top context.save() context.translate(margin_left, 0) rectangles_width = max_width_desc + max_width_amount + padding * 3 for c in self.sorted_categories: description = c if c is '': description = _('Unknown') context.save() context.translate(0, y) context.rectangle(0, 0, rectangles_width, max_height + padding) color = colors.get_category_color(c) context.set_source_rgb(color[0], color[1], color[2]) context.fill() if colors.is_too_light(colors.get_category_color_str(c)): context.set_source_rgb(0, 0, 0) else: context.set_source_rgb(1, 1, 1) context.save() x_bearing, y_bearing, width, height, x_advance, y_advance = \ context.text_extents(description) context.move_to(padding, padding * 2.5 + y_bearing) context.show_text(description) context.restore() context.save() text = locale.currency(self.category_total[c]) x_bearing, y_bearing, width, height, x_advance, y_advance = \ context.text_extents(text) context.move_to(rectangles_width - x_advance - padding, padding * 2.5 + y_bearing) context.show_text(text) context.restore() y += max_height + padding * 2 context.restore() context.restore() # draw the pie x = (image_width - rectangles_width) / 2 + rectangles_width y = image_height / 2 r = min(image_width, image_height) / 2 - 10 total = 0 for c in self.sorted_categories: total += self.category_total[c] if total != 0: angle = 0.0 for c in self.sorted_categories: slice = 2 * math.pi * self.category_total[c] / total color = colors.get_category_color(c) context.move_to(x, y) context.arc(x, y, r, angle, angle + slice) context.close_path() context.set_source_rgb(color[0], color[1], color[2]) context.fill() angle += slice
def build(self): # Build the category totals. self.category_total = {} for t in self.activity.visible_transactions: cat = t['category'] amount = t['amount'] if t['type'] == 'debit': if cat not in self.category_total: self.category_total[cat] = amount else: self.category_total[cat] += amount # Generate a list of names sorted by total. self.sorted_categories = self.category_total.keys() self.sorted_categories.sort() # Clear all widgets. for w in self.budgetbox.get_children(): self.budgetbox.remove(w) # Build header. catlabel = Gtk.Label() catlabel.set_markup( '<span size="x-large" foreground="white"><b>%s</b></span>' % _('Category')) spentlabel = Gtk.Label() spentlabel.set_markup( '<span size="x-large" foreground="white"><b>%s</b></span>' % _('Spent')) budgetlabel = Gtk.Label() budgetlabel.set_markup( '<span size="x-large" foreground="white"><b>%s</b></span>' % _('Budget')) header = Gtk.EventBox() header.modify_bg(Gtk.StateType.NORMAL, style.Color('#666666').get_gdk_color()) header.set_size_request(-1, style.GRID_CELL_SIZE) headerbox = Gtk.HBox() headerbox.pack_start(catlabel, False, True, 20) headerbox.pack_start(spentlabel, True, True, 10) headerbox.pack_start(budgetlabel, False, True, 20) header.add(headerbox) self.budgetbox.pack_start(header, False, False, 0) catgroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL) catgroup.add_widget(catlabel) spentgroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL) spentgroup.add_widget(spentlabel) budgetgroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL) budgetgroup.add_widget(budgetlabel) # Build categories. for c in self.sorted_categories: description = c # If there is no category, display as Unknown if c is '': description = _('Unknown') color = colors.get_category_color_str(c) if colors.is_too_light(color): font_color = '#000000' else: font_color = '#FFFFFF' catbox = Gtk.Label() catbox.set_markup( '<span color="%s">%s</span>' % (font_color, description)) catbox.set_padding(10, 0) ebox = Gtk.EventBox() parse, color = Gdk.Color.parse(color) ebox.modify_bg(Gtk.StateType.NORMAL, color) ebox.add(catbox) catgroup.add_widget(ebox) bar = Gtk.DrawingArea() bar.connect('draw', self.bar_draw_cb, c) spentgroup.add_widget(bar) budgetentry = Gtk.Entry() budgetentry.connect('changed', self.budget_changed_cb, c) budgetentry.set_width_chars(10) if c in self.activity.data['budgets']: b = self.activity.data['budgets'][c] budgetentry.set_text(locale.currency(b['amount'], False)) budgetgroup.add_widget(budgetentry) # freqcombo = Gtk.ComboBoxText() # freqcombo.append_text(_('Daily')) # freqcombo.append_text(_('Weekly')) # freqcombo.append_text(_('Monthly')) # freqcombo.append_text(_('Annually')) # freqcombo.set_active(2) hbox = Gtk.HBox() hbox.pack_start(ebox, False, False, 20) hbox.pack_start(bar, True, True, 10) hbox.pack_start(budgetentry, False, False, 20) # hbox.pack_start(freqcombo, True, True, 0) self.budgetbox.pack_start(hbox, False, False, 5) self.show_all()
def _create_pie_chart(self, context, image_width, image_height): _set_screen_dpi() scale = image_width / 1600. context.rectangle(0, 0, image_width, image_height) context.set_source_rgb(1, 1, 1) context.fill() margin_left = (style.GRID_CELL_SIZE / 2) * scale margin_top = (style.GRID_CELL_SIZE / 2) * scale padding = 20 * scale title_font_size = self._calculate_title_font_size(scale) title_width, title_height = self._measure_text( self._title, title_font_size, max_width=image_width - margin_left * 2) rectangles_width = 0 if self._show_labels: # measure the descriptions max_width_desc = 0 max_width_amount = 0 max_height = 0 label_font_size = 14 * scale for data in self._data: description = data['label'] # If there is no category, display as Unknown if description is '': description = _('Unknown') if len(description) > 30: description = description[:30] + '...' # need measure the description width to align the amounts width, height = self._measure_text(description, label_font_size) max_width_desc = max(max_width_desc, width) max_height = max(max_height, height) width, height = self._measure_text(str(data['value']), label_font_size) max_height = max(max_height, height) max_width_amount = max(max_width_amount, width) # draw the labels labels_height = (max_height * 2.5) * len(self._data) y = (image_height - labels_height) / 2 context.save() context.translate(margin_left, 0) rectangles_width = max_width_desc + max_width_amount + padding * 3 for data in self._data: description = data['label'] if description is '': description = _('Unknown') if len(description) > 30: description = description[:30] + '...' context.save() context.translate(0, y) draw_round_rect(context, 0, 0, rectangles_width, max_height * 2, 10) color = style.Color(data['color']) context.set_source_rgba(*color.get_rgba()) context.fill() if colors.is_too_light(data['color']): context.set_source_rgb(0, 0, 0) else: context.set_source_rgb(1, 1, 1) width, height = self._measure_text(description, label_font_size) self._print_text(context, padding, height * .5, description, label_font_size) text = str(data['value']) width, height = self._measure_text(text, label_font_size) self._print_text(context, rectangles_width - width - padding, height * .5, text, label_font_size) y += max_height * 2.5 context.restore() context.restore() self._print_text( context, 0, margin_top, self._title, title_font_size, max_width=image_width - margin_left * 2, alignment=Pango.Alignment.CENTER, color=self._title_color) margin_top += title_height + margin_top * 2 # draw the pie r = min(image_width - rectangles_width - margin_left * 3, image_height - margin_top - margin_left) / 2 y = max(r + margin_top, image_height / 2) if rectangles_width == 0: x = image_width / 2 else: x = image_width - margin_left - r total = 0 for data in self._data: total += data['value'] if total != 0: angle = 0.0 for data in self._data: value = data['value'] slice = 2 * math.pi * value / total color = style.Color(data['color']) context.move_to(x, y) context.arc(x, y, r, angle, angle + slice) context.close_path() context.set_source_rgba(*color.get_rgba()) context.fill() angle += slice