[hamster-applet] moved TagsEntry and TagBox into separate widget
- From: Toms Baugis <tbaugis src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [hamster-applet] moved TagsEntry and TagBox into separate widget
- Date: Sun, 22 Nov 2009 19:09:41 +0000 (UTC)
commit b866c2e5539044de0babc9617ffb7aaf30053b5d
Author: Toms Bauģis <toms baugis gmail com>
Date: Sun Nov 22 19:09:20 2009 +0000
moved TagsEntry and TagBox into separate widget
hamster/standalone.py | 311 +----------------------------------------
hamster/widgets/Makefile.am | 3 +-
hamster/widgets/__init__.py | 3 +
hamster/widgets/tags.py | 320 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 333 insertions(+), 304 deletions(-)
---
diff --git a/hamster/standalone.py b/hamster/standalone.py
index 1156b98..65b0b41 100755
--- a/hamster/standalone.py
+++ b/hamster/standalone.py
@@ -34,307 +34,6 @@ import gobject
import graphics
import pango, cairo
-from math import pi
-
-class TagsEntry(gtk.Entry):
- __gsignals__ = {
- 'tags-selected': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
- }
-
- def __init__(self):
- gtk.Entry.__init__(self)
- self.tags = None
- self.filter = None # currently applied filter string
- self.filter_tags = None #filtered tags
-
- self.popup = gtk.Window(type = gtk.WINDOW_POPUP)
- self.scroll_box = gtk.ScrolledWindow()
- self.scroll_box.set_shadow_type(gtk.SHADOW_IN)
- self.scroll_box.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
- viewport = gtk.Viewport()
- viewport.set_shadow_type(gtk.SHADOW_NONE)
-
- self.tag_box = TagBox()
- self.tag_box.connect("tag-selected", self.on_tag_selected)
- self.tag_box.connect("tag-unselected", self.on_tag_unselected)
-
-
- viewport.add(self.tag_box)
- self.scroll_box.add(viewport)
- self.popup.add(self.scroll_box)
-
- self.connect("button-press-event", self._on_button_press_event)
- self.connect("key-press-event", self._on_key_press_event)
- self.connect("key-release-event", self._on_key_release_event)
- self.connect("focus-out-event", self._on_focus_out_event)
- self.show()
- self.populate_suggestions()
-
- def get_tags(self):
- # splits the string by comma and filters out blanks
- return [tag.strip() for tag in self.get_text().split(",") if tag.strip()]
-
- def on_tag_selected(self, tag_box, tag):
- tags = self.get_tags()
- tags.append(tag)
-
- self.set_text(", ".join(tags))
- self.set_position(len(self.get_text()))
-
- def on_tag_unselected(self, tag_box, tag):
- tags = self.get_tags()
- print tags
- while tag in tags: #it could be that dear user is mocking us and entering same tag over and over again
- tags.remove(tag)
-
- print tags
-
- self.set_text(", ".join(tags))
- self.set_position(len(self.get_text()))
-
-
- def hide_popup(self):
- self.popup.hide()
-
- def show_popup(self):
- if not self.filter_tags:
- self.popup.hide()
- return
-
- alloc = self.get_allocation()
- x, y = self.get_parent_window().get_origin()
-
- self.popup.move(x + alloc.x,y + alloc.y + alloc.height)
-
- w = alloc.width
-
-
- self.popup.show_all()
- self.scroll_box.set_size_request(w, self.tag_box.count_height())
- self.popup.resize(w, self.tag_box.count_height())
-
-
- def complete_inline(self):
- return
-
- def refresh_activities(self):
- # scratch activities and categories so that they get repopulated on demand
- self.activities = None
- self.categories = None
-
- def populate_suggestions(self):
- cursor_tag = self.get_cursor_tag()
-
- self.tags = ["peh", "poh", "and so on", "etc", "true magic",
- "and so we go", "on and on", "until you drop", "somewhere",
- "and forget", "what we", "were", "actually doing"]
-
-
- self.filter = cursor_tag
-
- entered_tags = self.get_tags()
- self.tag_box.selected_tags = entered_tags
-
- self.filter_tags = [tag for tag in self.tags if tag.startswith(self.filter)]
-
- self.tag_box.draw(self.filter_tags)
-
-
-
- def _on_focus_out_event(self, widget, event):
- self.hide_popup()
-
- def _on_button_press_event(self, button, event):
- self.populate_suggestions()
- self.show_popup()
-
- def _on_key_release_event(self, entry, event):
- if (event.keyval in (gtk.keysyms.Return, gtk.keysyms.KP_Enter)):
- if self.popup.get_property("visible"):
- self.hide_popup()
- return True
- else:
- self.emit("tags-selected")
- return False
- elif (event.keyval == gtk.keysyms.Escape):
- if self.popup.get_property("visible"):
- self.hide_popup()
- return True
- else:
- return False
- else:
- self.populate_suggestions()
- self.show_popup()
-
- if event.keyval not in (gtk.keysyms.Delete, gtk.keysyms.BackSpace):
- self.complete_inline()
-
-
- def get_cursor_tag(self):
- #returns the tag on which the cursor is on right now
- if self.get_selection_bounds():
- cursor = self.get_selection_bounds()[0]
- else:
- cursor = self.get_position()
-
- text = self.get_text()
-
- return text[text.rfind(",", 0, cursor)+1:cursor].strip()
-
-
- def replace_tag(self, old_tag, new_tag):
- tags = self.get_tags()
- if old_tag in tags:
- tags[tags.index(old_tag)] = new_tag
-
- if self.get_selection_bounds():
- cursor = self.get_selection_bounds()[0]
- else:
- cursor = self.get_position()
-
- self.set_text(", ".join(tags))
- self.set_position(cursor + len(new_tag)-len(old_tag)) # put the cursor back
-
- def _on_key_press_event(self, entry, event):
-
- if event.keyval == gtk.keysyms.Tab:
- if self.popup.get_property("visible"):
- #we have to replace
- self.replace_tag(self.get_cursor_tag(), self.filter_tags[0])
- return True
- else:
- return False
-
- return False
-
-
-class TagBox(graphics.Area):
- __gsignals__ = {
- 'tag-selected': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (str,)),
- 'tag-unselected': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (str,)),
- }
-
- def __init__(self):
- graphics.Area.__init__(self)
- self.font_size = 10
- self.connect("mouse-over", self.on_tag_hover)
- self.connect("button-release", self.on_tag_click)
- self.hover_tag = None
- self.tags = []
- self.selected_tags = []
-
- def on_tag_hover(self, widget, regions):
- if regions:
- self.hover_tag = regions[0]
- else:
- self.hover_tag = None
-
- self.redraw_canvas()
-
- def on_tag_click(self, widget, regions):
- tag = regions[0]
- if tag in self.selected_tags:
- self.selected_tags.remove(tag)
- self.emit("tag-unselected", tag)
- else:
- self.selected_tags.append(tag)
- self.emit("tag-selected", tag)
-
- self.redraw_canvas()
-
- def draw(self, tags):
- """Draw chart with given data"""
- self.tags = tags
- self.show()
- self.redraw_canvas()
-
- def tag_size(self, label):
- text_w, text_h = self.set_text(label)
- w = text_w + 18 # padding (we have some diagonals to draw)
- h = text_h + 4
- return w, h
-
- def draw_tag(self, label, x, y, color):
- self.context.set_line_width(1)
-
- tag_x = x + 0.5
- tag_y = y + 0.5
-
- w, h = self.tag_size(label)
-
- self.move_to(x, y + 6)
- self.line_to(x + 6, y)
- self.line_to(x + w, y)
- self.line_to(x + w, y + h)
- self.line_to(x + 6, y + h)
- self.line_to(x, y + h - 6)
- self.line_to(x, y + 6)
- self.set_color(color)
- self.context.fill_preserve()
- self.set_color((200, 200, 200))
- self.context.stroke()
-
- self.context.set_antialias(cairo.ANTIALIAS_DEFAULT)
- self.context.arc(x + 6, y + h / 2 + 1, 2, 0, 2 * pi)
- self.set_color((255, 255, 255))
- self.context.fill_preserve()
- self.set_color((200, 200, 200))
- self.context.stroke()
- self.context.set_antialias(cairo.ANTIALIAS_NONE)
-
- self.set_color((0, 0, 0))
-
- #self.layout.set_width((self.width) * pango.SCALE)
- self.context.move_to(x + 12,y + 2)
-
- self.context.show_layout(self.layout)
-
-
- def count_height(self):
- if not self.width:
- return 120
-
- # tells you how much height in this width is needed to show all tags
- if not self.tags:
- return None
-
- cur_x, cur_y = 4, 4
- for tag in self.tags:
- w, h = self.tag_size(tag)
- if cur_x + w >= self.width - 5: #if we don't fit, we wrap
- cur_x = 5
- cur_y += h + 6
-
- cur_x += w + 8 #some padding too, please
-
- cur_y = cur_y + h + 6
-
- return cur_y
-
-
- def _render(self):
- self.fill_area(0, 0, self.width, self.height, (255,255,255))
-
- cur_x, cur_y = 4, 4
- for tag in self.tags:
- w, h = self.tag_size(tag)
- if cur_x + w >= self.width - 5: #if we don't fit, we wrap
- cur_x = 5
- cur_y += h + 6
-
- if tag in self.selected_tags:
- color = (242, 229, 97)
- elif tag == self.hover_tag:
- color = (252, 248, 204)
- else:
- color = (241, 234, 170)
-
- self.draw_tag(tag, cur_x, cur_y, color)
- self.register_mouse_region(cur_x, cur_y, cur_x + w, cur_y + h, tag)
-
- cur_x += w + 8 #some padding too, please
-
-
class MainWindow(object):
def __init__(self):
self._gui = stuff.load_ui_file("hamster.ui")
@@ -348,7 +47,13 @@ class MainWindow(object):
widgets.add_hint(self.new_name, _("Time and Name"))
self.get_widget("new_name_box").add(self.new_name)
- self.new_tags = TagsEntry()
+ self.new_tags = widgets.TagsEntry()
+
+ self.new_tags.set_entries(["peh", "poh", "and so on", "etc", "true magic",
+ "and so we go", "on and on", "until you drop",
+ "somewhere", "and forget", "what we", "were",
+ "actually doing"])
+
widgets.add_hint(self.new_tags, _("Tags or Description"))
self.get_widget("new_tags_box").add(self.new_tags)
@@ -359,7 +64,7 @@ class MainWindow(object):
gtk.link_button_set_uri_hook(self.magic)
- self.tag_box = TagBox()
+ self.tag_box = widgets.TagBox()
self.get_widget("tag_box").add(self.tag_box)
self._gui.connect_signals(self)
diff --git a/hamster/widgets/Makefile.am b/hamster/widgets/Makefile.am
index ef51a33..d237755 100644
--- a/hamster/widgets/Makefile.am
+++ b/hamster/widgets/Makefile.am
@@ -6,7 +6,8 @@ hamster_PYTHON = \
dateinput.py \
dayline.py \
timeline.py \
- reportchooserdialog.py
+ reportchooserdialog.py \
+ tags.py
clean-local:
rm -rf *.pyc *.pyo
diff --git a/hamster/widgets/__init__.py b/hamster/widgets/__init__.py
index 644633c..1bc2e5e 100644
--- a/hamster/widgets/__init__.py
+++ b/hamster/widgets/__init__.py
@@ -28,6 +28,9 @@ from timeinput import TimeInput
from timeline import TimeLine
from dayline import DayLine
+from tags import TagBox
+from tags import TagsEntry
+
from reportchooserdialog import ReportChooserDialog
# handy wrappers
diff --git a/hamster/widgets/tags.py b/hamster/widgets/tags.py
new file mode 100644
index 0000000..7ddf94d
--- /dev/null
+++ b/hamster/widgets/tags.py
@@ -0,0 +1,320 @@
+# - coding: utf-8 -
+
+# Copyright (C) 2009 Toms Bauģis <toms.baugis at gmail.com>
+
+# This file is part of Project Hamster.
+
+# Project Hamster is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Project Hamster is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Project Hamster. If not, see <http://www.gnu.org/licenses/>.
+
+import gtk, gobject
+import pango, cairo
+from math import pi
+
+from hamster import graphics
+
+class TagsEntry(gtk.Entry):
+ __gsignals__ = {
+ 'tags-selected': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
+ }
+
+ def __init__(self):
+ gtk.Entry.__init__(self)
+ self.tags = []
+ self.filter = None # currently applied filter string
+ self.filter_tags = [] #filtered tags
+
+ self.popup = gtk.Window(type = gtk.WINDOW_POPUP)
+ self.scroll_box = gtk.ScrolledWindow()
+ self.scroll_box.set_shadow_type(gtk.SHADOW_IN)
+ self.scroll_box.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ viewport = gtk.Viewport()
+ viewport.set_shadow_type(gtk.SHADOW_NONE)
+
+ self.tag_box = TagBox()
+ self.tag_box.connect("tag-selected", self.on_tag_selected)
+ self.tag_box.connect("tag-unselected", self.on_tag_unselected)
+
+
+ viewport.add(self.tag_box)
+ self.scroll_box.add(viewport)
+ self.popup.add(self.scroll_box)
+
+ self.connect("button-press-event", self._on_button_press_event)
+ self.connect("key-press-event", self._on_key_press_event)
+ self.connect("key-release-event", self._on_key_release_event)
+ self.connect("focus-out-event", self._on_focus_out_event)
+ self.show()
+ self.populate_suggestions()
+
+ def set_entries(self, tags):
+ self.tags = tags
+
+ def get_tags(self):
+ # splits the string by comma and filters out blanks
+ return [tag.strip() for tag in self.get_text().split(",") if tag.strip()]
+
+ def on_tag_selected(self, tag_box, tag):
+ tags = self.get_tags()
+ tags.append(tag)
+
+ self.set_text(", ".join(tags))
+ self.set_position(len(self.get_text()))
+
+ def on_tag_unselected(self, tag_box, tag):
+ tags = self.get_tags()
+ print tags
+ while tag in tags: #it could be that dear user is mocking us and entering same tag over and over again
+ tags.remove(tag)
+
+ print tags
+
+ self.set_text(", ".join(tags))
+ self.set_position(len(self.get_text()))
+
+
+ def hide_popup(self):
+ self.popup.hide()
+
+ def show_popup(self):
+ if not self.filter_tags:
+ self.popup.hide()
+ return
+
+ alloc = self.get_allocation()
+ x, y = self.get_parent_window().get_origin()
+
+ self.popup.move(x + alloc.x,y + alloc.y + alloc.height)
+
+ w = alloc.width
+
+
+ self.popup.show_all()
+ self.scroll_box.set_size_request(w, self.tag_box.count_height())
+ self.popup.resize(w, self.tag_box.count_height())
+
+
+ def complete_inline(self):
+ return
+
+ def refresh_activities(self):
+ # scratch activities and categories so that they get repopulated on demand
+ self.activities = None
+ self.categories = None
+
+ def populate_suggestions(self):
+ cursor_tag = self.get_cursor_tag()
+
+ self.filter = cursor_tag
+
+ entered_tags = self.get_tags()
+ self.tag_box.selected_tags = entered_tags
+
+ self.filter_tags = [tag for tag in self.tags if tag.startswith(self.filter)]
+
+ self.tag_box.draw(self.filter_tags)
+
+
+
+ def _on_focus_out_event(self, widget, event):
+ self.hide_popup()
+
+ def _on_button_press_event(self, button, event):
+ self.populate_suggestions()
+ self.show_popup()
+
+ def _on_key_release_event(self, entry, event):
+ if (event.keyval in (gtk.keysyms.Return, gtk.keysyms.KP_Enter)):
+ if self.popup.get_property("visible"):
+ self.hide_popup()
+ return True
+ else:
+ self.emit("tags-selected")
+ return False
+ elif (event.keyval == gtk.keysyms.Escape):
+ if self.popup.get_property("visible"):
+ self.hide_popup()
+ return True
+ else:
+ return False
+ else:
+ self.populate_suggestions()
+ self.show_popup()
+
+ if event.keyval not in (gtk.keysyms.Delete, gtk.keysyms.BackSpace):
+ self.complete_inline()
+
+
+ def get_cursor_tag(self):
+ #returns the tag on which the cursor is on right now
+ if self.get_selection_bounds():
+ cursor = self.get_selection_bounds()[0]
+ else:
+ cursor = self.get_position()
+
+ text = self.get_text()
+
+ return text[text.rfind(",", 0, cursor)+1:cursor].strip()
+
+
+ def replace_tag(self, old_tag, new_tag):
+ tags = self.get_tags()
+ if old_tag in tags:
+ tags[tags.index(old_tag)] = new_tag
+
+ if self.get_selection_bounds():
+ cursor = self.get_selection_bounds()[0]
+ else:
+ cursor = self.get_position()
+
+ self.set_text(", ".join(tags))
+ self.set_position(cursor + len(new_tag)-len(old_tag)) # put the cursor back
+
+ def _on_key_press_event(self, entry, event):
+
+ if event.keyval == gtk.keysyms.Tab:
+ if self.popup.get_property("visible"):
+ #we have to replace
+ self.replace_tag(self.get_cursor_tag(), self.filter_tags[0])
+ return True
+ else:
+ return False
+
+ return False
+
+
+class TagBox(graphics.Area):
+ __gsignals__ = {
+ 'tag-selected': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (str,)),
+ 'tag-unselected': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (str,)),
+ }
+
+ def __init__(self):
+ graphics.Area.__init__(self)
+ self.font_size = 10
+ self.connect("mouse-over", self.on_tag_hover)
+ self.connect("button-release", self.on_tag_click)
+ self.hover_tag = None
+ self.tags = []
+ self.selected_tags = []
+
+ def on_tag_hover(self, widget, regions):
+ if regions:
+ self.hover_tag = regions[0]
+ else:
+ self.hover_tag = None
+
+ self.redraw_canvas()
+
+ def on_tag_click(self, widget, regions):
+ tag = regions[0]
+ if tag in self.selected_tags:
+ self.selected_tags.remove(tag)
+ self.emit("tag-unselected", tag)
+ else:
+ self.selected_tags.append(tag)
+ self.emit("tag-selected", tag)
+
+ self.redraw_canvas()
+
+ def draw(self, tags):
+ """Draw chart with given data"""
+ self.tags = tags
+ self.show()
+ self.redraw_canvas()
+
+ def tag_size(self, label):
+ text_w, text_h = self.set_text(label)
+ w = text_w + 18 # padding (we have some diagonals to draw)
+ h = text_h + 4
+ return w, h
+
+ def draw_tag(self, label, x, y, color):
+ self.context.set_line_width(1)
+
+ tag_x = x + 0.5
+ tag_y = y + 0.5
+
+ w, h = self.tag_size(label)
+
+ self.move_to(x, y + 6)
+ self.line_to(x + 6, y)
+ self.line_to(x + w, y)
+ self.line_to(x + w, y + h)
+ self.line_to(x + 6, y + h)
+ self.line_to(x, y + h - 6)
+ self.line_to(x, y + 6)
+ self.set_color(color)
+ self.context.fill_preserve()
+ self.set_color((200, 200, 200))
+ self.context.stroke()
+
+ self.context.set_antialias(cairo.ANTIALIAS_DEFAULT)
+ self.context.arc(x + 6, y + h / 2 + 1, 2, 0, 2 * pi)
+ self.set_color((255, 255, 255))
+ self.context.fill_preserve()
+ self.set_color((200, 200, 200))
+ self.context.stroke()
+ self.context.set_antialias(cairo.ANTIALIAS_NONE)
+
+ self.set_color((0, 0, 0))
+
+ #self.layout.set_width((self.width) * pango.SCALE)
+ self.context.move_to(x + 12,y + 2)
+
+ self.context.show_layout(self.layout)
+
+
+ def count_height(self):
+ if not self.width:
+ return 120
+
+ # tells you how much height in this width is needed to show all tags
+ if not self.tags:
+ return None
+
+ cur_x, cur_y = 4, 4
+ for tag in self.tags:
+ w, h = self.tag_size(tag)
+ if cur_x + w >= self.width - 5: #if we don't fit, we wrap
+ cur_x = 5
+ cur_y += h + 6
+
+ cur_x += w + 8 #some padding too, please
+
+ cur_y = cur_y + h + 6
+
+ return cur_y
+
+
+ def _render(self):
+ self.fill_area(0, 0, self.width, self.height, (255,255,255))
+
+ cur_x, cur_y = 4, 4
+ for tag in self.tags:
+ w, h = self.tag_size(tag)
+ if cur_x + w >= self.width - 5: #if we don't fit, we wrap
+ cur_x = 5
+ cur_y += h + 6
+
+ if tag in self.selected_tags:
+ color = (242, 229, 97)
+ elif tag == self.hover_tag:
+ color = (252, 248, 204)
+ else:
+ color = (241, 234, 170)
+
+ self.draw_tag(tag, cur_x, cur_y, color)
+ self.register_mouse_region(cur_x, cur_y, cur_x + w, cur_y + h, tag)
+
+ cur_x += w + 8 #some padding too, please
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]