diff options
Diffstat (limited to 'toolbars.py')
-rwxr-xr-x | toolbars.py | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/toolbars.py b/toolbars.py new file mode 100755 index 0000000..b7c2323 --- /dev/null +++ b/toolbars.py @@ -0,0 +1,464 @@ +# toolbars.py +# +# Classes defining toolbars for Classroom Presenter +# B. Mayton <bmayton@cs.washington.edu> +# +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from sugar.activity import activity +from sugar.graphics.toolbutton import ToolButton +from sugar.graphics.menuitem import MenuItem +from sugar.graphics.objectchooser import ObjectChooser +from sugar.datastore import datastore + +import gtk +import gobject +import pango +import logging +import threading +import os, sys +import utils +from path import path +import slideshow +import subprocess +import listview + +#import htmlview +#import hulahop +from sugar import env +#hulahop.startup(os.path.join(env.get_profile_path(), 'gecko')) + +#from hulahop.webview import WebView + +DATASTORE = '/home/olpc/.sugar/default/datastore/store' + +class NavToolBar(gtk.Toolbar): + + def __init__(self, activity, shared, deck): + gtk.Toolbar.__init__(self) + + self.__deck = deck + self.__activity = activity + self.__shared = shared + self.__logger = logging.getLogger('Navigation Toolbar') + + self.__is_initiating = True + + self.__prevbtn = ToolButton('go-previous') + self.__prevbtn.set_tooltip("Previous slide") + self.__prevbtn.connect('clicked', self.previous) + self.insert(self.__prevbtn, -1) + self.__prevbtn.show() + + self.__nextbtn = ToolButton('go-next') + self.__nextbtn.set_tooltip("Next slide") + self.__nextbtn.connect('clicked', self.next) + self.insert(self.__nextbtn, -1) + self.__nextbtn.show() + + # page number widget and navigation + self.__num_page_item = gtk.ToolItem() + self.__num_current_page = 1 + + self.__num_page_entry = gtk.Entry() + self.__num_page_entry.set_text(str(self.__num_current_page)) + self.__num_page_entry.set_alignment(1) + self.__num_page_entry.connect('activate', self.num_page_activate) + + self.__num_page_entry.set_width_chars(4) + + self.__num_page_item.add(self.__num_page_entry) + self.__num_page_entry.show() + + self.insert(self.__num_page_item, -1) + self.__num_page_item.show() + + + # total page number widget + self.__total_page_item = gtk.ToolItem() + self.__total_page_label = gtk.Label() + + label_attributes = pango.AttrList() + label_attributes.insert(pango.AttrSize(14000, 0, -1)) + label_attributes.insert(pango.AttrForeground(65535, 65535, 65535, 0, -1)) + self.__total_page_label.set_attributes(label_attributes) + + self.__total_page_label.set_text(' / ' + str(self.__deck.getSlideCount())) + self.__total_page_item.add(self.__total_page_label) + self.__total_page_label.show() + + self.insert(self.__total_page_item, -1) + self.__total_page_item.show() + + # separator between navigation buttons and lock button + separator = gtk.SeparatorToolItem() + separator.set_draw(False) + separator.set_expand(True) + self.insert(separator, -1) + separator.show() + + # unlocked button + self.__unlockBtn = ToolButton('unlocked') + self.__unlockBtn.set_tooltip("Student Navigation Unlocked") + + # navigation is unlocked by default, so insert the unlock button + self.insert(self.__unlockBtn, 5) + self.__unlockBtn.show() + + # locked button + self.__lockBtn = ToolButton('locked') + self.__lockBtn.set_tooltip("Student Navigation Locked") + + self.__logger.debug("Connecting to navigation locking and activity sharing signals.") + self.__activity.connect('shared', self.activity_shared_cb) + self.__activity.connect('joined', self.activity_joined_cb) + self.__shared.connect('navigation-lock-change', self.set_lock_button) + + # triggers for when slides are changed + self.__deck.connect("slide-changed", self.slide_changed) + self.__deck.connect("deck-changed", self.slide_changed) + self.slide_changed(self.__deck) + self.show() + + def activity_shared_cb(self, widget): + #Callback for when the activity is shared + # bind the lock button click with switching lock mode + self.__lockBtn.connect('clicked', self.__shared.lock_mode_switch) + self.__unlockBtn.connect('clicked', self.__shared.lock_mode_switch) + + def activity_joined_cb(self, widget): + """ Callback for when the activity is joined """ + self.__is_initiating = False + + def set_lock_button(self, widget, is_locked): + self.__logger.debug("Changing lock button, lock mode %u, init %u", + is_locked, self.__is_initiating) + if is_locked: + new_button = self.__lockBtn + if not self.__is_initiating: + self.__prevbtn.set_sensitive(False) + self.__nextbtn.set_sensitive(False) + else: + new_button = self.__unlockBtn + if not self.__is_initiating: + self.__prevbtn.set_sensitive(True) + self.__nextbtn.set_sensitive(True) + + old = self.get_nth_item(5) + self.remove(old) + self.insert(new_button, 5) + new_button.show() + self.queue_draw() + + def next(self, widget): + self.__deck.next() + + def previous(self, widget): + self.__deck.previous() + + def slide_changed(self, widget): + self.__logger.debug("Changing slides!") + if self.__deck.isAtBeginning(): + self.__prevbtn.set_sensitive(False) + else: + self.__prevbtn.set_sensitive(True) + if self.__deck.isAtEnd(): + self.__nextbtn.set_sensitive(False) + else: + self.__nextbtn.set_sensitive(True) + + self.__num_current_page = self.__deck.getIndex() + self.__num_page_entry.set_text(str(self.__num_current_page + 1)) + self.__total_page_label.set_text(' / ' + str(self.__deck.getSlideCount())) + + def num_page_activate(self, entry): + page_entered = int(entry.get_text()) + + if page_entered < 1: + page_entered = 1 + elif self.__deck.getSlideCount() < page_entered: + page_entered = self.__deck.getSlideCount() + + self.__deck.goToIndex(page_entered - 1, is_local=True) + + +class InkToolBar(gtk.Toolbar): + + # Constructor + def __init__(self, slideviewer, deck): + + gtk.Toolbar.__init__(self) + + self.__slideviewer = slideviewer + self.__cur_color = slideviewer.get_color() + self.__cur_color_str = "blue" + self.__cur_pen = slideviewer.get_pen() + self.__deck = deck + self.__deck.connect('slide-redraw', self.update_buttons) + self.__slideviewer.connect('undo-redo-changed', self.update_buttons) + self.__is_instr = False + + # Red Ink + self.__red = gtk.RadioToolButton() + self.__red.set_icon_name('red-button') + self.insert(self.__red, -1) + self.__red.show() + #self.__red.set_tooltip('Red Ink') + self.__red.connect('clicked', self.set_ink_color, 1.0, 0.0, 0.0, "red") + + # Green Ink + self.__green = gtk.RadioToolButton(group=self.__red) + self.__green.set_icon_name('green-button') + self.insert(self.__green, -1) + self.__green.show() + #self.__green.set_tooltip('Green Ink') + self.__green.connect('clicked', self.set_ink_color, 0.0, 1.0, 0.0, "green") + + # Blue Ink + self.__blue = gtk.RadioToolButton(group=self.__red) + self.__blue.set_icon_name('blue-button') + self.insert(self.__blue, -1) + self.__blue.show() + #self.__blue.set_tooltip('Blue Ink') + self.__blue.connect('clicked', self.set_ink_color, 0.0, 0.0, 1.0, "blue") + + # Black Ink + self.__black = gtk.RadioToolButton(group=self.__red) + self.__black.set_icon_name('black-button') + self.insert(self.__black, -1) + self.__black.show() + #self.__black.set_tooltip('Black Ink') + self.__black.connect('clicked', self.set_ink_color, 0.0, 0.0, 0.0, "black") + + # Separate ink from untensils + separator = gtk.SeparatorToolItem() + separator.set_draw(False) + self.insert(separator, -1) + separator.show() + + # Pencil + self.__pencil = gtk.RadioToolButton() + self.__pencil.set_icon_name('tool-pencil') + self.insert(self.__pencil, -1) + self.__pencil.show() + #self.__pencil.set_tooltip('Pencil') + self.__pencil.connect('clicked', self.set_cur_pen, 4) + + # Brush + self.__brush = gtk.RadioToolButton(self.__pencil) + self.__brush.set_icon_name('tool-brush') + self.insert(self.__brush, -1) + self.__brush.show() + #self.__brush.set_tooltip('Brush') + self.__brush.connect('clicked', self.set_cur_pen, 8) + + # Erase + self.__erase = ToolButton('tool-eraser') + self.insert(self.__erase, -1) + self.__erase.show() + self.__erase.set_tooltip('Erase All Ink') + self.__erase.connect('clicked', self.set_erase) + + """ + # Text + self.__text = ToolButton('text') + self.insert(self.__text, -1) + self.__text.show() + self.__text.set_tooltip('Text') + """ + + # Separate tools from text + separator = gtk.SeparatorToolItem() + separator.set_draw(False) + self.insert(separator, -1) + separator.show() + + # Undo + self.__undo = ToolButton('edit-undo') + self.insert(self.__undo, -1) + self.__undo.show() + self.__undo.set_tooltip('Undo') + self.__undo.connect('clicked', self.undo) + + # Redo + self.__redo = ToolButton('edit-redo') + self.insert(self.__redo, -1) + self.__redo.show() + self.__redo.set_tooltip('Redo') + self.__redo.connect('clicked', self.redo) + + separator = gtk.SeparatorToolItem() + separator.set_draw(False) + separator.set_expand(True) + self.insert(separator, -1) + separator.show() + + self.__submit = ToolButton('dialog-ok') #FIXME (though actually not a terrible icon) + self.insert(self.__submit, -1) + self.__submit.show() + self.__submit.set_tooltip('Broadcast Submission') + self.__submit.connect('clicked', self.submit_ink) + + self.__deck.connect('instr_state_propagate', self.instructor_state_cb) + + self.set_tool_buttons() + self.show() + + def instructor_state_cb(self, widget, is_instr): + self.__is_instr = is_instr + if is_instr: + self.__submit.set_tooltip('Broadcast Submission') + else: + self.__submit.set_tooltip('Submit Ink') + + + def set_cur_pen(self, widget, size): + self.__slideviewer.set_pen(size) + + def set_ink_color(self, widget, r, g, b, color): + self.__slideviewer.set_color(r, g, b) + + + def set_erase(self, widget): + self.__slideviewer.clear_ink() + + def set_tool_buttons(self): + if self.__cur_color == (1.0, 0.0, 0.0): + self.__red.set_active(True) + elif self.__cur_color == (0.0, 1.0, 0.0): + self.__green.set_active(True) + elif self.__cur_color == (0.0, 0.0, 1.0): + self.__blue.set_active(True) + else: + self.__black.set_active(True) + + if self.__cur_pen == 2: + self.__pencil.set_active(True) + elif self.__cur_pen == 5: + self.__brush.set_active(True) + + + def submit_ink(self, widget): + if self.__is_instr: + self.broadcast_ink() + else: + self.__submit.set_sensitive(False) + self.__timer = threading.Timer(3.0, self.reenable_submissions) + self.__timer.start() + self.__slideviewer.submit_ink() + + def broadcast_ink(self): + self.__slideviewer.broadcast_ink() + + def reenable_submissions(self): + self.__submit.set_sensitive(True) + self.__submit.queue_draw() + + def undo(self, widget): + self.__slideviewer.undo() + + def redo(self, widget): + self.__slideviewer.redo() + + def update_buttons(self, widget=None): + can_undo, can_redo = self.__slideviewer.can_undo_redo() + self.__undo.set_sensitive(can_undo) + self.__redo.set_sensitive(can_redo) + if self.__is_instr: + if self.__deck.getActiveSubmission() == -1: + self.__submit.set_sensitive(False) + else: + self.__submit.set_sensitive(True) + +class MakeToolBar(gtk.Toolbar): + + def __init__(self, activity, deck): + gtk.Toolbar.__init__(self) + self.activity = activity + self.deck = deck + + #get mount points + ds_mounts = datastore.mounts() + pendrive = -1 + for i in range(0, len(ds_mounts), 1): + print 'mount', i, ds_mounts[i]['uri'] + if ds_mounts[i]['uri'].find('datastore') > 0: + journal = i + else: + pendrive = i + + + self.__newbtn = ToolButton('new-slideshow') + self.__newbtn.set_tooltip("New slideshow") + self.__newbtn.connect('clicked', self.new) + self.insert(self.__newbtn, -1) + self.__newbtn.show() + + self.__openbtn = ToolButton('slideshow') + self.__openbtn.set_tooltip("Choose slideshow") + self.__openbtn.connect('clicked', self.open) + self.insert(self.__openbtn, -1) + self.__openbtn.show() + + #self.__htmlbutton = ToolButton('new') + #self.__htmlbutton.set_tooltip("test tw") + #self.__htmlbutton.connect('clicked', self.showhtml) + #self.insert(self.__htmlbutton, -1) + #self.__htmlbutton.show() + + self.__journalbtn = ToolButton('activity-journal') + self.__journalbtn.set_tooltip("Choose image") + self.__journalbtn.connect('clicked', self.chooseimage, ds_mounts[journal]['id'], DATASTORE) + self.insert(self.__journalbtn, -1) + self.__journalbtn.show() + + #show pendrive button only if pendrive is mounted + if pendrive > -1: + self.__pendrivebutton = ToolButton('media-flash-usb') + self.__pendrivebutton.set_tooltip("Choose image") + self.__pendrivebutton.connect('clicked', self.chooseimage, ds_mounts[pendrive]['id'], ds_mounts[pendrive]['title']) + self.insert(self.__pendrivebutton, -1) + self.__pendrivebutton.show() + + self.show() + + def new(self, widget): + print 'New slideshow' + #no effect if slideshow is already 'new', e.g. when ShowNTell is opened + #directly not by read_file + #this needs to be changed to show slideshow with html title slide + self.activity.read_file(path(activity.get_bundle_path()) / 'resources' / 'new.cpxo') + + def open(self, widget): + print 'Open slideshow' + #here we need a listview to show existing cpxo bundles (all sources) + #there should be a standard 'open' function for both read_file and open + + def chooseimage(self, widget, source, pth): + scrn1, scrn2 = self.activity.get_window() + treeview = scrn2.get_treeView() + print 'set_store', source, pth + treeview.set_model(scrn2.set_store(source, pth)) + scrn1.hide() + scrn2.show() + + def showhtml(self, widget): + scrn1, scrn2, scrn3 = self.activity.get_window() + scrn1.hide() + scrn2.hide() + #we need to show blank editable tiddly or web page + scrn3.show() + + |