diff options
author | Gonzalo Odiard <godiard@gmail.com> | 2014-07-04 18:57:20 (GMT) |
---|---|---|
committer | Gonzalo Odiard <godiard@gmail.com> | 2014-07-04 18:57:20 (GMT) |
commit | db98cdaa181cecf3423341f5429f3d0852d18e3c (patch) | |
tree | e0761613d9b53a6d4b4a14751fcf8be19c69e152 | |
parent | 812afcaaee71ad528d33f168e64b60c066e7adcd (diff) |
Replace combo by palette
-rw-r--r-- | filtertoolitem.py | 180 | ||||
-rw-r--r-- | finance.py | 86 | ||||
-rw-r--r-- | icons/write-date.svg | 10 |
3 files changed, 237 insertions, 39 deletions
diff --git a/filtertoolitem.py b/filtertoolitem.py new file mode 100644 index 0000000..d28b14c --- /dev/null +++ b/filtertoolitem.py @@ -0,0 +1,180 @@ +import logging +from gettext import gettext as _ + +from gi.repository import GObject +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import Pango + +from sugar3.graphics import style +from sugar3.graphics.palette import Palette +from sugar3.graphics.palettemenu import PaletteMenuItem +from sugar3.graphics.palette import ToolInvoker +from sugar3.graphics.icon import Icon + + +class FilterToolItem(Gtk.ToolButton): + + _LABEL_MAX_WIDTH = 18 + _MAXIMUM_PALETTE_COLUMNS = 4 + + __gsignals__ = { + 'changed': (GObject.SignalFlags.RUN_LAST, None, ([str])), } + + def __init__(self, default_icon, default_value, options, palette_title): + self._palette_invoker = ToolInvoker() + self._options = options + self._palette_title = palette_title + Gtk.ToolButton.__init__(self) + logging.error('filter options %s', options) + self._value = default_value + self._label = self._options[default_value] + self.set_is_important(True) + self.set_size_request(style.GRID_CELL_SIZE, -1) + + self._label_widget = Gtk.Label() + self._label_widget.set_alignment(0.0, 0.5) + self._label_widget.set_ellipsize(Pango.EllipsizeMode.MIDDLE) + self._label_widget.set_max_width_chars(self._LABEL_MAX_WIDTH) + self._label_widget.set_use_markup(True) + self._label_widget.set_markup(self._label) + self.set_label_widget(self._label_widget) + self._label_widget.show() + + self.set_widget_icon(icon_name=default_icon) + + self._hide_tooltip_on_click = True + self._palette_invoker.attach_tool(self) + self._palette_invoker.props.toggle_palette = True + self._palette_invoker.props.lock_palette = True + + self.palette = Palette(self._palette_title) + self.palette.set_invoker(self._palette_invoker) + + self.props.palette.set_content(self.set_palette_list(options)) + + def set_options(self, options): + self._options = options + self.palette = Palette(self._palette_title) + self.palette.set_invoker(self._palette_invoker) + self.props.palette.set_content(self.set_palette_list(options)) + if self._value not in self._options.keys(): + new_value = self._options.keys()[0] + self._value = new_value + self._set_widget_label(self._options[new_value]) + self.emit('changed', new_value) + + def set_widget_icon(self, icon_name=None): + icon = Icon(icon_name=icon_name, + icon_size=style.SMALL_ICON_SIZE) + self.set_icon_widget(icon) + icon.show() + + def _set_widget_label(self, label=None): + # FIXME: Ellipsis is not working on these labels. + if label is None: + label = self._label + if len(label) > self._LABEL_MAX_WIDTH: + label = label[0:7] + '...' + label[-7:] + self._label_widget.set_markup(label) + self._label = label + + def __destroy_cb(self, icon): + if self._palette_invoker is not None: + self._palette_invoker.detach() + + def create_palette(self): + return None + + def get_palette(self): + return self._palette_invoker.palette + + def set_palette(self, palette): + self._palette_invoker.palette = palette + + palette = GObject.property( + type=object, setter=set_palette, getter=get_palette) + + def get_palette_invoker(self): + return self._palette_invoker + + def set_palette_invoker(self, palette_invoker): + self._palette_invoker.detach() + self._palette_invoker = palette_invoker + + palette_invoker = GObject.property( + type=object, setter=set_palette_invoker, getter=get_palette_invoker) + + def do_draw(self, cr): + if self.palette and self.palette.is_up(): + allocation = self.get_allocation() + # draw a black background, has been done by the engine before + cr.set_source_rgb(0, 0, 0) + cr.rectangle(0, 0, allocation.width, allocation.height) + cr.paint() + + Gtk.ToolButton.do_draw(self, cr) + + if self.palette and self.palette.is_up(): + invoker = self.palette.props.invoker + invoker.draw_rectangle(cr, self.palette) + + return False + + def set_palette_list(self, options): + _menu_item = PaletteMenuItem(text_label=options[options.keys()[0]]) + req2 = _menu_item.get_preferred_size()[1] + menuitem_width = req2.width + menuitem_height = req2.height + + palette_width = Gdk.Screen.width() - style.GRID_CELL_SIZE + palette_height = Gdk.Screen.height() - style.GRID_CELL_SIZE * 3 + + nx = min(self._MAXIMUM_PALETTE_COLUMNS, + int(palette_width / menuitem_width)) + ny = min(int(palette_height / menuitem_height), len(options) + 1) + if ny >= len(options): + nx = 1 + ny = len(options) + + grid = Gtk.Grid() + grid.set_row_spacing(style.DEFAULT_PADDING) + grid.set_column_spacing(0) + grid.set_border_width(0) + grid.show() + + x = 0 + y = 0 + + for key in sorted(options): + menu_item = PaletteMenuItem() + menu_item.set_label(options[key]) + + menu_item.set_size_request(style.GRID_CELL_SIZE * 3, -1) + + menu_item.connect('button-release-event', self._option_selected, + key) + grid.attach(menu_item, x, y, 1, 1) + x += 1 + if x == nx: + x = 0 + y += 1 + + menu_item.show() + + if palette_height < (y * menuitem_height + style.GRID_CELL_SIZE): + # if the grid is bigger than the palette, put in a scrolledwindow + scrolled_window = Gtk.ScrolledWindow() + scrolled_window.set_policy(Gtk.PolicyType.NEVER, + Gtk.PolicyType.AUTOMATIC) + scrolled_window.set_size_request(nx * menuitem_width, + (ny + 1) * menuitem_height) + scrolled_window.add_with_viewport(grid) + return scrolled_window + else: + return grid + + def _option_selected(self, menu_item, event, key): + self._set_widget_label(self._options[key]) + self._value = key + self.emit('changed', key) @@ -29,7 +29,6 @@ from gi.repository import Pango # Import Sugar UI modules. from sugar3.graphics.toolbutton import ToolButton -from sugar3.graphics.toolcombobox import ToolComboBox from sugar3.graphics.toolbarbox import ToolbarBox from sugar3.graphics.radiotoolbutton import RadioToolButton from sugar3.graphics import style @@ -44,6 +43,7 @@ import chartscreen import budgetscreen from helpbutton import HelpButton import colors +from filtertoolitem import FilterToolItem # Set up localization. locale.setlocale(locale.LC_ALL, '') @@ -53,12 +53,19 @@ log = logging.getLogger('Finance') log.setLevel(logging.DEBUG) logging.basicConfig() +DAY = 0 +WEEK = 1 +MONTH = 2 +YEAR = 3 +FOREVER = 4 + # This is the main Finance activity class. # # It owns the main application window, and all the various toolbars # and options. Screens are stored in a stack, with the currently # active screen on top. + class Finance(Activity): def __init__(self, handle): Activity.__init__(self, handle) @@ -87,7 +94,7 @@ class Finance(Activity): # self.create_test_data() # Initialize view period to the first of the month. - self.period = _('Month') + self.period = MONTH self.period_start = self.get_this_period() # Create screens. @@ -145,14 +152,12 @@ class Finance(Activity): self.nextperiodbtn.props.accelerator = '<Ctrl>Right' self.nextperiodbtn.connect('clicked', self.nextperiod_cb) - periodcombo = Gtk.ComboBoxText() - periodcombo.append_text(_('Day')) - periodcombo.append_text(_('Week')) - periodcombo.append_text(_('Month')) - periodcombo.append_text(_('Year')) - periodcombo.append_text(_('Forever')) - periodcombo.set_active(2) - periodcombo.connect('changed', self.period_changed_cb) + period_options = {DAY: _('Day'), WEEK: _('Week'), MONTH: _('Month'), + YEAR: _('Year'), FOREVER: _('Forever')} + periodcombo = FilterToolItem('write-date', MONTH, period_options, + _('Select period')) + + periodcombo.connect('changed', self.__period_changed_cb) self.header_controls_box.pack_end(self.thisperiodbtn, False, False, 0) self.header_controls_box.pack_end(self.nextperiodbtn, False, False, 0) @@ -321,23 +326,23 @@ class Finance(Activity): self.update_toolbar() def update_header(self): - if self.period == _('Day'): + if self.period == DAY: # TRANS: representation of the "Day" period text = self.period_start.strftime(_("%B %d, %Y")) - elif self.period == _('Week'): + elif self.period == WEEK: # TRANS: representation of the "Week of" period text = _('Week of') + self.period_start.strftime(_(" %B %d, %Y")) - elif self.period == _('Month'): + elif self.period == MONTH: # TRANS: representation of the "Month" period text = self.period_start.strftime(_("%B, %Y")) - elif self.period == _('Year'): + elif self.period == YEAR: # TRANS: representation of the "Year" period text = self.period_start.strftime(_("%Y")) - elif self.period == _('Forever'): + elif self.period == FOREVER: text = _('Forever') self.periodlabel.set_markup( @@ -397,23 +402,26 @@ class Finance(Activity): def update_toolbar(self): # Disable the navigation when Forever is selected. - next_prev = self.period != _('Forever') + next_prev = self.period != FOREVER self.prevperiodbtn.set_sensitive(next_prev) self.thisperiodbtn.set_sensitive(next_prev) self.nextperiodbtn.set_sensitive(next_prev) # This is a HACK to translate the string properly # http://bugs.sugarlabs.org/ticket/3190 - period = self.period.lower() - if period == _('Month').lower(): + if self.period == MONTH: text_previous_period = _('Previous Month') text_this_period = _('This Month') text_next_period = _('Next Month') - elif period == _('Day').lower(): + elif self.period == WEEK: + text_previous_period = _('Previous Week') + text_this_period = _('This Week') + text_next_period = _('Next Week') + elif self.period == DAY: text_previous_period = _('Previous Day') text_this_period = _('This Day') text_next_period = _('Next Day') - elif period == _('Year').lower(): + elif self.period == YEAR: text_previous_period = _('Previous Year') text_this_period = _('This Year') text_next_period = _('Next Year') @@ -432,72 +440,72 @@ class Finance(Activity): def get_this_period(self): today = datetime.date.today() - if self.period == _('Day'): + if self.period == DAY: return today - elif self.period == _('Week'): + elif self.period == WEEK: while today.weekday() != 0: today -= datetime.timedelta(days=1) return today - elif self.period == _('Month'): + elif self.period == MONTH: return datetime.date(today.year, today.month, 1) - elif self.period == _('Year'): + elif self.period == YEAR: return datetime.date(today.year, 1, 1) - elif self.period == _('Forever'): + elif self.period == FOREVER: return datetime.date(1900, 1, 1) def get_next_period(self, start): - if self.period == _('Day'): + if self.period == DAY: return start + datetime.timedelta(days=1) - elif self.period == _('Week'): + elif self.period == WEEK: return start + datetime.timedelta(days=7) - elif self.period == _('Month'): + elif self.period == MONTH: if start.month == 12: return datetime.date(start.year + 1, 1, 1) else: return datetime.date(start.year, start.month + 1, 1) - elif self.period == _('Year'): + elif self.period == YEAR: return datetime.date(start.year + 1, 1, 1) def get_prev_period(self, start): - if self.period == _('Day'): + if self.period == DAY: return start - datetime.timedelta(days=1) - elif self.period == _('Week'): + elif self.period == WEEK: return start - datetime.timedelta(days=7) - elif self.period == _('Month'): + elif self.period == MONTH: if start.month == 1: return datetime.date(start.year - 1, 12, 1) else: return datetime.date(start.year, start.month - 1, 1) - elif self.period == _('Year'): + elif self.period == YEAR: return datetime.date(start.year - 1, 1, 1) def thisperiod_cb(self, widget): - if self.period != _('Forever'): + if self.period != FOREVER: self.period_start = self.get_this_period() self.build_screen() def nextperiod_cb(self, widget): - if self.period != _('Forever'): + if self.period != FOREVER: self.period_start = self.get_next_period(self.period_start) self.build_screen() def prevperiod_cb(self, widget): - if self.period != _('Forever'): + if self.period != FOREVER: self.period_start = self.get_prev_period(self.period_start) self.build_screen() - def period_changed_cb(self, widget): - self.period = widget.get_active_text() + def __period_changed_cb(self, widget, value): + self.period = int(value) self.update_toolbar() # Jump to 'this period'. @@ -505,7 +513,7 @@ class Finance(Activity): self.build_screen() def build_visible_transactions(self): - if self.period == _('Forever'): + if self.period == FOREVER: self.visible_transactions = self.data['transactions'] else: diff --git a/icons/write-date.svg b/icons/write-date.svg new file mode 100644 index 0000000..8aee71c --- /dev/null +++ b/icons/write-date.svg @@ -0,0 +1,10 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" +[ + <!ENTITY fill_color "#FFFFFF"> + <!ENTITY stroke_color "#000000"> +]> +<svg contentScriptType="text/ecmascript" width="55px" xmlns:xlink="http://www.w3.org/1999/xlink" baseProfile="full" zoomAndPan="magnify" contentStyleType="text/css" height="55px" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" version="1.1"> + <rect x="16" y="9" width="33" height="36" fill="none" stroke="&stroke_color;" stroke-width="3.5"/> + <rect x="13" y="9" transform="matrix(1.0 0.0 -0.3 1.0 5 0.0)" fill="&fill_color;" width="32" height="31" stroke="&stroke_color;" stroke-width="3.5"/> + <text x="18" stroke="&stroke_color;" font-size="18" y="30.0" transform="matrix(1.0 0.0 -0.3 1.0 5 0.0)" font-family="'Courier New', 'Courier', 'MS Courier New', 'Prestige', monospace" font-weight="800" xml:space="preserve">26</text> +</svg> |