Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGonzalo Odiard <godiard@gmail.com>2014-07-04 18:57:20 (GMT)
committer Gonzalo Odiard <godiard@gmail.com>2014-07-04 18:57:20 (GMT)
commitdb98cdaa181cecf3423341f5429f3d0852d18e3c (patch)
treee0761613d9b53a6d4b4a14751fcf8be19c69e152
parent812afcaaee71ad528d33f168e64b60c066e7adcd (diff)
Replace combo by palette
-rw-r--r--filtertoolitem.py180
-rw-r--r--finance.py86
-rw-r--r--icons/write-date.svg10
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)
diff --git a/finance.py b/finance.py
index b664944..1bbb7fa 100644
--- a/finance.py
+++ b/finance.py
@@ -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>