Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWalter Bender <walter.bender@gmail.com>2013-03-12 15:20:00 (GMT)
committer Walter Bender <walter.bender@gmail.com>2013-03-12 15:20:00 (GMT)
commit7d88e037f8b30b6703a2e6ea5b6a4e64e4bb5804 (patch)
treedad825c4dc2b97a8a4df86b65176d28eb8ea8dab
parent022db68254762057dcf5b7aa8f4fe32d7791e558 (diff)
backport changes from gtk3 version
-rw-r--r--PortfolioActivity.py671
1 files changed, 422 insertions, 249 deletions
diff --git a/PortfolioActivity.py b/PortfolioActivity.py
index e83cf95..5cccee5 100644
--- a/PortfolioActivity.py
+++ b/PortfolioActivity.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-#Copyright (c) 2011, 2012 Walter Bender
+#Copyright (c) 2011-2013 Walter Bender
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -43,12 +43,13 @@ from sugar.graphics.alert import Alert
from sprites import Sprites, Sprite
from exportpdf import save_pdf
-from utils import get_path, lighter_color, svg_str_to_pixbuf, svg_rectangle, \
- play_audio_from_file, get_pixbuf_from_journal, genblank, get_hardware, \
- pixbuf_to_base64, base64_to_pixbuf, get_pixbuf_from_file
-
-from toolbar_utils import radio_factory, button_factory, separator_factory, \
- combo_factory, label_factory
+from utils import (get_path, lighter_color, svg_str_to_pixbuf, svg_rectangle,
+ play_audio_from_file, get_pixbuf_from_journal, genblank,
+ get_hardware, pixbuf_to_base64, base64_to_pixbuf,
+ get_pixbuf_from_file, parse_comments, get_tablet_mode)
+
+from toolbar_utils import (radio_factory, button_factory, separator_factory,
+ combo_factory, label_factory)
from grecord import Grecord
from gettext import gettext as _
@@ -56,11 +57,8 @@ from gettext import gettext as _
import logging
_logger = logging.getLogger("portfolio-activity")
-try:
- from sugar.graphics import style
- GRID_CELL_SIZE = style.GRID_CELL_SIZE
-except ImportError:
- GRID_CELL_SIZE = 0
+from sugar.graphics import style
+GRID_CELL_SIZE = style.GRID_CELL_SIZE
try:
_OLD_SUGAR_SYSTEM = False
@@ -88,11 +86,16 @@ IFACE = SERVICE
PATH = '/org/sugarlabs/PortfolioActivity'
# Size and position of title, preview image, and description
-PREVIEWW = 600
-PREVIEWH = 450
-PREVIEWY = 80
-TITLEH = 60
-DESCRIPTIONY = 550
+TITLE = [[GRID_CELL_SIZE, 10, 1200 - GRID_CELL_SIZE * 2, 100],
+ [GRID_CELL_SIZE, 10, 900 - GRID_CELL_SIZE * 2, 100]]
+PREVIEW = [[GRID_CELL_SIZE, 110, 560, 420],
+ [180, 110, 560, 420]]
+DESC = [[560 + GRID_CELL_SIZE, 110, 560, 420],
+ [GRID_CELL_SIZE, 530, 900 - GRID_CELL_SIZE * 2, 300]]
+NEW_COMMENT = [[GRID_CELL_SIZE, 530, 1200 - GRID_CELL_SIZE * 2, 100],
+ [GRID_CELL_SIZE, 840, 900 - GRID_CELL_SIZE * 2, 100]]
+COMMENTS = [[GRID_CELL_SIZE, 640, 1200 - GRID_CELL_SIZE * 2, 250],
+ [GRID_CELL_SIZE, 950, 900 - GRID_CELL_SIZE * 2, 240]]
TWO = 0
TEN = 1
@@ -103,10 +106,6 @@ UNIT_DICTIONARY = {TWO: (UNITS[TWO], 2),
TEN: (UNITS[TEN], 10),
THIRTY: (UNITS[THIRTY], 30),
SIXTY: (UNITS[SIXTY], 60)}
-XO1 = 'xo1'
-XO15 = 'xo1.5'
-XO175 = 'xo1.75'
-UNKNOWN = 'unknown'
# sprite layers
DRAG = 6
@@ -117,6 +116,8 @@ MIDDLE = 2
BOTTOM = 1
HIDE = 0
+OSK_SHIFT = 200
+
def _get_screen_dpi():
''' Return screen DPI '''
@@ -128,7 +129,7 @@ def _get_screen_dpi():
class Slide():
''' A container for a slide '''
- def __init__(self, owner, uid, colors, title, preview, desc):
+ def __init__(self, owner, uid, colors, title, preview, desc, comment):
self.active = True
self.owner = owner
self.uid = uid
@@ -137,6 +138,7 @@ class Slide():
self.preview = preview
self.preview2 = None # larger version for fullscreen mode
self.description = desc
+ self.comment = comment # A list of dictionaries
self.sound = None
self.dirty = False
self.fav = True
@@ -160,25 +162,15 @@ class PortfolioActivity(activity.Activity):
self.datapath = get_path(activity, 'instance')
self._buddies = [profile.get_nick_name()]
self._colors = profile.get_color().to_string().split(',')
+ self._my_colors = self._colors[:] # Save original colors
self.initiating = None # sharing (True) or joining (False)
-
- self._set_screen_dpi()
-
+ self._tablet_mode = get_tablet_mode()
self._playing = False
self._first_time = True
- self._width = gtk.gdk.screen_width()
- self._height = gtk.gdk.screen_height()
- self._scale = gtk.gdk.screen_height() / 900.
-
- self._titlewh = [self._width, TITLEH * self._scale]
- self._titlexy = [0, 0]
- self._previewwh = [PREVIEWW * self._scale, PREVIEWH * self._scale]
- self._previewxy = [(self._width - self._previewwh[0]) / 2,
- PREVIEWY * self._scale]
- self._descriptionwh = [self._width,
- self._height - DESCRIPTIONY * self._scale - 55]
- self._descriptionxy = [0, DESCRIPTIONY * self._scale]
+ self._set_scale_and_orientation()
+ self._set_screen_dpi()
+ self._set_xy_wh()
if hasattr(self, 'get_window') and \
hasattr(self.get_window(), 'get_cursor'):
@@ -204,20 +196,73 @@ class PortfolioActivity(activity.Activity):
self._keypress = None
self._selected_spr = None
- self._dead_key = ''
self._saved_string = ''
self._startpos = [0, 0]
self._dragpos = [0, 0]
self._setup_presence_service()
+ def _set_xy_wh(self):
+ orientation = self._orientation
+ self._title_wh = [TITLE[orientation][2] * self._scale,
+ TITLE[orientation][3] * self._scale]
+ self._title_xy = [TITLE[orientation][0] * self._scale,
+ TITLE[orientation][1] * self._scale]
+ self._title_xy[0] = int((self._width - self._title_wh[0]) / 2.)
+ self._preview_wh = [PREVIEW[orientation][2] * self._scale,
+ PREVIEW[orientation][3] * self._scale]
+ self._preview_xy = [PREVIEW[orientation][0] * self._scale,
+ PREVIEW[orientation][1] * self._scale]
+ if orientation == 0:
+ self._preview_xy[0] = self._title_xy[0]
+ else:
+ self._preview_xy[0] = int((self._width - self._preview_wh[0]) / 2.)
+ self._desc_wh = [DESC[orientation][2] * self._scale,
+ DESC[orientation][3] * self._scale]
+ if orientation == 0:
+ self._desc_wh[0] = \
+ self._width - self._preview_wh[0] - 2 * self._title_xy[0]
+ else:
+ self._desc_wh[0] = self._title_wh[0]
+ self._desc_xy = [DESC[orientation][0] * self._scale,
+ DESC[orientation][1] * self._scale]
+ if orientation == 0:
+ self._desc_xy[0] = self._preview_wh[0] + self._title_xy[0]
+ else:
+ self._desc_xy[0] = self._title_xy[0]
+ self._new_comment_wh = [NEW_COMMENT[orientation][2] * self._scale,
+ NEW_COMMENT[orientation][3] * self._scale]
+ self._new_comment_xy = [NEW_COMMENT[orientation][0] * self._scale,
+ NEW_COMMENT[orientation][1] * self._scale]
+ self._new_comment_xy[0] = self._title_xy[0]
+ self._new_comment_xy[1] = self._desc_xy[1] + self._desc_wh[1]
+ self._comment_wh = [COMMENTS[orientation][2] * self._scale,
+ COMMENTS[orientation][3] * self._scale]
+ self._comment_xy = [COMMENTS[orientation][0] * self._scale,
+ COMMENTS[orientation][1] * self._scale]
+ self._comment_xy[0] = self._title_xy[0]
+ self._comment_xy[1] = self._new_comment_xy[1] + self._new_comment_wh[1]
+
def _set_screen_dpi(self):
dpi = _get_screen_dpi()
- font_map_default = pangocairo.cairo_font_map_get_default()
+ font_map_default = PangoCairo.font_map_get_default()
font_map_default.set_resolution(dpi)
- def _tablet_mode(self):
- return False # FIXME: Sugar scrolls the window for me???
+ def _fixed_resize_cb(self, widget=None, rect=None):
+ ''' If a toolbar opens or closes, we need to resize the vbox
+ holding out scrolling window. '''
+ self.vbox.set_size_request(rect.width, rect.height)
+
+ '''
+ self._width = gtk.gdk.screen_width()
+ self._height = gtk.gdk.screen_height()
+ self._scale = gtk.gdk.screen_height() / 900.
+ '''
+
+ def _set_screen_dpi(self):
+ dpi = _get_screen_dpi()
+ font_map_default = pangocairo.cairo_font_map_get_default()
+ font_map_default.set_resolution(dpi)
def _fixed_resize_cb(self, widget=None, rect=None):
''' If a toolbar opens or closes, we need to resize the vbox
@@ -233,9 +278,8 @@ class PortfolioActivity(activity.Activity):
self.set_canvas(self.fixed)
self.vbox = gtk.VBox(False, 0)
- self.vbox.set_size_request(
- gtk.gdk.screen_width(),
- gtk.gdk.screen_height() - style.GRID_CELL_SIZE)
+ self.vbox.set_size_request(gtk.gdk.screen_width(),
+ gtk.gdk.screen_height())
self.fixed.put(self.vbox, 0, 0)
self.vbox.show()
@@ -243,7 +287,6 @@ class PortfolioActivity(activity.Activity):
self._canvas.set_size_request(int(gtk.gdk.screen_width()),
int(gtk.gdk.screen_height()))
self._canvas.show()
- # self.set_canvas(self._canvas)
self.show_all()
self.vbox.pack_end(self._canvas, True, True)
self.vbox.show()
@@ -259,32 +302,39 @@ class PortfolioActivity(activity.Activity):
self._canvas.connect('button-release-event', self._button_release_cb)
self._canvas.connect('motion-notify-event', self._mouse_move_cb)
self._canvas.connect('key-press-event', self._keypress_cb)
- self._canvas.connect('configure-event', self._configure_cb)
+ gtk.gdk.screen_get_default().connect('size-changed', self._configure_cb)
self._canvas.grab_focus()
- def _configure_cb(self, win, event):
- # landscape or portrait?
+ def _set_scale_and_orientation(self):
self._width = gtk.gdk.screen_width()
self._height = gtk.gdk.screen_height()
if self._width > self._height:
self._scale = gtk.gdk.screen_height() / 900.
+ self._orientation = 0
else:
- self._scale = gtk.gdk.screen_width() / 1200.
+ self._scale = gtk.gdk.screen_height() / 1200.
+ self._orientation = 1
+ def _configure_cb(self, win, event):
self._my_canvas.hide()
self._title.hide()
self._description.hide()
- self._titlewh = [self._width, TITLEH * self._scale]
- self._titlexy = [0, 0]
- self._previewwh = [PREVIEWW * self._scale, PREVIEWH * self._scale]
- self._previewxy = [(self._width - self._previewwh[0]) / 2,
- PREVIEWY * self._scale]
- self._descriptionwh = [self._width,
- self._height - DESCRIPTIONY * self._scale - 55]
- self._descriptionxy = [0, DESCRIPTIONY * self._scale]
+ self._comment.hide()
+ self._new_comment.hide()
+
+ self._set_scale_and_orientation()
+
+ self.vbox.set_size_request(gtk.gdk.screen_width(),
+ gtk.gdk.screen_height())
+ self.vbox.show()
+ self._canvas.set_size_request(int(gtk.gdk.screen_width()),
+ int(gtk.gdk.screen_height()))
+ self._canvas.show()
+ self._set_xy_wh()
self._configured_sprites() # Some sprites are sized to screen
+ self._my_canvas.set_layer(BOTTOM)
self._clear_screen()
if self._thumbnail_mode:
self._thumbs_cb()
@@ -301,17 +351,17 @@ class PortfolioActivity(activity.Activity):
self._colors[1] = tmp
if self._hw[0:2] == 'xo':
- self._titlef = 18
- self._descriptionf = 12
+ self.title_size = 18
+ self.desc_size = 12
else:
- self._titlef = 36
- self._descriptionf = 24
+ self.title_size = int(36 * self._scale)
+ self.desc_size = int(24 * self._scale)
# Generate the sprites we'll need...
self._sprites = Sprites(self._canvas)
if self._nobjects == 0:
- star_size = 55
+ star_size = GRID_CELL_SIZE
else:
star_size = int(150. / int(ceil(sqrt(self._nobjects))))
self._fav_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
@@ -323,16 +373,17 @@ class PortfolioActivity(activity.Activity):
self.record_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
os.path.join(activity.get_bundle_path(), 'icons',
- 'media-audio.svg'), 55, 55)
+ 'media-audio.svg'), GRID_CELL_SIZE, GRID_CELL_SIZE)
self.recording_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
os.path.join(activity.get_bundle_path(), 'icons',
- 'media-audio-recording.svg'), 55, 55)
+ 'media-audio-recording.svg'), GRID_CELL_SIZE,
+ GRID_CELL_SIZE)
self.playback_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
os.path.join(activity.get_bundle_path(), 'icons',
- 'speaker-100.svg'), 55, 55)
+ 'speaker-100.svg'), GRID_CELL_SIZE, GRID_CELL_SIZE)
self.playing_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
os.path.join(activity.get_bundle_path(), 'icons',
- 'speaker-0.svg'), 55, 55)
+ 'speaker-0.svg'), GRID_CELL_SIZE, GRID_CELL_SIZE)
self._record_button = Sprite(self._sprites, 0, 0, self.record_pixbuf)
self._record_button.set_layer(DRAG)
@@ -345,16 +396,18 @@ class PortfolioActivity(activity.Activity):
self.prev_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
os.path.join(activity.get_bundle_path(), 'icons',
- 'go-previous.svg'), 55, 55)
+ 'go-previous.svg'), GRID_CELL_SIZE, GRID_CELL_SIZE)
self.next_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
os.path.join(activity.get_bundle_path(), 'icons',
- 'go-next.svg'), 55, 55)
+ 'go-next.svg'), GRID_CELL_SIZE, GRID_CELL_SIZE)
self.prev_off_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
os.path.join(activity.get_bundle_path(), 'icons',
- 'go-previous-inactive.svg'), 55, 55)
+ 'go-previous-inactive.svg'), GRID_CELL_SIZE,
+ GRID_CELL_SIZE)
self.next_off_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
os.path.join(activity.get_bundle_path(), 'icons',
- 'go-next-inactive.svg'), 55, 55)
+ 'go-next-inactive.svg'), GRID_CELL_SIZE,
+ GRID_CELL_SIZE)
self._prev = Sprite(self._sprites, 0, 0, self.prev_off_pixbuf)
self._prev.set_layer(DRAG)
@@ -368,15 +421,15 @@ class PortfolioActivity(activity.Activity):
0, 0,
gtk.gdk.pixbuf_new_from_file_at_size(
os.path.join(activity.get_bundle_path(), 'help.png'),
- int(self._previewwh[0]),
- int(self._previewwh[1])))
+ int(self._preview_wh[0]),
+ int(self._preview_wh[1])))
self._help.hide()
self._preview = Sprite(self._sprites,
0, 0,
svg_str_to_pixbuf(genblank(
- int(self._previewwh[0]),
- int(self._previewwh[1]),
+ int(self._preview_wh[0]),
+ int(self._preview_wh[1]),
self._colors)))
self._configured_sprites() # Some sprites are sized to screen
@@ -393,34 +446,64 @@ class PortfolioActivity(activity.Activity):
''' Some sprites are sized or positioned based on screen
configuration '''
- self._preview.move((int(self._previewxy[0]),
- int(self._previewxy[1])))
- self._help.move((int(self._previewxy[0]),
- int(self._previewxy[1])))
- self._record_button.move((self._width - 55, self._titlewh[1]))
- self._playback_button.move((self._width - 55, self._titlewh[1] + 55))
- self._prev.move((0, int((self._height - 55) / 2)))
- self._next.move((self._width - 55, int((self._height - 55) / 2)))
+ self._preview.move((int(self._preview_xy[0]),
+ int(self._preview_xy[1])))
+ self._help.move((int(self._preview_xy[0]),
+ int(self._preview_xy[1])))
+ self._record_button.move((self._width - GRID_CELL_SIZE,
+ self._title_wh[1]))
+ self._playback_button.move((self._width - GRID_CELL_SIZE,
+ self._title_wh[1] + GRID_CELL_SIZE))
+ self._prev.move((0, int((self._height - GRID_CELL_SIZE) / 2)))
+ self._next.move((self._width - GRID_CELL_SIZE,
+ int((self._height - GRID_CELL_SIZE) / 2)))
self._title = Sprite(self._sprites,
- int(self._titlexy[0]),
- int(self._titlexy[1]),
+ int(self._title_xy[0]),
+ int(self._title_xy[1]),
svg_str_to_pixbuf(
- genblank(self._titlewh[0], self._titlewh[1], self._colors)))
- self._title.set_label_attributes(int(self._titlef * self._scale),
- rescale=False)
+ genblank(self._title_wh[0], self._title_wh[1], self._colors)))
+ self._title.set_label_attributes(self.title_size, rescale=False)
self._title.type = 'title'
self._description = Sprite(self._sprites,
- int(self._descriptionxy[0]),
- int(self._descriptionxy[1]),
+ int(self._desc_xy[0]),
+ int(self._desc_xy[1]),
svg_str_to_pixbuf(
- genblank(int(self._descriptionwh[0]),
- int(self._descriptionwh[1]),
+ genblank(int(self._desc_wh[0]),
+ int(self._desc_wh[1]),
self._colors)))
- self._description.set_label_attributes(
- int(self._descriptionf * self._scale), vert_align='top')
+ self._description.set_label_attributes(self.desc_size,
+ horiz_align="left",
+ rescale=False, vert_align="top")
+ m = int(self.desc_size / 2)
+ self._description.set_margins(l=m, t=m, r=m, b=m)
self._description.type = 'description'
+ self._comment = Sprite(self._sprites,
+ int(self._comment_xy[0]),
+ int(self._comment_xy[1]),
+ svg_str_to_pixbuf(
+ genblank(int(self._comment_wh[0]),
+ int(self._comment_wh[1]),
+ self._colors)))
+ self._comment.set_label_attributes(int(self.desc_size * 0.67),
+ vert_align="top",
+ horiz_align="left",
+ rescale=False)
+ self._comment.set_margins(l=m, t=m, r=m, b=m)
+ self._new_comment = Sprite(self._sprites,
+ int(self._new_comment_xy[0]),
+ int(self._new_comment_xy[1]),
+ svg_str_to_pixbuf(
+ genblank(int(self._new_comment_wh[0]),
+ int(self._new_comment_wh[1]),
+ self._colors)))
+ self._new_comment.set_label_attributes(self.desc_size,
+ horiz_align="left",
+ vert_align="top", rescale=False)
+ self._new_comment.type = 'comment'
+ self._new_comment.set_label(_('Enter comments here.'))
+
self._my_canvas = Sprite(
self._sprites, 0, 0, svg_str_to_pixbuf(genblank(
self._width, self._height, (self._colors[0],
@@ -573,6 +656,12 @@ class PortfolioActivity(activity.Activity):
title = dsobj.metadata['title']
if 'description' in dsobj.metadata:
desc = dsobj.metadata['description']
+ if 'comments' in dsobj.metadata:
+ try:
+ comment = json.loads(dsobj.metadata['comments'])
+ _logger.debug(comment)
+ except:
+ comment = []
if 'mime_type' in dsobj.metadata and \
dsobj.metadata['mime_type'][0:5] == 'image':
preview = get_pixbuf_from_file(dsobj.file_path,
@@ -585,15 +674,17 @@ class PortfolioActivity(activity.Activity):
if slide is None:
self._slides.append(Slide(owner,
- dsobj.object_id,
- self._colors,
- title,
- preview,
- desc))
+ dsobj.object_id,
+ self._colors,
+ title,
+ preview,
+ desc,
+ comment))
else:
slide.title = title
slide.preview = preview
slide.description = desc
+ slide.comment = comment
slide.active = True
slide.fav = True
if slide.star is not None:
@@ -698,7 +789,11 @@ class PortfolioActivity(activity.Activity):
self._title.hide()
self._preview.hide()
self._description.hide()
- self.invalt(0, 0, self._width, self._height)
+ self._comment.hide()
+ self._new_comment.hide()
+
+ # Why do we need this?
+ # self.invalt(0, 0, self._width, self._height)
# Reset drag settings
self._press = None
@@ -707,19 +802,24 @@ class PortfolioActivity(activity.Activity):
self._total_drag = [0, 0]
self.last_spr_moved = None
+
def _show_slide(self, direction=1):
''' Display a title, preview image, and decription for slide
i. Play an audio note if there is one recorded for this
object. '''
self._clear_screen()
- if len(self._slides) == 0:
+ if self._nobjects == 0:
self._prev.set_image(self.prev_off_pixbuf)
self._next.set_image(self.next_off_pixbuf)
self._description.set_label(
_('Do you have any items in your Journal starred?'))
self._help.set_layer(TOP)
self._description.set_layer(MIDDLE)
+ self._prev.hide()
+ self._next.hide()
+ self._record_button.hide()
+ self._playback_button.hide()
return
slide = self._slides[self.i]
@@ -738,22 +838,24 @@ class PortfolioActivity(activity.Activity):
return
slide = self._slides[self.i]
- if self.i == 0:
+ if self.i == 0:
self._prev.set_image(self.prev_off_pixbuf)
else:
self._prev.set_image(self.prev_pixbuf)
- if self.i == len(self._slides) - 1:
+ if self.i > self._nobjects - 2:
self._next.set_image(self.next_off_pixbuf)
else:
self._next.set_image(self.next_pixbuf)
+ self._prev.set_layer(DRAG)
+ self._next.set_layer(DRAG)
pixbuf = slide.preview
if pixbuf is not None:
self._preview.set_shape(pixbuf.scale_simple(
- int(PREVIEWW * self._scale),
- int(PREVIEWH * self._scale),
- gtk.gdk.INTERP_NEAREST))
+ int(PREVIEW[self._orientation][2] * self._scale),
+ int(PREVIEW[self._orientation][3] * self._scale),
+ GdkPixbuf.InterpType.NEAREST))
self._preview.set_layer(MIDDLE)
else:
if self._preview is not None:
@@ -762,9 +864,17 @@ class PortfolioActivity(activity.Activity):
self._title.set_label(slide.title)
self._title.set_layer(MIDDLE)
- self._description.set_label(slide.description)
+ if len(slide.description) == 0:
+ self._description.set_label(_('This project is about...'))
+ else:
+ self._description.set_label(slide.description)
self._description.set_layer(MIDDLE)
+ self._comment.set_label(parse_comments(slide.comment))
+ self._comment.set_layer(MIDDLE)
+
+ self._new_comment.set_layer(MIDDLE)
+
if self.initiating is None or self.initiating:
if slide.sound is None:
slide.sound = self._search_for_audio_note(slide.uid)
@@ -787,9 +897,7 @@ class PortfolioActivity(activity.Activity):
def _slides_cb(self, button=None):
if self._thumbnail_mode:
self._thumbnail_mode = False
- self.i = self._current_slide
- self._prev.set_layer(DRAG)
- self._next.set_layer(DRAG)
+ self.i = self._current_slide
self._record_button.set_layer(DRAG)
self._playback_button.set_layer(DRAG)
self._show_slide()
@@ -851,8 +959,8 @@ class PortfolioActivity(activity.Activity):
slide.thumb = None
if slide.thumb is None:
if slide.preview is not None:
- pixbuf_thumb = slide.preview.scale_simple(int(w), int(h),
- gtk.gdk.INTERP_TILES)
+ pixbuf_thumb = slide.preview.scale_simple(
+ int(w), int(h), GdkPixbuf.InterpType.TILES)
else:
pixbuf_thumb = svg_str_to_pixbuf(genblank(int(w), int(h),
self._colors))
@@ -866,20 +974,22 @@ class PortfolioActivity(activity.Activity):
slide.star.set_layer(STAR)
slide.star.move((x, y))
- def _expose_cb(self, win, event):
- ''' Callback to handle window expose events '''
- self.do_expose_event(event)
+ def _draw_cb(self, win, context):
+ ''' Callback to handle window draw events '''
+ self.do_draw_event(context)
return True
- # Handle the expose-event by drawing
- def do_expose_event(self, event):
+ # Handle the draw-event by drawing
+ def do_draw_event(self, context):
+
+ allocation = self.get_allocation()
# Create the cairo context
- cr = self.canvas.window.cairo_create()
+ cr = self.canvas.props.window.cairo_create()
- # Restrict Cairo to the exposed area; avoid extra work
- cr.rectangle(event.area.x, event.area.y,
- event.area.width, event.area.height)
+ # Restrict Cairo to the drawn area; avoid extra work
+ cr.rectangle(allocation.x, allocation.y,
+ allocation.width, allocation.height)
cr.clip()
# Refresh sprite list
@@ -896,25 +1006,17 @@ class PortfolioActivity(activity.Activity):
os.remove(os.path.join(self.datapath, 'output.ogg'))
def do_fullscreen_cb(self, button):
- ''' Hide the Sugar toolbars. '''
+ ''' Hide the sugar3 toolbars. '''
self.fullscreen()
- def invalt(self, x, y, w, h):
- ''' Mark a region for refresh '''
- self._canvas.window.invalidate_rect(
- gtk.gdk.Rectangle(int(x), int(y), int(w), int(h)), False)
-
- def _add_text_no_changed_cb(self, widget=None, event=None):
- pass
-
def _text_focus_out_cb(self, widget=None, event=None):
bounds = self.text_buffer.get_bounds()
- text = self.text_buffer.get_text(bounds[0], bounds[1])
+ text = self.text_buffer.get_text(bounds[0], bounds[1], True)
self._selected_spr.set_label(text)
self._saved_string = self._selected_spr.labels[0]
def _button_press_cb(self, win, event):
- ''' The mouse button was pressed. Is it on asprite? '''
+ ''' The mouse button was pressed. Is it on a sprite? '''
x, y = map(int, event.get_coords())
self._dragpos = [x, y]
@@ -926,8 +1028,8 @@ class PortfolioActivity(activity.Activity):
self._press = None
self._release = None
- # Are we clicking on a title or description?
- if spr.type == 'title' or spr.type == 'description':
+ # Are we clicking on a title or description or comment?
+ if spr.type in ['title', 'description', 'comment']:
if spr == self._selected_spr:
return True
elif self._selected_spr is not None:
@@ -935,21 +1037,27 @@ class PortfolioActivity(activity.Activity):
self._selected_spr = spr
self._saved_string = spr.labels[0]
if spr.type == 'description':
- if self.initiating is not None and not self.initiating:
- label = '%s\n[%s] ' % (self._selected_spr.labels[0],
- profile.get_nick_name())
- else:
+ if self.initiating is None or self.initiating:
label = self._selected_spr.labels[0]
+ self._selected_spr.set_label(label)
+ else:
+ self._selected_spr = None
+ return True
self._selected_spr.set_label(label)
if not hasattr(self, 'desc_entry'):
- self.desc_entry = gtk.TextView()
- self.desc_entry.set_justification(gtk.JUSTIFY_CENTER)
- self.desc_entry.set_pixels_above_lines(4)
- font_desc = pango.FontDescription('Sans')
- font_desc.set_size(int(
- self._descriptionf * pango.SCALE * self._scale))
+ self.desc_entry = Gtk.TextView()
+ self.desc_entry.set_wrap_mode(Gtk.WrapMode.WORD)
+ self.desc_entry.set_pixels_above_lines(0)
+ self.desc_entry.set_size_request(self._desc_wh[0],
+ self._desc_wh[1])
+ rgba = Gdk.RGBA()
+ rgba.red, rgba.green, rgba.blue = rgb(self._colors[1])
+ rgba.alpha = 1.
+ self.desc_entry.override_background_color(
+ Gtk.StateFlags.NORMAL, rgba)
+ font_desc = Pango.font_description_from_string(
+ str(self.desc_size))
self.desc_entry.modify_font(font_desc)
- self.desc_buffer = self.desc_entry.get_buffer()
self.fixed.put(self.desc_entry, 0, 0)
self.text_entry = self.desc_entry
self.text_buffer = self.desc_entry.get_buffer()
@@ -960,25 +1068,56 @@ class PortfolioActivity(activity.Activity):
self._selected_spr.set_label(label)
else:
self._selected_spr = None
+ return True
if not hasattr(self, 'title_entry'):
- self.title_entry = gtk.TextView()
- self.title_entry.set_justification(gtk.JUSTIFY_CENTER)
- self.title_entry.set_pixels_above_lines(4)
- font_desc = pango.FontDescription('Sans')
- font_desc.set_size(int(
- self._titlef * pango.SCALE * self._scale))
+ self.title_entry = Gtk.TextView()
+ self.title_entry.set_justification(Gtk.Justification.CENTER)
+ self.title_entry.set_pixels_above_lines(1)
+ rgba = Gdk.RGBA()
+ rgba.red, rgba.green, rgba.blue = rgb(self._colors[1])
+ rgba.alpha = 1.
+ self.title_entry.override_background_color(
+ Gtk.StateFlags.NORMAL, rgba)
+ font_desc = Pango.font_description_from_string(
+ str(self.title_size))
self.title_entry.modify_font(font_desc)
- self.title_buffer = self.title_entry.get_buffer()
self.fixed.put(self.title_entry, 0, 0)
self.text_entry = self.title_entry
self.text_buffer = self.title_entry.get_buffer()
+ self.text_buffer.connect('insert-text', self._insert_text_cb)
self.title_entry.show()
- self.text_buffer.set_text('')
+ elif spr.type == 'comment':
+ self._selected_spr.set_label('')
+ self._saved_string = spr.labels[0]
+ if not hasattr(self, 'comment_entry'):
+ self.comment_entry = Gtk.TextView()
+ self.comment_entry.set_wrap_mode(Gtk.WrapMode.WORD)
+ self.comment_entry.set_pixels_above_lines(0)
+ self.comment_entry.set_size_request(
+ self._new_comment_wh[0], self._new_comment_wh[1])
+ rgba = Gdk.RGBA()
+ rgba.red, rgba.green, rgba.blue = rgb(self._colors[1])
+ rgba.alpha = 1.
+ self.comment_entry.override_background_color(
+ Gtk.StateFlags.NORMAL, rgba)
+ font_desc = Pango.font_description_from_string(
+ str(self.desc_size))
+ self.comment_entry.modify_font(font_desc)
+ self.fixed.put(self.comment_entry, 0, 0)
+ self.text_entry = self.comment_entry
+ self.text_buffer = self.comment_entry.get_buffer()
+ self.text_buffer.connect('insert-text', self._insert_text_cb)
+ self.comment_entry.show()
self.text_buffer.set_text(self._saved_string)
- spr.set_label('') # Clear the label while the text_entry is visible
+ # Clear the label while the text_entry is visible
+ spr.set_label('')
w = spr.label_safe_width()
h = spr.label_safe_height()
+
+ if spr.type == 'comment':
+ if self._tablet_mode:
+ self._OSK_shift(spr, -OSK_SHIFT)
bx, by = spr.get_xy()
mx, my = spr.label_left_top()
self.text_entry.set_size_request(w, h)
@@ -1031,16 +1170,24 @@ class PortfolioActivity(activity.Activity):
self.last_spr_moved = spr
self._press = spr
self._press.set_layer(DRAG)
- slide.star.set_layer(DRAG+1)
+ slide.star.set_layer(DRAG + 1)
return False
+ def _OSK_shift(self, spr, dy):
+ ''' Move some sprites when OSK appears/disappears '''
+ dy *= self._scale
+ spr.move_relative((0, dy))
+ self._title.move_relative((0, dy))
+ self._preview.move_relative((0, dy))
+ self._description.move_relative((0, dy))
+
def _mouse_move_cb(self, win, event):
''' Drag a thumbnail with the mouse. '''
spr = self._press
if spr is None:
self._dragpos = [0, 0]
return False
- # win.grab_focus()
+ win.grab_focus()
x, y = map(int, event.get_coords())
dx = x - self._dragpos[0]
dy = y - self._dragpos[1]
@@ -1056,7 +1203,7 @@ class PortfolioActivity(activity.Activity):
def _button_release_cb(self, win, event):
''' Button event is used to swap slides or goto next slide. '''
- # win.grab_focus()
+ win.grab_focus()
self._dragpos = [0, 0]
x, y = map(int, event.get_coords())
@@ -1111,6 +1258,10 @@ class PortfolioActivity(activity.Activity):
self._release = None
return False
+ def _insert_text_cb(self, textbuffer, textiter, text, length):
+ if '\12' in text:
+ self._unselect()
+
def _swap_slides(self, i, j):
''' Swap order and x, y position of two slides '''
tmp = self._slides[i]
@@ -1137,6 +1288,11 @@ class PortfolioActivity(activity.Activity):
if self._grecord is None:
_logger.debug('setting up grecord')
self._grecord = Grecord(self)
+ if self.i < 0 or self.i > len(self._slides) - 1:
+ _logger.debug('bad slide index %d' % (self.i))
+ return
+ else:
+ _logger.debug('slide #%d' % (self.i))
if self._recording: # Was recording, so stop (and save?)
_logger.debug('recording...True. Preparing to save.')
self._grecord.stop_recording_audio()
@@ -1148,9 +1304,9 @@ class PortfolioActivity(activity.Activity):
self._playback_button.type = 'play'
self._playback_button.set_layer(DRAG)
# Autosave if there was not already a recording
- slide = self._slides[self.i]
_logger.debug('Autosaving recording')
self._notify_successful_save(title=_('Save recording'))
+ self._transcoding_wait_counter = 0
gobject.timeout_add(100, self._wait_for_transcoding_to_finish)
else: # Wasn't recording, so start
_logger.debug('recording...False. Start recording.')
@@ -1161,16 +1317,26 @@ class PortfolioActivity(activity.Activity):
self._recording = True
def _wait_for_transcoding_to_finish(self, button=None):
- while not self._grecord.transcoding_complete():
- time.sleep(1)
- if self._alert is not None:
- self.remove_alert(self._alert)
- self._alert = None
- self._save_recording()
+ self._transcoding_wait_counter += 1
+ if self._transcoding_wait_counter < 60 and \
+ not self._grecord.transcoding_complete():
+ gobject.timeout_add(1000, self._wait_for_transcoding_to_finish)
+ else:
+ if self._alert is not None:
+ self.remove_alert(self._alert)
+ self._alert = None
+ self._save_recording()
+ return False
def _playback_recording_cb(self, button=None):
''' Play back current recording '''
_logger.debug('Playback current recording from output.ogg...')
+ if self.i < 0 or self.i > len(self._slides) - 1:
+ _logger.debug('bad slide index %d' % (self.i))
+ return
+ if self._slides[self.i].sound is None:
+ _logger.debug('slide %d has no sound' % (self.i))
+ return
self._playback_button.set_image(self.playing_pixbuf)
self._playback_button.set_layer(DRAG)
self._playback_button.type = 'playing'
@@ -1236,6 +1402,7 @@ class PortfolioActivity(activity.Activity):
self._slides.index(slide)))
jobject = datastore.get(slide.uid)
jobject.metadata['description'] = slide.description
+ jobject.metadata['comments'] = json.dumps(slide.comment)
jobject.metadata['title'] = slide.title
datastore.write(jobject,
update_mtime=False,
@@ -1243,7 +1410,7 @@ class PortfolioActivity(activity.Activity):
error_handler=self.datastore_write_error_cb)
def datastore_write_cb(self):
- pass
+ self._unselect()
def datastore_write_error_cb(self, error):
_logger.error('datastore_write_error_cb: %r' % error)
@@ -1258,9 +1425,9 @@ class PortfolioActivity(activity.Activity):
def _keypress_cb(self, area, event):
''' Keyboard '''
- keyname = gtk.gdk.keyval_name(event.keyval)
- keyunicode = gtk.gdk.keyval_to_unicode(event.keyval)
- if event.get_state() & gtk.gdk.MOD1_MASK:
+ keyname = Gdk.keyval_name(event.keyval)
+ keyunicode = Gdk.keyval_to_unicode(event.keyval)
+ if event.get_state() & Gdk.ModifierType.MOD1_MASK:
alt_mask = True
alt_flag = 'T'
else:
@@ -1289,6 +1456,10 @@ class PortfolioActivity(activity.Activity):
def _unselect(self):
if hasattr(self, 'text_entry'):
+ if self._selected_spr is not None:
+ if self._selected_spr.type == 'comment':
+ if self._tablet_mode:
+ self._OSK_shift(self._selected_spr, OSK_SHIFT)
self.text_entry.hide()
if self._selected_spr is not None:
@@ -1298,13 +1469,27 @@ class PortfolioActivity(activity.Activity):
if self.initiating is not None and self.initiating:
self._send_event('t:%s' % (self._data_dumper(
[slide.uid, slide.title])))
- else:
+ slide.dirty = True
+ elif self._selected_spr.type == 'description':
slide.description = self._selected_spr.labels[0]
if self.initiating is not None:
- self._send_event('d:%s' % (self._data_dumper(
- [slide.uid, slide.description])))
- _logger.debug('marking %d as dirty' % (self.i))
- slide.dirty = True
+ self._send_event('d:%s' % (
+ self._data_dumper([slide.uid, slide.description])))
+ slide.dirty = True
+ elif self._selected_spr.type == 'comment':
+ message = self._selected_spr.labels[0]
+ if message != '':
+ slide.comment.append({'from':profile.get_nick_name(),
+ 'message':message,
+ # Use my colors in case of sharing
+ 'icon':[self._my_colors[0],
+ self._my_colors[1]]})
+ if self.initiating is not None:
+ self._send_event('c:%s' % (self._data_dumper(
+ [slide.uid, slide.comment])))
+ self._comment.set_label(parse_comments(slide.comment))
+ self._selected_spr.set_label('')
+ slide.dirty = True
self._selected_spr = None
self._saved_string = ''
@@ -1312,18 +1497,14 @@ class PortfolioActivity(activity.Activity):
''' No longer waiting, so restore standard cursor. '''
if not hasattr(self, 'get_window'):
return
- if hasattr(self.get_window(), 'get_cursor'):
- self.get_window().set_cursor(self.old_cursor)
- else:
- self.get_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
+ self.get_window().set_cursor(self.old_cursor)
def _waiting_cursor(self):
''' Waiting, so set watch cursor. '''
if not hasattr(self, 'get_window'):
return
- if hasattr(self.get_window(), 'get_cursor'):
- self.old_cursor = self.get_window().get_cursor()
- self.get_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
+ self.old_cursor = self.get_window().get_cursor()
+ self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
# Serialize
@@ -1331,26 +1512,22 @@ class PortfolioActivity(activity.Activity):
''' Dump data for sharing.'''
_logger.debug('dumping %s' % (slide.uid))
if slide.preview is None:
- data = [slide.uid, slide.title, None, slide.description]
+ data = [slide.uid, slide.title, None, slide.description,
+ slide.comment]
else:
data = [slide.uid, slide.title,
pixbuf_to_base64(activity, slide.preview,
width=300, height=225),
- slide.description]
+ slide.description, slide.comment]
return self._data_dumper(data)
def _data_dumper(self, data):
- if _OLD_SUGAR_SYSTEM:
- return json.write(data)
- else:
- io = StringIO()
- jdump(data, io)
- return io.getvalue()
+ return json.dumps(data)
def _load(self, data):
''' Load slide data from a sharer. '''
self._restore_cursor()
- uid, title, base64, description = self._data_loader(data)
+ uid, title, base64, description, comment = self._data_loader(data)
if self._uid_to_slide(uid) is None:
_logger.debug('loading %s' % (uid))
if base64 is None:
@@ -1362,7 +1539,8 @@ class PortfolioActivity(activity.Activity):
self._colors,
title,
preview,
- description))
+ description,
+ comment))
else:
_logger.debug('updating description for %s' % (uid))
slide = self._uid_to_slide(uid)
@@ -1372,23 +1550,23 @@ class PortfolioActivity(activity.Activity):
else:
slide.preview = base64_to_pixbuf(activity, base64)
slide.description = description
+ slide.comment = comment
slide.active = True
if not slide.fav:
slide.fav = True
if slide.star is not None:
slide.star.set_shape(self._fav_pixbuf)
slide.star.type = 'star'
+
+ self._nobjects += 1
+
if not self._thumbnail_mode:
self._thumb_button.set_active(True)
else:
self._show_thumbs()
def _data_loader(self, data):
- if _OLD_SUGAR_SYSTEM:
- return json.read(data)
- else:
- io = StringIO(data)
- return jload(io)
+ return json.loads(data)
# When portfolio is shared, only sharer sends out slides, joiners
# send back comments.
@@ -1406,18 +1584,18 @@ class PortfolioActivity(activity.Activity):
def _shared_cb(self, activity):
''' Either set up initial share...'''
- if self._shared_activity is None:
+ if self.get_shared_activity() is None:
_logger.error('Failed to share or join activity ... \
- _shared_activity is null in _shared_cb()')
+ shared_activity is null in _shared_cb()')
return
self.initiating = True
self.waiting = False
_logger.debug('I am sharing...')
- self.conn = self._shared_activity.telepathy_conn
- self.tubes_chan = self._shared_activity.telepathy_tubes_chan
- self.text_chan = self._shared_activity.telepathy_text_chan
+ self.conn = self.shared_activity.telepathy_conn
+ self.tubes_chan = self.shared_activity.telepathy_tubes_chan
+ self.text_chan = self.shared_activity.telepathy_text_chan
self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal(
'NewTube', self._new_tube_cb)
@@ -1428,17 +1606,17 @@ class PortfolioActivity(activity.Activity):
def _joined_cb(self, activity):
''' ...or join an exisiting share. '''
- if self._shared_activity is None:
+ if self.get_shared_activity() is None:
_logger.error('Failed to share or join activity ... \
- _shared_activity is null in _shared_cb()')
+ shared_activity is null in _shared_cb()')
return
self.initiating = False
_logger.debug('I joined a shared activity.')
- self.conn = self._shared_activity.telepathy_conn
- self.tubes_chan = self._shared_activity.telepathy_tubes_chan
- self.text_chan = self._shared_activity.telepathy_text_chan
+ self.conn = self.shared_activity.telepathy_conn
+ self.tubes_chan = self.shared_activity.telepathy_tubes_chan
+ self.text_chan = self.shared_activity.telepathy_text_chan
self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal(\
'NewTube', self._new_tube_cb)
@@ -1453,6 +1631,9 @@ class PortfolioActivity(activity.Activity):
for slide in self._slides:
slide.active = False
self._clear_screen()
+ self.i = 0
+ self._current_slide = 0
+ self._nobjects = 0
self._help.hide()
self._description.set_layer(TOP)
self._description.set_label(_('Please wait.'))
@@ -1491,8 +1672,9 @@ class PortfolioActivity(activity.Activity):
def event_received_cb(self, text):
''' Data is passed as tuples: cmd:text '''
dispatch_table = {'s': self._load,
- 'c': self._update_colors,
+ 'C': self._update_colors,
'd': self._update_description,
+ 'c': self._update_comment,
't': self._update_title,
'S': self._update_star,
'R': self._reset,
@@ -1530,32 +1712,32 @@ class PortfolioActivity(activity.Activity):
def _update_colors(self, data):
colors = self._data_loader(data)
- if colors[0] != self._colors[0] or \
- colors[1] != self._colors[1]:
- self._colors = colors[:]
- self._my_canvas.set_image(svg_str_to_pixbuf(
- genblank(self._width, self._height, [self._colors[0],
- self._colors[0]])))
- self._description.set_image(svg_str_to_pixbuf(
- genblank(
- int(self._descriptionwh[0]),
- int(self._descriptionwh[1]),
- self._colors)))
- self._title.set_image(svg_str_to_pixbuf(
- genblank(int(self._titlewh[0]),
- int(self._titlewh[1]),
- self._colors)))
-
- def _update_description(self, data):
- uid, text = self._data_loader(data)
+ colors[0] = str(colors[0])
+ colors[1] = str(colors[1])
+ self._my_canvas.set_image(svg_str_to_pixbuf(
+ genblank(self._width, self._height, [colors[0], colors[0]])))
+ self._title.set_image(
+ svg_str_to_pixbuf(genblank(
+ int(self._title_wh[0]), int(self._title_wh[1]), colors)))
+ self._description.set_image(
+ svg_str_to_pixbuf(genblank(
+ int(self._desc_wh[0]), int(self._desc_wh[1]), colors)))
+ self._comment.set_image(
+ svg_str_to_pixbuf(genblank(
+ int(self._comment_wh[0]), int(self._comment_wh[1]),
+ colors)))
+ # Don't update new_comment colors
+
+ def _update_comment(self, data):
+ uid, comment = self._data_loader(data)
slide = self._uid_to_slide(uid)
if slide is None:
_logger.debug('slide %s not found' % (uid))
return
- _logger.debug('updating description %s' % (uid))
- slide.description = text
+ _logger.debug('updating comment %s' % (uid))
+ slide.comment = comment
if self.i == self._slides.index(slide):
- self._description.set_label(text)
+ self._comment.set_label(parse_comments(slide.comment))
if self.initiating:
slide.dirty = True
@@ -1572,13 +1754,26 @@ class PortfolioActivity(activity.Activity):
if self.initiating:
slide.dirty = True
+ def _update_description(self, data):
+ uid, text = self._data_loader(data)
+ slide = self._uid_to_slide(uid)
+ if slide is None:
+ _logger.debug('slide %s not found' % (uid))
+ return
+ _logger.debug('updating title %s' % (uid))
+ slide.description = text
+ if self.i == self._slides.index(slide):
+ self._description.set_label(text)
+ if self.initiating:
+ slide.dirty = True
+
def _share_nick(self):
_logger.debug('sharing nick')
self._send_event('j:%s' % (profile.get_nick_name()))
def _share_colors(self):
_logger.debug('sharing colors')
- self._send_event('c:%s' % (self._data_dumper(self._colors)))
+ self._send_event('C:%s' % (self._data_dumper(self._colors)))
def _share_slides(self):
for slide in self._slides:
@@ -1619,25 +1814,3 @@ class ChatTube(ExportedGObject):
@signal(dbus_interface=IFACE, signature='s')
def SendText(self, text):
self.stack = text
-
-
-def check_output(command, warning):
- ''' Workaround for old systems without subprocess.check_output'''
- if hasattr(subprocess, 'check_output'):
- try:
- output = subprocess.check_output(command)
- except subprocess.CalledProcessError:
- log.warning(warning)
- return None
- else:
- import commands
-
- cmd = ''
- for c in command:
- cmd += c
- cmd += ' '
- (status, output) = commands.getstatusoutput(cmd)
- if status != 0:
- log.warning(warning)
- return None
- return output