def build_toolbar(self): toolbar_box = ToolbarBox() view_toolbar = ViewToolbar() view_toolbar.connect('go-fullscreen', self.view_toolbar_go_fullscreen_cb) view_toolbar.show() view_toolbar_button = ToolbarButton(page=view_toolbar, icon_name='toolbar-view') toolbar_box.toolbar.insert(view_toolbar_button, -1) view_toolbar_button.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl><Shift>Q' toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show()
def build_toolbar(self): toolbar_box = ToolbarBox() view_toolbar = ViewToolbar() view_toolbar.connect('go-fullscreen', self.view_toolbar_go_fullscreen_cb) view_toolbar.show() view_toolbar_button = ToolbarButton( page=view_toolbar, icon_name='toolbar-view') toolbar_box.toolbar.insert(view_toolbar_button, -1) view_toolbar_button.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl><Shift>Q' toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show()
def add_page(self, ebook_reader_tab_instance): # Add the "content" for the section. tab_name = ebook_reader_tab_instance.get_tab_label() tab_widget = ebook_reader_tab_instance.get_widget_to_attach_notebook_tab() tab_toolbar = ebook_reader_tab_instance.get_tab_toolbar() if tab_toolbar is not None: tab_widget.pack_start(tab_toolbar, False, False, 0) tab_widget.reorder_child(tab_toolbar, 0) self._tab_toolbars_list.append(tab_toolbar) self.notebook.add_page(tab_name, tab_widget) # Add the "(secondary) toolbar" for the section. icon_name = \ ebook_reader_tab_instance.get_tab_toolbar_icon_name() toolbar_button = ToolbarButton(page=None, icon_name=icon_name + '-select') self._toolbar_buttons_list.append(toolbar_button) toolbar_button.connect('clicked', self.load_corresponding_page, ebook_reader_tab_instance.get_pagenum()) ebook_reader_tab_instance.show() toolbar_button.set_tooltip(tab_name) self._toolbar_box._toolbar.insert(toolbar_button, -1) toolbar_button.show() self._toolbar_box.show_all()
def setup_toolbar(self): '''Setup the top toolbar. Groupthink needs some work here.''' toolbox = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() self.set_toolbar_box(toolbox) toolbox.show() toolbar = toolbox.toolbar self.edit_toolbar = EditToolbar() edit_toolbar_button = ToolbarButton(page=self.edit_toolbar, icon_name='toolbar-edit') self.edit_toolbar.show() toolbar.insert(edit_toolbar_button, -1) edit_toolbar_button.show() self.edit_toolbar.undo.connect('clicked', self.undobutton_cb) self.edit_toolbar.redo.connect('clicked', self.redobutton_cb) self.edit_toolbar.copy.connect('clicked', self.copybutton_cb) self.edit_toolbar.paste.connect('clicked', self.pastebutton_cb) separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' toolbox.toolbar.insert(stop_button, -1) stop_button.show()
def add_page(self, ebook_reader_tab_instance): # Add the "content" for the section. tab_name = ebook_reader_tab_instance.get_tab_label() tab_widget = ebook_reader_tab_instance.get_widget_to_attach_notebook_tab( ) tab_toolbar = ebook_reader_tab_instance.get_tab_toolbar() if tab_toolbar is not None: tab_widget.pack_start(tab_toolbar, False, False, 0) tab_widget.reorder_child(tab_toolbar, 0) self._tab_toolbars_list.append(tab_toolbar) self.notebook.add_page(tab_name, tab_widget) # Add the "(secondary) toolbar" for the section. icon_name = \ ebook_reader_tab_instance.get_tab_toolbar_icon_name() toolbar_button = ToolbarButton(page=None, icon_name=icon_name + '-select') self._toolbar_buttons_list.append(toolbar_button) toolbar_button.connect('clicked', self.load_corresponding_page, ebook_reader_tab_instance.get_pagenum()) ebook_reader_tab_instance.show() toolbar_button.set_tooltip(tab_name) self._toolbar_box._toolbar.insert(toolbar_button, -1) toolbar_button.show() self._toolbar_box.show_all()
def createPercussionToolbar(self, toolbar_box): self.beats_pm_button = IntensitySelector(list(range(2, 13)), 4, imagefile('beat3.svg')) self.tempo_button = \ IntensitySelector(list(range(PLAYER_TEMPO_LOWER, PLAYER_TEMPO_UPPER + 1, PLAYER_TEMPO_STEP)), PLAYER_TEMPO, imagefile('tempo5.png')) self.complexity_button = IntensitySelector(xfrange(0, 1, 0.1), self.regularity, imagefile('complex6.svg')) self._play_percussion_btn = ToolButton( icon_name='media-playback-start') self._play_percussion_btn.set_property('can-default', True) self._play_percussion_btn.show() self._play_percussion_btn.connect('clicked', self.handlePlayButton) beats_toolbar = ToolbarBox() beats_toolbar.toolbar.insert(self._play_percussion_btn, -1) self._what_drum_widget = Gtk.ToolItem() self._what_drum_search_button = FilterToolItem( _('Select Drum'), 'view-type', _('Jazz / Rock Kit'), self._what_drum_widget) self._what_drum_search_button.set_widget_icon( file_name=imagefile("drum1kit.svg")) self._what_drum_widget.show() beats_toolbar.toolbar.insert(self._what_drum_search_button, -1) self._what_drum_search_button.show() self._what_drum_search_button.set_is_important(True) beats_toolbar.toolbar.insert(Gtk.SeparatorToolItem(), -1) beats_toolbar.toolbar.insert(self.complexity_button, -1) beats_toolbar.toolbar.insert(self.beats_pm_button, -1) beats_toolbar.toolbar.insert(self.tempo_button, -1) beats_toolbar_button = ToolbarButton(icon_name='toolbar-drums', page=beats_toolbar) beats_toolbar_button.show() toolbar_box.toolbar.insert(beats_toolbar_button, 1) self.beats_pm_button.set_tooltip(_("Beats per bar")) self.beats_pm_button.show() self.beats_pm_button.connect('changed', self.beatSliderChange, True) self.tempo_button.connect('changed', self.tempoSliderChange, True) self.complexity_button.connect('changed', self.handleComplexityChange, True) self.complexity_button.set_tooltip(_("Beat complexity")) self.tempo_button.show() self.tempo_button.set_tooltip(_('Tempo')) self.complexity_button.show()
def createPercussionToolbar(self, toolbar_box): self.beats_pm_button = IntensitySelector(range(2, 13), 4, imagefile('beat3.svg')) self.tempo_button = \ IntensitySelector(range(PLAYER_TEMPO_LOWER, PLAYER_TEMPO_UPPER + 1, PLAYER_TEMPO_STEP), PLAYER_TEMPO, imagefile('tempo5.png')) self.complexity_button = IntensitySelector(xfrange(0, 1, 0.1), self.regularity, imagefile('complex6.svg')) self._play_percussion_btn = ToolButton( icon_name='media-playback-start') self._play_percussion_btn.set_property('can-default', True) self._play_percussion_btn.show() self._play_percussion_btn.connect('clicked', self.handlePlayButton) beats_toolbar = ToolbarBox() beats_toolbar.toolbar.insert(self._play_percussion_btn, -1) self._what_drum_widget = Gtk.ToolItem() self._what_drum_search_button = FilterToolItem( _('Select Drum'), 'view-type', _('Jazz / Rock Kit'), self._what_drum_widget) self._what_drum_search_button.set_widget_icon( file_name=imagefile("drum1kit.svg")) self._what_drum_widget.show() beats_toolbar.toolbar.insert(self._what_drum_search_button, -1) self._what_drum_search_button.show() self._what_drum_search_button.set_is_important(True) beats_toolbar.toolbar.insert(Gtk.SeparatorToolItem(), -1) beats_toolbar.toolbar.insert(self.complexity_button, -1) beats_toolbar.toolbar.insert(self.beats_pm_button, -1) beats_toolbar.toolbar.insert(self.tempo_button, -1) beats_toolbar_button = ToolbarButton(icon_name='toolbar-drums', page=beats_toolbar) beats_toolbar_button.show() toolbar_box.toolbar.insert(beats_toolbar_button, 1) self.beats_pm_button.set_tooltip(_("Beats per bar")) self.beats_pm_button.show() self.beats_pm_button.connect('changed', self.beatSliderChange, True) self.tempo_button.connect('changed', self.tempoSliderChange, True) self.complexity_button.connect('changed', self.handleComplexityChange, True) self.complexity_button.set_tooltip(_("Beat complexity")) self.tempo_button.show() self.tempo_button.set_tooltip(_('Tempo')) self.complexity_button.show()
def make_toolbar(self): # toolbar with the new toolbar redesign toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() toolbarview = Gtk.Toolbar() langtoolbar_button = ToolbarButton( label=_('View'), page=toolbarview, icon_name='settings') langtoolbar_button.show() toolbar_box.toolbar.insert(langtoolbar_button, -1) tool = ToolButton('en') tool.set_tooltip(_('English')) tool.connect('clicked', self.language_en) tool.show() toolbarview.insert(tool, -1) tool = ToolButton('es') tool.set_tooltip(_('Spanish')) tool.connect('clicked', self.language_es) tool.show() toolbarview.insert(tool, -1) tool = ToolButton('fr') tool.set_tooltip(_('French')) tool.connect('clicked', self.language_fr) tool.show() toolbarview.insert(tool, -1) tool = ToolButton('remote') tool.set_tooltip(_('Server settings')) tool.connect('clicked', self.settings) tool.show() toolbarview.insert(tool, -1) toolbarview.show() favorite_button = ToolButton(self.favorite_status) favorite_button.set_tooltip('Filter on favorite') favorite_button.connect('clicked', self.favorite) toolbar_box.toolbar.insert(favorite_button, -1) favorite_button.show() self.favorite_button = favorite_button separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show()
def make_toolbar(self): # toolbar with the new toolbar redesign toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() toolbarview = Gtk.Toolbar() langtoolbar_button = ToolbarButton(label=_('View'), page=toolbarview, icon_name='settings') langtoolbar_button.show() toolbar_box.toolbar.insert(langtoolbar_button, -1) tool = ToolButton('en') tool.set_tooltip(_('English')) tool.connect('clicked', self.language_en) tool.show() toolbarview.insert(tool, -1) tool = ToolButton('es') tool.set_tooltip(_('Spanish')) tool.connect('clicked', self.language_es) tool.show() toolbarview.insert(tool, -1) tool = ToolButton('fr') tool.set_tooltip(_('French')) tool.connect('clicked', self.language_fr) tool.show() toolbarview.insert(tool, -1) tool = ToolButton('remote') tool.set_tooltip(_('Server settings')) tool.connect('clicked', self.settings) tool.show() toolbarview.insert(tool, -1) toolbarview.show() favorite_button = ToolButton(self.favorite_status) favorite_button.set_tooltip('Filter on favorite') favorite_button.connect('clicked', self.favorite) toolbar_box.toolbar.insert(favorite_button, -1) favorite_button.show() self.favorite_button = favorite_button separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show()
def build_birth_toolbar(self, toolbox): birth_bar = Gtk.Toolbar() item1 = Gtk.ToolItem() self.label_birth = Gtk.Label() self.label_birth.set_text(_('Birth:') + ' ' + _('Day') + ' ') item1.add(self.label_birth) birth_bar.insert(item1, -1) item2 = Gtk.ToolItem() self.day_birth_spin = Gtk.SpinButton() self.day_birth_spin.set_range(1, 31) self.day_birth_spin.set_increments(1, 5) self.day_birth_spin.props.value = 10 self.day_birth_spin.connect('notify::value', self.day_birth_change) item2.add(self.day_birth_spin) birth_bar.insert(item2, -1) item3 = Gtk.ToolItem() self.label_birth_month = Gtk.Label() self.label_birth_month.set_text(' ' + _('Month') + ' ') item3.add(self.label_birth_month) birth_bar.insert(item3, -1) item4 = Gtk.ToolItem() self.month_birth_spin = Gtk.SpinButton() self.month_birth_spin.set_range(1, 12) self.month_birth_spin.set_increments(1, 4) self.month_birth_spin.props.value = 2 self.month_birth_spin.connect('notify::value', self.month_birth_change) item4.add(self.month_birth_spin) birth_bar.insert(item4, -1) item5 = Gtk.ToolItem() self.label_birth_year = Gtk.Label() self.label_birth_year.set_text(' ' + _('Year') + ' ') item5.add(self.label_birth_year) birth_bar.insert(item5, -1) item6 = Gtk.ToolItem() self.year_birth_spin = Gtk.SpinButton() self.year_birth_spin.set_range(1900, self._now.year) self.year_birth_spin.set_increments(1, 10) self.year_birth_spin.props.value = 1990 self.year_birth_spin.connect('notify::value', self.year_birth_change) item6.add(self.year_birth_spin) birth_bar.insert(item6, -1) birth_bar.show_all() birth_button = ToolbarButton(label=_('Birth'), page=birth_bar, icon_name='write-date') toolbox.toolbar.insert(birth_button, -1) birth_button.show()
def build_today_toolbar(self, toolbox): today_bar = Gtk.Toolbar() item1 = Gtk.ToolItem() self.label_today = Gtk.Label() self.label_today.set_text(_('Today:') + ' ' + _('Day') + ' ') item1.add(self.label_today) today_bar.insert(item1, -1) item2 = Gtk.ToolItem() self.day_today_spin = Gtk.SpinButton() self.day_today_spin.set_range(1, 31) self.day_today_spin.set_increments(1, 5) self.day_today_spin.props.value = self._today[0] self.day_today_spin.connect('notify::value', self.day_today_change) item2.add(self.day_today_spin) today_bar.insert(item2, -1) item3 = Gtk.ToolItem() self.label_today_month = Gtk.Label() self.label_today_month.set_text(' ' + _('Month') + ' ') item3.add(self.label_today_month) today_bar.insert(item3, -1) item4 = Gtk.ToolItem() self.month_today_spin = Gtk.SpinButton() self.month_today_spin.set_range(1, 12) self.month_today_spin.set_increments(1, 4) self.month_today_spin.props.value = self._today[1] self.month_today_spin.connect('notify::value', self.month_today_change) item4.add(self.month_today_spin) today_bar.insert(item4, -1) item5 = Gtk.ToolItem() self.label_today_year = Gtk.Label() self.label_today_year.set_text(' ' + _('Year') + ' ') item5.add(self.label_today_year) today_bar.insert(item5, -1) item6 = Gtk.ToolItem() self.year_today_spin = Gtk.SpinButton() self.year_today_spin.set_range(1900, self._now.year + 1) self.year_today_spin.set_increments(1, 10) self.year_today_spin.props.value = self._today[2] self.year_today_spin.connect('notify::value', self.year_today_change) item6.add(self.year_today_spin) today_bar.insert(item6, -1) today_bar.show_all() today_button = ToolbarButton(label=_('Today'), page=today_bar, icon_name='write-time') toolbox.toolbar.insert(today_button, -1) today_button.show()
def build_resolution_toolbar(self, toolbox): resolution_bar = Gtk.Toolbar() item1 = Gtk.ToolItem() label1 = Gtk.Label() label1.set_text(' ' + _('Show size') + ' ') item1.add(label1) resolution_bar.insert(item1, -1) item2 = Gtk.ToolItem() x_size_spin = Gtk.SpinButton() x_size_spin.set_range(160, 1200) x_size_spin.set_increments(1, 10) x_size_spin.props.value = int(self.show_size[0]) x_size_spin.connect('notify::value', self.x_size_spin_change) item2.add(x_size_spin) resolution_bar.insert(item2, -1) item3 = Gtk.ToolItem() label3 = Gtk.Label() label3.set_text(' X ') item3.add(label3) resolution_bar.insert(item3, -1) item4 = Gtk.ToolItem() y_size_spin = Gtk.SpinButton() y_size_spin.set_range(120, 900) y_size_spin.set_increments(1, 10) y_size_spin.props.value = int(self.show_size[1]) y_size_spin.connect('notify::value', self.y_size_spin_change) item4.add(y_size_spin) resolution_bar.insert(item4, -1) separator1 = Gtk.SeparatorToolItem() separator1.props.draw = True resolution_bar.insert(separator1, -1) item5 = Gtk.ToolItem() label5 = Gtk.Label() label5.set_text(' ' + _('Show grid')) item5.add(label5) resolution_bar.insert(item5, -1) grid = ToolButton('grid-icon') grid.connect('clicked', self.grid_click) resolution_bar.insert(grid, -1) resolution_bar.show_all() resolution_button = ToolbarButton(label=_('Resolution'), page=resolution_bar, icon_name='camera') toolbox.toolbar.insert(resolution_button, -1) resolution_button.show()
def build_toolbar(self): toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() viewtoolbar = ViewToolbar(self) viewbutton = ToolbarButton(page=viewtoolbar, icon_name='toolbar-view') toolbar_box.toolbar.insert(viewbutton, -1) viewbutton.show() separator = Gtk.SeparatorToolItem() toolbar_box.toolbar.insert(separator, -1) separator.show() # lets reuse the code below navtoolbar = Toolbar(self.web_view, self) toolitem = Gtk.ToolItem() navtoolbar._home.reparent(toolitem) toolbar_box.toolbar.insert(toolitem, -1) navtoolbar._home.show() toolitem.show() toolitem = Gtk.ToolItem() navtoolbar._back.reparent(toolitem) toolbar_box.toolbar.insert(toolitem, -1) navtoolbar._back.show() toolitem.show() toolitem = Gtk.ToolItem() navtoolbar._forward.reparent(toolitem) toolbar_box.toolbar.insert(toolitem, -1) navtoolbar._forward.show() toolitem.show() # we do not have collaboration features # make the share option insensitive self.max_participants = 1 separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show()
def make_toolbar(self): # toolbar with the new toolbar redesign toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() self.toolbarview = Gtk.Toolbar() langtoolbar_button = ToolbarButton( label=_('Filter'), page=self.toolbarview, icon_name='filter') langtoolbar_button.show() toolbar_box.toolbar.insert(langtoolbar_button, -1) self.toolbarview.show() box_search_item = Gtk.ToolItem() self.search_entry = Gtk.Entry() self.search_entry.connect('changed', self.text_filter) self.search_entry.set_size_request(300, -1) box_search_item.add(self.search_entry) self.search_entry.show() box_search_item.show() toolbar_box.toolbar.insert(box_search_item, -1) favorite_button = ToolButton(self.favorite_status) favorite_button.set_tooltip('Filter on favorite') favorite_button.connect('clicked', self.favorite) toolbar_box.toolbar.insert(favorite_button, -1) favorite_button.show() self.favorite_button = favorite_button library_button = ToolButton('library') library_button.set_tooltip('Show libraries') library_button.connect('clicked', self.library_clicked) toolbar_box.toolbar.insert(library_button, -1) library_button.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show()
def __init__(self, handle): if not hasattr(self, 'confvars'): self.confvars = read_conf_from_info(get_bundle_path()) logging.error("Starting server database: %s port: %s" % (self.confvars['path'], self.confvars['port'])) os.chdir(os.environ['SUGAR_BUNDLE_PATH']) self.confvars['ip'] = '0.0.0.0' server.run_server(self.confvars) handle.uri = 'http://%s:%s%s' % ( self.confvars['ip'], self.confvars['port'], self.confvars['home_page']) webactivity.WebActivity.__init__(self, handle) if USE_GTK2: # Use xpcom to set a RAM cache limit. (Trac #7081.) from xpcom import components from xpcom.components import interfaces cls = components.classes['@mozilla.org/preferences-service;1'] pref_service = cls.getService(interfaces.nsIPrefService) branch = pref_service.getBranch("browser.cache.memory.") branch.setIntPref("capacity", "5000") # Use xpcom to turn off "offline mode" detection, which disables # access to localhost for no good reason. (Trac #6250.) ios_class = components.classes["@mozilla.org/network/io-service;1"] io_service = ios_class.getService(interfaces.nsIIOService2) io_service.manageOfflineStatus = False self.searchtoolbar = SearchToolbar(self) search_toolbar_button = ToolbarButton() search_toolbar_button.set_page(self.searchtoolbar) search_toolbar_button.props.icon_name = 'search-wiki' search_toolbar_button.props.label = _('Search') self.get_toolbar_box().toolbar.insert(search_toolbar_button, 1) search_toolbar_button.show() # Hide add-tabs button if hasattr(self._primary_toolbar, '_add_tab'): self._primary_toolbar._add_tab.hide() self.searchtoolbar.show()
def build_size_toolbar(self, toolbox): size_bar = Gtk.Toolbar() #Horizontal item1 = Gtk.ToolItem() label1 = Gtk.Label() label1.set_text(' %s ' % _('H')) item1.add(label1) size_bar.insert(item1, -1) item2 = Gtk.ToolItem() self.h_spin = Gtk.SpinButton() self.h_spin.set_range(2, 30) self.h_spin.set_increments(1, 2) self.h_spin.props.value = self.game_size[0] self.h_spin.connect('notify::value', self.h_spin_change) item2.add(self.h_spin) size_bar.insert(item2, -1) #Vertical item3 = Gtk.ToolItem() label2 = Gtk.Label() label2.set_text(' %s ' % _('V')) item3.add(label2) size_bar.insert(item3, -1) item4 = Gtk.ToolItem() self.v_spin = Gtk.SpinButton() self.v_spin.set_range(2, 20) self.v_spin.set_increments(1, 2) self.v_spin.props.value = self.game_size[1] self.v_spin.connect('notify::value', self.v_spin_change) item4.add(self.v_spin) size_bar.insert(item4, -1) size_bar.show_all() size_button = ToolbarButton(label=_('Board size'), page=size_bar, icon_name='preferences-system') toolbox.toolbar.insert(size_button, -1) size_button.show()
def build_toolbar(self): toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() edit_toolbar = self._create_edit_toolbar() edit_toolbar_button = ToolbarButton(page=edit_toolbar, icon_name='toolbar-edit') edit_toolbar.show() toolbar_box.toolbar.insert(edit_toolbar_button, -1) edit_toolbar_button.show() view_toolbar = self._create_view_toolbar() view_toolbar_button = ToolbarButton(page=view_toolbar, icon_name='toolbar-view') view_toolbar.show() toolbar_box.toolbar.insert(view_toolbar_button, -1) view_toolbar_button.show() self._delete_tab_toolbar = None self._previous_tab_toolbar = None self._next_tab_toolbar = None helpbutton = self._create_help_button() toolbar_box.toolbar.insert(helpbutton, -1) helpbutton.show_all() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl><Shift>Q' toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show()
def setup_toolbar(self): '''Setup the top toolbar. Groupthink needs some work here.''' toolbox = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() self.set_toolbar_box(toolbox) toolbox.show() toolbar = toolbox.toolbar self.edit_toolbar = EditToolbar() edit_toolbar_button = ToolbarButton( page=self.edit_toolbar, icon_name='toolbar-edit') self.edit_toolbar.show() toolbar.insert(edit_toolbar_button, -1) edit_toolbar_button.show() self.edit_toolbar.undo.connect('clicked', self.undobutton_cb) self.edit_toolbar.redo.connect('clicked', self.redobutton_cb) self.edit_toolbar.copy.connect('clicked', self.copybutton_cb) self.edit_toolbar.paste.connect('clicked', self.pastebutton_cb) separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' toolbox.toolbar.insert(stop_button, -1) stop_button.show()
class AbacusActivity(activity.Activity): def __init__(self, handle): ''' Initiate activity. ''' super(AbacusActivity, self).__init__(handle) self._setting_up = True self.bead_colors = profile.get_color().to_string().split(',') # no sharing self.max_participants = 1 self.sep = [] self.abacus_toolbar = Gtk.Toolbar() custom_toolbar = Gtk.Toolbar() edit_toolbar = Gtk.Toolbar() toolbox = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() edit_toolbar_button = ToolbarButton(label=_('Edit'), page=edit_toolbar, icon_name='toolbar-edit') edit_toolbar_button.show() toolbox.toolbar.insert(edit_toolbar_button, -1) edit_toolbar_button.show() self.abacus_toolbar_button = ToolbarButton( page=self.abacus_toolbar, icon_name='abacus-list') self.abacus_toolbar.show() toolbox.toolbar.insert(self.abacus_toolbar_button, -1) self.abacus_toolbar_button.show() self.custom_toolbar_button = ToolbarButton( page=custom_toolbar, icon_name='view-source') custom_toolbar.show() toolbox.toolbar.insert(self.custom_toolbar_button, -1) self.custom_toolbar_button.show() separator_factory(toolbox.toolbar, False, True) button_factory('edit-delete', toolbox.toolbar, self._reset_cb, tooltip=_('Reset')) separator_factory(toolbox.toolbar, False, True) self._label = label_factory(NAMES['suanpan'], toolbox.toolbar) separator_factory(toolbox.toolbar, True, False) stop_button = StopButton(self) stop_button.props.accelerator = _('<Ctrl>Q') toolbox.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbox) toolbox.show() self.abacus_buttons = {} # Traditional self._add_abacus_button('decimal', None) self._add_abacus_button('soroban', self.abacus_buttons['decimal']) self._add_abacus_button('suanpan', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Bases other than 10 self._add_abacus_button('nepohualtzintzin', self.abacus_buttons['decimal']) self._add_abacus_button('hexadecimal', self.abacus_buttons['decimal']) self._add_abacus_button('binary', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Fractions self._add_abacus_button('schety', self.abacus_buttons['decimal']) # self._add_abacus_button('fraction', self.abacus_buttons['decimal']) self._add_abacus_button('caacupe', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Non-traditional self._add_abacus_button('cuisenaire', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Custom self._add_abacus_button('custom', self.abacus_buttons['decimal']) preferences_button = ToolButton('preferences-system') preferences_button.set_tooltip(_('Custom')) custom_toolbar.insert(preferences_button, -1) preferences_button.palette_invoker.props.toggle_palette = True preferences_button.palette_invoker.props.lock_palette = True preferences_button.props.hide_tooltip_on_click = False preferences_button.show() self._palette = preferences_button.get_palette() button_box = Gtk.VBox() # TRANS: Number of rods on the abacus self._rods_spin = add_spinner_and_label( 15, 1, MAX_RODS, _('Rods:'), self._rods_spin_cb, button_box) # TRANS: Number of beads in the top section of the abacus self._top_spin = add_spinner_and_label( 2, 0, MAX_TOP, _('Top:'), self._top_spin_cb, button_box) # TRANS: Number of beads in the bottom section of the abacus self._bottom_spin = add_spinner_and_label( 5, 0, MAX_BOT, _('Bottom:'), self._bottom_spin_cb, button_box) # TRANS: Scale factor between bottom and top beads self._value_spin = add_spinner_and_label( 5, 1, MAX_BOT + 1, _('Factor:'), self._value_spin_cb, button_box) # TRANS: Scale factor between rods self._base_spin = add_spinner_and_label( 10, 1, (MAX_TOP + 1) * MAX_BOT, _('Base:'), self._base_spin_cb, button_box) hbox = Gtk.HBox() hbox.pack_start(button_box, True, True, style.DEFAULT_SPACING) hbox.show_all() self._palette.set_content(hbox) separator_factory(custom_toolbar, False, False) self.custom_maker = button_factory('new-abacus', custom_toolbar, self._custom_cb, tooltip=_('Custom')) button_factory('edit-copy', edit_toolbar, self._copy_cb, tooltip=_('Copy'), accelerator='<Ctrl>c') button_factory('edit-paste', edit_toolbar, self._paste_cb, tooltip=_('Paste'), accelerator='<Ctrl>v') # Create a canvas canvas = Gtk.DrawingArea() canvas.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self.set_canvas(canvas) canvas.show() self.show_all() # Initialize the canvas self.abacus = Abacus(canvas, self) self._setting_up = False # Read the current mode from the Journal if 'rods' in self.metadata: self._rods_spin.set_value(int(self.metadata['rods'])) if 'top' in self.metadata: self._top_spin.set_value(int(self.metadata['top'])) if 'bottom' in self.metadata: self._bottom_spin.set_value(int(self.metadata['bottom'])) if 'factor' in self.metadata: self._value_spin.set_value(int(self.metadata['factor'])) if 'base' in self.metadata: self._base_spin.set_value(int(self.metadata['base'])) if 'abacus' in self.metadata: if self.metadata['abacus'] in self.abacus_buttons: _logger.debug('restoring %s', self.metadata['abacus']) if self.metadata['abacus'] == 'custom': self._custom_cb() self.abacus_buttons[self.metadata['abacus']].set_active(True) else: # Default is Chinese self.abacus_buttons['suanpan'].set_active(True) if 'value' in self.metadata: _logger.debug('restoring value %s', self.metadata['value']) self.abacus.mode.set_value(self.metadata['value']) self.abacus.mode.label(self.abacus.generate_label()) self.abacus.init() # Start with abacus toolbar expanded and suanpan as default self.abacus_toolbar_button.set_expanded(True) def _add_abacus_button(self, name, group): self.abacus_buttons[name] = radio_factory( name, self.abacus_toolbar, self._radio_cb, cb_arg=name, tooltip=NAMES[name], group=group) def _radio_cb(self, button, abacus): self._select_abacus(abacus) def _reset_cb(self, button=None): self.abacus.mode.reset_abacus() self.abacus.mode.label(self.abacus.generate_label()) def _notify_new_abacus(self, prompt): ''' Loading a new abacus can be slooow, so alert the user. ''' # a busy cursor is adequate self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) def _select_abacus(self, abacus): ''' Notify the user of an expected delay and then... ''' if not hasattr(self, 'abacus') or self._setting_up: _logger.debug('setting up') return # Not selected? if not self.abacus_buttons[abacus].get_active(): _logger.debug('%s not active' % abacus) return self._notify_new_abacus(NAMES[abacus]) # Give the cursor/alert time to load GObject.idle_add(self._switch_modes, abacus) def _switch_modes(self, abacus): ''' Display the selected abacus ''' _logger.debug('switching modes to %s', abacus) if abacus == self.abacus.mode.name: _logger.debug('do not switch already in the same mode') self.get_window().set_cursor(None) return # Save current value value = int(float(self.abacus.mode.value())) if abacus == 'custom' and self.abacus.custom is None: self.custom_toolbar_button.set_expanded(True) # self.abacus.mode = self.abacus.custom self.get_window().set_cursor(None) else: _logger.debug('switch_mode: setting abacus to %s' % abacus) self.abacus.select_abacus(abacus) # Load saved value self.abacus.mode.set_value_from_number(value) self.abacus.mode.label(self.abacus.generate_label()) self._label.set_text(NAMES[abacus]) self.get_window().set_cursor(None) def _rods_spin_cb(self, button=None): return def _top_spin_cb(self, button=None): return def _bottom_spin_cb(self, button=None): return def _value_spin_cb(self, button=None): return def _base_spin_cb(self, button=None): return def _custom_cb(self, button=None): ''' Display the custom abacus; hide the others ''' value = float(self.abacus.mode.value(count_beads=False)) self.abacus.mode.hide() if self.abacus.custom is not None: self.abacus.custom.hide() self.abacus.custom = Custom(self.abacus, self.abacus.bead_colors) self.abacus.custom.set_custom_parameters( rods=self._rods_spin.get_value_as_int(), top=self._top_spin.get_value_as_int(), bot=self._bottom_spin.get_value_as_int(), factor=self._value_spin.get_value_as_int(), base=self._base_spin.get_value_as_int()) self.abacus.custom.create() self.abacus.custom.draw_rods_and_beads() self.abacus.custom.show() self._label.set_text(NAMES['custom']) self.abacus.mode = self.abacus.custom self.abacus.mode_dict['custom'][0] = self.abacus.custom self.abacus_toolbar_button.set_expanded(True) self.abacus.mode.set_value_from_number(value) def _copy_cb(self, arg=None): ''' Copy a number to the clipboard from the active abacus. ''' clipBoard = Gtk.Clipboard() text = self.abacus.generate_label(sum_only=True) if text is not None: clipBoard.set_text(text) return def _paste_cb(self, arg=None): ''' Paste a number from the clipboard to the active abacus. ''' clipBoard = Gtk.Clipboard() text = clipBoard.wait_for_text() if text is not None: try: self.abacus.mode.set_value_from_number(float(text)) except ValueError, e: _logger.debug(str(e)) return self.abacus.mode.label(self.abacus.generate_label()) return
def build_options_toolbar(self, toolbox): options_bar = Gtk.Toolbar() item1 = Gtk.ToolItem() label1 = Gtk.Label() label1.set_text(' ' + _('Pixels') + ' ') item1.add(label1) options_bar.insert(item1, -1) item2 = Gtk.ToolItem() pixels = Gtk.SpinButton() pixels.set_range(0, 1000) pixels.set_increments(1, 10) pixels.props.value = self.pixels pixels.connect('notify::value', self.pixels_value) item2.add(pixels) options_bar.insert(item2, -1) separator1 = Gtk.SeparatorToolItem() separator1.props.draw = True options_bar.insert(separator1, -1) item3 = Gtk.ToolItem() self.label_threshold_red = Gtk.Label() self.label_threshold_red.set_text(' ' + _('Threshold:') + ' ' + _('Red') + ' ') item3.add(self.label_threshold_red) options_bar.insert(item3, -1) item4 = Gtk.ToolItem() red_spin = Gtk.SpinButton() red_spin.set_range(0, 255) red_spin.set_increments(1, 10) red_spin.props.value = self.threshold[0] red_spin.connect('notify::value', self.red_spin_threshold) item4.add(red_spin) options_bar.insert(item4, -1) item5 = Gtk.ToolItem() self.label_threshold_green = Gtk.Label() self.label_threshold_green.set_text(' ' + _('Green') + ' ') item5.add(self.label_threshold_green) options_bar.insert(item5, -1) item6 = Gtk.ToolItem() green_spin = Gtk.SpinButton() green_spin.set_range(0, 255) green_spin.set_increments(1, 10) green_spin.props.value = self.threshold[1] green_spin.connect('notify::value', self.green_spin_threshold) item6.add(green_spin) options_bar.insert(item6, -1) item7 = Gtk.ToolItem() self.label_threshold_blue = Gtk.Label() self.label_threshold_blue.set_text(' ' + _('Blue') + ' ') item7.add(self.label_threshold_blue) options_bar.insert(item7, -1) item8 = Gtk.ToolItem() blue_spin = Gtk.SpinButton() blue_spin.set_range(0, 255) blue_spin.set_increments(1, 10) blue_spin.props.value = self.threshold[2] blue_spin.connect('notify::value', self.blue_spin_threshold) item8.add(blue_spin) options_bar.insert(item8, -1) options_bar.show_all() options_button = ToolbarButton(label=_('Options'), page=options_bar, icon_name='view-source') toolbox.toolbar.insert(options_button, -1) options_button.show()
def _setup_toolbars(self): """ Setup the toolbars.. """ project_toolbar = Gtk.Toolbar() custom_slide_toolbar = Gtk.Toolbar() custom_stator_toolbar = Gtk.Toolbar() edit_toolbar = Gtk.Toolbar() # no sharing self.max_participants = 1 toolbox = ToolbarBox() # Activity toolbar activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() project_toolbar_button = ToolbarButton(page=project_toolbar, icon_name='sliderule') project_toolbar.show() toolbox.toolbar.insert(project_toolbar_button, -1) project_toolbar_button.show() custom_slide_toolbar_button = ToolbarButton(page=custom_slide_toolbar, icon_name='custom-slide') custom_slide_toolbar.show() toolbox.toolbar.insert(custom_slide_toolbar_button, -1) custom_slide_toolbar_button.show() custom_stator_toolbar_button = ToolbarButton( page=custom_stator_toolbar, icon_name='custom-stator') custom_stator_toolbar.show() toolbox.toolbar.insert(custom_stator_toolbar_button, -1) custom_stator_toolbar_button.show() edit_toolbar_button = ToolbarButton(label=_('Edit'), page=edit_toolbar, icon_name='toolbar-edit') edit_toolbar_button.show() toolbox.toolbar.insert(edit_toolbar_button, -1) edit_toolbar_button.show() self.set_toolbar_box(toolbox) toolbox.show() toolbar = toolbox.toolbar # Add the buttons to the toolbars self._function_combo = combo_factory(FUNCTIONS, project_toolbar, self._function_combo_cb, default=FC_multiply, tooltip=_('select function')) self.top_button = button_factory('C', project_toolbar, self._dummy_cb, tooltip=_('active slide')) self._slide_combo = combo_factory(SLIDE_TABLE, project_toolbar, self._slide_combo_cb, default=C_slide, tooltip=_('select slide')) self.bottom_button = button_factory('D', project_toolbar, self._dummy_cb, tooltip=_('active stator')) self._stator_combo = combo_factory(STATOR_TABLE, project_toolbar, self._stator_combo_cb, default=D_slide, tooltip=_('select stator')) separator_factory(project_toolbar) self.realign_button = button_factory('realign', project_toolbar, self.realign_cb, tooltip=_('realign slides')) self._offset_function = [] self._calculate_function = [] self._label_function = [] self._domain_min = [] self._domain_max = [] self._step_size = [] self.custom = [] ENTRY = ['C', 'D'] ENTRY_TOOLBAR = [custom_slide_toolbar, custom_stator_toolbar] ENTRY_BUTTON = ['custom-slide', 'custom-stator'] ENTRY_TOOLTIP = [_('create custom slide'), _('create custom stator')] ENTRY_CALLBACK = [self._custom_slide_cb, self._custom_stator_cb] for i in range(2): self._offset_function.append( entry_factory(DEFINITIONS[ENTRY[i]][0], ENTRY_TOOLBAR[i], tooltip=_('position function'), max=10)) self._calculate_function.append( entry_factory(DEFINITIONS[ENTRY[i]][1], ENTRY_TOOLBAR[i], tooltip=_('result function'), max=10)) self._label_function.append( entry_factory(DEFINITIONS[ENTRY[i]][2], ENTRY_TOOLBAR[i], tooltip=_('label function'), max=10)) self._domain_min.append( entry_factory(DEFINITIONS[ENTRY[i]][3], ENTRY_TOOLBAR[i], tooltip=_('domain minimum'), max=4)) self._domain_max.append( entry_factory(DEFINITIONS[ENTRY[i]][4], ENTRY_TOOLBAR[i], tooltip=_('domain maximum'), max=4)) self._step_size.append( entry_factory(DEFINITIONS[ENTRY[i]][5], ENTRY_TOOLBAR[i], tooltip=_('step size'), max=4)) self.custom.append( button_factory(ENTRY_BUTTON[i], ENTRY_TOOLBAR[i], ENTRY_CALLBACK[i], tooltip=ENTRY_TOOLTIP[i])) copy = button_factory('edit-copy', edit_toolbar, self._copy_cb, tooltip=_('Copy'), accelerator='<Ctrl>c') paste = button_factory('edit-paste', edit_toolbar, self._paste_cb, tooltip=_('Paste'), accelerator='<Ctrl>v') separator_factory(toolbox.toolbar, True, False) stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' toolbox.toolbar.insert(stop_button, -1) stop_button.show() # workaround to #2050 edit_toolbar_button.set_expanded(True) # start with project toolbar enabled project_toolbar_button.set_expanded(True)
def __init__(self, handle): activity.Activity.__init__(self, handle) self.props.max_participants = 1 self._web_view = WebKit.WebView() self._web_view.set_full_content_zoom(True) _scrolled_window = Gtk.ScrolledWindow() _scrolled_window.add(self._web_view) _scrolled_window.show() toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() viewtoolbar = ViewToolbar(self) viewbutton = ToolbarButton(page=viewtoolbar, icon_name='toolbar-view') toolbar_box.toolbar.insert(viewbutton, -1) viewbutton.show() separator = Gtk.SeparatorToolItem() toolbar_box.toolbar.insert(separator, -1) separator.show() # lets reuse the code below navtoolbar = Toolbar(self._web_view) toolitem = Gtk.ToolItem() navtoolbar._home.reparent(toolitem) toolbar_box.toolbar.insert(toolitem, -1) navtoolbar._home.show() toolitem.show() toolitem = Gtk.ToolItem() navtoolbar._back.reparent(toolitem) toolbar_box.toolbar.insert(toolitem, -1) navtoolbar._back.show() toolitem.show() toolitem = Gtk.ToolItem() navtoolbar._forward.reparent(toolitem) toolbar_box.toolbar.insert(toolitem, -1) navtoolbar._forward.show() toolitem.show() # we do not have collaboration features # make the share option insensitive self.max_participants = 1 separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() self.set_canvas(_scrolled_window) self._web_view.show() self._web_view.connect("resource-request-starting", self._resource_request_starting_cb) self._web_view.load_uri(get_index_uri())
def __init__(self, handle): """Set up the Weather activity.""" activity.Activity.__init__(self, handle) # we do not have collaboration features # make the share option insensitive self.max_participants = 1 self.wind_scale = 'm/s' self.pressure_scale = 'hPa' self.humidity_scale = '%' self.cloud_scale = '%' self.temp_scale = 'K' self.input = '' self.selected_city = None self.temp_scales = { 'Kelvin': 'K', 'Celcius': u'\u00b0C'.encode('utf-8'), 'Farenheit': u'\u00b0F'.encode('utf-8') } # view toolbar view_toolbar = Gtk.Toolbar() toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() temp_label = Gtk.Label(_('Temperature:')) temp_label.show() temp_label_item = Gtk.ToolItem() temp_label_item.add(temp_label) temp_label_item.show() temp_scale_store = Gtk.ListStore(str) for key in self.temp_scales.keys(): temp_scale_store.append([key]) self.temp_scale_combo = Gtk.ComboBox.new_with_model(temp_scale_store) renderer_text = Gtk.CellRendererText() self.temp_scale_combo.pack_start(renderer_text, True) self.temp_scale_combo.add_attribute(renderer_text, 'text', 0) self.temp_scale_combo.connect('changed', self.temp_scale_combo_toggled) self.temp_scale_combo.show() temp_scale_combo_item = ToolComboBox(self.temp_scale_combo) temp_scale_combo_item.show() view_toolbar.insert(temp_label_item, -1) view_toolbar.insert(temp_scale_combo_item, -1) view_toolbar.show() view_toolbar_button = ToolbarButton(icon_name='toolbar-view', page=view_toolbar) toolbar_box.toolbar.insert(view_toolbar_button, -1) view_toolbar_button.show() # toolbar separator = Gtk.SeparatorToolItem() toolbar_box.toolbar.insert(separator, -1) separator.set_draw(False) separator.set_expand(True) separator.show() self.search_entry = iconentry.IconEntry() self.search_entry.connect('key-press-event', self.entry_key_press_cb) self.search_entry.connect('icon-press', self.refresh) self.search_entry.show() self.search_entry_item = Gtk.ToolItem() self.search_entry_item.set_size_request(SCREEN_WIDTH / 3, -1) self.search_entry_item.add(self.search_entry) toolbar_box.toolbar.insert(self.search_entry_item, -1) self.search_entry_item.show() self.back_button = ToolButton('go-previous-paired') self.back_button.connect('clicked', self.back_button_clicked) self.back_button.set_sensitive(False) self.back_button.set_tooltip(_('Back')) toolbar_box.toolbar.insert(self.back_button, -1) self.back_button.show() self.forecast_button = ToolButton('go-next-paired') self.forecast_button.connect('clicked', self.forecast_button_clicked) self.forecast_button.set_sensitive(False) self.forecast_button.set_tooltip(_('Forecast')) toolbar_box.toolbar.insert(self.forecast_button, -1) self.forecast_button.show() separator = Gtk.SeparatorToolItem() toolbar_box.toolbar.insert(separator, -1) separator.set_draw(False) separator.set_expand(True) separator.show() stop_button = StopButton(self) toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() # set up screen self.search_screen = searchscreen.SearchScreen(self) self.forecast_screen = forecastscreen.ForecastScreen(self) self.screen = self.search_screen howto_label = Gtk.Label() howto_label.set_justify(Gtk.Justification.CENTER) howto_label.set_markup(howto) howto_label.show() world_image = Gtk.Image() world_image.modify_bg(Gtk.StateType.NORMAL, Gdk.Color.parse(GREY)[1]) pixbuf = GdkPixbuf.Pixbuf.new_from_file('world.svg') scaled_pixbuf = pixbuf.scale_simple(SCREEN_WIDTH, SCREEN_HEIGHT - 170, GdkPixbuf.InterpType.BILINEAR) world_image.set_from_pixbuf(scaled_pixbuf) world_image.show() box = Gtk.Box() box.set_orientation(Gtk.Orientation.VERTICAL) box.pack_start(howto_label, expand=True, fill=False, padding=0) box.pack_start(world_image, expand=True, fill=True, padding=0) box.show() self.set_canvas(box) self.temp_scale_combo.set_active(1) self.search_entry.grab_focus()
def build_colors_toolbar(self, toolbox): barra_colors = Gtk.Toolbar() item1 = Gtk.ToolItem() label1 = Gtk.Label() label1.set_text(_('Color mode') + ' ') item1.add(label1) barra_colors.insert(item1, -1) item2 = Gtk.ToolItem() modes = ('RGB', 'YUV', 'HSV') combo = Combo(modes) item2.add(combo) combo.connect('changed', self.change_combo) barra_colors.insert(item2, -1) separator1 = Gtk.SeparatorToolItem() separator1.props.draw = True barra_colors.insert(separator1, -1) item_l = Gtk.ToolItem() label4 = Gtk.Label() label4.set_text(_('Brightness') + ' ') item_l.add(label4) barra_colors.insert(item_l, -1) item = Gtk.ToolItem() brightness_spin = Gtk.SpinButton() brightness_spin.set_range(-1, 255) brightness_spin.set_increments(1, 10) brightness_spin.props.value = int(self.brightness) brightness_spin.connect('notify::value', self.brightness_spin_change) item.add(brightness_spin) barra_colors.insert(item, -1) separator2 = Gtk.SeparatorToolItem() separator2.props.draw = True barra_colors.insert(separator2, -1) item3 = Gtk.ToolItem() label3 = Gtk.Label() label3.set_text(_('Threshold view')) item3.add(label3) barra_colors.insert(item3, -1) threshold_view = ToolButton('media-playback-stop') threshold_view.connect('clicked', self.threshold_view) threshold_view.set_tooltip(_('Yes')) barra_colors.insert(threshold_view, -1) separator3 = Gtk.SeparatorToolItem() separator3.props.draw = True barra_colors.insert(separator3, -1) item4 = Gtk.ToolItem() label4 = Gtk.Label() label4.set_text(_('Outline')) item4.add(label4) barra_colors.insert(item4, -1) outline_view = ToolButton('media-playback-stop') outline_view.connect('clicked', self.outline_view) outline_view.set_tooltip(_('Yes')) barra_colors.insert(outline_view, -1) separator4 = Gtk.SeparatorToolItem() separator4.props.draw = True barra_colors.insert(separator4, -1) item5 = Gtk.ToolItem() label5 = Gtk.Label() label5.set_text(_('Rects')) item5.add(label5) barra_colors.insert(item5, -1) rects_view = ToolButton('media-playback-stop') rects_view.connect('clicked', self.rects_view) rects_view.set_tooltip(_('Yes')) barra_colors.insert(rects_view, -1) barra_colors.show_all() colors_button = ToolbarButton(label=_('Colors'), page=barra_colors, icon_name='toolbar-colors') toolbox.toolbar.insert(colors_button, -1) colors_button.show()
def _setup_toolbars(self): """ Setup the toolbars. """ self.max_participants = 1 # No collaboration toolbox = ToolbarBox() # Activity toolbar activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() self.set_toolbar_box(toolbox) toolbox.show() self.toolbar = toolbox.toolbar name_game_button = radio_factory('name-game', toolbox.toolbar, self._level_cb, cb_arg=0, tooltip=_(LABELS[0]), group=None) group_game_button = radio_factory('group-game', toolbox.toolbar, self._level_cb, cb_arg=1, tooltip=_(LABELS[1]), group=name_game_button) calorie_game_button = radio_factory('calorie-game', toolbox.toolbar, self._level_cb, cb_arg=2, tooltip=_(LABELS[2]), group=name_game_button) pyramid_game_button = radio_factory('pyramid-game', toolbox.toolbar, self._level_cb, cb_arg=3, tooltip=_(LABELS[3]), group=name_game_button) balance_game_button = radio_factory('balance-game', toolbox.toolbar, self._level_cb, cb_arg=4, tooltip=_(LABELS[4]), group=name_game_button) separator_factory(toolbox.toolbar, False, True) self._label = label_factory(toolbox.toolbar, LABELS[0], width=150) separator_factory(toolbox.toolbar, True, False) tools_toolbar = Gtk.Toolbar() tools_toolbar_button = ToolbarButton(page=tools_toolbar, icon_name='view-source') tools_toolbar.show() toolbox.toolbar.insert(tools_toolbar_button, -1) tools_toolbar_button.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' toolbox.toolbar.insert(stop_button, -1) stop_button.show() self.name_entry = entry_factory( _('food name'), tools_toolbar, tooltip=_('Enter a name for the new food item.'), max=20) self.calories_entry = entry_factory( _('calories'), tools_toolbar, tooltip=_('Enter the calories in for the new food item.'), max=8) self.food_spinner = combo_factory( PYRAMID, tools_toolbar, self._food_pyramid_cb, default=PYRAMID[2], tooltip=_('Select level in the Food Pyramid.')) image_button = button_factory( 'image-tools', tools_toolbar, self._load_image_cb, tooltip=_('Load a picture of the new food item.')) separator_factory(tools_toolbar, True, False) create_button = button_factory('new-food', tools_toolbar, self._create_custom_food_cb, tooltip=_('Add a new food item.'))
class OneSupportActivity(activity.Activity): ''' An activity for sending bug reports ''' def __init__(self, handle): ''' Initialize the toolbar ''' try: super(OneSupportActivity, self).__init__(handle) except dbus.exceptions.DBusException as e: _logger.error(str(e)) self.connect('realize', self.__realize_cb) if hasattr(self, 'metadata') and 'font_size' in self.metadata: self.font_size = int(self.metadata['font_size']) else: self.font_size = 8 self.zoom_level = self.font_size / float(len(FONT_SIZES)) _logger.debug('zoom level is %f' % self.zoom_level) # _check_gconf_settings() # For debugging purposes self._setup_toolbars() self.modify_bg(Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color()) self.bundle_path = activity.get_bundle_path() self._copy_entry = None self._paste_entry = None self._webkit = None self._clipboard_text = '' self._fixed = None self._notify_transfer_status = False get_power_manager().inhibit_suspend() self._launch_task_master() def can_close(self): get_power_manager().restore_suspend() return True def busy_cursor(self): self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) def reset_cursor(self): self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.LEFT_PTR)) def _launch_task_master(self): # Most things need only be done once if self._fixed is None: self._fixed = Gtk.Fixed() self._fixed.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) # Offsets from the bottom of the screen dy1 = 3 * style.GRID_CELL_SIZE dy2 = 2 * style.GRID_CELL_SIZE self._progress_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._progress_area.set_size_request(Gdk.Screen.width(), -1) self._fixed.put(self._progress_area, 0, Gdk.Screen.height() - dy2) self._progress_area.show() self._button_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._button_area.set_size_request(Gdk.Screen.width(), -1) self._fixed.put(self._button_area, 0, Gdk.Screen.height() - dy1) self._button_area.show() self._scrolled_window = Gtk.ScrolledWindow() self._scrolled_window.set_size_request( Gdk.Screen.width(), Gdk.Screen.height() - dy1) self._set_scroll_policy() self._graphics_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._scrolled_window.add_with_viewport(self._graphics_area) self._graphics_area.show() self._fixed.put(self._scrolled_window, 0, 0) self._scrolled_window.show() self._task_master = TaskMaster(self) self._task_master.show() Gdk.Screen.get_default().connect('size-changed', self._configure_cb) self._toolbox.connect('hide', self._resize_hide_cb) self._toolbox.connect('show', self._resize_show_cb) self._task_master.set_events(Gdk.EventMask.KEY_PRESS_MASK) self._task_master.connect('key_press_event', self._task_master.keypress_cb) self._task_master.set_can_focus(True) self._task_master.grab_focus() self.set_canvas(self._fixed) self._fixed.show() self._task_master.task_master() def reset_scrolled_window_adjustments(self): adj = self._scrolled_window.get_hadjustment() if adj is not None: adj.set_value(0) adj = self._scrolled_window.get_vadjustment() if adj is not None: adj.set_value(0) def load_graphics_area(self, widget): self._graphics_area.add(widget) def load_button_area(self, widget): self._button_area.add(widget) def load_progress_area(self, widget): self._progress_area.add(widget) def _load_intro_graphics(self, file_name='generic-problem.html', message=None): center_in_panel = Gtk.Alignment.new(0.5, 0, 0, 0) url = os.path.join(self.bundle_path, 'html-content', file_name) graphics = Graphics() if message is None: graphics.add_uri('file://' + url) else: graphics.add_uri('file://' + url + '?MSG=' + utils.get_safe_text(message)) graphics.set_zoom_level(0.667) center_in_panel.add(graphics) graphics.show() self.set_canvas(center_in_panel) center_in_panel.show() def _resize_hide_cb(self, widget): self._resize_canvas(widget, True) def _resize_show_cb(self, widget): self._resize_canvas(widget, False) def _configure_cb(self, event): self._fixed.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self._set_scroll_policy() self._resize_canvas(None) self._task_master.reload_graphics() def _resize_canvas(self, widget, fullscreen=False): # When a toolbar is expanded or collapsed, resize the canvas # to ensure that the progress bar is still visible. if hasattr(self, '_task_master'): if self.toolbar_expanded(): dy1 = 4 * style.GRID_CELL_SIZE dy2 = 3 * style.GRID_CELL_SIZE else: dy1 = 3 * style.GRID_CELL_SIZE dy2 = 2 * style.GRID_CELL_SIZE if fullscreen: dy1 -= 2 * style.GRID_CELL_SIZE dy2 -= 2 * style.GRID_CELL_SIZE self._scrolled_window.set_size_request( Gdk.Screen.width(), Gdk.Screen.height() - dy1) self._fixed.move(self._progress_area, 0, Gdk.Screen.height() - dy2) self._fixed.move(self._button_area, 0, Gdk.Screen.height() - dy1) def get_activity_version(self): info_path = os.path.join(self.bundle_path, 'activity', 'activity.info') try: info_file = open(info_path, 'r') except Exception as e: _logger.error('Could not open %s: %s' % (info_path, e)) return 'unknown' cp = ConfigParser() cp.readfp(info_file) section = 'Activity' if cp.has_option(section, 'activity_version'): activity_version = cp.get(section, 'activity_version') else: activity_version = 'unknown' return activity_version def get_uid(self): if len(self.volume_data) == 1: return self.volume_data[0]['uid'] else: return 'unknown' def write_file(self, file_path): self.metadata['font_size'] = str(self.font_size) def _setup_toolbars(self): ''' Setup the toolbars. ''' self.max_participants = 1 # No sharing self._toolbox = ToolbarBox() self.activity_button = ActivityToolbarButton(self) self.activity_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.activity_button, 0) self.activity_button.show() self.set_toolbar_box(self._toolbox) self._toolbox.show() self.toolbar = self._toolbox.toolbar view_toolbar = Gtk.Toolbar() self.view_toolbar_button = ToolbarButton( page=view_toolbar, label=_('View'), icon_name='toolbar-view') self.view_toolbar_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.view_toolbar_button, 1) view_toolbar.show() self.view_toolbar_button.show() button = ToolButton('view-fullscreen') button.set_tooltip(_('Fullscreen')) button.props.accelerator = '<Alt>Return' view_toolbar.insert(button, -1) button.show() button.connect('clicked', self._fullscreen_cb) self._zoom_in = ToolButton('zoom-in') self._zoom_in.set_tooltip(_('Increase size')) view_toolbar.insert(self._zoom_in, -1) self._zoom_in.show() self._zoom_in.connect('clicked', self._zoom_in_cb) self._zoom_out = ToolButton('zoom-out') self._zoom_out.set_tooltip(_('Decrease size')) view_toolbar.insert(self._zoom_out, -1) self._zoom_out.show() self._zoom_out.connect('clicked', self._zoom_out_cb) self._zoom_eq = ToolButton('zoom-original') self._zoom_eq.set_tooltip(_('Restore original size')) view_toolbar.insert(self._zoom_eq, -1) self._zoom_eq.show() self._zoom_eq.connect('clicked', self._zoom_eq_cb) self._set_zoom_buttons_sensitivity() edit_toolbar = Gtk.Toolbar() self.edit_toolbar_button = ToolbarButton( page=edit_toolbar, label=_('Edit'), icon_name='toolbar-edit') self.edit_toolbar_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.edit_toolbar_button, 1) edit_toolbar.show() self.edit_toolbar_button.show() self._copy_button = ToolButton('edit-copy') self._copy_button.set_tooltip(_('Copy')) self._copy_button.props.accelerator = '<Ctrl>C' edit_toolbar.insert(self._copy_button, -1) self._copy_button.show() self._copy_button.connect('clicked', self._copy_cb) self._copy_button.set_sensitive(False) self._paste_button = ToolButton('edit-paste') self._paste_button.set_tooltip(_('Paste')) self._paste_button.props.accelerator = '<Ctrl>V' edit_toolbar.insert(self._paste_button, -1) self._paste_button.show() self._paste_button.connect('clicked', self._paste_cb) self._paste_button.set_sensitive(False) separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) self._toolbox.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' self._toolbox.toolbar.insert(stop_button, -1) stop_button.show() def __realize_cb(self, window): self.window_xid = window.get_window().get_xid() def set_copy_widget(self, webkit=None, text_entry=None): # Each task is responsible for setting a widget for copy if webkit is not None: self._webkit = webkit else: self._webkit = None if text_entry is not None: self._copy_entry = text_entry else: self._copy_entry = None self._copy_button.set_sensitive(webkit is not None or text_entry is not None) def _copy_cb(self, button): if self._copy_entry is not None: self._copy_entry.copy_clipboard() elif self._webkit is not None: self._webkit.copy_clipboard() else: _logger.debug('No widget set for copy.') def set_paste_widget(self, text_entry=None): # Each task is responsible for setting a widget for paste if text_entry is not None: self._paste_entry = text_entry self._paste_button.set_sensitive(text_entry is not None) def _paste_cb(self, button): clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.clipboard_text = clipboard.wait_for_text() if self._paste_entry is not None: self._paste_entry.paste_clipboard() else: _logger.debug('No widget set for paste (%s).' % self.clipboard_text) def _fullscreen_cb(self, button): ''' Hide the Sugar toolbars. ''' self.fullscreen() def _set_zoom_buttons_sensitivity(self): if self.font_size < len(FONT_SIZES) - 1: self._zoom_in.set_sensitive(True) else: self._zoom_in.set_sensitive(False) if self.font_size > 0: self._zoom_out.set_sensitive(True) else: self._zoom_out.set_sensitive(False) if hasattr(self, '_scrolled_window'): self._set_scroll_policy() def _set_scroll_policy(self): if Gdk.Screen.width() < Gdk.Screen.height() or self.zoom_level > 0.667: self._scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) else: self._scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) def _zoom_eq_cb(self, button): self.font_size = 8 self.zoom_level = 0.667 self._set_zoom_buttons_sensitivity() self._task_master.reload_graphics() def _zoom_in_cb(self, button): if self.font_size < len(FONT_SIZES) - 1: self.font_size += 1 self.zoom_level *= 1.1 self._set_zoom_buttons_sensitivity() self._task_master.reload_graphics() def _zoom_out_cb(self, button): if self.font_size > 0: self.font_size -= 1 self.zoom_level /= 1.1 self._set_zoom_buttons_sensitivity() self._task_master.reload_graphics() def _remove_alert_cb(self, alert, response_id): self.remove_alert(alert) def _close_alert_cb(self, alert, response_id): self.remove_alert(alert) if response_id is Gtk.ResponseType.OK: self.close() def _reboot_alert_cb(self, alert, response_id): self.remove_alert(alert) if response_id is Gtk.ResponseType.OK: try: utils.reboot() except Exception as e: _logger.error('Cannot reboot: %s' % e) def _mount_added_cb(self, volume_monitor, device): _logger.error('mount added') if self.check_volume_data(): _logger.debug('launching') self._launcher() def _mount_removed_cb(self, volume_monitor, device): _logger.error('mount removed') if self.check_volume_data(): _logger.debug('launching') self._launcher()
def build_colors_toolbar(self, toolbox): colors_bar = Gtk.Toolbar() ######################################################################## # Point color item = Gtk.ToolItem() label = Gtk.Label() label.set_text('%s ' % _('Points')) item.add(label) colors_bar.insert(item, -1) # select color item = Gtk.ToolItem() fill_color = ColorToolButton() fill_color.connect('notify::color', self.color_point_change) item.add(fill_color) colors_bar.insert(item, -1) # Separator separator = Gtk.SeparatorToolItem() colors_bar.insert(separator, -1) separator.show() ######################################################################## # Back color item = Gtk.ToolItem() label = Gtk.Label() label.set_text('%s ' % _('Background')) item.add(label) colors_bar.insert(item, -1) # select color item = Gtk.ToolItem() _fill_color = ColorToolButton() c = Gdk.RGBA() c.red = 21588 c.green = 47546 c.blue = 18504 _fill_color.set_color(c) _fill_color.connect('notify::color', self.color_back_change) item.add(_fill_color) colors_bar.insert(item, -1) # Separator separator = Gtk.SeparatorToolItem() colors_bar.insert(separator, -1) separator.show() ######################################################################## # Line color item = Gtk.ToolItem() label = Gtk.Label() label.set_text('%s ' % _('Lines')) item.add(label) colors_bar.insert(item, -1) # select color item = Gtk.ToolItem() _fill_color = ColorToolButton() _fill_color.connect('notify::color', self.color_line_change) item.add(_fill_color) colors_bar.insert(item, -1) # Separator separator = Gtk.SeparatorToolItem() colors_bar.insert(separator, -1) separator.show() ######################################################################## # Owner color item = Gtk.ToolItem() label = Gtk.Label() label.set_text('%s ' % _('Owner')) item.add(label) colors_bar.insert(item, -1) # select color item = Gtk.ToolItem() _fill_color = ColorToolButton() c = Gdk.RGBA() c.red = 65535 _fill_color.set_color(c) _fill_color.connect('notify::color', self.color_owner_change) item.add(_fill_color) colors_bar.insert(item, -1) colors_bar.show_all() colors_button = ToolbarButton(label=_('Colors'), page=colors_bar, icon_name='toolbar-colors') toolbox.toolbar.insert(colors_button, -1) colors_button.show()
class FractionBounceActivity(activity.Activity): def __init__(self, handle): ''' Initiate activity. ''' super(FractionBounceActivity, self).__init__(handle) self.nick = profile.get_nick_name() if profile.get_color() is not None: self._colors = profile.get_color().to_string().split(',') else: self._colors = ['#A0FFA0', '#FF8080'] self.max_participants = 4 # sharing self._playing = True self._setup_toolbars() self._setup_dispatch_table() canvas = self._setup_canvas() # Read any custom fractions from the project metadata if 'custom' in self.metadata: custom = self.metadata['custom'] else: custom = None self._current_ball = 'soccerball' self._toolbar_was_expanded = False # Initialize the canvas self._bounce_window = Bounce(canvas, activity.get_bundle_path(), self) Gdk.Screen.get_default().connect('size-changed', self._configure_cb) # Restore any custom fractions if custom is not None: fractions = custom.split(',') for f in fractions: self._bounce_window.add_fraction(f) if self.shared_activity: # We're joining if not self.get_shared(): xocolors = XoColor(profile.get_color().to_string()) share_icon = Icon(icon_name='zoom-neighborhood', xo_color=xocolors) self._joined_alert = NotifyAlert() self._joined_alert.props.icon = share_icon self._joined_alert.props.title = _('Please wait') self._joined_alert.props.msg = _('Starting connection...') self._joined_alert.connect('response', self._alert_cancel_cb) self.add_alert(self._joined_alert) self._label.set_label(_('Wait for the sharer to start.')) # Wait for joined signal self.connect("joined", self._joined_cb) self._setup_sharing() def _configure_cb(self, event): if Gdk.Screen.width() < 1024: self._label.set_size_request(275, -1) self._label.set_label('') self._separator.set_expand(False) else: self._label.set_size_request(500, -1) self._separator.set_expand(True) self._bounce_window.configure_cb(event) if self._toolbar_expanded(): self._bounce_window.bar.bump_bars('up') self._bounce_window.ball.ball.move_relative( (0, -style.GRID_CELL_SIZE)) def _toolbar_expanded(self): if self._activity_button.is_expanded(): return True elif self._custom_toolbar_button.is_expanded(): return True return False def _update_graphics(self, widget): # We need to catch opening and closing of toolbars and ignore # switching between open toolbars. if self._toolbar_expanded(): if not self._toolbar_was_expanded: self._bounce_window.bar.bump_bars('up') self._bounce_window.ball.ball.move_relative( (0, -style.GRID_CELL_SIZE)) self._toolbar_was_expanded = True else: if self._toolbar_was_expanded: self._bounce_window.bar.bump_bars('down') self._bounce_window.ball.ball.move_relative( (0, style.GRID_CELL_SIZE)) self._toolbar_was_expanded = False def _setup_toolbars(self): custom_toolbar = Gtk.Toolbar() toolbox = ToolbarBox() self._toolbar = toolbox.toolbar self._activity_button = ActivityToolbarButton(self) self._activity_button.connect('clicked', self._update_graphics) self._toolbar.insert(self._activity_button, 0) self._activity_button.show() self._custom_toolbar_button = ToolbarButton( label=_('Custom'), page=custom_toolbar, icon_name='view-source') self._custom_toolbar_button.connect('clicked', self._update_graphics) custom_toolbar.show() self._toolbar.insert(self._custom_toolbar_button, -1) self._custom_toolbar_button.show() self._load_standard_buttons(self._toolbar) self._separator = Gtk.SeparatorToolItem() self._separator.props.draw = False self._separator.set_expand(True) self._toolbar.insert(self._separator, -1) self._separator.show() stop_button = StopButton(self) stop_button.props.accelerator = _('<Ctrl>Q') self._toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbox) toolbox.show() self._load_custom_buttons(custom_toolbar) def _load_standard_buttons(self, toolbar): fraction_button = RadioToolButton(group=None) fraction_button.set_icon_name('fraction') fraction_button.set_tooltip(_('fractions')) fraction_button.connect('clicked', self._fraction_cb) toolbar.insert(fraction_button, -1) fraction_button.show() sector_button = RadioToolButton(group=fraction_button) sector_button.set_icon_name('sector') sector_button.set_tooltip(_('sectors')) sector_button.connect('clicked', self._sector_cb) toolbar.insert(sector_button, -1) sector_button.show() percent_button = RadioToolButton(group=fraction_button) percent_button.set_icon_name('percent') percent_button.set_tooltip(_('percents')) percent_button.connect('clicked', self._percent_cb) toolbar.insert(percent_button, -1) percent_button.show() self._player = Gtk.Image() self._player.set_from_pixbuf(svg_str_to_pixbuf( generate_xo_svg(scale=0.8, colors=['#282828', '#282828']))) self._player.set_tooltip_text(self.nick) toolitem = Gtk.ToolItem() toolitem.add(self._player) self._player.show() toolbar.insert(toolitem, -1) toolitem.show() self._label = Gtk.Label(_("Click the ball to start.")) self._label.set_line_wrap(True) if Gdk.Screen.width() < 1024: self._label.set_size_request(275, -1) else: self._label.set_size_request(500, -1) self.toolitem = Gtk.ToolItem() self.toolitem.add(self._label) self._label.show() toolbar.insert(self.toolitem, -1) self.toolitem.show() def _load_custom_buttons(self, toolbar): self.numerator = Gtk.Entry() self.numerator.set_text('') self.numerator.set_tooltip_text(_('numerator')) self.numerator.set_width_chars(3) toolitem = Gtk.ToolItem() toolitem.add(self.numerator) self.numerator.show() toolbar.insert(toolitem, -1) toolitem.show() label = Gtk.Label(' / ') toolitem = Gtk.ToolItem() toolitem.add(label) label.show() toolbar.insert(toolitem, -1) toolitem.show() self.denominator = Gtk.Entry() self.denominator.set_text('') self.denominator.set_tooltip_text(_('denominator')) self.denominator.set_width_chars(3) toolitem = Gtk.ToolItem() toolitem.add(self.denominator) self.denominator.show() toolbar.insert(toolitem, -1) toolitem.show() button = ToolButton('list-add') button.set_tooltip(_('add new fraction')) button.props.sensitive = True button.props.accelerator = 'Return' button.connect('clicked', self._add_fraction_cb) toolbar.insert(button, -1) button.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(False) toolbar.insert(separator, -1) separator.show() button = ToolButton('soccerball') button.set_tooltip(_('choose a ball')) button.props.sensitive = True button.connect('clicked', self._button_palette_cb) toolbar.insert(button, -1) button.show() self._ball_palette = button.get_palette() button_grid = Gtk.Grid() row = 0 for ball in BALLDICT.keys(): if ball == 'custom': button = ToolButton('view-source') else: button = ToolButton(ball) button.connect('clicked', self._load_ball_cb, None, ball) eventbox = Gtk.EventBox() eventbox.connect('button_press_event', self._load_ball_cb, ball) label = Gtk.Label(BALLDICT[ball][0]) eventbox.add(label) label.show() button_grid.attach(button, 0, row, 1, 1) button.show() button_grid.attach(eventbox, 1, row, 1, 1) eventbox.show() row += 1 self._ball_palette.set_content(button_grid) button_grid.show() button = ToolButton('insert-picture') button.set_tooltip(_('choose a background')) button.props.sensitive = True button.connect('clicked', self._button_palette_cb) toolbar.insert(button, -1) button.show() self._bg_palette = button.get_palette() button_grid = Gtk.Grid() row = 0 for bg in BGDICT.keys(): if bg == 'custom': button = ToolButton('view-source') else: button = ToolButton(bg) button.connect('clicked', self._load_bg_cb, None, bg) eventbox = Gtk.EventBox() eventbox.connect('button_press_event', self._load_bg_cb, bg) label = Gtk.Label(BGDICT[bg][0]) eventbox.add(label) label.show() button_grid.attach(button, 0, row, 1, 1) button.show() button_grid.attach(eventbox, 1, row, 1, 1) eventbox.show() row += 1 self._bg_palette.set_content(button_grid) button_grid.show() def _button_palette_cb(self, button): palette = button.get_palette() if palette: if not palette.is_up(): palette.popup(immediate=True, state=palette.SECONDARY) else: palette.popdown(immediate=True) def can_close(self): # Let everyone know we are leaving... if hasattr(self, '_bounce_window') and \ self._bounce_window.we_are_sharing(): self._playing = False self.send_event('l', {"data": (json_dump([self.nick]))}) return True def _setup_canvas(self): canvas = Gtk.DrawingArea() canvas.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self.set_canvas(canvas) canvas.show() return canvas def _load_bg_cb(self, widget, event, bg): if bg == 'custom': chooser(self, 'Image', self._new_background_from_journal) else: self._bounce_window.set_background(BGDICT[bg][1]) def _load_ball_cb(self, widget, event, ball): if ball == 'custom': chooser(self, 'Image', self._new_ball_from_journal) else: self._bounce_window.ball.new_ball(os.path.join( activity.get_bundle_path(), 'images', ball + '.svg')) self._bounce_window.set_background(BGDICT[BALLDICT[ball][1]][1]) self._current_ball = ball def _reset_ball(self): ''' If we switch back from sector mode, we need to restore the ball ''' if self._bounce_window.mode != 'sectors': return if self._current_ball == 'custom': # TODO: Reload custom ball self._current_ball = 'soccerball' self._bounce_window.ball.new_ball(os.path.join( activity.get_bundle_path(), 'images', self._current_ball + '.svg')) def _new_ball_from_journal(self, dsobject): ''' Load an image from the Journal. ''' self._bounce_window.ball.new_ball_from_image( dsobject.file_path, os.path.join(activity.get_activity_root(), 'tmp', 'custom.png')) def _new_background_from_journal(self, dsobject): ''' Load an image from the Journal. ''' self._bounce_window.new_background_from_image(None, dsobject=dsobject) def _fraction_cb(self, arg=None): ''' Set fraction mode ''' self._reset_ball() self._bounce_window.mode = 'fractions' def _percent_cb(self, arg=None): ''' Set percent mode ''' self._reset_ball() self._bounce_window.mode = 'percents' def _sector_cb(self, arg=None): ''' Set sector mode ''' self._bounce_window.mode = 'sectors' def _add_fraction_cb(self, arg=None): ''' Read entries and add a fraction to the list ''' try: numerator = int(self.numerator.get_text().strip()) except ValueError: self.numerator.set_text('NAN') numerator = 0 try: denominator = int(self.denominator.get_text().strip()) except ValueError: self.denominator.set_text('NAN') denominator = 1 if denominator == 0: self.denominator.set_text('ZDE') if numerator > denominator: numerator = 0 if numerator > 0 and denominator > 1: fraction = '%d/%d' % (numerator, denominator) self._bounce_window.add_fraction(fraction) if 'custom' in self.metadata: # Save to Journal self.metadata['custom'] = '%s,%s' % ( self.metadata['custom'], fraction) else: self.metadata['custom'] = fraction self.alert( _('New fraction'), _('Your fraction, %s, has been added to the program' % (fraction))) def reset_label(self, label): ''' update the challenge label ''' self._label.set_label(label) def alert(self, title, text=None): alert = NotifyAlert(timeout=5) alert.props.title = title alert.props.msg = text self.add_alert(alert) alert.connect('response', self._alert_cancel_cb) alert.show() def _alert_cancel_cb(self, alert, response_id): self.remove_alert(alert) # Collaboration-related methods def _setup_sharing(self): ''' Setup the Presence Service. ''' self.pservice = presenceservice.get_instance() self.initiating = None # sharing (True) or joining (False) owner = self.pservice.get_owner() self.owner = owner self._bounce_window.buddies.append(self.nick) self._player_colors = [self._colors] self._player_pixbufs = [ svg_str_to_pixbuf(generate_xo_svg(scale=0.8, colors=self._colors)) ] self._share = '' self.connect('shared', self._shared_cb) self.connect('joined', self._joined_cb) def _shared_cb(self, activity): ''' Either set up initial share...''' self._new_tube_common(True) def _joined_cb(self, activity): ''' ...or join an exisiting share. ''' self._new_tube_common(False) def _new_tube_common(self, sharer): ''' Joining and sharing are mostly the same... ''' if self.shared_activity is None: _logger.debug('Error: Failed to share or join activity ... \ shared_activity is null in _shared_cb()') return self.initiating = sharer self.waiting_for_fraction = not sharer 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) if sharer: _logger.debug('This is my activity: making a tube...') id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( SERVICE, {}) self._label.set_label(_('Wait for others to join.')) else: _logger.debug('I am joining an activity: waiting for a tube...') self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb) # display your XO on the toolbar self._player.set_from_pixbuf(self._player_pixbufs[0]) def _list_tubes_reply_cb(self, tubes): ''' Reply to a list request. ''' for tube_info in tubes: self._new_tube_cb(*tube_info) def _list_tubes_error_cb(self, e): ''' Log errors. ''' _logger.debug('Error: ListTubes() failed: %s', e) def _new_tube_cb(self, id, initiator, type, service, params, state): ''' Create a new tube. ''' _logger.debug( 'Newtube: ID=%d initator=%d type=%d service=%s params=%r state=%d', id, initiator, type, service, params, state) if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE): if state == telepathy.TUBE_STATE_LOCAL_PENDING: self.tubes_chan[ \ telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id) self.collab = CollabWrapper(self) self.collab.message.connect(self.event_received_cb) self.collab.setup() # Let the sharer know a new joiner has arrived. if self.waiting_for_fraction: self.send_event('j', {"data": (json_dump([self.nick, self._colors]))}) def _setup_dispatch_table(self): self._processing_methods = { 'j': [self._new_joiner, 'new joiner'], 'b': [self._buddy_list, 'buddy list'], 'f': [self._receive_a_fraction, 'receive a fraction'], 't': [self._take_a_turn, 'take a turn'], 'l': [self._buddy_left, 'buddy left'] } def event_received_cb(self, event_message): ''' Data from a tube has arrived. ''' if len(event_message) == 0: return try: command, payload = event_message.split('|', 2) except ValueError: _logger.debug('Could not split event message %s', event_message) return _logger.debug('received an event %s|%s', command, payload) if self._playing: self._processing_methods[command][0](payload) def _buddy_left(self, payload): [nick] = json_load(payload) self._label.set_label(nick + ' ' + _('has left.')) if self.initiating: self._remove_player(nick) payload = json_dump([self._bounce_window.buddies, self._player_colors]) self.send_event('b', {"data": payload}) # Restart from sharer's turn self._bounce_window.its_my_turn() def _new_joiner(self, payload): ''' Someone has joined; sharer adds them to the buddy list. ''' [nick, colors] = json_load(payload) self._label.set_label(nick + ' ' + _('has joined.')) if self.initiating: self._append_player(nick, colors) payload = json_dump([self._bounce_window.buddies, self._player_colors]) self.send_event('b', {"data": payload}) if self._bounce_window.count == 0: # Haven't started yet... self._bounce_window.its_my_turn() def _remove_player(self, nick): if nick in self._bounce_window.buddies: i = self._bounce_window.buddies.index(nick) self._bounce_window.buddies.remove(nick) self._player_colors.remove(self._player_colors[i]) self._player_pixbufs.remove(self._player_pixbufs[i]) def _append_player(self, nick, colors): ''' Keep a list of players, their colors, and an XO pixbuf ''' if not nick in self._bounce_window.buddies: _logger.debug('appending %s to the buddy list', nick) self._bounce_window.buddies.append(nick) self._player_colors.append([str(colors[0]), str(colors[1])]) self._player_pixbufs.append(svg_str_to_pixbuf( generate_xo_svg(scale=0.8, colors=self._player_colors[-1]))) def _buddy_list(self, payload): '''Sharer sent the updated buddy list, so regenerate internal lists''' if not self.initiating: [buddies, colors] = json_load(payload) self._bounce_window.buddies = buddies[:] self._player_colors = colors[:] self._player_pixbufs = [] for colors in self._player_colors: self._player_pixbufs.append(svg_str_to_pixbuf( generate_xo_svg(scale=0.8, colors=[str(colors[0]), str(colors[1])]))) def send_a_fraction(self, fraction): ''' Send a fraction to other players. ''' payload = json_dump(fraction) self.send_event('f', {"data": payload}) def _receive_a_fraction(self, payload): ''' Receive a fraction from another player. ''' fraction = json_load(payload) self._bounce_window.play_a_fraction(fraction) def _take_a_turn(self, nick): ''' If it is your turn, take it, otherwise, wait. ''' if nick == self.nick: self._bounce_window.its_my_turn() else: self._bounce_window.its_their_turn(nick) def send_event(self, command, data): ''' Send event through the tube. ''' _logger.debug('sending event: %s', command) if hasattr(self, 'collab') and self.collab is not None: data["command"] = command self.collab.post(data) def set_player_on_toolbar(self, nick): ''' Display the XO icon of the player whose turn it is. ''' self._player.set_from_pixbuf(self._player_pixbufs[ self._bounce_window.buddies.index(nick)]) self._player.set_tooltip_text(nick)
class RulerActivity(activity.Activity): def __init__(self, handle): super(RulerActivity, self).__init__(handle) self.button_dict = {} self.callback_dict = {} self._ready = False font = 'helvetica 12' font_bold = 'helvetica bold 12' # # We need a canvas # self._canvas = MyCanvas() self.set_canvas(self._canvas) self._canvas.show() screen = Gdk.Screen() width = screen.width() height = screen.height() - GRID_CELL_SIZE dpi, self.known_dpi = calc_dpi() self._canvas.set_dpi(dpi) # Create instances of our graphics self._r = show_rulers.ScreenOfRulers(font, font_bold, width, height) self._gcm = show_grids.ScreenGrid_cm(font, font_bold, width, height) self._gmm = show_grids.ScreenGrid_mm(font, font_bold, width, height) self._a90 = show_angles.Angles90(font, font_bold, width, height) self._a360 = show_angles.Angles360(font, font_bold, width, height) self._c = show_checkers.ScreenOfCircles(font, font_bold, width, height) # start with a ruler self._current = self._r self._canvas.add_a_ruler(self._current) # other settings self._grids_mode = "cm" self._angles_mode = "90" # # We need some toolbars # self.max_participants = 1 toolbar_box = ToolbarBox() # Buttons added to the Activity toolbar activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() self.rulers = radio_factory('ruler', toolbar_box.toolbar, self._rulers_cb, tooltip=_('Ruler'), group=None) self.grids = radio_factory('grid-a', toolbar_box.toolbar, self._grids_cb, tooltip=_('Grid'), group=self.rulers) self.angles = radio_factory('angles-90', toolbar_box.toolbar, self._angles_cb, tooltip=_('Angles'), group=self.rulers) self.checker = radio_factory('checker', toolbar_box.toolbar, self._checker_cb, tooltip=_('Checker'), group=self.rulers) self.wrapper = Gtk.ToolItem() self.wrapper2 = Gtk.ToolItem() self.wrapper3 = Gtk.ToolItem() self.custom_unit_entry = Gtk.Entry() self.txt1 = Gtk.Label() self.txt1.set_text(_('1 custom unit equals ')) self.txt2 = Gtk.Label() # TRANS: mm is for Milli Meters self.txt2.set_text(_(' mm.')) self.wrapper.add(self.txt1) self.wrapper2.add(self.custom_unit_entry) self.wrapper3.add(self.txt2) self.wrapper.show_all() self.wrapper2.show_all() self.wrapper3.show_all() separator = Gtk.SeparatorToolItem() separator.props.draw = True separator.set_expand(False) separator.show() toolbar_box.toolbar.insert(separator, -1) custom_units_toolbox = ToolbarBox() custom_units_toolbox.toolbar.insert(self.wrapper, -1) custom_units_toolbox.toolbar.insert(self.wrapper2, -1) custom_units_toolbox.toolbar.insert(self.wrapper3, -1) custom_units_toolbox.show() self.custom_units_button = ToolbarButton(icon_name='view-source', page=custom_units_toolbox) toolbar_box.toolbar.insert(self.custom_units_button, -1) self.custom_unit_entry.connect('changed', self.custom_unit_change_cb) self.custom_units_button.show() if not self.known_dpi: separator = Gtk.SeparatorToolItem() separator.show() toolbar_box.toolbar.insert(separator, -1) dpi = self._canvas.get_dpi() self._dpi_spin_adj = Gtk.Adjustment(dpi, 72, 200, 2, 32, 0) self._dpi_spin = Gtk.SpinButton(self._dpi_spin_adj, 0, 0) self._dpi_spin_id = self._dpi_spin.connect('value-changed', self._dpi_spin_cb) self._dpi_spin.set_numeric(True) self._dpi_spin.show() self.tool_item_dpi = Gtk.ToolItem() self.tool_item_dpi.add(self._dpi_spin) toolbar_box.toolbar.insert(self.tool_item_dpi, -1) self.tool_item_dpi.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) separator.show() toolbar_box.toolbar.insert(separator, -1) # The ever-present Stop Button stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>Q' toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() self.show_all() # Restore state if previously saved self._ready = True if 'ruler' in self.metadata and \ self.metadata['ruler'] in self.button_dict: _logger.debug('restoring %s', self.metadata['ruler']) self.button_dict[self.metadata['ruler']].set_active(True) self.callback_dict[self.metadata['ruler']] else: self._rulers_cb() self.rulers.set_active(True) if 'custom_unit' in self.metadata: self.custom_unit_entry.set_text(self.metadata['custom_unit']) else: # set the default self.custom_unit_entry.set_text("25.4") # # Button callbacks # def _rulers_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(True) self._current = self._r self._canvas.add_a_ruler(self._current) _logger.debug('selecting ruler') self.metadata['ruler'] = 'ruler' return False def custom_unit_change_cb(self, widget): try: new = float(widget.get_text()) except ValueError: new = MMPERINCH new = abs(new) if new == 0: new = MMPERINCH if widget.get_text != '': widget.set_text(str(new)) self._canvas.add_a_ruler(self._r) self._r.custom_unit_in_mm = new self._r.draw_custom_ruler(self._r.custom_unit_in_mm) self.metadata['custom_unit'] = str(new) def _grids_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) if self._grids_mode == "cm": self._current = self._gcm if hasattr(self, 'grids'): self.grids.set_icon_name("grid-c") self._grids_mode = "mm" else: self._current = self._gmm if hasattr(self, 'grids'): self.grids.set_icon_name("grid-a") self._grids_mode = "cm" self._canvas.add_a_ruler(self._current) _logger.debug('selecting grids') self.metadata['ruler'] = 'grids' return False def _angles_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) if self._angles_mode == "90": self._current = self._a90 if hasattr(self, 'angles'): self.angles.set_icon_name("angles-360") self._angles_mode = "360" else: self._current = self._a360 if hasattr(self, 'angles'): self.angles.set_icon_name("angles-90") self._angles_mode = "90" self._canvas.add_a_ruler(self._current) _logger.debug('selecting angles') self.metadata['ruler'] = 'angles' return False def _checker_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) self._current = self._c self._canvas.add_a_ruler(self._current) _logger.debug('selecting checker') self.metadata['ruler'] = 'checker' return False def _dpi_spin_cb(self, button): self._canvas.set_dpi(self._dpi_spin.get_value_as_int()) self._canvas.add_a_ruler(self._current) return def write_file(self, file_path): ''' Write the dpi to the Journal ''' dpi = self._canvas.get_dpi() _logger.debug("Write dpi: " + str(dpi)) self.metadata['dpi'] = str(dpi)
def _setup_toolbars(self): """ Setup the toolbars. """ self.max_participants = 1 # No collaboration toolbox = ToolbarBox() # Activity toolbar activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() self.set_toolbar_box(toolbox) toolbox.show() self.toolbar = toolbox.toolbar name_game_button = radio_factory( 'name-game', toolbox.toolbar, self._level_cb, cb_arg=0, tooltip=_(LABELS[0]), group=None) group_game_button = radio_factory( 'group-game', toolbox.toolbar, self._level_cb, cb_arg=1, tooltip=_(LABELS[1]), group=name_game_button) calorie_game_button = radio_factory( 'calorie-game', toolbox.toolbar, self._level_cb, cb_arg=2, tooltip=_(LABELS[2]), group=name_game_button) pyramid_game_button = radio_factory( 'pyramid-game', toolbox.toolbar, self._level_cb, cb_arg=3, tooltip=_(LABELS[3]), group=name_game_button) balance_game_button = radio_factory( 'balance-game', toolbox.toolbar, self._level_cb, cb_arg=4, tooltip=_(LABELS[4]), group=name_game_button) separator_factory(toolbox.toolbar, False, True) self._label = label_factory(toolbox.toolbar, LABELS[0], width=150) separator_factory(toolbox.toolbar, True, False) tools_toolbar = Gtk.Toolbar() tools_toolbar_button = ToolbarButton( page=tools_toolbar, icon_name='view-source') tools_toolbar.show() toolbox.toolbar.insert(tools_toolbar_button, -1) tools_toolbar_button.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' toolbox.toolbar.insert(stop_button, -1) stop_button.show() self.name_entry = entry_factory( _('food name'), tools_toolbar, tooltip=_('Enter a name for the new food item.'), max=20) self.calories_entry = entry_factory( _('calories'), tools_toolbar, tooltip=_('Enter the calories in for the new food item.'), max=8) self.food_spinner = combo_factory( PYRAMID, tools_toolbar, self._food_pyramid_cb, default=PYRAMID[2], tooltip=_('Select level in the Food Pyramid.')) image_button = button_factory( 'image-tools', tools_toolbar, self._load_image_cb, tooltip=_('Load a picture of the new food item.')) separator_factory(tools_toolbar, True, False) create_button = button_factory( 'new-food', tools_toolbar, self._create_custom_food_cb, tooltip=_('Add a new food item.'))
class NapierActivity(activity.Activity): ''' Napier's bones: Napier's bones were invented by John Napier (1550-1617), a Scottish mathematician and scientist. They help you to do multiplication. ''' # TODO: Define your own bone. def __init__(self, handle): ''' Initialize the toolbars and the work surface ''' super(NapierActivity, self).__init__(handle) if os.path.exists(os.path.join('~', 'Activities', 'Napier.activity')): self._bone_path = os.path.join('~', 'Activities', 'Napier.activity', 'bones') else: self._bone_path = os.path.join('.', 'bones') self._bones = [] self._bone_images = [ None, None, None, None, None, None, None, None, None, None ] self._blank_image = None self._number = 0 self._number_of_bones = 0 self._setup_toolbars() self._setup_canvas() self._circles = [None, None] self._ovals = [] self._setup_workspace() self._restore() def _setup_canvas(self): ''' Create a canvas ''' self._canvas = Gtk.DrawingArea() self._canvas.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self.set_canvas(self._canvas) self._canvas.show() self.show_all() self._canvas.add_events(Gdk.EventMask.BUTTON_PRESS_MASK) self._canvas.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK) self._canvas.add_events(Gdk.EventMask.POINTER_MOTION_MASK) self._canvas.connect("draw", self.__draw_cb) self._canvas.connect("motion-notify-event", self._mouse_move_cb) # self._canvas.connect("key_press_event", self._key_press_cb) def _setup_workspace(self): ''' Add the bones. ''' self._width = Gdk.Screen.width() self._height = int(Gdk.Screen.height() - (GRID_CELL_SIZE * 2)) self._scale = self._height * 1.0 / BONE_HEIGHT self._bone_width = int(BONE_WIDTH * self._scale) self._bone_height = int(BONE_HEIGHT * self._scale) # Generate the sprites we'll need... self._sprites = Sprites(self._canvas) self._bone_index = Sprite( self._sprites, 0, 0, _load_svg_from_file( os.path.join(self._bone_path, 'bones-index.svg'), self._bone_width, self._bone_height)) self._max_bones = int(self._width / self._bone_width) - 1 self._blank_image = _load_svg_from_file( os.path.join(self._bone_path, 'blank-bone.svg'), self._bone_width, self._bone_height) for bones in range(self._max_bones): self._bones.append( Sprite(self._sprites, bones * self._bone_width, 0, self._blank_image)) circle_image = _load_svg_from_file( os.path.join(self._bone_path, 'circle.svg'), int(self._scale * 45), int(self._scale * 45)) self._circles[0] = Sprite(self._sprites, 0, -100, circle_image) self._circles[1] = Sprite(self._sprites, 0, -100, circle_image) oval_image = _load_svg_from_file( os.path.join(self._bone_path, 'oval.svg'), int(self._scale * 129), int(self._scale * 92)) for bones in range(self._max_bones - 1): self._ovals.append(Sprite(self._sprites, 0, -100, oval_image)) def _setup_toolbars(self): ''' Setup the toolbars. ''' self.max_participants = 1 # no sharing toolbox = ToolbarBox() # Activity toolbar activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() self._bones_toolbar = Gtk.Toolbar() self._bones_toolbar_button = ToolbarButton(label=_('Select a bone'), page=self._bones_toolbar, icon_name='bones') self._bones_toolbar_button.show() toolbox.toolbar.insert(self._bones_toolbar_button, -1) self.set_toolbar_box(toolbox) toolbox.show() self.toolbar = toolbox.toolbar self._new_calc_button = button_factory('erase', self.toolbar, self._new_calc_cb, tooltip=_('Clear')) self._status = label_factory(self.toolbar, '') button_factory('number-0', self._bones_toolbar, self._number_cb, cb_arg=0, tooltip=_('zero')) button_factory('number-1', self._bones_toolbar, self._number_cb, cb_arg=1, tooltip=_('one')) button_factory('number-2', self._bones_toolbar, self._number_cb, cb_arg=2, tooltip=_('two')) button_factory('number-3', self._bones_toolbar, self._number_cb, cb_arg=3, tooltip=_('three')) button_factory('number-4', self._bones_toolbar, self._number_cb, cb_arg=4, tooltip=_('four')) button_factory('number-5', self._bones_toolbar, self._number_cb, cb_arg=5, tooltip=_('five')) button_factory('number-6', self._bones_toolbar, self._number_cb, cb_arg=6, tooltip=_('six')) button_factory('number-7', self._bones_toolbar, self._number_cb, cb_arg=7, tooltip=_('seven')) button_factory('number-8', self._bones_toolbar, self._number_cb, cb_arg=8, tooltip=_('eight')) button_factory('number-9', self._bones_toolbar, self._number_cb, cb_arg=9, tooltip=_('nine')) separator_factory(toolbox.toolbar, True, False) stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' toolbox.toolbar.insert(stop_button, -1) stop_button.show() self._bones_toolbar_button.set_expanded(True) def _new_calc_cb(self, button=None): ''' Start a new calculation. ''' for bone in range(self._max_bones): self._bones[bone].set_shape(self._blank_image) self._bones[bone].inval() self._number_of_bones = 0 self._number = 0 self._status.set_label('') return def _number_cb(self, button=None, value=0): ''' Try to add a digit. ''' if self._number_of_bones == self._max_bones: return self._number_of_bones += 1 if self._bone_images[value] is None: self._bone_images[value] = _svg_str_to_pixbuf( _bone_factory(value, scale=self._scale)) self._bones[self._number_of_bones].set_shape(self._bone_images[value]) self._bones[self._number_of_bones].inval() self._number = self._number * 10 + value def _mouse_move_cb(self, win, event): ''' Determine which row we are in and then calculate the product. ''' win.grab_focus() x, y = list(map(int, event.get_coords())) factor = int(y / self._bone_width) # The row determines a factor if self._number == 0 or factor == 0: self._status.set_label('') self._circles[0].move((0, -100)) self._circles[1].move((0, -100)) for number in range(self._max_bones - 1): self._ovals[number].move((0, -100)) else: c0dx = int(4 * self._scale) c0dy = int(12 * self._scale) c1dx = int(44 * self._scale) c1dy = int(47 * self._scale) odx = int(42 * self._scale) ody = int(2 * self._scale) self._circles[0].move( (self._bone_width + c0dx, factor * self._bone_width + c0dy)) self._circles[1].move( (self._number_of_bones * self._bone_width + c1dx, factor * self._bone_width + c1dy)) for number in range(self._number_of_bones - 1): self._ovals[number].move( ((number + 1) * self._bone_width + odx, factor * self._bone_width + ody)) self._status.set_label('{}×{}={}'.format( factor + 1, self._number, (factor + 1) * self._number)) return True def _key_press_cb(self, win, event): ''' TODO: Add bones by typing numbers ''' return True def __draw_cb(self, canvas, cr): self._sprites.redraw_sprites(cr=cr) def do_expose_event(self, event): ''' Handle the expose-event by drawing ''' # Restrict Cairo to the exposed area cr = self._canvas.window.cairo_create() cr.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) cr.clip() # Refresh sprite list self._sprites.redraw_sprites(cr=cr) def _destroy_cb(self, win, event): Gtk.main_quit() def _restore(self): ''' Try to restore previous state. ''' if 'number' in self.metadata and self.metadata['number'] != '0': for digit in range(len(self.metadata['number'])): self._number_cb(button=None, value=int(self.metadata['number'][digit])) def write_file(self, file_path): ''' Write the status to the Journal. ''' if not hasattr(self, '_number'): return self.metadata['number'] = str(self._number)
class LogActivity(activity.Activity): def __init__(self, handle): activity.Activity.__init__(self, handle) self._autosearch_timer = None # Paths to watch: ~/.sugar/someuser/logs, /var/log paths = [] paths.append(env.get_profile_path('logs')) paths.append('/var/log') # Additional misc files. ext_files = [] ext_files.append(os.path.expanduser('~/.bash_history')) self.viewer = MultiLogView(paths, ext_files) self.set_canvas(self.viewer) self.viewer.grab_focus() self._build_toolbox() # Get Sugar's clipboard self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.show() self._configure_cb(None) Gdk.Screen.get_default().connect('size-changed', self._configure_cb) def _build_toolbox(self): toolbar_box = ToolbarBox() self.max_participants = 1 activity_button = ActivityToolbarButton(self) activity_toolbar = activity_button.page self._toolbar = toolbar_box.toolbar self._toolbar.insert(activity_button, -1) self._secondary_toolbar = Gtk.Toolbar() self._secondary_toolbar_button = ToolbarButton( page=self._secondary_toolbar, icon_name='system-search') self._secondary_toolbar.show() self._toolbar.insert(self._secondary_toolbar_button, -1) self._secondary_toolbar_button.hide() show_list = ToggleToolButton('view-list') show_list.set_active(True) show_list.set_tooltip(_('Show list of files')) show_list.connect('toggled', self._list_toggled_cb) self._toolbar.insert(show_list, -1) show_list.show() copy = CopyButton() copy.connect('clicked', self.__copy_clicked_cb) self._toolbar.insert(copy, -1) wrap_btn = ToggleToolButton("format-wrap") wrap_btn.set_tooltip(_('Word Wrap')) wrap_btn.connect('clicked', self._wrap_cb) self._toolbar.insert(wrap_btn, -1) self.search_entry = iconentry.IconEntry() self.search_entry.set_size_request(Gdk.Screen.width() / 3, -1) self.search_entry.set_icon_from_name( iconentry.ICON_ENTRY_PRIMARY, 'entry-search') self.search_entry.add_clear_button() self.search_entry.connect('activate', self._search_entry_activate_cb) self.search_entry.connect('changed', self._search_entry_changed_cb) self._search_item = Gtk.ToolItem() self._search_item.add(self.search_entry) self._toolbar.insert(self._search_item, -1) self._search_prev = ToolButton('go-previous-paired') self._search_prev.set_tooltip(_('Previous')) self._search_prev.connect('clicked', self._search_prev_cb) self._toolbar.insert(self._search_prev, -1) self._search_next = ToolButton('go-next-paired') self._search_next.set_tooltip(_('Next')) self._search_next.connect('clicked', self._search_next_cb) self._toolbar.insert(self._search_next, -1) self._update_search_buttons() self.collector_palette = CollectorPalette(self) collector_btn = ToolButton('log-export') collector_btn.set_palette(self.collector_palette) collector_btn.connect('clicked', self._logviewer_cb) collector_btn.show() activity_toolbar.insert(collector_btn, -1) self._delete_btn = ToolButton('list-remove') self._delete_btn = ToolButton('list-remove', accelerator='<ctrl>d') self._delete_btn.set_tooltip(_('Delete Log File')) self._delete_btn.connect('clicked', self._delete_log_cb) self._toolbar.insert(self._delete_btn, -1) self._separator = Gtk.SeparatorToolItem() self._separator.set_expand(True) self._separator.set_draw(False) self._toolbar.insert(self._separator, -1) self._stop_btn = StopButton(self) self._toolbar.insert(self._stop_btn, -1) toolbar_box.show_all() self.set_toolbar_box(toolbar_box) def _configure_cb(self, event=None): for control in [self._stop_btn, self._separator, self._delete_btn]: if control in self._toolbar: self._toolbar.remove(control) if Gdk.Screen.width() < Gdk.Screen.height(): self._secondary_toolbar_button.show() self._secondary_toolbar_button.set_expanded(True) self._remove_controls(self._toolbar) self._add_controls(self._secondary_toolbar) else: self._secondary_toolbar_button.set_expanded(False) self._secondary_toolbar_button.hide() self._remove_controls(self._secondary_toolbar) self._add_controls(self._toolbar) for control in [self._delete_btn, self._separator, self._stop_btn]: if control not in self._toolbar: self._toolbar.insert(control, -1) def _remove_controls(self, toolbar): for control in [self._search_item, self._search_prev, self._search_next]: if control in toolbar: toolbar.remove(control) def _add_controls(self, toolbar): for control in [self._search_item, self._search_prev, self._search_next]: if control not in toolbar: toolbar.insert(control, -1) control.show() def _list_toggled_cb(self, widget): if widget.get_active(): self.viewer.list_scroll.show() else: self.viewer.list_scroll.hide() def __copy_clicked_cb(self, button): if self.viewer.active_log: self.viewer.active_log.copy_clipboard(self.clipboard) def _wrap_cb(self, button): if button.get_active(): self.viewer._textview.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) else: self.viewer._textview.set_wrap_mode(Gtk.WrapMode.NONE) def _search_entry_activate_cb(self, entry): if self._autosearch_timer: GLib.source_remove(self._autosearch_timer) self._autosearch_timer = None self.viewer.set_search_text(entry.props.text) self._update_search_buttons() def _search_entry_changed_cb(self, entry): if self._autosearch_timer: GLib.source_remove(self._autosearch_timer) self._autosearch_timer = GLib.timeout_add(_AUTOSEARCH_TIMEOUT, self.__autosearch_cb) def __autosearch_cb(self): self._autosearch_timer = None self.search_entry.activate() return False def _search_prev_cb(self, button): self.viewer.search_next('backward') self._update_search_buttons() def _search_next_cb(self, button): self.viewer.search_next('forward') self._update_search_buttons() def _update_search_buttons(self,): if len(self.viewer.search_text) == 0: self._search_prev.props.sensitive = False self._search_next.props.sensitive = False else: prev_result = self.viewer.get_next_result('backward') next_result = self.viewer.get_next_result('forward') self._search_prev.props.sensitive = prev_result is not None self._search_next.props.sensitive = next_result is not None def _delete_log_cb(self, widget): if self.viewer.active_log: logfile = self.viewer.active_log.logfile try: os.remove(logfile) except OSError as err: notify = NotifyAlert() notify.props.title = _('Error') notify.props.msg = _('%(error)s when deleting %(file)s') % \ {'error': err.strerror, 'file': logfile} notify.connect('response', _notify_response_cb, self) self.add_alert(notify) def _logviewer_cb(self, widget): self.collector_palette.popup(True)
def __init__(self, handle): activity.Activity.__init__(self, handle) self.player = None self._alert = None self._playlist_jobject = None self.set_title(_('Jukebox Activity')) self.max_participants = 1 self._toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) activity_toolbar = activity_button.page self._toolbar_box.toolbar.insert(activity_button, 0) self.title_entry = activity_toolbar.title self._view_toolbar = ViewToolbar() self._view_toolbar.connect('go-fullscreen', self.__go_fullscreen_cb) self._view_toolbar.connect('toggle-playlist', self.__toggle_playlist_cb) view_toolbar_button = ToolbarButton( page=self._view_toolbar, icon_name='toolbar-view') self._view_toolbar.show() self._toolbar_box.toolbar.insert(view_toolbar_button, -1) view_toolbar_button.show() self._control_toolbar = Gtk.Toolbar() self._control_toolbar_button = ToolbarButton( page=self._control_toolbar, icon_name='media-playback-start') self._control_toolbar.show() self._toolbar_box.toolbar.insert(self._control_toolbar_button, -1) self._control_toolbar_button.hide() self.set_toolbar_box(self._toolbar_box) self._toolbar_box.show_all() self.connect('key_press_event', self.__key_press_event_cb) self.connect('playlist-finished', self.__playlist_finished_cb) # We want to be notified when the activity gets the focus or # loses it. When it is not active, we don't need to keep # reproducing the video self.connect('notify::active', self.__notify_active_cb) self._video_canvas = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self._playlist_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.playlist_widget = PlayList() self.playlist_widget.connect('play-index', self.__play_index_cb) self.playlist_widget.connect('missing-tracks', self.__missing_tracks_cb) self.playlist_widget.set_size_request( Gdk.Screen.width() * PLAYLIST_WIDTH_PROP, 0) self.playlist_widget.show() self._playlist_box.pack_start(self.playlist_widget, expand=True, fill=True, padding=0) self._playlist_toolbar = Gtk.Toolbar() move_up = ToolButton("go-up") move_up.set_tooltip(_("Move up")) move_up.connect("clicked", self._move_up_cb) self._playlist_toolbar.insert(move_up, 0) move_down = ToolButton("go-down") move_down.set_tooltip(_("Move down")) move_down.connect("clicked", self._move_down_cb) self._playlist_toolbar.insert(move_down, 1) self._playlist_box.pack_end(self._playlist_toolbar, False, False, 0) self._video_canvas.pack_start(self._playlist_box, False, False, 0) # Create the player just once logging.debug('Instantiating GstPlayer') self.player = GstPlayer() self.player.connect('eos', self.__player_eos_cb) self.player.connect('error', self.__player_error_cb) self.player.connect('play', self.__player_play_cb) self.control = Controls(self, self._toolbar_box.toolbar, self._control_toolbar) self._separator = Gtk.SeparatorToolItem() self._separator.props.draw = False self._separator.set_expand(True) self._separator.show() self._toolbar_box.toolbar.insert(self._separator, -1) self._stop = StopButton(self) self._toolbar_box.toolbar.insert(self._stop, -1) self._empty_widget = Gtk.Label(label="") self._empty_widget.show() self.videowidget = VideoWidget() self.set_canvas(self._video_canvas) self._init_view_area() self.show_all() # need hide the playlist by default self._playlist_box.hide() self._configure_cb() self.player.init_view_area(self.videowidget) self._volume_monitor = Gio.VolumeMonitor.get() self._volume_monitor.connect('mount-added', self.__mount_added_cb) self._volume_monitor.connect('mount-removed', self.__mount_removed_cb) if handle.object_id is None: # The activity was launched from scratch. We need to show # the Empty Widget self.playlist_widget.hide() emptypanel.show(self, 'activity-jukebox', _('No media'), _('Choose media files'), self.control.show_picker_cb) self.control.check_if_next_prev() Gdk.Screen.get_default().connect('size-changed', self._configure_cb)
class JukeboxActivity(activity.Activity): __gsignals__ = { 'playlist-finished': (GObject.SignalFlags.RUN_FIRST, None, []), } def __init__(self, handle): activity.Activity.__init__(self, handle) self.player = None self._alert = None self._playlist_jobject = None self.set_title(_('Jukebox Activity')) self.max_participants = 1 self._toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) activity_toolbar = activity_button.page self._toolbar_box.toolbar.insert(activity_button, 0) self.title_entry = activity_toolbar.title self._view_toolbar = ViewToolbar() self._view_toolbar.connect('go-fullscreen', self.__go_fullscreen_cb) self._view_toolbar.connect('toggle-playlist', self.__toggle_playlist_cb) view_toolbar_button = ToolbarButton( page=self._view_toolbar, icon_name='toolbar-view') self._view_toolbar.show() self._toolbar_box.toolbar.insert(view_toolbar_button, -1) view_toolbar_button.show() self._control_toolbar = Gtk.Toolbar() self._control_toolbar_button = ToolbarButton( page=self._control_toolbar, icon_name='media-playback-start') self._control_toolbar.show() self._toolbar_box.toolbar.insert(self._control_toolbar_button, -1) self._control_toolbar_button.hide() self.set_toolbar_box(self._toolbar_box) self._toolbar_box.show_all() self.connect('key_press_event', self.__key_press_event_cb) self.connect('playlist-finished', self.__playlist_finished_cb) # We want to be notified when the activity gets the focus or # loses it. When it is not active, we don't need to keep # reproducing the video self.connect('notify::active', self.__notify_active_cb) self._video_canvas = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self._playlist_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.playlist_widget = PlayList() self.playlist_widget.connect('play-index', self.__play_index_cb) self.playlist_widget.connect('missing-tracks', self.__missing_tracks_cb) self.playlist_widget.set_size_request( Gdk.Screen.width() * PLAYLIST_WIDTH_PROP, 0) self.playlist_widget.show() self._playlist_box.pack_start(self.playlist_widget, expand=True, fill=True, padding=0) self._playlist_toolbar = Gtk.Toolbar() move_up = ToolButton("go-up") move_up.set_tooltip(_("Move up")) move_up.connect("clicked", self._move_up_cb) self._playlist_toolbar.insert(move_up, 0) move_down = ToolButton("go-down") move_down.set_tooltip(_("Move down")) move_down.connect("clicked", self._move_down_cb) self._playlist_toolbar.insert(move_down, 1) self._playlist_box.pack_end(self._playlist_toolbar, False, False, 0) self._video_canvas.pack_start(self._playlist_box, False, False, 0) # Create the player just once logging.debug('Instantiating GstPlayer') self.player = GstPlayer() self.player.connect('eos', self.__player_eos_cb) self.player.connect('error', self.__player_error_cb) self.player.connect('play', self.__player_play_cb) self.control = Controls(self, self._toolbar_box.toolbar, self._control_toolbar) self._separator = Gtk.SeparatorToolItem() self._separator.props.draw = False self._separator.set_expand(True) self._separator.show() self._toolbar_box.toolbar.insert(self._separator, -1) self._stop = StopButton(self) self._toolbar_box.toolbar.insert(self._stop, -1) self._empty_widget = Gtk.Label(label="") self._empty_widget.show() self.videowidget = VideoWidget() self.set_canvas(self._video_canvas) self._init_view_area() self.show_all() # need hide the playlist by default self._playlist_box.hide() self._configure_cb() self.player.init_view_area(self.videowidget) self._volume_monitor = Gio.VolumeMonitor.get() self._volume_monitor.connect('mount-added', self.__mount_added_cb) self._volume_monitor.connect('mount-removed', self.__mount_removed_cb) if handle.object_id is None: # The activity was launched from scratch. We need to show # the Empty Widget self.playlist_widget.hide() emptypanel.show(self, 'activity-jukebox', _('No media'), _('Choose media files'), self.control.show_picker_cb) self.control.check_if_next_prev() Gdk.Screen.get_default().connect('size-changed', self._configure_cb) def _move_up_cb(self, button): self.playlist_widget.move_up() def _move_down_cb(self, button): self.playlist_widget.move_down() def _configure_cb(self, event=None): self._toolbar_box.toolbar.remove(self._stop) self._toolbar_box.toolbar.remove(self._separator) if Gdk.Screen.width() < Gdk.Screen.height(): self._control_toolbar_button.show() self._control_toolbar_button.set_expanded(True) self.control.update_layout(landscape=False) self._toolbar_box.toolbar.insert(self._separator, -1) else: self._control_toolbar_button.set_expanded(False) self._control_toolbar_button.hide() self.control.update_layout(landscape=True) self._toolbar_box.toolbar.insert(self._stop, -1) def __notify_active_cb(self, widget, event): """Sugar notify us that the activity is becoming active or inactive. When we are inactive, we stop the player if it is reproducing a video. """ logging.debug('JukeboxActivity notify::active signal received') if self.player.player.props.current_uri is not None and \ self.player.playing_video(): if not self.player.is_playing() and self.props.active: self.player.play() if self.player.is_playing() and not self.props.active: self.player.pause() def _init_view_area(self): """ Use a notebook with two pages, one empty an another with the videowidget """ self.view_area = Gtk.Notebook() self.view_area.set_show_tabs(False) self.view_area.append_page(self._empty_widget, None) self.view_area.append_page(self.videowidget, None) self._video_canvas.pack_end(self.view_area, expand=True, fill=True, padding=0) def _switch_canvas(self, show_video): """Show or hide the video visualization in the canvas. When hidden, the canvas is filled with an empty widget to ensure redrawing. """ if show_video: self.view_area.set_current_page(1) else: self.view_area.set_current_page(0) self._video_canvas.queue_draw() def __key_press_event_cb(self, widget, event): keyname = Gdk.keyval_name(event.keyval) logging.info("Keyname Press: %s, time: %s", keyname, event.time) if self.title_entry.has_focus(): return False if keyname == "space": self.control._button_clicked_cb(None) return True def __playlist_finished_cb(self, widget): self._switch_canvas(show_video=False) self._view_toolbar._show_playlist.set_active(True) self.unfullscreen() # Select the first stream to be played when Play button will # be pressed self.playlist_widget.set_current_playing(0) self.control.check_if_next_prev() def songchange(self, direction): current_playing = self.playlist_widget.get_current_playing() if direction == 'prev' and current_playing > 0: self.play_index(current_playing - 1) elif direction == 'next' and \ current_playing < len(self.playlist_widget._items) - 1: self.play_index(current_playing + 1) else: self.emit('playlist-finished') def play_index(self, index): # README: this line is no more necessary because of the # .playing_video() method # self._switch_canvas(show_video=True) self.playlist_widget.set_current_playing(index) path = self.playlist_widget._items[index]['path'] if self.playlist_widget.check_available_media(path): if self.playlist_widget.is_from_journal(path): path = self.playlist_widget.get_path_from_journal(path) self.control.check_if_next_prev() self.player.set_uri(path) self.player.play() else: self.songchange('next') def __play_index_cb(self, widget, index, path): # README: this line is no more necessary because of the # .playing_video() method # self._switch_canvas(show_video=True) self.playlist_widget.set_current_playing(index) if self.playlist_widget.is_from_journal(path): path = self.playlist_widget.get_path_from_journal(path) self.control.check_if_next_prev() self.player.set_uri(path) self.player.play() def __player_eos_cb(self, widget): self.songchange('next') def _show_error_alert(self, title, msg=None): self._alert = ErrorAlert() self._alert.props.title = title if msg is not None: self._alert.props.msg = msg self.add_alert(self._alert) self._alert.connect('response', self._alert_cancel_cb) self._alert.show() def __mount_added_cb(self, volume_monitor, device): logging.debug('Mountpoint added. Checking...') self.remove_alert(self._alert) self.playlist_widget.update() def __mount_removed_cb(self, volume_monitor, device): logging.debug('Mountpoint removed. Checking...') self.remove_alert(self._alert) self.playlist_widget.update() def __missing_tracks_cb(self, widget, tracks): self._show_missing_tracks_alert(tracks) def _show_missing_tracks_alert(self, tracks): self._alert = Alert() title = _('%s tracks not found.') % len(tracks) self._alert.props.title = title icon = Icon(icon_name='dialog-cancel') self._alert.add_button(Gtk.ResponseType.CANCEL, _('Dismiss'), icon) icon.show() icon = Icon(icon_name='dialog-ok') self._alert.add_button(Gtk.ResponseType.APPLY, _('Details'), icon) icon.show() self.add_alert(self._alert) self._alert.connect( 'response', self.__missing_tracks_alert_response_cb, tracks) def __missing_tracks_alert_response_cb(self, alert, response_id, tracks): if response_id == Gtk.ResponseType.APPLY: vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) vbox.props.valign = Gtk.Align.CENTER label = Gtk.Label(label='') label.set_markup(_('<b>Missing tracks</b>')) vbox.pack_start(label, False, False, 15) for track in tracks: label = Gtk.Label(label=track['path']) vbox.add(label) _missing_tracks = Gtk.ScrolledWindow() _missing_tracks.add_with_viewport(vbox) _missing_tracks.show_all() self.view_area.append_page(_missing_tracks, None) self.view_area.set_current_page(2) self.remove_alert(alert) def _alert_cancel_cb(self, alert, response_id): self.remove_alert(alert) def __player_play_cb(self, widget): # Do not show the visualization widget if we are playing just # an audio stream def callback(): if self.player.playing_video(): self._switch_canvas(True) else: self._switch_canvas(False) return False # HACK: we need a timeout here because gstreamer returns # n-video = 0 if we call it immediately GObject.timeout_add(1000, callback) def __player_error_cb(self, widget, message, detail): self.player.stop() self.control.set_disabled() logging.error('ERROR MESSAGE: %s', message) logging.error('ERROR DETAIL: %s', detail) file_path = self.playlist_widget._items[ self.playlist_widget.get_current_playing()]['path'] mimetype = mime.get_for_file(file_path) title = _('Error') msg = _('This "%s" file can\'t be played') % mimetype self._switch_canvas(False) self._show_error_alert(title, msg) def can_close(self): # We need to put the Gst.State in NULL so gstreamer can # cleanup the pipeline self.player.stop() return True def read_file(self, file_path): """Load a file from the datastore on activity start.""" logging.debug('JukeBoxAtivity.read_file: %s', file_path) title = self.metadata['title'] self.playlist_widget.load_file(file_path, title) self._view_toolbar._show_playlist.set_active(True) def write_file(self, file_path): def write_playlist_to_file(file_path): """Open the file at file_path and write the playlist. It is saved in audio/x-mpegurl format. """ list_file = open(file_path, 'w') for uri in self.playlist_widget._items: list_file.write('#EXTINF:%s\n' % uri['title']) list_file.write('%s\n' % uri['path']) list_file.close() if not self.metadata['mime_type']: self.metadata['mime_type'] = 'audio/x-mpegurl' if self.metadata['mime_type'] == 'audio/x-mpegurl': write_playlist_to_file(file_path) else: if self._playlist_jobject is None: self._playlist_jobject = \ self.playlist_widget.create_playlist_jobject() # Add the playlist to the playlist jobject description. # This is only done if the activity was not started from a # playlist or from scratch: description = '' for uri in self.playlist_widget._items: description += '%s\n' % uri['title'] self._playlist_jobject.metadata['description'] = description write_playlist_to_file(self._playlist_jobject.file_path) datastore.write(self._playlist_jobject) def __go_fullscreen_cb(self, toolbar): self.fullscreen() def __toggle_playlist_cb(self, toolbar): if self._view_toolbar._show_playlist.get_active(): self._playlist_box.show_all() else: self._playlist_box.hide() self._video_canvas.queue_draw()
class ReflectActivity(activity.Activity): ''' An activity for reflecting on one's work ''' def __init__(self, handle): ''' Initialize the toolbar ''' try: super(ReflectActivity, self).__init__(handle) except dbus.exceptions.DBusException as e: _logger.error(str(e)) logging.error('setting reflection data to []') self.reflection_data = [] self.connect('realize', self.__realize_cb) self.font_size = 8 self.max_participants = 4 self._setup_toolbars() color = profile.get_color() color_stroke = color.get_stroke_color() color_fill = color.get_fill_color() lighter = utils.lighter_color([color_stroke, color_fill]) darker = 1 - lighter if lighter == 0: self.bg_color = style.Color(color_stroke) self.fg_color = style.Color(color_fill) else: self.bg_color = style.Color(color_fill) self.fg_color = style.Color(color_stroke) self.modify_bg(Gtk.StateType.NORMAL, self.bg_color.get_gdk_color()) self.bundle_path = activity.get_bundle_path() self.tmp_path = os.path.join(activity.get_activity_root(), 'instance') self.sharing = False self._copy_entry = None self._paste_entry = None self._webkit = None self._clipboard_text = '' self._fixed = None self.initiating = True if self.shared_activity: # We're joining if not self.get_shared(): self.initiating = False self.busy_cursor() share_icon = Icon(icon_name='zoom-neighborhood') self._joined_alert = Alert() self._joined_alert.props.icon = share_icon self._joined_alert.props.title = _('Please wait') self._joined_alert.props.msg = _('Starting connection...') self.add_alert(self._joined_alert) # Wait for joined signal self.connect("joined", self._joined_cb) self._open_reflect_windows() self._setup_presence_service() # Joiners wait to receive data from sharer # Otherwise, load reflections from local store if not self.shared_activity: self.busy_cursor() GObject.idle_add(self._load_reflections) def read_file(self, file_path): fd = open(file_path, 'r') data = fd.read() fd.close() self.reflection_data = json.loads(data) def write_file(self, file_path): data = json.dumps(self.reflection_data) fd = open(file_path, 'w') fd.write(data) fd.close() self.metadata['font_size'] = str(self.font_size) def _load_reflections(self): self._find_starred() self._reflect_window.load(self.reflection_data) self.reset_cursor() def _found_obj_id(self, obj_id): for item in self.reflection_data: if 'obj_id' in item and item['obj_id'] == obj_id: return True return False def reload_data(self, data): ''' Reload data after sorting or searching ''' self._reflection_data = data[:] self._reflect_window.reload(self._reflection_data) self.reset_scrolled_window_adjustments() def _find_starred(self): ''' Find all the _stars in the Journal. ''' self.dsobjects, self._nobjects = datastore.find({'keep': '1'}) for dsobj in self.dsobjects: if self._found_obj_id(dsobj.object_id): continue # Already have this object -- TODO: update it self._add_new_from_journal(dsobj) def _add_new_from_journal(self, dsobj): self.reflection_data.append({ 'title': _('Untitled'), 'obj_id': dsobj.object_id }) if hasattr(dsobj, 'metadata'): if 'creation_time' in dsobj.metadata: self.reflection_data[-1]['creation_time'] = \ dsobj.metadata['creation_time'] else: self.reflection_data[-1]['creation_time'] = \ int(time.time()) if 'timestamp' in dsobj.metadata: self.reflection_data[-1]['modification_time'] = \ dsobj.metadata['timestamp'] else: self.reflection_data[-1]['modification_time'] = \ self.reflection_data[-1]['creation_time'] if 'activity' in dsobj.metadata: self.reflection_data[-1]['activities'] = \ [utils.bundle_id_to_icon(dsobj.metadata['activity'])] if 'title' in dsobj.metadata: self.reflection_data[-1]['title'] = \ dsobj.metadata['title'] if 'description' in dsobj.metadata: self.reflection_data[-1]['content'] = \ [{'text': dsobj.metadata['description']}] else: self.reflection_data[-1]['content'] = [] if 'tags' in dsobj.metadata: self.reflection_data[-1]['tags'] = [] tags = dsobj.metadata['tags'].split() for tag in tags: if tag[0] != '#': self.reflection_data[-1]['tags'].append('#' + tag) else: self.reflection_data[-1]['tags'].append(tag) if 'comments' in dsobj.metadata: try: comments = json.loads(dsobj.metadata['comments']) except BaseException: comments = [] self.reflection_data[-1]['comments'] = [] for comment in comments: try: data = { 'nick': comment['from'], 'comment': comment['message'] } if 'icon-color' in comment: colors = comment['icon-color'].split(',') darker = 1 - utils.lighter_color(colors) data['color'] = colors[darker] else: data['color'] = '#000000' self.reflection_data[-1]['comments'].append(data) except BaseException: _logger.debug('could not parse comment %s' % comment) if 'mime_type' in dsobj.metadata and \ dsobj.metadata['mime_type'][0:5] == 'image': new_path = os.path.join(self.tmp_path, dsobj.object_id) try: shutil.copy(dsobj.file_path, new_path) except Exception as e: logging.error("Couldn't copy %s to %s: %s" % (dsobj.file_path, new_path, e)) self.reflection_data[-1]['content'].append({'image': new_path}) elif 'preview' in dsobj.metadata: pixbuf = utils.get_pixbuf_from_journal(dsobj, 300, 225) if pixbuf is not None: path = os.path.join(self.tmp_path, dsobj.object_id + '.png') utils.save_pixbuf_to_file(pixbuf, path) self.reflection_data[-1]['content'].append({'image': path}) self.reflection_data[-1]['stars'] = 0 def delete_item(self, obj_id): for i, obj in enumerate(self.reflection_data): if obj['obj_id'] == obj_id: self.reflection_data.remove(self.reflection_data[i]) return def busy_cursor(self): self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) def reset_cursor(self): self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.LEFT_PTR)) def _open_reflect_windows(self): # Most things need only be done once if self._fixed is None: self._fixed = Gtk.Fixed() self._fixed.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) # Offsets from the bottom of the screen dy1 = 2 * style.GRID_CELL_SIZE dy2 = 1 * style.GRID_CELL_SIZE self._button_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._button_area.set_size_request(Gdk.Screen.width(), style.GRID_CELL_SIZE) self._fixed.put(self._button_area, 0, 0) self._button_area.show() self._scrolled_window = Gtk.ScrolledWindow() self._scrolled_window.set_size_request(Gdk.Screen.width(), Gdk.Screen.height() - dy1) self._set_scroll_policy() self._graphics_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._scrolled_window.add_with_viewport(self._graphics_area) self._graphics_area.show() self._fixed.put(self._scrolled_window, 0, dy2) self._scrolled_window.show() self._overlay_window = Gtk.ScrolledWindow() self._overlay_window.set_size_request(style.GRID_CELL_SIZE * 10, style.GRID_CELL_SIZE * 6) self._overlay_window.modify_bg(Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color()) self._overlay_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self._overlay_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._overlay_window.add_with_viewport(self._overlay_area) self._overlay_area.show() x = int((Gdk.Screen.width() - style.GRID_CELL_SIZE * 10) / 2) self._fixed.put(self._overlay_window, 0, Gdk.Screen.height()) self._overlay_window.show() self._old_overlay_widget = None self._reflect_window = ReflectWindow(self) self._reflect_window.show() Gdk.Screen.get_default().connect('size-changed', self._configure_cb) self._toolbox.connect('hide', self._resize_hide_cb) self._toolbox.connect('show', self._resize_show_cb) self._reflect_window.set_events(Gdk.EventMask.KEY_PRESS_MASK) self._reflect_window.connect('key_press_event', self._reflect_window.keypress_cb) self._reflect_window.set_can_focus(True) self._reflect_window.grab_focus() self.set_canvas(self._fixed) self._fixed.show() def reset_scrolled_window_adjustments(self): adj = self._scrolled_window.get_hadjustment() if adj is not None: adj.set_value(0) adj = self._scrolled_window.get_vadjustment() if adj is not None: adj.set_value(0) def load_graphics_area(self, widget): self._graphics_area.add(widget) def load_button_area(self, widget): self._button_area.add(widget) def load_overlay_area(self, widget): if self._old_overlay_widget is not None: self._overlay_area.remove(self._old_overlay_widget) self._overlay_area.add(widget) self._old_overlay_widget = widget def show_overlay_area(self): x = int((Gdk.Screen.width() - style.GRID_CELL_SIZE * 10) / 2) self._fixed.move(self._overlay_window, x, style.GRID_CELL_SIZE) def hide_overlay_area(self): self._fixed.move(self._overlay_window, 0, Gdk.Screen.height()) def collapse_overlay_area(self, button, event): self._fixed.move(self._overlay_window, 0, Gdk.Screen.height()) def _resize_hide_cb(self, widget): self._resize_canvas(widget, True) def _resize_show_cb(self, widget): self._resize_canvas(widget, False) def _configure_cb(self, event): self._fixed.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self._set_scroll_policy() self._resize_canvas(None) self._reflect_window.reload_graphics() def _resize_canvas(self, widget, fullscreen=False): # When a toolbar is expanded or collapsed, resize the canvas if hasattr(self, '_reflect_window'): if self.toolbar_expanded(): dy1 = 3 * style.GRID_CELL_SIZE dy2 = 2 * style.GRID_CELL_SIZE else: dy1 = 2 * style.GRID_CELL_SIZE dy2 = 1 * style.GRID_CELL_SIZE if fullscreen: dy1 -= 2 * style.GRID_CELL_SIZE dy2 -= 2 * style.GRID_CELL_SIZE self._scrolled_window.set_size_request(Gdk.Screen.width(), Gdk.Screen.height() - dy2) self._fixed.move(self._button_area, 0, 0) self._about_panel_visible = False def toolbar_expanded(self): if self.activity_button.is_expanded(): return True elif self.edit_toolbar_button.is_expanded(): return True elif self.view_toolbar_button.is_expanded(): return True return False def get_activity_version(self): info_path = os.path.join(self.bundle_path, 'activity', 'activity.info') try: info_file = open(info_path, 'r') except Exception as e: _logger.error('Could not open %s: %s' % (info_path, e)) return 'unknown' cp = ConfigParser() cp.readfp(info_file) section = 'Activity' if cp.has_option(section, 'activity_version'): activity_version = cp.get(section, 'activity_version') else: activity_version = 'unknown' return activity_version def get_uid(self): if len(self.volume_data) == 1: return self.volume_data[0]['uid'] else: return 'unknown' def _setup_toolbars(self): ''' Setup the toolbars. ''' self._toolbox = ToolbarBox() self.activity_button = ActivityToolbarButton(self) self.activity_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.activity_button, 0) self.activity_button.show() self.set_toolbar_box(self._toolbox) self._toolbox.show() self.toolbar = self._toolbox.toolbar view_toolbar = Gtk.Toolbar() self.view_toolbar_button = ToolbarButton(page=view_toolbar, label=_('View'), icon_name='toolbar-view') self.view_toolbar_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.view_toolbar_button, 1) view_toolbar.show() self.view_toolbar_button.show() button = ToolButton('view-fullscreen') button.set_tooltip(_('Fullscreen')) button.props.accelerator = '<Alt>Return' view_toolbar.insert(button, -1) button.show() button.connect('clicked', self._fullscreen_cb) edit_toolbar = Gtk.Toolbar() self.edit_toolbar_button = ToolbarButton(page=edit_toolbar, label=_('Edit'), icon_name='toolbar-edit') self.edit_toolbar_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.edit_toolbar_button, 1) edit_toolbar.show() self.edit_toolbar_button.show() self._copy_button = ToolButton('edit-copy') self._copy_button.set_tooltip(_('Copy')) self._copy_button.props.accelerator = '<Ctrl>C' edit_toolbar.insert(self._copy_button, -1) self._copy_button.show() self._copy_button.connect('clicked', self._copy_cb) self._copy_button.set_sensitive(False) self._paste_button = ToolButton('edit-paste') self._paste_button.set_tooltip(_('Paste')) self._paste_button.props.accelerator = '<Ctrl>V' edit_toolbar.insert(self._paste_button, -1) self._paste_button.show() self._paste_button.connect('clicked', self._paste_cb) self._paste_button.set_sensitive(False) button = ToolButton('list-add') button.set_tooltip(_('Add Item')) button.props.accelerator = '<Ctrl>+' self._toolbox.toolbar.insert(button, -1) button.show() button.connect('clicked', self.__add_item_cb) self._date_button = RadioToolButton('date-sort', group=None) self._date_button.set_tooltip(_('Sort by Date')) self._date_button.connect('clicked', self._date_button_cb) self._toolbox.toolbar.insert(self._date_button, -1) self._date_button.show() self._title_button = RadioToolButton('title-sort', group=self._date_button) self._title_button.set_tooltip(_('Sort by Title')) self._title_button.connect('clicked', self._title_button_cb) self._toolbox.toolbar.insert(self._title_button, -1) self._title_button.show() self._stars_button = RadioToolButton('stars-sort', group=self._date_button) self._stars_button.set_tooltip(_('Sort by Favourite')) self._stars_button.connect('clicked', self._stars_button_cb) self._toolbox.toolbar.insert(self._stars_button, -1) self._stars_button.show() # setup the search options self._search_entry = iconentry.IconEntry() self._search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY, 'system-search') self._search_entry.connect('activate', self._search_entry_activated_cb) self._search_entry.connect('changed', self._search_entry_changed_cb) self._search_entry.add_clear_button() tool_item = Gtk.ToolItem() tool_item.set_expand(True) tool_item.add(self._search_entry) self._search_entry.show() self._toolbox.toolbar.insert(tool_item, -1) tool_item.show() self._search_button = ToolButton('dialog-ok') self._search_button.set_tooltip(_('Search by Tags')) self._search_button.connect('clicked', self._search_button_cb) self._toolbox.toolbar.insert(self._search_button, -1) self._search_button.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) self._toolbox.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' self._toolbox.toolbar.insert(stop_button, -1) stop_button.show() def _search_button_cb(self, button): self.busy_cursor() self._do_search() def _search_entry_activated_cb(self, entry): self.busy_cursor() self._do_search() def _do_search(self): logging.debug('_search_entry_activated_cb') if self._search_entry.props.text == '': logging.debug('clearing search') for item in self.reflection_data: item['hidden'] = False else: tags = self._search_entry.props.text.split() for i, tag in enumerate(tags): if not tag[0] == '#': tags[i] = '#%s' % tag logging.error(tags) for item in self.reflection_data: hidden = True if 'tags' in item: for tag in tags: if tag in item['tags']: hidden = False item['hidden'] = hidden self.reload_data(self.reflection_data) self.reset_cursor() def _search_entry_changed_cb(self, entry): logging.debug('_search_entry_changed_cb search for \'%s\'', self._search_entry.props.text) self.busy_cursor() self._do_search_changed() def _do_search_changed(self): if self._search_entry.props.text == '': logging.debug('clearing search') for item in self.reflection_data: item['hidden'] = False self.reload_data(self.reflection_data) self.reset_cursor() def _title_button_cb(self, button): ''' sort by title ''' self.busy_cursor() GObject.idle_add(self._title_sort) def _title_sort(self): sorted_data = sorted(self.reflection_data, key=lambda item: item['title'].lower()) self.reload_data(sorted_data) self.reset_cursor() def _date_button_cb(self, button): ''' sort by modification date ''' self.busy_cursor() GObject.idle_add(self._date_sort) def _date_sort(self): sorted_data = sorted(self.reflection_data, key=lambda item: int(item['modification_time']), reverse=True) self.reload_data(sorted_data) self.reset_cursor() def _stars_button_cb(self, button): ''' sort by number of stars ''' self.busy_cursor() GObject.idle_add(self._stars_sort) def _stars_sort(self): sorted_data = sorted(self.reflection_data, key=lambda item: item['stars'], reverse=True) self.reload_data(sorted_data) self.reset_cursor() def __realize_cb(self, window): self.window_xid = window.get_window().get_xid() def set_copy_widget(self, webkit=None, text_entry=None): # Each task is responsible for setting a widget for copy if webkit is not None: self._webkit = webkit else: self._webkit = None if text_entry is not None: self._copy_entry = text_entry else: self._copy_entry = None self._copy_button.set_sensitive(webkit is not None or text_entry is not None) def _copy_cb(self, button): if self._copy_entry is not None: self._copy_entry.copy_clipboard() elif self._webkit is not None: self._webkit.copy_clipboard() else: _logger.debug('No widget set for copy.') def set_paste_widget(self, text_entry=None): # Each task is responsible for setting a widget for paste if text_entry is not None: self._paste_entry = text_entry self._paste_button.set_sensitive(text_entry is not None) def _paste_cb(self, button): clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.clipboard_text = clipboard.wait_for_text() if self._paste_entry is not None: self._paste_entry.paste_clipboard() else: _logger.debug('No widget set for paste (%s).' % self.clipboard_text) def _fullscreen_cb(self, button): ''' Hide the Sugar toolbars. ''' self.fullscreen() def __add_item_cb(self, button): try: chooser = ObjectChooser(parent=self, what_filter=None) except TypeError: chooser = ObjectChooser( None, self._reflection.activity, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT) try: result = chooser.run() if result == Gtk.ResponseType.ACCEPT: jobject = chooser.get_selected_object() if jobject: self._add_new_from_journal(jobject) self.reload_data(self.reflection_data) finally: chooser.destroy() del chooser def _set_scroll_policy(self): if Gdk.Screen.width() < Gdk.Screen.height(): self._scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) else: self._scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) def _remove_alert_cb(self, alert, response_id): self.remove_alert(alert) def _close_alert_cb(self, alert, response_id): self.remove_alert(alert) if response_id is Gtk.ResponseType.OK: self.close() def _setup_presence_service(self): ''' Setup the Presence Service. ''' self.pservice = presenceservice.get_instance() owner = self.pservice.get_owner() self.owner = owner self._share = '' self.connect('shared', self._shared_cb) self.connect('joined', self._joined_cb) def _shared_cb(self, activity): ''' Either set up initial share...''' if self.shared_activity is None: _logger.error('Failed to share or join activity ... \ shared_activity is null in _shared_cb()') return self.initiating = True self._waiting_for_reflections = 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.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal( 'NewTube', self._new_tube_cb) _logger.debug('This is my activity: making a tube...') self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( SERVICE, {}) self.sharing = True def _joined_cb(self, activity): ''' ...or join an exisiting share. ''' if self.shared_activity is None: _logger.error('Failed to share or join activity ... \ shared_activity is null in _shared_cb()') return if self._joined_alert is not None: self.remove_alert(self._joined_alert) self._joined_alert = None self.initiating = False self._waiting_for_reflections = True _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.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal( 'NewTube', self._new_tube_cb) _logger.debug('I am joining an activity: waiting for a tube...') self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb) self.sharing = True def _list_tubes_reply_cb(self, tubes): ''' Reply to a list request. ''' for tube_info in tubes: self._new_tube_cb(*tube_info) def _list_tubes_error_cb(self, e): ''' Log errors. ''' _logger.error('ListTubes() failed: %s', e) def _new_tube_cb(self, id, initiator, type, service, params, state): ''' Create a new tube. ''' _logger.debug( 'New tube: ID=%d initator=%d type=%d service=%s ' 'params=%r state=%d', id, initiator, type, service, params, state) if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE): if state == telepathy.TUBE_STATE_LOCAL_PENDING: self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube( id) self.collab = CollabWrapper(self) self.collab.message.connect(self.event_received_cb) self.collab.setup() if self._waiting_for_reflections: self.send_event(JOIN_CMD, {}) self._joined_alert = Alert() self._joined_alert.props.title = _('Please wait') self._joined_alert.props.msg = _('Requesting reflections...') self.add_alert(self._joined_alert) def event_received_cb(self, collab, buddy, msg): ''' Data is passed as tuples: cmd:text ''' command = msg.get("command") payload = msg.get("payload") logging.debug(command) if command == JOIN_CMD: # Sharer needs to send reflections database to joiners. if self.initiating: # Send pictures first. for item in self.reflection_data: if 'content' in item: for content in item['content']: if 'image' in content: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size( content['image'], 120, 90) if pixbuf is not None: data = utils.pixbuf_to_base64(pixbuf) self.send_event( PICTURE_CMD, { "image": os.path.basename( content['image']), "data": data }) data = json.dumps(self.reflection_data) self.send_event(SHARE_CMD, {"data": data}) elif command == NEW_REFLECTION_CMD: self._reflect_window.add_new_reflection(payload) elif command == TITLE_CMD: obj_id = payload.get("obj_id") title = payload.get("title") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True self._reflect_window.update_title(obj_id, title) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == TAG_CMD: obj_id = payload.get("obj_id") data = payload.get("data") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True self._reflect_window.update_tags(obj_id, data) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == ACTIVITY_CMD: obj_id = payload.get("obj_id") bundle_id = payload.get("bundle_id") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True self._reflect_window.insert_activity(obj_id, bundle_id) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == STAR_CMD: obj_id = payload.get("obj_id") stars = payload.get("stars") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True self._reflect_window.update_stars(obj_id, int(stars)) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == COMMENT_CMD: found_the_object = False # Receive a comment and associated reflection ID obj_id = payload.get("obj_id") nick = payload.get("nick") color = payload.get("color") comment = payload.get("comment") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True if 'comments' not in item: item['comments'] = [] data = {'nick': nick, 'comment': comment, 'color': color} item['comments'].append(data) self._reflect_window.insert_comment(obj_id, data) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == REFLECTION_CMD: found_the_object = False # Receive a reflection and associated reflection ID obj_id = payload.get("obj_id") reflection = payload.get("reflection") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True if '' not in item: item['content'] = [] item['content'].append({'text': reflection}) self._reflect_window.insert_reflection(obj_id, reflection) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == IMAGE_REFLECTION_CMD: found_the_object = False # Receive a picture reflection and associated reflection ID obj_id = payload.get("obj_id") basename = payload.get("basename") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True if '' not in item: item['content'] = [] item['content'].append( {'image': os.path.join(self.tmp_path, basename)}) self._reflect_window.insert_picture( obj_id, os.path.join(self.tmp_path, basename)) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == PICTURE_CMD: # Receive a picture (MAYBE DISPLAY IT AS IT ARRIVES?) basename = payload.get("basename") data = payload.get("data") utils.base64_to_file(data, os.path.join(self.tmp_path, basename)) elif command == SHARE_CMD: # Joiner needs to load reflection database. if not self.initiating: # Note that pictures should be received. self.reflection_data = payload self._reflect_window.load(self.reflection_data) self._waiting_for_reflections = False self.reset_cursor() if self._joined_alert is not None: self.remove_alert(self._joined_alert) self._joined_alert = None def send_event(self, command, data): ''' Send event through the tube. ''' if hasattr(self, 'collab') and self.collab is not None: data["command"] = command self.collab.post(data)
class TrainingActivity(activity.Activity): ''' A series of training exercises ''' transfer_started_signal = GObject.Signal('started', arg_types=([])) transfer_progressed_signal = GObject.Signal('progressed', arg_types=([])) transfer_completed_signal = GObject.Signal('completed', arg_types=([])) transfer_failed_signal = GObject.Signal('failed', arg_types=([])) def __init__(self, handle): ''' Initialize the toolbars and the game board ''' try: super(TrainingActivity, self).__init__(handle) except dbus.exceptions.DBusException as e: _logger.error(str(e)) self.connect('realize', self.__realize_cb) self.connect('started', self.__transfer_started_cb) self.connect('progressed', self.__transfer_progressed_cb) self.connect('completed', self.__transfer_completed_cb) self.connect('failed', self.__transfer_failed_cb) self.volume_monitor = Gio.VolumeMonitor.get() self.volume_monitor.connect('mount-added', self._mount_added_cb) self.volume_monitor.connect('mount-removed', self._mount_removed_cb) if hasattr(self, 'metadata') and 'font_size' in self.metadata: self.font_size = int(self.metadata['font_size']) else: self.font_size = 8 self.zoom_level = self.font_size / float(len(FONT_SIZES)) _logger.debug('zoom level is %f' % self.zoom_level) _check_gconf_settings() # For debugging purposes self._setup_toolbars() self.modify_bg(Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color()) self.bundle_path = activity.get_bundle_path() self.volume_data = [] self.help_palette = None self.help_panel_visible = False self._copy_entry = None self._paste_entry = None self._webkit = None self._clipboard_text = '' self._fixed = None self._notify_transfer_status = False if self._load_extension() and self.check_volume_data(): self._launcher() def _launcher(self): get_power_manager().inhibit_suspend() # We are resuming the activity or we are launching a new instance? # * Is there a data file to sync on the USB key? # * Do we create a new data file on the USB key? path = self._check_for_USB_data() if path is None: self._launch_task_master() elif self._sync_data_from_USB(path): self._copy_data_from_USB() # Flash a welcome back screen. self._load_intro_graphics(file_name='welcome-back.html') GObject.timeout_add(1500, self._launch_task_master) def can_close(self): get_power_manager().restore_suspend() return True def busy_cursor(self): self._old_cursor = self.get_window().get_cursor() self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) def reset_cursor(self): if hasattr(self, '_old_cursor'): self.get_window().set_cursor(self._old_cursor) def check_volume_data(self): # Before we begin (and before each task), # we need to find any and all USB keys # and any and all training-data files on them. _logger.debug(utils.get_volume_paths()) self.volume_data = [] for path in utils.get_volume_paths(): os.path.basename(path) self.volume_data.append( {'basename': os.path.basename(path), 'files': utils.look_for_training_data(path), 'sugar_path': os.path.join(self.get_activity_root(), 'data'), 'usb_path': path}) _logger.debug(self.volume_data[-1]) # (1) We require a USB key if len(self.volume_data) == 0: _logger.error('NO USB KEY INSERTED') alert = ConfirmationAlert() alert.props.title = _('USB key required') alert.props.msg = _('You must insert a USB key before launching ' 'this activity.') alert.connect('response', self._remove_alert_cb) self.add_alert(alert) self._load_intro_graphics(file_name='insert-usb.html') return False # (2) Only one USB key if len(self.volume_data) > 1: _logger.error('MULTIPLE USB KEYS INSERTED') alert = ConfirmationAlert() alert.props.title = _('Multiple USB keys found') alert.props.msg = _('Only one USB key must be inserted while ' 'running this program.\nPlease remove any ' 'additional USB keys before launching ' 'this activity.') alert.connect('response', self._remove_alert_cb) self.add_alert(alert) self._load_intro_graphics(message=alert.props.msg) return False volume = self.volume_data[0] # (3) At least 10MB of free space if utils.is_full(volume['usb_path'], required=_MINIMUM_SPACE): _logger.error('USB IS FULL') alert = ConfirmationAlert() alert.props.title = _('USB key is full') alert.props.msg = _('No room on USB') alert.connect('response', self._close_alert_cb) self.add_alert(alert) self._load_intro_graphics(message=alert.props.msg) return False # (4) File is read/write if not utils.is_writeable(volume['usb_path']): _logger.error('CANNOT WRITE TO USB') alert = ConfirmationAlert() alert.props.title = _('Cannot write to USB') alert.props.msg = _('USB key seems to be read-only.') alert.connect('response', self._close_alert_cb) self.add_alert(alert) self._load_intro_graphics(message=alert.props.msg) return False # (5) Only one set of training data per USB key # We expect UIDs to formated as XXXX-XXXX # We need to make sure we have proper UIDs associated with # the USBs and the files on them match the UID. # (a) If there are no files, we will assign the UID based on the # volume path; # (b) If there is one file with a valid UID, we use that UID; if len(volume['files']) == 0: volume['uid'] = 'training-data-%s' % \ utils.format_volume_name(volume['basename']) _logger.debug('No training data found. Using UID %s' % volume['uid']) return True elif len(volume['files']) == 1: volume['uid'] = 'training-data-%s' % volume['files'][0][-9:] _logger.debug('Training data found. Using UID %s' % volume['uid']) return True else: _logger.error('MULTIPLE TRAINING-DATA FILES FOUND') alert = ConfirmationAlert() alert.props.title = _('Multiple training-data files found.') alert.props.msg = _('There can only be one set of training ' 'data per USB key.') alert.connect('response', self._close_alert_cb) self.add_alert(alert) self._load_intro_graphics(message=alert.props.msg) return False def _check_for_USB_data(self): usb_path = os.path.join(self.volume_data[0]['usb_path'], self.volume_data[0]['uid']) if os.path.exists(usb_path): return usb_path else: return None def _sync_data_from_USB(self, usb_data_path=None): # We need to sync up file on USB with file on disk, # but only if the email addresses match. Otherwise, # raise an error. if usb_data_path is not None: usb_data = {} if os.path.exists(usb_data_path): fd = open(usb_data_path, 'r') json_data = fd.read() fd.close() if len(json_data) > 0: try: usb_data = json.loads(json_data) except ValueError as e: _logger.error('Cannot load USB data: %s' % e) else: _logger.error('Cannot find USB data: %s' % usb_data_path) sugar_data_path = os.path.join( self.volume_data[0]['sugar_path'], self.volume_data[0]['uid']) sugar_data = {} if os.path.exists(sugar_data_path): fd = open(sugar_data_path, 'r') json_data = fd.read() fd.close() if len(json_data) > 0: try: sugar_data = json.loads(json_data) except ValueError as e: _logger.error('Cannot load Sugar data: %s' % e) else: _logger.error('Cannot find Sugar data: %s' % sugar_data_path) # First, check to make sure email_address matches if EMAIL_UID in usb_data: usb_email = usb_data[EMAIL_UID] else: usb_email = None if EMAIL_UID in sugar_data: sugar_email = sugar_data[EMAIL_UID] else: sugar_email = None if usb_email != sugar_email: if usb_email is None and sugar_email is not None: _logger.warning('Using email address from Sugar: %s' % sugar_email) usb_data[EMAIL_UID] = sugar_email elif usb_email is not None and sugar_email is None: _logger.warning('Using email address from USB: %s' % usb_email) sugar_data[EMAIL_UID] = usb_email elif usb_email is None and sugar_email is None: _logger.warning('No email address found') else: # FIX ME: We need to resolve this, but for right now, punt. alert = ConfirmationAlert() alert.props.title = _('Data mismatch') alert.props.msg = _('Are you %(usb)s or %(sugar)s?' % {'usb': usb_email, 'sugar': sugar_email}) alert.connect('response', self._close_alert_cb) self.add_alert(alert) self._load_intro_graphics(message=alert.props.msg) return False def count_completed(data): count = 0 for key in data: if isinstance(data[key], dict) and \ 'completed' in data[key] and \ data[key]['completed']: count += 1 return count # The database with the most completed tasks takes precedence. if count_completed(usb_data) >= count_completed(sugar_data): _logger.debug('data sync: USB data takes precedence') data_one = usb_data data_two = sugar_data else: _logger.debug('data sync: Sugar data takes precedence') data_one = sugar_data data_two = usb_data # Copy completed tasks from one to two for key in data_one: if isinstance(data_one[key], dict) and \ 'completed' in data_one[key] and \ data_one[key]['completed']: data_two[key] = data_one[key] # Copy completed tasks from two to one for key in data_two: if isinstance(data_two[key], dict) and \ 'completed' in data_two[key] and \ data_two[key]['completed']: data_one[key] = data_two[key] # Copy incompleted tasks from one to two for key in data_one: if isinstance(data_one[key], dict) and \ (not 'completed' in data_one[key] or not data_one[key]['completed']): data_two[key] = data_one[key] # Copy incompleted tasks from two to one for key in data_two: if isinstance(data_two[key], dict) and \ (not 'completed' in data_two[key] or not data_two[key]['completed']): data_one[key] = data_two[key] # Copy name, email_address, current_task... for key in data_one: if not isinstance(data_one[key], dict): data_two[key] = data_one[key] for key in data_two: if not isinstance(data_two[key], dict): data_one[key] = data_two[key] # Finally, write to the USB and ... json_data = json.dumps(data_one) fd = open(usb_data_path, 'w') fd.write(json_data) fd.close() # ...save a shadow copy in Sugar fd = open(sugar_data_path, 'w') fd.write(json_data) fd.close() return True else: _logger.error('No data to sync on USB') return False def _copy_data_from_USB(self): usb_path = self._check_for_USB_data() if usb_path is not None: try: subprocess.call(['cp', usb_path, self.volume_data[0]['sugar_path']]) except OSError as e: _logger.error('Could not copy %s to %s: %s' % ( usb_path, self.volume_data[0]['sugar_path'], e)) else: _logger.error('No data found on USB') def toolbar_expanded(self): if self.activity_button.is_expanded(): return True elif self.edit_toolbar_button.is_expanded(): return True elif self.view_toolbar_button.is_expanded(): return True elif hasattr(self, 'progress_toolbar_button') and \ self.progress_toolbar_button.is_expanded(): return True def _launch_task_master(self): # Most things need only be done once if self._fixed is None: self._fixed = Gtk.Fixed() self._fixed.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) # Offsets from the bottom of the screen dy1 = 3 * style.GRID_CELL_SIZE dy2 = 2 * style.GRID_CELL_SIZE self._progress_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._progress_area.set_size_request(Gdk.Screen.width(), -1) self._fixed.put(self._progress_area, 0, Gdk.Screen.height() - dy2) self._progress_area.show() self._button_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._button_area.set_size_request(Gdk.Screen.width(), -1) self._fixed.put(self._button_area, 0, Gdk.Screen.height() - dy1) self._button_area.show() self._scrolled_window = Gtk.ScrolledWindow() self._scrolled_window.set_size_request( Gdk.Screen.width(), Gdk.Screen.height() - dy1) self._set_scroll_policy() self._graphics_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._scrolled_window.add_with_viewport(self._graphics_area) self._graphics_area.show() self._fixed.put(self._scrolled_window, 0, 0) self._scrolled_window.show() self._task_master = TaskMaster(self) self._task_master.show() # Now that we have the tasks, we can build the progress toolbar and # help panel. self._build_progress_toolbar() self._help_panel = HelpPanel(self._task_master) self.help_palette = self._help_button.get_palette() self.help_palette.set_content(self._help_panel) self._help_panel.show() self._help_button.set_sensitive(True) Gdk.Screen.get_default().connect('size-changed', self._configure_cb) self._toolbox.connect('hide', self._resize_hide_cb) self._toolbox.connect('show', self._resize_show_cb) self._task_master.set_events(Gdk.EventMask.KEY_PRESS_MASK) self._task_master.connect('key_press_event', self._task_master.keypress_cb) self._task_master.set_can_focus(True) self._task_master.grab_focus() self.set_canvas(self._fixed) self._fixed.show() self.completed = False self._update_completed_sections() self._check_connected_task_status() self._task_master.task_master() def load_graphics_area(self, widget): self._graphics_area.add(widget) def load_button_area(self, widget): self._button_area.add(widget) def load_progress_area(self, widget): self._progress_area.add(widget) def _load_intro_graphics(self, file_name='generic-problem.html', message=None): center_in_panel = Gtk.Alignment.new(0.5, 0, 0, 0) url = os.path.join(self.bundle_path, 'html-content', file_name) graphics = Graphics() if message is None: graphics.add_uri('file://' + url) else: graphics.add_uri('file://' + url + '?MSG=' + utils.get_safe_text(message)) graphics.set_zoom_level(0.667) center_in_panel.add(graphics) graphics.show() self.set_canvas(center_in_panel) center_in_panel.show() def _resize_hide_cb(self, widget): self._resize_canvas(widget, True) def _resize_show_cb(self, widget): self._resize_canvas(widget, False) def _configure_cb(self, event): self._fixed.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self._set_scroll_policy() self._resize_canvas(None) self._task_master.reload_graphics() def _resize_canvas(self, widget, fullscreen=False): # When a toolbar is expanded or collapsed, resize the canvas # to ensure that the progress bar is still visible. if hasattr(self, '_task_master'): if self.toolbar_expanded(): dy1 = 4 * style.GRID_CELL_SIZE dy2 = 3 * style.GRID_CELL_SIZE else: dy1 = 3 * style.GRID_CELL_SIZE dy2 = 2 * style.GRID_CELL_SIZE if fullscreen: dy1 -= 2 * style.GRID_CELL_SIZE dy2 -= 2 * style.GRID_CELL_SIZE self._scrolled_window.set_size_request( Gdk.Screen.width(), Gdk.Screen.height() - dy1) self._fixed.move(self._progress_area, 0, Gdk.Screen.height() - dy2) self._fixed.move(self._button_area, 0, Gdk.Screen.height() - dy1) self.help_panel_visible = False def get_activity_version(self): info_path = os.path.join(self.bundle_path, 'activity', 'activity.info') try: info_file = open(info_path, 'r') except Exception as e: _logger.error('Could not open %s: %s' % (info_path, e)) return 'unknown' cp = ConfigParser() cp.readfp(info_file) section = 'Activity' if cp.has_option(section, 'activity_version'): activity_version = cp.get(section, 'activity_version') else: activity_version = 'unknown' return activity_version def get_uid(self): if len(self.volume_data) == 1: return self.volume_data[0]['uid'] else: return 'unknown' def write_file(self, file_path): # Only write if we have a valid USB/data file to work with. if len(self.volume_data) == 1 and \ len(self.volume_data[0]['files']) == 1: self.metadata[TRAINING_DATA_UID] = self.volume_data[0]['uid'] # We may have failed before getting to init of taskmaster if hasattr(self, '_task_master'): self._task_master.write_task_data( 'current_task', self._task_master.current_task) self.update_activity_title() email = self._task_master.read_task_data(EMAIL_UID) if email is None: email = '' self.metadata[TRAINING_DATA_EMAIL] = email name = self._task_master.read_task_data(NAME_UID) if name is None: name = '' self.metadata[TRAINING_DATA_FULLNAME] = name self.metadata['font_size'] = str(self.font_size) def update_activity_title(self): name = self._task_master.read_task_data(NAME_UID) if name is not None: bundle_name = activity.get_bundle_name() self.metadata['title'] = _('%(name)s %(bundle)s Activity') % \ {'name': name, 'bundle': bundle_name} def _setup_toolbars(self): ''' Setup the toolbars. ''' self.max_participants = 1 # No sharing self._toolbox = ToolbarBox() self.activity_button = ActivityToolbarButton(self) self.activity_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.activity_button, 0) self.activity_button.show() self.set_toolbar_box(self._toolbox) self._toolbox.show() self.toolbar = self._toolbox.toolbar view_toolbar = Gtk.Toolbar() self.view_toolbar_button = ToolbarButton( page=view_toolbar, label=_('View'), icon_name='toolbar-view') self.view_toolbar_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.view_toolbar_button, 1) view_toolbar.show() self.view_toolbar_button.show() button = ToolButton('view-fullscreen') button.set_tooltip(_('Fullscreen')) button.props.accelerator = '<Alt>Return' view_toolbar.insert(button, -1) button.show() button.connect('clicked', self._fullscreen_cb) self._zoom_in = ToolButton('zoom-in') self._zoom_in.set_tooltip(_('Increase size')) view_toolbar.insert(self._zoom_in, -1) self._zoom_in.show() self._zoom_in.connect('clicked', self._zoom_in_cb) self._zoom_out = ToolButton('zoom-out') self._zoom_out.set_tooltip(_('Decrease size')) view_toolbar.insert(self._zoom_out, -1) self._zoom_out.show() self._zoom_out.connect('clicked', self._zoom_out_cb) self._zoom_eq = ToolButton('zoom-original') self._zoom_eq.set_tooltip(_('Restore original size')) view_toolbar.insert(self._zoom_eq, -1) self._zoom_eq.show() self._zoom_eq.connect('clicked', self._zoom_eq_cb) self._set_zoom_buttons_sensitivity() edit_toolbar = Gtk.Toolbar() self.edit_toolbar_button = ToolbarButton( page=edit_toolbar, label=_('Edit'), icon_name='toolbar-edit') self.edit_toolbar_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.edit_toolbar_button, 1) edit_toolbar.show() self.edit_toolbar_button.show() self._copy_button = ToolButton('edit-copy') self._copy_button.set_tooltip(_('Copy')) self._copy_button.props.accelerator = '<Ctrl>C' edit_toolbar.insert(self._copy_button, -1) self._copy_button.show() self._copy_button.connect('clicked', self._copy_cb) self._copy_button.set_sensitive(False) self._paste_button = ToolButton('edit-paste') self._paste_button.set_tooltip(_('Paste')) self._paste_button.props.accelerator = '<Ctrl>V' edit_toolbar.insert(self._paste_button, -1) self._paste_button.show() self._paste_button.connect('clicked', self._paste_cb) self._paste_button.set_sensitive(False) self._progress_toolbar = Gtk.Toolbar() self.progress_toolbar_button = ToolbarButton( page=self._progress_toolbar, label=_('Check progress'), icon_name='check-progress') self.progress_toolbar_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.progress_toolbar_button, -1) self._progress_toolbar.show() self.progress_toolbar_button.show() self._help_button = ToolButton('toolbar-help') self._help_button.set_tooltip(_('Help')) self._help_button.props.accelerator = '<Ctrl>H' self._toolbox.toolbar.insert(self._help_button, -1) self._help_button.show() self._help_button.connect('clicked', self._help_cb) self._help_button.set_sensitive(False) self._help_button.palette_invoker.props.lock_palette = True self.transfer_button = ToolButton('transfer') self.transfer_button.set_tooltip(_('Training data upload status')) self._toolbox.toolbar.insert(self.transfer_button, -1) self.transfer_button.connect('clicked', self._transfer_cb) self.transfer_button.hide() self.progress_label = Gtk.Label() self.progress_label.set_line_wrap(True) self.progress_label.set_size_request(300, -1) self.progress_label.set_use_markup(True) toolitem = Gtk.ToolItem() toolitem.add(self.progress_label) self.progress_label.show() self._toolbox.toolbar.insert(toolitem, -1) toolitem.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) self._toolbox.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' self._toolbox.toolbar.insert(stop_button, -1) stop_button.show() def _build_progress_toolbar(self): self._progress_buttons = [] progress = self._task_master.get_completed_sections() for section_index in range(self._task_master.get_number_of_sections()): icon = self._task_master.get_section_icon(section_index) if section_index in progress: icon = icon + '-white' else: icon = icon + '-grey' name = self._task_master.get_section_name(section_index) if section_index == 0: group = None else: group = self._progress_buttons[0] self._progress_buttons.append(RadioToolButton(group=group)) self._progress_buttons[-1].set_icon_name(icon) self._progress_buttons[-1].set_tooltip(name) self._progress_toolbar.insert(self._progress_buttons[-1], -1) self._progress_buttons[-1].show() self._progress_buttons[-1].connect( 'clicked', self._jump_to_section_cb, section_index) self._radio_buttons_live = False section_index, task_index = \ self._task_master.get_section_and_task_index() self._progress_buttons[section_index].set_active(True) self._radio_buttons_live = True def _check_connected_task_status(self): ''' We only want to turn on notifications if we expect connectivity ''' task = self._task_master.uid_to_task(GET_CONNECTED_TASK) self.set_notify_transfer_status(task.is_completed()) def _update_completed_sections(self): progress = self._task_master.get_completed_sections() for section in range(self._task_master.get_number_of_sections()): icon = self._task_master.get_section_icon(section) if section in progress: icon = icon + '-white' else: icon = icon + '-grey' self._progress_buttons[section].set_icon_name(icon) self._radio_buttons_live = False section_index, task_index = \ self._task_master.get_section_and_task_index() self._progress_buttons[section_index].set_active(True) self._radio_buttons_live = True def mark_section_as_complete(self, section): icon = self._task_master.get_section_icon(section) + '-white' self._progress_buttons[section].set_icon_name(icon) if section < self._task_master.get_number_of_sections() - 1: self._radio_buttons_live = False self._progress_buttons[section + 1].set_active(True) self._radio_buttons_live = True def set_notify_transfer_status(self, state): _logger.debug('Setting transfer status to %s' % (str(state))) self._notify_transfer_status = state def _update_transfer_button(self, icon_name, tooltip): self.transfer_button.set_icon_name(icon_name) self.transfer_button.set_tooltip(tooltip) if self._notify_transfer_status: self.transfer_button.show() else: self.transfer_button.hide() def _transfer_cb(self, button): ''' Hide the button to dismiss notification ''' self.transfer_button.set_tooltip(_('Training data upload status')) self.transfer_button.hide() def __transfer_started_cb(self, widget): self._update_transfer_button('transfer', _('Data transfer started')) def __transfer_progressed_cb(self, widget): self._update_transfer_button('transfer', _('Data transfer progressing')) def __transfer_completed_cb(self, widget): self._update_transfer_button('transfer-complete', _('Data transfer completed')) def __transfer_failed_cb(self, widget): self._update_transfer_button('transfer-failed', _('Data transfer failed')) def __realize_cb(self, window): self.window_xid = window.get_window().get_xid() def set_copy_widget(self, webkit=None, text_entry=None): # Each task is responsible for setting a widget for copy if webkit is not None: self._webkit = webkit else: self._webkit = None if text_entry is not None: self._copy_entry = text_entry else: self._copy_entry = None self._copy_button.set_sensitive(webkit is not None or text_entry is not None) def _copy_cb(self, button): if self._copy_entry is not None: self._copy_entry.copy_clipboard() elif self._webkit is not None: self._webkit.copy_clipboard() else: _logger.debug('No widget set for copy.') def set_paste_widget(self, text_entry=None): # Each task is responsible for setting a widget for paste if text_entry is not None: self._paste_entry = text_entry self._paste_button.set_sensitive(text_entry is not None) def _paste_cb(self, button): clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.clipboard_text = clipboard.wait_for_text() if self._paste_entry is not None: self._paste_entry.paste_clipboard() else: _logger.debug('No widget set for paste (%s).' % self.clipboard_text) def _fullscreen_cb(self, button): ''' Hide the Sugar toolbars. ''' self.fullscreen() def _set_zoom_buttons_sensitivity(self): if self.font_size < len(FONT_SIZES) - 1: self._zoom_in.set_sensitive(True) else: self._zoom_in.set_sensitive(False) if self.font_size > 0: self._zoom_out.set_sensitive(True) else: self._zoom_out.set_sensitive(False) if hasattr(self, '_scrolled_window'): self._set_scroll_policy() def _set_scroll_policy(self): if Gdk.Screen.width() < Gdk.Screen.height() or self.zoom_level > 0.667: self._scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) else: self._scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) def _zoom_eq_cb(self, button): self.font_size = 8 self.zoom_level = 0.667 self._set_zoom_buttons_sensitivity() self._task_master.reload_graphics() def _zoom_in_cb(self, button): if self.font_size < len(FONT_SIZES) - 1: self.font_size += 1 self.zoom_level *= 1.1 self._set_zoom_buttons_sensitivity() self._task_master.reload_graphics() def _zoom_out_cb(self, button): if self.font_size > 0: self.font_size -= 1 self.zoom_level /= 1.1 self._set_zoom_buttons_sensitivity() self._task_master.reload_graphics() def _jump_to_section_cb(self, button, section_index): if self._radio_buttons_live: if self._task_master.requirements_are_met(section_index, 0): uid = self._task_master.section_and_task_to_uid(section_index) self._task_master.current_task = \ self._task_master.uid_to_task_number(uid) self._task_master.reload_graphics() else: section_index, task_index = \ self._task_master.get_section_and_task_index() self._progress_buttons[section_index].set_active(True) def _help_cb(self, button): # title, help_file = self._task_master.get_help_info() # _logger.debug('%s: %s' % (title, help_file)) # if not hasattr(self, 'window_xid'): # self.window_xid = self.get_window().get_xid() # if title is not None and help_file is not None: # self.viewhelp = ViewHelp(title, help_file, self.window_xid) # self.viewhelp.show() try: self._help_panel.set_connected( utils.nm_status() == 'network-wireless-connected') except Exception as e: _logger.error('Could not read NM status: %s' % (e)) self._help_panel.set_connected(False) if self.help_palette: # FIXME: is_up() is always returning False, so we # "debounce" using help_panel_visible. if not self.help_palette.is_up() and not self.help_panel_visible: self.help_palette.popup( immediate=True, state=self.help_palette.SECONDARY) self.help_panel_visible = True else: self.help_palette.popdown(immediate=True) self.help_panel_visible = False self._help_button.set_expanded(False) def add_badge(self, msg, icon="training-trophy", name="One Academy"): sugar_icons = os.path.join(os.path.expanduser('~'), '.icons') if not os.path.exists(sugar_icons): try: subprocess.call(['mkdir', sugar_icons]) except OSError as e: _logger.error('Could not mkdir %s, %s' % (sugar_icons, e)) badge = { 'icon': icon, 'from': name, 'message': msg } # Use icons from html-content directory since default colors are # intended for white background. icon_dir = os.path.join(self.bundle_path, 'html-content', 'images') icon_path = os.path.join(icon_dir, icon + '.svg') try: subprocess.call(['cp', icon_path, sugar_icons]) except OSError as e: _logger.error('Could not copy %s to %s, %s' % (icon_path, sugar_icons, e)) if 'comments' in self.metadata: comments = json.loads(self.metadata['comments']) comments.append(badge) self.metadata['comments'] = json.dumps(comments) else: self.metadata['comments'] = json.dumps([badge]) def _load_extension(self): if not WEBSERVICES_AVAILABLE: _logger.error('Webservices not available on this version of Sugar') self._webservice_alert(_('Sugar upgrade required.')) return False extensions_path = os.path.join(os.path.expanduser('~'), '.sugar', 'default', 'extensions') webservice_path = os.path.join(extensions_path, 'webservice') sugarservices_path = os.path.join(self.bundle_path, 'sugarservices') init_path = os.path.join(self.bundle_path, 'sugarservices', '__init__.py') if not os.path.exists(extensions_path): try: subprocess.call(['mkdir', extensions_path]) except OSError as e: _logger.error('Could not mkdir %s, %s' % (extensions_path, e)) self._webservice_alert(_('System error.')) return False if not os.path.exists(webservice_path): try: subprocess.call(['mkdir', webservice_path]) except OSError as e: _logger.error('Could not mkdir %s, %s' % (webservice_path, e)) self._webservice_alert(_('System error.')) return False try: subprocess.call(['cp', init_path, webservice_path]) except OSError as e: _logger.error('Could not cp %s to %s, %s' % (init_path, webservice_path, e)) self._webservice_alert(_('System error.')) return False install = False if not os.path.exists(os.path.join(webservice_path, 'sugarservices')): _logger.error('SugarServices webservice not found. Installing...') install = True elif utils.get_sugarservices_version() < \ _REQUIRED_SUGARSERVICES_VERSION: _logger.error('Found old SugarServices version. Installing...') install = True if install: try: subprocess.call(['cp', '-r', sugarservices_path, webservice_path]) except OSError as e: _logger.error('Could not copy %s to %s, %s' % (sugarservices_path, webservice_path, e)) self._webservice_alert(_('System error.')) return False alert = ConfirmationAlert() alert.props.title = _('Restart required') alert.props.msg = _('We needed to install some software on your ' 'system.\nSugar must be restarted before ' 'sugarservices can commence.') alert.connect('response', self._reboot_alert_cb) self.add_alert(alert) self._load_intro_graphics(file_name='restart.html') return not install def _webservice_alert(self, message): alert = ConfirmationAlert() alert.props.title = message alert.props.msg = _('We are unable to install some software on your ' 'system.\nSugar must be upgraded before this ' 'activity can be run.') alert.connect('response', self._close_alert_cb) self.add_alert(alert) self._load_intro_graphics(message=message) def _remove_alert_cb(self, alert, response_id): self.remove_alert(alert) def _close_alert_cb(self, alert, response_id): self.remove_alert(alert) if response_id is Gtk.ResponseType.OK: self.close() def _reboot_alert_cb(self, alert, response_id): self.remove_alert(alert) if response_id is Gtk.ResponseType.OK: try: utils.reboot() except Exception as e: _logger.error('Cannot reboot: %s' % e) def _mount_added_cb(self, volume_monitor, device): _logger.error('mount added') if self.check_volume_data(): _logger.debug('launching') self._launcher() def _mount_removed_cb(self, volume_monitor, device): _logger.error('mount removed') if self.check_volume_data(): _logger.debug('launching') self._launcher()
class NapierActivity(activity.Activity): ''' Napier's bones: Napier's bones were invented by John Napier (1550-1617), a Scottish mathematician and scientist. They help you to do multiplication. ''' # TODO: Define your own bone. def __init__(self, handle): ''' Initialize the toolbars and the work surface ''' super(NapierActivity, self).__init__(handle) if os.path.exists(os.path.join('~', 'Activities', 'Napier.activity')): self._bone_path = os.path.join('~', 'Activities', 'Napier.activity', 'bones') else: self._bone_path = os.path.join('.', 'bones') self._bones = [] self._bone_images = [None, None, None, None, None, None, None, None, None, None] self._blank_image = None self._number = 0 self._number_of_bones = 0 self._setup_toolbars() self._setup_canvas() self._circles = [None, None] self._ovals = [] self._setup_workspace() self._restore() def _setup_canvas(self): ''' Create a canvas ''' self._canvas = Gtk.DrawingArea() self._canvas.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self.set_canvas(self._canvas) self._canvas.show() self.show_all() self._canvas.add_events(Gdk.EventMask.BUTTON_PRESS_MASK) self._canvas.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK) self._canvas.add_events(Gdk.EventMask.POINTER_MOTION_MASK) self._canvas.connect("draw", self.__draw_cb) self._canvas.connect("motion-notify-event", self._mouse_move_cb) # self._canvas.connect("key_press_event", self._key_press_cb) def _setup_workspace(self): ''' Add the bones. ''' self._width = Gdk.Screen.width() self._height = int(Gdk.Screen.height() - (GRID_CELL_SIZE * 2)) self._scale = self._height * 1.0 / BONE_HEIGHT self._bone_width = int(BONE_WIDTH * self._scale) self._bone_height = int(BONE_HEIGHT * self._scale) # Generate the sprites we'll need... self._sprites = Sprites(self._canvas) self._bone_index = Sprite(self._sprites, 0, 0, _load_svg_from_file( os.path.join(self._bone_path, 'bones-index.svg'), self._bone_width, self._bone_height)) self._max_bones = int(self._width / self._bone_width) - 1 self._blank_image = _load_svg_from_file( os.path.join(self._bone_path, 'blank-bone.svg'), self._bone_width, self._bone_height) for bones in range(self._max_bones): self._bones.append(Sprite(self._sprites, bones * self._bone_width, 0, self._blank_image)) circle_image = _load_svg_from_file( os.path.join(self._bone_path, 'circle.svg'), int(self._scale * 45), int(self._scale * 45)) self._circles[0] = Sprite(self._sprites, 0, -100, circle_image) self._circles[1] = Sprite(self._sprites, 0, -100, circle_image) oval_image = _load_svg_from_file( os.path.join(self._bone_path, 'oval.svg'), int(self._scale * 129), int(self._scale * 92)) for bones in range(self._max_bones - 1): self._ovals.append(Sprite(self._sprites, 0, -100, oval_image)) def _setup_toolbars(self): ''' Setup the toolbars. ''' self.max_participants = 1 # no sharing toolbox = ToolbarBox() # Activity toolbar activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() self._bones_toolbar = Gtk.Toolbar() self._bones_toolbar_button = ToolbarButton(label=_('Select a bone'), page=self._bones_toolbar, icon_name='bones') self._bones_toolbar_button.show() toolbox.toolbar.insert(self._bones_toolbar_button, -1) self.set_toolbar_box(toolbox) toolbox.show() self.toolbar = toolbox.toolbar self._new_calc_button = button_factory( 'erase', self.toolbar, self._new_calc_cb, tooltip=_('Clear')) self._status = label_factory(self.toolbar, '') button_factory('number-0', self._bones_toolbar, self._number_cb, cb_arg=0, tooltip=_('zero')) button_factory('number-1', self._bones_toolbar, self._number_cb, cb_arg=1, tooltip=_('one')) button_factory('number-2', self._bones_toolbar, self._number_cb, cb_arg=2, tooltip=_('two')) button_factory('number-3', self._bones_toolbar, self._number_cb, cb_arg=3, tooltip=_('three')) button_factory('number-4', self._bones_toolbar, self._number_cb, cb_arg=4, tooltip=_('four')) button_factory('number-5', self._bones_toolbar, self._number_cb, cb_arg=5, tooltip=_('five')) button_factory('number-6', self._bones_toolbar, self._number_cb, cb_arg=6, tooltip=_('six')) button_factory('number-7', self._bones_toolbar, self._number_cb, cb_arg=7, tooltip=_('seven')) button_factory('number-8', self._bones_toolbar, self._number_cb, cb_arg=8, tooltip=_('eight')) button_factory('number-9', self._bones_toolbar, self._number_cb, cb_arg=9, tooltip=_('nine')) separator_factory(toolbox.toolbar, True, False) stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' toolbox.toolbar.insert(stop_button, -1) stop_button.show() self._bones_toolbar_button.set_expanded(True) def _new_calc_cb(self, button=None): ''' Start a new calculation. ''' for bone in range(self._max_bones): self._bones[bone].set_shape(self._blank_image) self._bones[bone].inval() self._number_of_bones = 0 self._number = 0 self._status.set_label('') return def _number_cb(self, button=None, value=0): ''' Try to add a digit. ''' if self._number_of_bones == self._max_bones: return self._number_of_bones += 1 if self._bone_images[value] is None: self._bone_images[value] = _svg_str_to_pixbuf( _bone_factory(value, scale=self._scale)) self._bones[self._number_of_bones].set_shape(self._bone_images[value]) self._bones[self._number_of_bones].inval() self._number = self._number * 10 + value def _mouse_move_cb(self, win, event): ''' Determine which row we are in and then calculate the product. ''' win.grab_focus() x, y = map(int, event.get_coords()) factor = int(y / self._bone_width) # The row determines a factor if self._number == 0 or factor == 0: self._status.set_label('') self._circles[0].move((0, -100)) self._circles[1].move((0, -100)) for number in range(self._max_bones - 1): self._ovals[number].move((0, -100)) else: c0dx = int(4 * self._scale) c0dy = int(12 * self._scale) c1dx = int(44 * self._scale) c1dy = int(47 * self._scale) odx = int(42 * self._scale) ody = int(2 * self._scale) self._circles[0].move((self._bone_width + c0dx, factor * self._bone_width + c0dy)) self._circles[1].move(( self._number_of_bones * self._bone_width + c1dx, factor * self._bone_width + c1dy)) for number in range(self._number_of_bones - 1): self._ovals[number].move(((number + 1) * self._bone_width + odx, factor * self._bone_width + ody)) self._status.set_label('%d × %d = %d' % ( factor + 1, self._number, (factor + 1) * self._number)) return True def _key_press_cb(self, win, event): ''' TODO: Add bones by typing numbers ''' return True def __draw_cb(self, canvas, cr): self._sprites.redraw_sprites(cr=cr) def do_expose_event(self, event): ''' Handle the expose-event by drawing ''' # Restrict Cairo to the exposed area cr = self._canvas.window.cairo_create() cr.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) cr.clip() # Refresh sprite list self._sprites.redraw_sprites(cr=cr) def _destroy_cb(self, win, event): Gtk.main_quit() def _restore(self): ''' Try to restore previous state. ''' if 'number' in self.metadata and self.metadata['number'] != '0': for digit in range(len(self.metadata['number'])): self._number_cb(button=None, value=int(self.metadata['number'][digit])) def write_file(self, file_path): ''' Write the status to the Journal. ''' if not hasattr(self, '_number'): return self.metadata['number'] = str(self._number)
def build_colors_toolbar(self, toolbox): colors_bar = Gtk.Toolbar() ######################################################################## # Point color item = Gtk.ToolItem() label = Gtk.Label() label.set_text('%s ' % _('Points')) item.add(label) colors_bar.insert(item, -1) # select color item = Gtk.ToolItem() fill_color = ColorToolButton() fill_color.connect('notify::color', self.color_point_change) item.add(fill_color) colors_bar.insert(item, -1) # Separator separator = Gtk.SeparatorToolItem() colors_bar.insert(separator, -1) separator.show() ######################################################################## # Back color item = Gtk.ToolItem() label = Gtk.Label() label.set_text('%s ' % _('Background')) item.add(label) colors_bar.insert(item, -1) # select color item = Gtk.ToolItem() _fill_color = ColorToolButton() c = Gdk.Color(red=21588, green=47546, blue=18504) _fill_color.set_color(c) _fill_color.connect('notify::color', self.color_back_change) item.add(_fill_color) colors_bar.insert(item, -1) # Separator separator = Gtk.SeparatorToolItem() colors_bar.insert(separator, -1) separator.show() ######################################################################## # Line color item = Gtk.ToolItem() label = Gtk.Label() label.set_text('%s ' % _('Lines')) item.add(label) colors_bar.insert(item, -1) # select color item = Gtk.ToolItem() _fill_color = ColorToolButton() _fill_color.connect('notify::color', self.color_line_change) item.add(_fill_color) colors_bar.insert(item, -1) # Separator separator = Gtk.SeparatorToolItem() colors_bar.insert(separator, -1) separator.show() ######################################################################## # Owner color item = Gtk.ToolItem() label = Gtk.Label() label.set_text('%s ' % _('Owner')) item.add(label) colors_bar.insert(item, -1) # select color item = Gtk.ToolItem() _fill_color = ColorToolButton() c = Gdk.Color(red=65535, green=0, blue=0) _fill_color.set_color(c) _fill_color.connect('notify::color', self.color_owner_change) item.add(_fill_color) colors_bar.insert(item, -1) colors_bar.show_all() colors_button = ToolbarButton(label=_('Colors'), page=colors_bar, icon_name='toolbar-colors') toolbox.toolbar.insert(colors_button, -1) colors_button.show()
class RulerActivity(activity.Activity): def __init__(self, handle): super(RulerActivity, self).__init__(handle) self.button_dict = {} self.callback_dict = {} self._ready = False font = 'helvetica 12' font_bold = 'helvetica bold 12' # # We need a canvas # self._canvas = MyCanvas() self.set_canvas(self._canvas) self._canvas.show() screen = GdkX11.X11Screen() width = screen.width() height = screen.height() - GRID_CELL_SIZE dpi, self.known_dpi = calc_dpi() self._canvas.set_dpi(dpi) # Create instances of our graphics self._r = show_rulers.ScreenOfRulers(font, font_bold, width, height) self._gcm = show_grids.ScreenGrid_cm(font, font_bold, width, height) self._gmm = show_grids.ScreenGrid_mm(font, font_bold, width, height) self._a90 = show_angles.Angles90(font, font_bold, width, height) self._a360 = show_angles.Angles360(font, font_bold, width, height) self._c = show_checkers.ScreenOfCircles(font, font_bold, width, height) # start with a ruler self._current = self._r self._canvas.add_a_ruler(self._current) # other settings self._grids_mode = "cm" self._angles_mode = "90" # # We need some toolbars # self.max_participants = 1 toolbar_box = ToolbarBox() # Buttons added to the Activity toolbar activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() self.rulers = radio_factory('ruler', toolbar_box.toolbar, self._rulers_cb, tooltip=_('Ruler'), group=None) self.grids = radio_factory('grid-a', toolbar_box.toolbar, self._grids_cb, tooltip=_('Grid'), group=self.rulers) self.angles = radio_factory('angles-90', toolbar_box.toolbar, self._angles_cb, tooltip=_('Angles'), group=self.rulers) self.checker = radio_factory('checker', toolbar_box.toolbar, self._checker_cb, tooltip=_('Checker'), group=self.rulers) self.wrapper = Gtk.ToolItem() self.wrapper2 = Gtk.ToolItem() self.wrapper3 = Gtk.ToolItem() self.custom_unit_entry = Gtk.Entry() self.txt1 = Gtk.Label() self.txt1.set_text(_('1 custom unit equals ')) self.txt2 = Gtk.Label() # TRANS: mm is for Milli Meters self.txt2.set_text(_(' mm.')) self.wrapper.add(self.txt1) self.wrapper2.add(self.custom_unit_entry) self.wrapper3.add(self.txt2) self.wrapper.show_all() self.wrapper2.show_all() self.wrapper3.show_all() separator = Gtk.SeparatorToolItem() separator.props.draw = True separator.set_expand(False) separator.show() toolbar_box.toolbar.insert(separator, -1) custom_units_toolbox = ToolbarBox() custom_units_toolbox.toolbar.insert(self.wrapper, -1) custom_units_toolbox.toolbar.insert(self.wrapper2, -1) custom_units_toolbox.toolbar.insert(self.wrapper3, -1) custom_units_toolbox.show() self.custom_units_button = ToolbarButton(icon_name='view-source', page=custom_units_toolbox) toolbar_box.toolbar.insert(self.custom_units_button, -1) self.custom_unit_entry.connect('changed', self.custom_unit_change_cb) self.custom_units_button.show() if not self.known_dpi: separator = Gtk.SeparatorToolItem() separator.show() toolbar_box.toolbar.insert(separator, -1) dpi = self._canvas.get_dpi() self._dpi_spin_adj = Gtk.Adjustment(dpi, 72, 200, 2, 32, 0) self._dpi_spin = Gtk.SpinButton(self._dpi_spin_adj, 0, 0) self._dpi_spin_id = self._dpi_spin.connect('value-changed', self._dpi_spin_cb) self._dpi_spin.set_numeric(True) self._dpi_spin.show() self.tool_item_dpi = Gtk.ToolItem() self.tool_item_dpi.add(self._dpi_spin) toolbar_box.toolbar.insert(self.tool_item_dpi, -1) self.tool_item_dpi.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) separator.show() toolbar_box.toolbar.insert(separator, -1) # The ever-present Stop Button stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>Q' toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() self.show_all() # Restore state if previously saved self._ready = True if 'ruler' in self.metadata and \ self.metadata['ruler'] in self.button_dict: _logger.debug('restoring %s', self.metadata['ruler']) self.button_dict[self.metadata['ruler']].set_active(True) self.callback_dict[self.metadata['ruler']] else: self._rulers_cb() self.rulers.set_active(True) if 'custom_unit' in self.metadata: self.custom_unit_entry.set_text(str(self.metadata['custom_unit'])) else: # set the default self.custom_unit_entry.set_text("25.4") # # Button callbacks # def _rulers_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(True) self._current = self._r self._canvas.add_a_ruler(self._current) _logger.debug('selecting ruler') self.metadata['ruler'] = 'ruler' return False def custom_unit_change_cb(self, widget): try: new = float(widget.get_text()) except ValueError: new = MMPERINCH new = abs(new) if new == 0: new = MMPERINCH if widget.get_text != '': widget.set_text(str(new)) self._canvas.add_a_ruler(self._r) self._r.custom_unit_in_mm = new self._r.draw_custom_ruler(self._r.custom_unit_in_mm) self.metadata['custom_unit'] = new def _grids_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) if self._grids_mode == "cm": self._current = self._gcm if hasattr(self, 'grids'): self.grids.set_icon_name("grid-c") self._grids_mode = "mm" else: self._current = self._gmm if hasattr(self, 'grids'): self.grids.set_icon_name("grid-a") self._grids_mode = "cm" self._canvas.add_a_ruler(self._current) _logger.debug('selecting grids') self.metadata['ruler'] = 'grids' return False def _angles_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) if self._angles_mode == "90": self._current = self._a90 if hasattr(self, 'angles'): self.angles.set_icon_name("angles-360") self._angles_mode = "360" else: self._current = self._a360 if hasattr(self, 'angles'): self.angles.set_icon_name("angles-90") self._angles_mode = "90" self._canvas.add_a_ruler(self._current) _logger.debug('selecting angles') self.metadata['ruler'] = 'angles' return False def _checker_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) self._current = self._c self._canvas.add_a_ruler(self._current) _logger.debug('selecting checker') self.metadata['ruler'] = 'checker' return False def _dpi_spin_cb(self, button): self._canvas.set_dpi(self._dpi_spin.get_value_as_int()) self._canvas.add_a_ruler(self._current) return def write_file(self, file_path): ''' Write the dpi to the Journal ''' dpi = self._canvas.get_dpi() _logger.debug("Write dpi: " + str(dpi)) self.metadata['dpi'] = str(dpi)
def __init__(self, handle): "The entry point to the Activity" global page activity.Activity.__init__(self, handle) toolbar_box = ToolbarBox() activity_button = CustomActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() self.edit_toolbar = EditToolbar() self.edit_toolbar.undo.props.visible = False self.edit_toolbar.redo.props.visible = False self.edit_toolbar.separator.props.visible = False self.edit_toolbar.copy.set_sensitive(False) self.edit_toolbar.copy.connect('clicked', self.edit_toolbar_copy_cb) self.edit_toolbar.paste.props.visible = False edit_toolbar_button = ToolbarButton( page=self.edit_toolbar, icon_name='toolbar-edit') self.edit_toolbar.show() toolbar_box.toolbar.insert(edit_toolbar_button, -1) edit_toolbar_button.show() view_toolbar = ViewToolbar() view_toolbar.connect('go-fullscreen', self.view_toolbar_go_fullscreen_cb) view_toolbar.zoom_in.connect('clicked', self.zoom_in_cb) view_toolbar.zoom_out.connect('clicked', self.zoom_out_cb) view_toolbar.show() view_toolbar_button = ToolbarButton( page=view_toolbar, icon_name='toolbar-view') toolbar_box.toolbar.insert(view_toolbar_button, -1) view_toolbar_button.show() self.back = ToolButton('go-previous') self.back.set_tooltip(_('Back')) self.back.props.sensitive = False self.back.connect('clicked', self.go_back_cb) toolbar_box.toolbar.insert(self.back, -1) self.back.show() self.forward = ToolButton('go-next') self.forward.set_tooltip(_('Forward')) self.forward.props.sensitive = False self.forward.connect('clicked', self.go_forward_cb) toolbar_box.toolbar.insert(self.forward, -1) self.forward.show() num_page_item = Gtk.ToolItem() self.num_page_entry = Gtk.Entry() self.num_page_entry.set_text('0') self.num_page_entry.set_alignment(1) self.num_page_entry.connect('insert-text', self.num_page_entry_insert_text_cb) self.num_page_entry.connect('activate', self.num_page_entry_activate_cb) self.num_page_entry.set_width_chars(4) num_page_item.add(self.num_page_entry) self.num_page_entry.show() toolbar_box.toolbar.insert(num_page_item, -1) num_page_item.show() total_page_item = Gtk.ToolItem() self.total_page_label = Gtk.Label() self.total_page_label.set_markup("<span foreground='#FFF'" \ " size='14000'></span>") self.total_page_label.set_text(' / 0') total_page_item.add(self.total_page_label) self.total_page_label.show() toolbar_box.toolbar.insert(total_page_item, -1) total_page_item.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl><Shift>Q' toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() self.scrolled_window = Gtk.ScrolledWindow() self.scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.textview = Gtk.TextView() self.textview.set_editable(False) self.textview.set_cursor_visible(False) self.textview.set_left_margin(50) self.textview.connect("key_press_event", self.keypress_cb) self.scrolled_window.add(self.textview) self.set_canvas(self.scrolled_window) self.textview.show() self.scrolled_window.show() page = 0 self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.textview.grab_focus() self.font_desc = Pango.FontDescription("sans %d" % style.zoom(10)) self.textview.modify_font(self.font_desc) buffer = self.textview.get_buffer() self.markset_id = buffer.connect("mark-set", self.mark_set_cb)
def __init__(self, handle): activity.Activity.__init__(self, handle) # HACK to avoid Escape key disable fullscreen mode on Terminal Activity # This is related with http://bugs.sugarlabs.org/ticket/440 self.disconnect_by_func(self._Window__key_press_cb) self.connect('key-press-event', self.__key_press_cb) self.max_participants = 1 toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() edit_toolbar = self._create_edit_toolbar() edit_toolbar_button = ToolbarButton( page=edit_toolbar, icon_name='toolbar-edit') edit_toolbar.show() toolbar_box.toolbar.insert(edit_toolbar_button, -1) edit_toolbar_button.show() view_toolbar = self._create_view_toolbar() view_toolbar_button = ToolbarButton( page=view_toolbar, icon_name='toolbar-view') view_toolbar.show() toolbar_box.toolbar.insert(view_toolbar_button, -1) view_toolbar_button.show() self._delete_tab_toolbar = None self._previous_tab_toolbar = None self._next_tab_toolbar = None helpbutton = self._create_help_button() toolbar_box.toolbar.insert(helpbutton, -1) helpbutton.show_all() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl><Shift>Q' toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() self._notebook = BrowserNotebook() self._notebook.connect("tab-added", self.__open_tab_cb) self._notebook.set_property("tab-pos", Gtk.PositionType.TOP) self._notebook.set_scrollable(True) self._notebook.show() self.set_canvas(self._notebook) self._create_tab(None)
class AbacusActivity(activity.Activity): def __init__(self, handle): ''' Initiate activity. ''' super(AbacusActivity, self).__init__(handle) self._setting_up = True self.bead_colors = profile.get_color().to_string().split(',') # no sharing self.max_participants = 1 self.sep = [] self.abacus_toolbar = Gtk.Toolbar() custom_toolbar = Gtk.Toolbar() edit_toolbar = Gtk.Toolbar() toolbox = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() edit_toolbar_button = ToolbarButton(label=_('Edit'), page=edit_toolbar, icon_name='toolbar-edit') edit_toolbar_button.show() toolbox.toolbar.insert(edit_toolbar_button, -1) edit_toolbar_button.show() self.abacus_toolbar_button = ToolbarButton( page=self.abacus_toolbar, icon_name='abacus-list') self.abacus_toolbar.show() toolbox.toolbar.insert(self.abacus_toolbar_button, -1) self.abacus_toolbar_button.show() self.custom_toolbar_button = ToolbarButton( page=custom_toolbar, icon_name='view-source') custom_toolbar.show() toolbox.toolbar.insert(self.custom_toolbar_button, -1) self.custom_toolbar_button.show() separator_factory(toolbox.toolbar, False, True) button_factory('edit-delete', toolbox.toolbar, self._reset_cb, tooltip=_('Reset')) separator_factory(toolbox.toolbar, False, True) self._label = label_factory(NAMES['suanpan'], toolbox.toolbar) separator_factory(toolbox.toolbar, True, False) stop_button = StopButton(self) stop_button.props.accelerator = _('<Ctrl>Q') toolbox.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbox) toolbox.show() self.abacus_buttons = {} # Traditional self._add_abacus_button('decimal', None) self._add_abacus_button('soroban', self.abacus_buttons['decimal']) self._add_abacus_button('suanpan', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Bases other than 10 self._add_abacus_button('nepohualtzintzin', self.abacus_buttons['decimal']) self._add_abacus_button('hexadecimal', self.abacus_buttons['decimal']) self._add_abacus_button('binary', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Fractions self._add_abacus_button('schety', self.abacus_buttons['decimal']) # self._add_abacus_button('fraction', self.abacus_buttons['decimal']) self._add_abacus_button('caacupe', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Non-traditional self._add_abacus_button('cuisenaire', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Custom self._add_abacus_button('custom', self.abacus_buttons['decimal']) preferences_button = ToolButton('preferences-system') preferences_button.set_tooltip(_('Custom')) custom_toolbar.insert(preferences_button, -1) preferences_button.palette_invoker.props.toggle_palette = True preferences_button.palette_invoker.props.lock_palette = True preferences_button.props.hide_tooltip_on_click = False preferences_button.show() self._palette = preferences_button.get_palette() button_box = Gtk.VBox() # TRANS: Number of rods on the abacus self._rods_spin = add_spinner_and_label( 15, 1, MAX_RODS, _('Rods:'), self._rods_spin_cb, button_box) # TRANS: Number of beads in the top section of the abacus self._top_spin = add_spinner_and_label( 2, 0, MAX_TOP, _('Top:'), self._top_spin_cb, button_box) # TRANS: Number of beads in the bottom section of the abacus self._bottom_spin = add_spinner_and_label( 5, 0, MAX_BOT, _('Bottom:'), self._bottom_spin_cb, button_box) # TRANS: Scale factor between bottom and top beads self._value_spin = add_spinner_and_label( 5, 1, MAX_BOT + 1, _('Factor:'), self._value_spin_cb, button_box) # TRANS: Scale factor between rods self._base_spin = add_spinner_and_label( 10, 1, (MAX_TOP + 1) * MAX_BOT, _('Base:'), self._base_spin_cb, button_box) hbox = Gtk.HBox() hbox.pack_start(button_box, True, True, style.DEFAULT_SPACING) hbox.show_all() self._palette.set_content(hbox) separator_factory(custom_toolbar, False, False) self.custom_maker = button_factory('new-abacus', custom_toolbar, self._custom_cb, tooltip=_('Custom')) button_factory('edit-copy', edit_toolbar, self._copy_cb, tooltip=_('Copy'), accelerator='<Ctrl>c') button_factory('edit-paste', edit_toolbar, self._paste_cb, tooltip=_('Paste'), accelerator='<Ctrl>v') # Create a canvas canvas = Gtk.DrawingArea() canvas.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self.set_canvas(canvas) canvas.show() self.show_all() # Initialize the canvas self.abacus = Abacus(canvas, self) self._setting_up = False # Read the current mode from the Journal if 'rods' in self.metadata: self._rods_spin.set_value(int(self.metadata['rods'])) if 'top' in self.metadata: self._top_spin.set_value(int(self.metadata['top'])) if 'bottom' in self.metadata: self._bottom_spin.set_value(int(self.metadata['bottom'])) if 'factor' in self.metadata: self._value_spin.set_value(int(self.metadata['factor'])) if 'base' in self.metadata: self._base_spin.set_value(int(self.metadata['base'])) if 'abacus' in self.metadata: if self.metadata['abacus'] in self.abacus_buttons: _logger.debug('restoring %s', self.metadata['abacus']) if self.metadata['abacus'] == 'custom': self._custom_cb() self.abacus_buttons[self.metadata['abacus']].set_active(True) else: # Default is Chinese self.abacus_buttons['suanpan'].set_active(True) if 'value' in self.metadata: _logger.debug('restoring value %s', self.metadata['value']) self.abacus.mode.set_value(self.metadata['value']) self.abacus.mode.label(self.abacus.generate_label()) self.abacus.init() # Start with abacus toolbar expanded and suanpan as default self.abacus_toolbar_button.set_expanded(True) def _add_abacus_button(self, name, group): self.abacus_buttons[name] = radio_factory( name, self.abacus_toolbar, self._radio_cb, cb_arg=name, tooltip=NAMES[name], group=group) def _radio_cb(self, button, abacus): self._select_abacus(abacus) def _reset_cb(self, button=None): self.abacus.mode.reset_abacus() self.abacus.mode.label(self.abacus.generate_label()) def _notify_new_abacus(self, prompt): ''' Loading a new abacus can be slooow, so alert the user. ''' # a busy cursor is adequate self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) def _select_abacus(self, abacus): ''' Notify the user of an expected delay and then... ''' if not hasattr(self, 'abacus') or self._setting_up: _logger.debug('setting up') return # Not selected? if not self.abacus_buttons[abacus].get_active(): _logger.debug('%s not active' % abacus) return self._notify_new_abacus(NAMES[abacus]) # Give the cursor/alert time to load GObject.idle_add(self._switch_modes, abacus) def _switch_modes(self, abacus): ''' Display the selected abacus ''' _logger.debug('switching modes to %s', abacus) if abacus == self.abacus.mode.name: _logger.debug('do not switch already in the same mode') self.get_window().set_cursor(None) return # Save current value value = int(float(self.abacus.mode.value())) if abacus == 'custom' and self.abacus.custom is None: self.custom_toolbar_button.set_expanded(True) # self.abacus.mode = self.abacus.custom self.get_window().set_cursor(None) else: _logger.debug('switch_mode: setting abacus to %s' % abacus) self.abacus.select_abacus(abacus) # Load saved value self.abacus.mode.set_value_from_number(value) self.abacus.mode.label(self.abacus.generate_label()) self._label.set_text(NAMES[abacus]) self.get_window().set_cursor(None) def _rods_spin_cb(self, button=None): return def _top_spin_cb(self, button=None): return def _bottom_spin_cb(self, button=None): return def _value_spin_cb(self, button=None): return def _base_spin_cb(self, button=None): return def _custom_cb(self, button=None): ''' Display the custom abacus; hide the others ''' value = float(self.abacus.mode.value(count_beads=False)) self.abacus.mode.hide() if self.abacus.custom is not None: self.abacus.custom.hide() self.abacus.custom = Custom(self.abacus, self.abacus.bead_colors) self.abacus.custom.set_custom_parameters( rods=self._rods_spin.get_value_as_int(), top=self._top_spin.get_value_as_int(), bot=self._bottom_spin.get_value_as_int(), factor=self._value_spin.get_value_as_int(), base=self._base_spin.get_value_as_int()) self.abacus.custom.create() self.abacus.custom.draw_rods_and_beads() self.abacus.custom.show() self._label.set_text(NAMES['custom']) self.abacus.mode = self.abacus.custom self.abacus.mode_dict['custom'][0] = self.abacus.custom self.abacus_toolbar_button.set_expanded(True) self.abacus.mode.set_value_from_number(value) def _copy_cb(self, arg=None): ''' Copy a number to the clipboard from the active abacus. ''' clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) text = self.abacus.generate_label(sum_only=True) if text is not None: clipboard.set_text(text, -1) return def _paste_cb(self, arg=None): ''' Paste a number from the clipboard to the active abacus. ''' clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) text = clipboard.wait_for_text() if text is not None: try: self.abacus.mode.set_value_from_number(float(text)) except ValueError, e: _logger.debug(str(e)) return self.abacus.mode.label(self.abacus.generate_label()) return
def __init__(self, handle): ''' Initiate activity. ''' super(AbacusActivity, self).__init__(handle) self._setting_up = True self.bead_colors = profile.get_color().to_string().split(',') # no sharing self.max_participants = 1 self.sep = [] self.abacus_toolbar = Gtk.Toolbar() custom_toolbar = Gtk.Toolbar() edit_toolbar = Gtk.Toolbar() toolbox = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() edit_toolbar_button = ToolbarButton(label=_('Edit'), page=edit_toolbar, icon_name='toolbar-edit') edit_toolbar_button.show() toolbox.toolbar.insert(edit_toolbar_button, -1) edit_toolbar_button.show() self.abacus_toolbar_button = ToolbarButton( page=self.abacus_toolbar, icon_name='abacus-list') self.abacus_toolbar.show() toolbox.toolbar.insert(self.abacus_toolbar_button, -1) self.abacus_toolbar_button.show() self.custom_toolbar_button = ToolbarButton( page=custom_toolbar, icon_name='view-source') custom_toolbar.show() toolbox.toolbar.insert(self.custom_toolbar_button, -1) self.custom_toolbar_button.show() separator_factory(toolbox.toolbar, False, True) button_factory('edit-delete', toolbox.toolbar, self._reset_cb, tooltip=_('Reset')) separator_factory(toolbox.toolbar, False, True) self._label = label_factory(NAMES['suanpan'], toolbox.toolbar) separator_factory(toolbox.toolbar, True, False) stop_button = StopButton(self) stop_button.props.accelerator = _('<Ctrl>Q') toolbox.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbox) toolbox.show() self.abacus_buttons = {} # Traditional self._add_abacus_button('decimal', None) self._add_abacus_button('soroban', self.abacus_buttons['decimal']) self._add_abacus_button('suanpan', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Bases other than 10 self._add_abacus_button('nepohualtzintzin', self.abacus_buttons['decimal']) self._add_abacus_button('hexadecimal', self.abacus_buttons['decimal']) self._add_abacus_button('binary', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Fractions self._add_abacus_button('schety', self.abacus_buttons['decimal']) # self._add_abacus_button('fraction', self.abacus_buttons['decimal']) self._add_abacus_button('caacupe', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Non-traditional self._add_abacus_button('cuisenaire', self.abacus_buttons['decimal']) self.sep.append(separator_factory(self.abacus_toolbar)) # Custom self._add_abacus_button('custom', self.abacus_buttons['decimal']) preferences_button = ToolButton('preferences-system') preferences_button.set_tooltip(_('Custom')) custom_toolbar.insert(preferences_button, -1) preferences_button.palette_invoker.props.toggle_palette = True preferences_button.palette_invoker.props.lock_palette = True preferences_button.props.hide_tooltip_on_click = False preferences_button.show() self._palette = preferences_button.get_palette() button_box = Gtk.VBox() # TRANS: Number of rods on the abacus self._rods_spin = add_spinner_and_label( 15, 1, MAX_RODS, _('Rods:'), self._rods_spin_cb, button_box) # TRANS: Number of beads in the top section of the abacus self._top_spin = add_spinner_and_label( 2, 0, MAX_TOP, _('Top:'), self._top_spin_cb, button_box) # TRANS: Number of beads in the bottom section of the abacus self._bottom_spin = add_spinner_and_label( 5, 0, MAX_BOT, _('Bottom:'), self._bottom_spin_cb, button_box) # TRANS: Scale factor between bottom and top beads self._value_spin = add_spinner_and_label( 5, 1, MAX_BOT + 1, _('Factor:'), self._value_spin_cb, button_box) # TRANS: Scale factor between rods self._base_spin = add_spinner_and_label( 10, 1, (MAX_TOP + 1) * MAX_BOT, _('Base:'), self._base_spin_cb, button_box) hbox = Gtk.HBox() hbox.pack_start(button_box, True, True, style.DEFAULT_SPACING) hbox.show_all() self._palette.set_content(hbox) separator_factory(custom_toolbar, False, False) self.custom_maker = button_factory('new-abacus', custom_toolbar, self._custom_cb, tooltip=_('Custom')) button_factory('edit-copy', edit_toolbar, self._copy_cb, tooltip=_('Copy'), accelerator='<Ctrl>c') button_factory('edit-paste', edit_toolbar, self._paste_cb, tooltip=_('Paste'), accelerator='<Ctrl>v') # Create a canvas canvas = Gtk.DrawingArea() canvas.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self.set_canvas(canvas) canvas.show() self.show_all() # Initialize the canvas self.abacus = Abacus(canvas, self) self._setting_up = False # Read the current mode from the Journal if 'rods' in self.metadata: self._rods_spin.set_value(int(self.metadata['rods'])) if 'top' in self.metadata: self._top_spin.set_value(int(self.metadata['top'])) if 'bottom' in self.metadata: self._bottom_spin.set_value(int(self.metadata['bottom'])) if 'factor' in self.metadata: self._value_spin.set_value(int(self.metadata['factor'])) if 'base' in self.metadata: self._base_spin.set_value(int(self.metadata['base'])) if 'abacus' in self.metadata: if self.metadata['abacus'] in self.abacus_buttons: _logger.debug('restoring %s', self.metadata['abacus']) if self.metadata['abacus'] == 'custom': self._custom_cb() self.abacus_buttons[self.metadata['abacus']].set_active(True) else: # Default is Chinese self.abacus_buttons['suanpan'].set_active(True) if 'value' in self.metadata: _logger.debug('restoring value %s', self.metadata['value']) self.abacus.mode.set_value(self.metadata['value']) self.abacus.mode.label(self.abacus.generate_label()) self.abacus.init() # Start with abacus toolbar expanded and suanpan as default self.abacus_toolbar_button.set_expanded(True)
def build_calibrate_toolbar(self, toolbox): calibrate_bar = Gtk.Toolbar() item1 = Gtk.ToolItem() label1 = Gtk.Label() label1.set_text(' ' + _('Calibrate/Follow') + ' ') item1.add(label1) calibrate_bar.insert(item1, -1) stop_calibrate = ToolButton('media-playback-stop') stop_calibrate.set_tooltip(_('Stop')) stop_calibrate.set_accelerator('<ctrl>space') stop_calibrate.connect('clicked', self.stop_execute) calibrate_bar.insert(stop_calibrate, -1) separator1 = Gtk.SeparatorToolItem() separator1.props.draw = True calibrate_bar.insert(separator1, -1) item3 = Gtk.ToolItem() self.label_color_red = Gtk.Label() self.label_color_red.set_text(' ' + _('Calibrated color:') + ' ' + _('Red') + ' ') item3.add(self.label_color_red) calibrate_bar.insert(item3, -1) item4 = Gtk.ToolItem() self.red_spin = Gtk.SpinButton() self.red_spin.set_range(0, 255) self.red_spin.set_increments(1, 10) self.red_spin.props.value = self.colorC[0] self.red_spin.connect('notify::value', self.red_spin_color) item4.add(self.red_spin) calibrate_bar.insert(item4, -1) item5 = Gtk.ToolItem() self.label_color_green = Gtk.Label() self.label_color_green.set_text(' ' + _('Green') + ' ') item5.add(self.label_color_green) calibrate_bar.insert(item5, -1) item6 = Gtk.ToolItem() self.green_spin = Gtk.SpinButton() self.green_spin.set_range(0, 255) self.green_spin.set_increments(1, 10) self.green_spin.props.value = self.colorC[1] self.green_spin.connect('notify::value', self.green_spin_color) item6.add(self.green_spin) calibrate_bar.insert(item6, -1) item7 = Gtk.ToolItem() self.label_color_blue = Gtk.Label() self.label_color_blue.set_text(' ' + _('Blue') + ' ') item7.add(self.label_color_blue) calibrate_bar.insert(item7, -1) item8 = Gtk.ToolItem() self.blue_spin = Gtk.SpinButton() self.blue_spin.set_range(0, 255) self.blue_spin.set_increments(1, 10) self.blue_spin.props.value = self.colorC[2] self.blue_spin.connect('notify::value', self.blue_spin_color) item8.add(self.blue_spin) calibrate_bar.insert(item8, -1) calibrate_bar.show_all() calibrate_button = ToolbarButton(label=_('Calibrate'), page=calibrate_bar, icon_name='preferences-system') toolbox.toolbar.insert(calibrate_button, -1) calibrate_button.show()
def __init__(self, activity): GObject.GObject.__init__(self) self.activity = activity self.instrumentDB = InstrumentDB.getRef() self.noteDB = NoteDB.NoteDB() #-- initial settings ---------------------------------- self.tempo = Config.PLAYER_TEMPO self.beatDuration = 60.0 / self.tempo self.ticksPerSecond = Config.TICKS_PER_BEAT * self.tempo / 60.0 self.volume = 0.5 self.csnd = new_csound_client() for i in range(0, 9): self.csnd.setTrackVolume(100, i) # csnd expects a range 0-100 for now self.csnd.setMasterVolume(self.volume * 100) self.csnd.setTempo(self.tempo) self.muted = False #-- Drawing ------------------------------------------- def darken(hex): hexToDec = {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "A": 10, "B": 11, "C": 12, "D": 13, "E": 14, "F": 15, "a": 10, "b": 11, "c": 12, "d": 13, "e": 14, "f": 15} r = int(0.7 * (16 * hexToDec[hex[1]] + hexToDec[hex[2]])) g = int(0.7 * (16 * hexToDec[hex[3]] + hexToDec[hex[4]])) b = int(0.7 * (16 * hexToDec[hex[5]] + hexToDec[hex[6]])) return r * 256, g * 256, b * 256 def lighten(hex): hexToDec = {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "A": 10, "B": 11, "C": 12, "D": 13, "E": 14, "F": 15, "a": 10, "b": 11, "c": 12, "d": 13, "e": 14, "f": 15} r = 255 - int(0.7 * (255 - ( 16 * hexToDec[hex[1]] + hexToDec[hex[2]]))) g = 255 - int(0.7 * (255 - ( 16 * hexToDec[hex[3]] + hexToDec[hex[4]]))) b = 255 - int(0.7 * (255 - ( 16 * hexToDec[hex[5]] + hexToDec[hex[6]]))) return r * 256, g * 256, b * 256 xoColor = profile.get_color() if not xoColor: xoColorKey = ("#8D8D8D,#FFDDEA") xoColor = XoColor(xoColorKey) # colors in Config and in XoColor are strings, # the colors in style are style.Color, transform all to Gdk.Color self.colors = {"bg": CairoUtil.get_gdk_color(Config.PANEL_BCK_COLOR), "black": style.COLOR_BLACK.get_gdk_color(), #"Picker_Bg": colormap.alloc_color("#404040"), #"Picker_Bg_Inactive": colormap.alloc_color("#808080"), "Picker_Bg": style.COLOR_TOOLBAR_GREY.get_gdk_color(), "Picker_Bg_Inactive": style.COLOR_BUTTON_GREY.get_gdk_color(), "Picker_Fg": style.COLOR_WHITE.get_gdk_color(), "Border_Active": \ CairoUtil.get_gdk_color(xoColor.get_stroke_color()), "Border_Inactive": CairoUtil.get_gdk_color("#8D8D8D"), "Border_Highlight": CairoUtil.get_gdk_color("#FFFFFF"), "Bg_Active": CairoUtil.get_gdk_color(xoColor.get_fill_color()), "Bg_Inactive": CairoUtil.get_gdk_color("#DBDBDB"), "Preview_Note_Fill": CairoUtil.get_gdk_color(Config.BG_COLOR), "Preview_Note_Border": CairoUtil.get_gdk_color(Config.FG_COLOR), "Preview_Note_Selected": style.COLOR_WHITE.get_gdk_color(), # TODO: lighten here can be removed, check if is used in other # places "Note_Fill_Active": Gdk.Color(*lighten("#590000")), # base "Border_Active" "Note_Fill_Inactive": Gdk.Color(*lighten("#8D8D8D")), # base "Border_Inactive" "Beat_Line": CairoUtil.get_gdk_color("#959595")} self.colors["Note_Border_Active"] = self.colors["Border_Active"] self.colors["Note_Border_Inactive"] = self.colors["Border_Inactive"] self.sampleNoteHeight = 7 self.sampleBg = cairo.ImageSurface.create_from_png( imagefile('sampleBG.png')) self.loopPitchOffset = 4 self.loopTickOffset = 13 self.pitchPerPixel = float(Config.NUMBER_OF_POSSIBLE_PITCHES - 1) / \ (Block.Loop.HEIGHT - 2 * self.loopPitchOffset - \ self.sampleNoteHeight) self.pixelsPerPitch = float(Block.Loop.HEIGHT - \ 2 * self.loopPitchOffset - self.sampleNoteHeight) / \ (Config.MAXIMUM_PITCH - Config.MINIMUM_PITCH) self.pixelsPerTick = Block.Loop.BEAT / float(Config.TICKS_PER_BEAT) self.ticksPerPixel = 1.0 / self.pixelsPerTick #-- Instruments --------------------------------------- self.instrumentImage = {} self.instrumentImageActive = {} for inst in self.instrumentDB.getSet("All"): if not inst.kitStage: self.prepareInstrumentImage(inst.instrumentId, inst.img) self.csnd.load_instrument(inst.name) #-- Loop Images --------------------------------------- self.loopImage = {} # get filled in through updateLoopImage self.loopImageActive = {} #-- Key Images ---------------------------------------- self.keyImage = {} self.keyImageActive = {} # use hardware key codes to work on any keyboard layout (hopefully) self.valid_shortcuts = {18: "9", 19: "0", 20: "-", 21: "=", 32: "O", 33: "P", 34: "[", 35: "]", 47: ";", 48: "'", 51: "\\", 60: ".", 61: "/", None: " "} for key in self.valid_shortcuts.keys(): self.prepareKeyImage(key) #-- Toolbars ------------------------------------------ self.jamToolbar = JamToolbar(self) jam_toolbar_button = ToolbarButton(label=_('Jam'), page=self.jamToolbar, icon_name='voltemp') self.jamToolbar.show() jam_toolbar_button.show() self.activity.toolbar_box.toolbar.insert(jam_toolbar_button, -1) self.beatToolbar = BeatToolbar(self) beat_toolbar_button = ToolbarButton(label=_('Beat'), page=self.beatToolbar, icon_name='heart') self.beatToolbar.show() beat_toolbar_button.show() self.activity.toolbar_box.toolbar.insert(beat_toolbar_button, -1) self.desktopToolbar = DesktopToolbar(self) desktop_toolbar_button = ToolbarButton(label=_('Desktop'), page=self.desktopToolbar, icon_name='jam-presets-list') self.desktopToolbar.show() desktop_toolbar_button.show() self.activity.toolbar_box.toolbar.insert(desktop_toolbar_button, -1) if Config.FEATURES_MIC or Config.FEATURES_NEWSOUNDS: self.recordToolbar = RecordToolbar(self) record_toolbar_button = ToolbarButton(label=_('Record'), page=self.recordToolbar, icon_name='microphone') self.recordToolbar.show() record_toolbar_button.show() self.activity.toolbar_box.toolbar.insert(record_toolbar_button, -1) separator = Gtk.SeparatorToolItem() separator.props.draw = True separator.set_expand(False) self.activity.toolbar_box.toolbar.insert(separator, -1) separator.show() common_playback_buttons(self.activity.toolbar_box.toolbar, self) #-- GUI ----------------------------------------------- if True: # GUI self.modify_bg(Gtk.StateType.NORMAL, self.colors["bg"]) self.GUI = {} self.GUI["mainVBox"] = Gtk.VBox() self.add(self.GUI["mainVBox"]) #-- Desktop ------------------------------------------- self.desktop = self.GUI["desktop"] = Desktop(self) self.GUI["mainVBox"].pack_start(self.GUI["desktop"], True, True, 0) #-- Bank ---------------------------------------------- separator = Gtk.Label(label=" ") separator.set_size_request(-1, style.TOOLBOX_SEPARATOR_HEIGHT) self.GUI["mainVBox"].pack_start(separator, False, True, 0) self.GUI["notebook"] = Gtk.Notebook() self.GUI["notebook"].set_scrollable(True) self.GUI["notebook"].modify_bg(Gtk.StateType.NORMAL, self.colors["Picker_Bg"]) self.GUI["notebook"].modify_bg(Gtk.StateType.ACTIVE, self.colors["Picker_Bg_Inactive"]) # TODO gtk3 no available anymore? #self.GUI["notebook"].props.tab_vborder = style.TOOLBOX_TAB_VBORDER #self.GUI["notebook"].props.tab_hborder = style.TOOLBOX_TAB_HBORDER self.GUI["notebook"].set_size_request(-1, scale(160)) self.GUI["notebook"].connect("switch-page", self.setPicker) self.GUI["mainVBox"].pack_start(self.GUI["notebook"], False, False, 0) self.pickers = {} self.pickerScroll = {} for type in [Picker.Instrument, Picker.Drum, Picker.Loop]: self.pickers[type] = type(self) def prepareLabel(name): label = Gtk.Label(label=Tooltips.categories.get(name) or name) label.set_alignment(0.0, 0.5) label.modify_fg(Gtk.StateType.NORMAL, self.colors["Picker_Fg"]) label.modify_fg(Gtk.StateType.ACTIVE, self.colors["Picker_Fg"]) return label self.GUI["notebook"].append_page(self.pickers[Picker.Drum], prepareLabel(_("Drum Kits"))) self.GUI["notebook"].append_page(self.pickers[Picker.Loop], prepareLabel(_("Loops"))) sets = self.instrumentDB.getLabels()[:] sets.sort() for set in sets: page = Gtk.HBox() page.set = set self.GUI["notebook"].append_page(page, prepareLabel(set)) self.show_all() self.GUI["notebook"].set_current_page(0) #-- Keyboard ------------------------------------------ self.key_dict = {} self.nextTrack = 2 self.keyboardListener = None self.recordingNote = None self.keyMap = {} # default instrument self._updateInstrument( self.instrumentDB.instNamed["kalimba"].instrumentId, 0.5) self.instrumentStack = [] # metronome page = NoteDB.Page(1, local=False) self.metronomePage = self.noteDB.addPage(-1, page) self.metronome = False #-- Drums --------------------------------------------- self.drumLoopId = None # use dummy values for now self.drumFillin = Fillin( 2, 100, self.instrumentDB.instNamed["drum1kit"].instrumentId, 0, 1) #-- Desktops ------------------------------------------ self.curDesktop = None # copy preset desktops path = Config.FILES_DIR + "/Desktops/" filelist = os.listdir(path) for file in filelist: shutil.copyfile(path + file, Config.TMP_DIR + '/' + file) #-- Network ------------------------------------------- self.network = Net.Network() self.network.addWatcher(self.networkStatusWatcher) self.network.connectMessage(Net.HT_SYNC_REPLY, self.processHT_SYNC_REPLY) self.network.connectMessage(Net.HT_TEMPO_UPDATE, self.processHT_TEMPO_UPDATE) self.network.connectMessage(Net.PR_SYNC_QUERY, self.processPR_SYNC_QUERY) self.network.connectMessage(Net.PR_TEMPO_QUERY, self.processPR_TEMPO_QUERY) self.network.connectMessage(Net.PR_REQUEST_TEMPO_CHANGE, self.processPR_REQUEST_TEMPO_CHANGE) # sync self.syncQueryStart = {} self.syncTimeout = None self.heartbeatLoop = self.csnd.loopCreate() self.syncBeats = 4 self.syncTicks = self.syncBeats * Config.TICKS_PER_BEAT self.offsetTicks = 0 # offset from the true heartbeat self.csnd.loopSetNumTicks(self.syncTicks * HEARTBEAT_BUFFER, self.heartbeatLoop) self.heartbeatStart = time.time() self.csnd.loopStart(self.heartbeatLoop) self.curBeat = 0 self.beatWheelTimeout = GObject.timeout_add(100, self.updateBeatWheel) # data packing classes self.packer = xdrlib.Packer() self.unpacker = xdrlib.Unpacker("") # handle forced networking if self.network.isHost(): self.updateSync() self.syncTimeout = GObject.timeout_add(1000, self.updateSync) elif self.network.isPeer(): self.sendTempoQuery() self.syncTimeout = GObject.timeout_add(1000, self.updateSync) self.activity.connect("shared", self.shared) if self.activity.shared_activity: # PEER self.activity.shared_activity.connect("buddy-joined", self.buddy_joined) self.activity.shared_activity.connect("buddy-left", self.buddy_left) self.activity.connect("joined", self.joined) self.network.setMode(Net.MD_WAIT) #-- Final Set Up -------------------------------------- self.setVolume(self.volume) self.setTempo(self.tempo) #self.activity.toolbar_box.set_current_toolbar(1) # JamToolbar self.setDesktop(0, True)
class ReflectActivity(activity.Activity): ''' An activity for reflecting on one's work ''' def __init__(self, handle): ''' Initialize the toolbar ''' try: super(ReflectActivity, self).__init__(handle) except dbus.exceptions.DBusException as e: _logger.error(str(e)) logging.error('setting reflection data to []') self.reflection_data = [] self.connect('realize', self.__realize_cb) self.font_size = 8 self.max_participants = 4 self._setup_toolbars() color = profile.get_color() color_stroke = color.get_stroke_color() color_fill = color.get_fill_color() lighter = utils.lighter_color([color_stroke, color_fill]) darker = 1 - lighter if lighter == 0: self.bg_color = style.Color(color_stroke) self.fg_color = style.Color(color_fill) else: self.bg_color = style.Color(color_fill) self.fg_color = style.Color(color_stroke) self.modify_bg(Gtk.StateType.NORMAL, self.bg_color.get_gdk_color()) self.bundle_path = activity.get_bundle_path() self.tmp_path = os.path.join(activity.get_activity_root(), 'instance') self.sharing = False self._copy_entry = None self._paste_entry = None self._webkit = None self._clipboard_text = '' self._fixed = None self.initiating = True if self.shared_activity: # We're joining if not self.get_shared(): self.initiating = False self.busy_cursor() share_icon = Icon(icon_name='zoom-neighborhood') self._joined_alert = Alert() self._joined_alert.props.icon = share_icon self._joined_alert.props.title = _('Please wait') self._joined_alert.props.msg = _('Starting connection...') self.add_alert(self._joined_alert) # Wait for joined signal self.connect("joined", self._joined_cb) self._open_reflect_windows() self._setup_presence_service() # Joiners wait to receive data from sharer # Otherwise, load reflections from local store if not self.shared_activity: self.busy_cursor() GObject.idle_add(self._load_reflections) def read_file(self, file_path): fd = open(file_path, 'r') data = fd.read() fd.close() self.reflection_data = json.loads(data) def write_file(self, file_path): data = json.dumps(self.reflection_data) fd = open(file_path, 'w') fd.write(data) fd.close() self.metadata['font_size'] = str(self.font_size) def _load_reflections(self): self._find_starred() self._reflect_window.load(self.reflection_data) self.reset_cursor() def _found_obj_id(self, obj_id): for item in self.reflection_data: if 'obj_id' in item and item['obj_id'] == obj_id: return True return False def reload_data(self, data): ''' Reload data after sorting or searching ''' self._reflection_data = data[:] self._reflect_window.reload(self._reflection_data) self.reset_scrolled_window_adjustments() def _find_starred(self): ''' Find all the _stars in the Journal. ''' self.dsobjects, self._nobjects = datastore.find({'keep': '1'}) for dsobj in self.dsobjects: if self._found_obj_id(dsobj.object_id): continue # Already have this object -- TODO: update it self._add_new_from_journal(dsobj) def _add_new_from_journal(self, dsobj): self.reflection_data.append({ 'title': _('Untitled'), 'obj_id': dsobj.object_id}) if hasattr(dsobj, 'metadata'): if 'creation_time' in dsobj.metadata: self.reflection_data[-1]['creation_time'] = \ dsobj.metadata['creation_time'] else: self.reflection_data[-1]['creation_time'] = \ int(time.time()) if 'timestamp' in dsobj.metadata: self.reflection_data[-1]['modification_time'] = \ dsobj.metadata['timestamp'] else: self.reflection_data[-1]['modification_time'] = \ self.reflection_data[-1]['creation_time'] if 'activity' in dsobj.metadata: self.reflection_data[-1]['activities'] = \ [utils.bundle_id_to_icon(dsobj.metadata['activity'])] if 'title' in dsobj.metadata: self.reflection_data[-1]['title'] = \ dsobj.metadata['title'] if 'description' in dsobj.metadata: self.reflection_data[-1]['content'] = \ [{'text': dsobj.metadata['description']}] else: self.reflection_data[-1]['content'] = [] if 'tags' in dsobj.metadata: self.reflection_data[-1]['tags'] = [] tags = dsobj.metadata['tags'].split() for tag in tags: if tag[0] != '#': self.reflection_data[-1]['tags'].append('#' + tag) else: self.reflection_data[-1]['tags'].append(tag) if 'comments' in dsobj.metadata: try: comments = json.loads(dsobj.metadata['comments']) except: comments = [] self.reflection_data[-1]['comments'] = [] for comment in comments: try: data = {'nick': comment['from'], 'comment': comment['message']} if 'icon-color' in comment: colors = comment['icon-color'].split(',') darker = 1 - utils.lighter_color(colors) data['color'] = colors[darker] else: data['color'] = '#000000' self.reflection_data[-1]['comments'].append(data) except: _logger.debug('could not parse comment %s' % comment) if 'mime_type' in dsobj.metadata and \ dsobj.metadata['mime_type'][0:5] == 'image': new_path = os.path.join(self.tmp_path, dsobj.object_id) try: shutil.copy(dsobj.file_path, new_path) except Exception as e: logging.error("Couldn't copy %s to %s: %s" % (dsobj.file_path, new_path, e)) self.reflection_data[-1]['content'].append( {'image': new_path}) elif 'preview' in dsobj.metadata: pixbuf = utils.get_pixbuf_from_journal(dsobj, 300, 225) if pixbuf is not None: path = os.path.join(self.tmp_path, dsobj.object_id + '.png') utils.save_pixbuf_to_file(pixbuf, path) self.reflection_data[-1]['content'].append( {'image': path}) self.reflection_data[-1]['stars'] = 0 def delete_item(self, obj_id): for i, obj in enumerate(self.reflection_data): if obj['obj_id'] == obj_id: self.reflection_data.remove(self.reflection_data[i]) return def busy_cursor(self): self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) def reset_cursor(self): self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.LEFT_PTR)) def _open_reflect_windows(self): # Most things need only be done once if self._fixed is None: self._fixed = Gtk.Fixed() self._fixed.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) # Offsets from the bottom of the screen dy1 = 2 * style.GRID_CELL_SIZE dy2 = 1 * style.GRID_CELL_SIZE self._button_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._button_area.set_size_request(Gdk.Screen.width(), style.GRID_CELL_SIZE) self._fixed.put(self._button_area, 0, 0) self._button_area.show() self._scrolled_window = Gtk.ScrolledWindow() self._scrolled_window.set_size_request( Gdk.Screen.width(), Gdk.Screen.height() - dy1) self._set_scroll_policy() self._graphics_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._scrolled_window.add_with_viewport(self._graphics_area) self._graphics_area.show() self._fixed.put(self._scrolled_window, 0, dy2) self._scrolled_window.show() self._overlay_window = Gtk.ScrolledWindow() self._overlay_window.set_size_request( style.GRID_CELL_SIZE * 10, style.GRID_CELL_SIZE * 6) self._overlay_window.modify_bg( Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color()) self._overlay_window.set_policy( Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self._overlay_area = Gtk.Alignment.new(0.5, 0, 0, 0) self._overlay_window.add_with_viewport(self._overlay_area) self._overlay_area.show() x = int((Gdk.Screen.width() - style.GRID_CELL_SIZE * 10) / 2) self._fixed.put(self._overlay_window, 0, Gdk.Screen.height()) self._overlay_window.show() self._old_overlay_widget = None self._reflect_window = ReflectWindow(self) self._reflect_window.show() Gdk.Screen.get_default().connect('size-changed', self._configure_cb) self._toolbox.connect('hide', self._resize_hide_cb) self._toolbox.connect('show', self._resize_show_cb) self._reflect_window.set_events(Gdk.EventMask.KEY_PRESS_MASK) self._reflect_window.connect('key_press_event', self._reflect_window.keypress_cb) self._reflect_window.set_can_focus(True) self._reflect_window.grab_focus() self.set_canvas(self._fixed) self._fixed.show() def reset_scrolled_window_adjustments(self): adj = self._scrolled_window.get_hadjustment() if adj is not None: adj.set_value(0) adj = self._scrolled_window.get_vadjustment() if adj is not None: adj.set_value(0) def load_graphics_area(self, widget): self._graphics_area.add(widget) def load_button_area(self, widget): self._button_area.add(widget) def load_overlay_area(self, widget): if self._old_overlay_widget is not None: self._overlay_area.remove(self._old_overlay_widget) self._overlay_area.add(widget) self._old_overlay_widget = widget def show_overlay_area(self): x = int((Gdk.Screen.width() - style.GRID_CELL_SIZE * 10) / 2) self._fixed.move(self._overlay_window, x, style.GRID_CELL_SIZE) def hide_overlay_area(self): self._fixed.move( self._overlay_window, 0, Gdk.Screen.height()) def _resize_hide_cb(self, widget): self._resize_canvas(widget, True) def _resize_show_cb(self, widget): self._resize_canvas(widget, False) def _configure_cb(self, event): self._fixed.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self._set_scroll_policy() self._resize_canvas(None) self._reflect_window.reload_graphics() def _resize_canvas(self, widget, fullscreen=False): # When a toolbar is expanded or collapsed, resize the canvas if hasattr(self, '_reflect_window'): if self.toolbar_expanded(): dy1 = 3 * style.GRID_CELL_SIZE dy2 = 2 * style.GRID_CELL_SIZE else: dy1 = 2 * style.GRID_CELL_SIZE dy2 = 1 * style.GRID_CELL_SIZE if fullscreen: dy1 -= 2 * style.GRID_CELL_SIZE dy2 -= 2 * style.GRID_CELL_SIZE self._scrolled_window.set_size_request( Gdk.Screen.width(), Gdk.Screen.height() - dy2) self._fixed.move(self._button_area, 0, 0) self._about_panel_visible = False def toolbar_expanded(self): if self.activity_button.is_expanded(): return True elif self.edit_toolbar_button.is_expanded(): return True elif self.view_toolbar_button.is_expanded(): return True return False def get_activity_version(self): info_path = os.path.join(self.bundle_path, 'activity', 'activity.info') try: info_file = open(info_path, 'r') except Exception as e: _logger.error('Could not open %s: %s' % (info_path, e)) return 'unknown' cp = ConfigParser() cp.readfp(info_file) section = 'Activity' if cp.has_option(section, 'activity_version'): activity_version = cp.get(section, 'activity_version') else: activity_version = 'unknown' return activity_version def get_uid(self): if len(self.volume_data) == 1: return self.volume_data[0]['uid'] else: return 'unknown' def _setup_toolbars(self): ''' Setup the toolbars. ''' self._toolbox = ToolbarBox() self.activity_button = ActivityToolbarButton(self) self.activity_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.activity_button, 0) self.activity_button.show() self.set_toolbar_box(self._toolbox) self._toolbox.show() self.toolbar = self._toolbox.toolbar view_toolbar = Gtk.Toolbar() self.view_toolbar_button = ToolbarButton( page=view_toolbar, label=_('View'), icon_name='toolbar-view') self.view_toolbar_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.view_toolbar_button, 1) view_toolbar.show() self.view_toolbar_button.show() button = ToolButton('view-fullscreen') button.set_tooltip(_('Fullscreen')) button.props.accelerator = '<Alt>Return' view_toolbar.insert(button, -1) button.show() button.connect('clicked', self._fullscreen_cb) edit_toolbar = Gtk.Toolbar() self.edit_toolbar_button = ToolbarButton( page=edit_toolbar, label=_('Edit'), icon_name='toolbar-edit') self.edit_toolbar_button.connect('clicked', self._resize_canvas) self._toolbox.toolbar.insert(self.edit_toolbar_button, 1) edit_toolbar.show() self.edit_toolbar_button.show() self._copy_button = ToolButton('edit-copy') self._copy_button.set_tooltip(_('Copy')) self._copy_button.props.accelerator = '<Ctrl>C' edit_toolbar.insert(self._copy_button, -1) self._copy_button.show() self._copy_button.connect('clicked', self._copy_cb) self._copy_button.set_sensitive(False) self._paste_button = ToolButton('edit-paste') self._paste_button.set_tooltip(_('Paste')) self._paste_button.props.accelerator = '<Ctrl>V' edit_toolbar.insert(self._paste_button, -1) self._paste_button.show() self._paste_button.connect('clicked', self._paste_cb) self._paste_button.set_sensitive(False) button = ToolButton('list-add') button.set_tooltip(_('Add Item')) button.props.accelerator = '<Ctrl>+' self._toolbox.toolbar.insert(button, -1) button.show() button.connect('clicked', self.__add_item_cb) self._date_button = RadioToolButton('date-sort', group=None) self._date_button.set_tooltip(_('Sort by Date')) self._date_button.connect('clicked', self._date_button_cb) self._toolbox.toolbar.insert(self._date_button, -1) self._date_button.show() self._title_button = RadioToolButton('title-sort', group=self._date_button) self._title_button.set_tooltip(_('Sort by Title')) self._title_button.connect('clicked', self._title_button_cb) self._toolbox.toolbar.insert(self._title_button, -1) self._title_button.show() self._stars_button = RadioToolButton('stars-sort', group=self._date_button) self._stars_button.set_tooltip(_('Sort by Favourite')) self._stars_button.connect('clicked', self._stars_button_cb) self._toolbox.toolbar.insert(self._stars_button, -1) self._stars_button.show() # setup the search options self._search_entry = iconentry.IconEntry() self._search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY, 'system-search') self._search_entry.connect('activate', self._search_entry_activated_cb) self._search_entry.connect('changed', self._search_entry_changed_cb) self._search_entry.add_clear_button() tool_item = Gtk.ToolItem() tool_item.set_expand(True) tool_item.add(self._search_entry) self._search_entry.show() self._toolbox.toolbar.insert(tool_item, -1) tool_item.show() self._search_button = ToolButton('dialog-ok') self._search_button.set_tooltip(_('Search by Tags')) self._search_button.connect('clicked', self._search_button_cb) self._toolbox.toolbar.insert(self._search_button, -1) self._search_button.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) self._toolbox.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' self._toolbox.toolbar.insert(stop_button, -1) stop_button.show() def _search_button_cb(self, button): self.busy_cursor() self._do_search() def _search_entry_activated_cb(self, entry): self.busy_cursor() self._do_search() def _do_search(self): logging.debug('_search_entry_activated_cb') if self._search_entry.props.text == '': logging.debug('clearing search') for item in self.reflection_data: item['hidden'] = False else: tags = self._search_entry.props.text.split() for i, tag in enumerate(tags): if not tag[0] == '#': tags[i] = '#%s' % tag logging.error(tags) for item in self.reflection_data: hidden = True if 'tags' in item: for tag in tags: if tag in item['tags']: hidden = False item['hidden'] = hidden self.reload_data(self.reflection_data) self.reset_cursor() def _search_entry_changed_cb(self, entry): logging.debug('_search_entry_changed_cb search for \'%s\'', self._search_entry.props.text) self.busy_cursor() self._do_search_changed() def _do_search_changed(self): if self._search_entry.props.text == '': logging.debug('clearing search') for item in self.reflection_data: item['hidden'] = False self.reload_data(self.reflection_data) self.reset_cursor() def _title_button_cb(self, button): ''' sort by title ''' self.busy_cursor() GObject.idle_add(self._title_sort) def _title_sort(self): sorted_data = sorted(self.reflection_data, key=lambda item: item['title'].lower()) self.reload_data(sorted_data) self.reset_cursor() def _date_button_cb(self, button): ''' sort by modification date ''' self.busy_cursor() GObject.idle_add(self._date_sort) def _date_sort(self): sorted_data = sorted(self.reflection_data, key=lambda item: int(item['modification_time']), reverse=True) self.reload_data(sorted_data) self.reset_cursor() def _stars_button_cb(self, button): ''' sort by number of stars ''' self.busy_cursor() GObject.idle_add(self._stars_sort) def _stars_sort(self): sorted_data = sorted(self.reflection_data, key=lambda item: item['stars'], reverse=True) self.reload_data(sorted_data) self.reset_cursor() def __realize_cb(self, window): self.window_xid = window.get_window().get_xid() def set_copy_widget(self, webkit=None, text_entry=None): # Each task is responsible for setting a widget for copy if webkit is not None: self._webkit = webkit else: self._webkit = None if text_entry is not None: self._copy_entry = text_entry else: self._copy_entry = None self._copy_button.set_sensitive(webkit is not None or text_entry is not None) def _copy_cb(self, button): if self._copy_entry is not None: self._copy_entry.copy_clipboard() elif self._webkit is not None: self._webkit.copy_clipboard() else: _logger.debug('No widget set for copy.') def set_paste_widget(self, text_entry=None): # Each task is responsible for setting a widget for paste if text_entry is not None: self._paste_entry = text_entry self._paste_button.set_sensitive(text_entry is not None) def _paste_cb(self, button): clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.clipboard_text = clipboard.wait_for_text() if self._paste_entry is not None: self._paste_entry.paste_clipboard() else: _logger.debug('No widget set for paste (%s).' % self.clipboard_text) def _fullscreen_cb(self, button): ''' Hide the Sugar toolbars. ''' self.fullscreen() def __add_item_cb(self, button): try: chooser = ObjectChooser(parent=self, what_filter=None) except TypeError: chooser = ObjectChooser( None, self._reflection.activity, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT) try: result = chooser.run() if result == Gtk.ResponseType.ACCEPT: jobject = chooser.get_selected_object() if jobject: self._add_new_from_journal(jobject) self.reload_data(self.reflection_data) finally: chooser.destroy() del chooser def _set_scroll_policy(self): if Gdk.Screen.width() < Gdk.Screen.height(): self._scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) else: self._scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) def _remove_alert_cb(self, alert, response_id): self.remove_alert(alert) def _close_alert_cb(self, alert, response_id): self.remove_alert(alert) if response_id is Gtk.ResponseType.OK: self.close() def _setup_presence_service(self): ''' Setup the Presence Service. ''' self.pservice = presenceservice.get_instance() owner = self.pservice.get_owner() self.owner = owner self._share = '' self.connect('shared', self._shared_cb) self.connect('joined', self._joined_cb) def _shared_cb(self, activity): ''' Either set up initial share...''' if self.shared_activity is None: _logger.error('Failed to share or join activity ... \ shared_activity is null in _shared_cb()') return self.initiating = True self._waiting_for_reflections = 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.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal( 'NewTube', self._new_tube_cb) _logger.debug('This is my activity: making a tube...') self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( SERVICE, {}) self.sharing = True def _joined_cb(self, activity): ''' ...or join an exisiting share. ''' if self.shared_activity is None: _logger.error('Failed to share or join activity ... \ shared_activity is null in _shared_cb()') return if self._joined_alert is not None: self.remove_alert(self._joined_alert) self._joined_alert = None self.initiating = False self._waiting_for_reflections = True _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.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal( 'NewTube', self._new_tube_cb) _logger.debug('I am joining an activity: waiting for a tube...') self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb) self.sharing = True def _list_tubes_reply_cb(self, tubes): ''' Reply to a list request. ''' for tube_info in tubes: self._new_tube_cb(*tube_info) def _list_tubes_error_cb(self, e): ''' Log errors. ''' _logger.error('ListTubes() failed: %s', e) def _new_tube_cb(self, id, initiator, type, service, params, state): ''' Create a new tube. ''' _logger.debug('New tube: ID=%d initator=%d type=%d service=%s ' 'params=%r state=%d', id, initiator, type, service, params, state) if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE): if state == telepathy.TUBE_STATE_LOCAL_PENDING: self.tubes_chan[ telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id) self.collab = CollabWrapper(self) self.collab.message.connect(self.event_received_cb) self.collab.setup() if self._waiting_for_reflections: self.send_event(JOIN_CMD, {}) self._joined_alert = Alert() self._joined_alert.props.title = _('Please wait') self._joined_alert.props.msg = _('Requesting reflections...') self.add_alert(self._joined_alert) def event_received_cb(self, collab, buddy, msg): ''' Data is passed as tuples: cmd:text ''' command = msg.get("command") payload = msg.get("payload") logging.debug(command) if command == JOIN_CMD: # Sharer needs to send reflections database to joiners. if self.initiating: # Send pictures first. for item in self.reflection_data: if 'content' in item: for content in item['content']: if 'image' in content: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size( content['image'], 120, 90) if pixbuf is not None: data = utils.pixbuf_to_base64(pixbuf) self.send_event(PICTURE_CMD, {"image": os.path.basename(content['image']), "data": data}) data = json.dumps(self.reflection_data) self.send_event(SHARE_CMD, {"data": data}) elif command == NEW_REFLECTION_CMD: self._reflect_window.add_new_reflection(payload) elif command == TITLE_CMD: obj_id = payload.get("obj_id") title = payload.get("title") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True self._reflect_window.update_title(obj_id, title) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == TAG_CMD: obj_id = payload.get("obj_id") data = payload.get("data") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True self._reflect_window.update_tags(obj_id, data) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == ACTIVITY_CMD: obj_id = payload.get("obj_id") bundle_id = payload.get("bundle_id") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True self._reflect_window.insert_activity(obj_id, bundle_id) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == STAR_CMD: obj_id = payload.get("obj_id") stars = payload.get("stars") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True self._reflect_window.update_stars(obj_id, int(stars)) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == COMMENT_CMD: found_the_object = False # Receive a comment and associated reflection ID obj_id = payload.get("obj_id") nick = payload.get("nick") color = payload.get("color") comment = payload.get("comment") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True if not 'comments' in item: item['comments'] = [] data = {'nick': nick, 'comment': comment, 'color': color} item['comments'].append(data) self._reflect_window.insert_comment(obj_id, data) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == REFLECTION_CMD: found_the_object = False # Receive a reflection and associated reflection ID obj_id = payload.get("obj_id") reflection = payload.get("reflection") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True if not '' in item: item['content'] = [] item['content'].append({'text': reflection}) self._reflect_window.insert_reflection(obj_id, reflection) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == IMAGE_REFLECTION_CMD: found_the_object = False # Receive a picture reflection and associated reflection ID obj_id = payload.get("obj_id") basename = payload.get("basename") for item in self.reflection_data: if item['obj_id'] == obj_id: found_the_object = True if not '' in item: item['content'] = [] item['content'].append( {'image': os.path.join(self.tmp_path, basename)}) self._reflect_window.insert_picture( obj_id, os.path.join(self.tmp_path, basename)) break if not found_the_object: logging.error('Could not find obj_id %s' % obj_id) elif command == PICTURE_CMD: # Receive a picture (MAYBE DISPLAY IT AS IT ARRIVES?) basename = payload.get("basename") data = payload.get("data") utils.base64_to_file(data, os.path.join(self.tmp_path, basename)) elif command == SHARE_CMD: # Joiner needs to load reflection database. if not self.initiating: # Note that pictures should be received. self.reflection_data = payload self._reflect_window.load(self.reflection_data) self._waiting_for_reflections = False self.reset_cursor() if self._joined_alert is not None: self.remove_alert(self._joined_alert) self._joined_alert = None def send_event(self, command, data): ''' Send event through the tube. ''' if hasattr(self, 'collab') and self.collab is not None: data["command"] = command self.collab.post(data)
class FractionBounceActivity(activity.Activity): def __init__(self, handle): ''' Initiate activity. ''' super(FractionBounceActivity, self).__init__(handle) self.nick = profile.get_nick_name() if profile.get_color() is not None: self._colors = profile.get_color().to_string().split(',') else: self._colors = ['#A0FFA0', '#FF8080'] self.max_participants = 4 # sharing self._playing = True self._setup_toolbars() self._setup_dispatch_table() canvas = self._setup_canvas() # Read any custom fractions from the project metadata if 'custom' in self.metadata: custom = self.metadata['custom'] else: custom = None self._current_ball = 'soccerball' self._toolbar_was_expanded = False # Initialize the canvas self._bounce_window = Bounce(canvas, activity.get_bundle_path(), self) Gdk.Screen.get_default().connect('size-changed', self._configure_cb) # Restore any custom fractions if custom is not None: fractions = custom.split(',') for f in fractions: self._bounce_window.add_fraction(f) if self.shared_activity: # We're joining if not self.get_shared(): xocolors = XoColor(profile.get_color().to_string()) share_icon = Icon(icon_name='zoom-neighborhood', xo_color=xocolors) self._joined_alert = NotifyAlert() self._joined_alert.props.icon = share_icon self._joined_alert.props.title = _('Please wait') self._joined_alert.props.msg = _('Starting connection...') self._joined_alert.connect('response', self._alert_cancel_cb) self.add_alert(self._joined_alert) self._label.set_label(_('Wait for the sharer to start.')) # Wait for joined signal self.connect("joined", self._joined_cb) self._setup_sharing() def _configure_cb(self, event): if Gdk.Screen.width() < 1024: self._label.set_size_request(275, -1) self._label.set_label('') self._separator.set_expand(False) else: self._label.set_size_request(500, -1) self._separator.set_expand(True) self._bounce_window.configure_cb(event) if self._toolbar_expanded(): self._bounce_window.bar.bump_bars('up') self._bounce_window.ball.ball.move_relative( (0, -style.GRID_CELL_SIZE)) def _toolbar_expanded(self): if self._activity_button.is_expanded(): return True elif self._custom_toolbar_button.is_expanded(): return True return False def _update_graphics(self, widget): # We need to catch opening and closing of toolbars and ignore # switching between open toolbars. if self._toolbar_expanded(): if not self._toolbar_was_expanded: self._bounce_window.bar.bump_bars('up') self._bounce_window.ball.ball.move_relative( (0, -style.GRID_CELL_SIZE)) self._toolbar_was_expanded = True else: if self._toolbar_was_expanded: self._bounce_window.bar.bump_bars('down') self._bounce_window.ball.ball.move_relative( (0, style.GRID_CELL_SIZE)) self._toolbar_was_expanded = False def _setup_toolbars(self): custom_toolbar = Gtk.Toolbar() toolbox = ToolbarBox() self._toolbar = toolbox.toolbar self._activity_button = ActivityToolbarButton(self) self._activity_button.connect('clicked', self._update_graphics) self._toolbar.insert(self._activity_button, 0) self._activity_button.show() self._custom_toolbar_button = ToolbarButton(label=_('Custom'), page=custom_toolbar, icon_name='view-source') self._custom_toolbar_button.connect('clicked', self._update_graphics) custom_toolbar.show() self._toolbar.insert(self._custom_toolbar_button, -1) self._custom_toolbar_button.show() self._load_standard_buttons(self._toolbar) self._separator = Gtk.SeparatorToolItem() self._separator.props.draw = False self._separator.set_expand(True) self._toolbar.insert(self._separator, -1) self._separator.show() stop_button = StopButton(self) stop_button.props.accelerator = _('<Ctrl>Q') self._toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbox) toolbox.show() self._load_custom_buttons(custom_toolbar) def _load_standard_buttons(self, toolbar): fraction_button = RadioToolButton(group=None) fraction_button.set_icon_name('fraction') fraction_button.set_tooltip(_('fractions')) fraction_button.connect('clicked', self._fraction_cb) toolbar.insert(fraction_button, -1) fraction_button.show() sector_button = RadioToolButton(group=fraction_button) sector_button.set_icon_name('sector') sector_button.set_tooltip(_('sectors')) sector_button.connect('clicked', self._sector_cb) toolbar.insert(sector_button, -1) sector_button.show() percent_button = RadioToolButton(group=fraction_button) percent_button.set_icon_name('percent') percent_button.set_tooltip(_('percents')) percent_button.connect('clicked', self._percent_cb) toolbar.insert(percent_button, -1) percent_button.show() self._player = Gtk.Image() self._player.set_from_pixbuf( svg_str_to_pixbuf( generate_xo_svg(scale=0.8, colors=['#282828', '#282828']))) self._player.set_tooltip_text(self.nick) toolitem = Gtk.ToolItem() toolitem.add(self._player) self._player.show() toolbar.insert(toolitem, -1) toolitem.show() self._label = Gtk.Label(_("Click the ball to start.")) self._label.set_line_wrap(True) if Gdk.Screen.width() < 1024: self._label.set_size_request(275, -1) else: self._label.set_size_request(500, -1) self.toolitem = Gtk.ToolItem() self.toolitem.add(self._label) self._label.show() toolbar.insert(self.toolitem, -1) self.toolitem.show() def _load_custom_buttons(self, toolbar): self.numerator = Gtk.Entry() self.numerator.set_text('') self.numerator.set_tooltip_text(_('numerator')) self.numerator.set_width_chars(3) toolitem = Gtk.ToolItem() toolitem.add(self.numerator) self.numerator.show() toolbar.insert(toolitem, -1) toolitem.show() label = Gtk.Label(' / ') toolitem = Gtk.ToolItem() toolitem.add(label) label.show() toolbar.insert(toolitem, -1) toolitem.show() self.denominator = Gtk.Entry() self.denominator.set_text('') self.denominator.set_tooltip_text(_('denominator')) self.denominator.set_width_chars(3) toolitem = Gtk.ToolItem() toolitem.add(self.denominator) self.denominator.show() toolbar.insert(toolitem, -1) toolitem.show() button = ToolButton('list-add') button.set_tooltip(_('add new fraction')) button.props.sensitive = True button.props.accelerator = 'Return' button.connect('clicked', self._add_fraction_cb) toolbar.insert(button, -1) button.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(False) toolbar.insert(separator, -1) separator.show() button = ToolButton('soccerball') button.set_tooltip(_('choose a ball')) button.props.sensitive = True button.connect('clicked', self._button_palette_cb) toolbar.insert(button, -1) button.show() self._ball_palette = button.get_palette() button_grid = Gtk.Grid() row = 0 for ball in BALLDICT.keys(): if ball == 'custom': button = ToolButton('view-source') else: button = ToolButton(ball) button.connect('clicked', self._load_ball_cb, None, ball) eventbox = Gtk.EventBox() eventbox.connect('button_press_event', self._load_ball_cb, ball) label = Gtk.Label(BALLDICT[ball][0]) eventbox.add(label) label.show() button_grid.attach(button, 0, row, 1, 1) button.show() button_grid.attach(eventbox, 1, row, 1, 1) eventbox.show() row += 1 self._ball_palette.set_content(button_grid) button_grid.show() button = ToolButton('insert-picture') button.set_tooltip(_('choose a background')) button.props.sensitive = True button.connect('clicked', self._button_palette_cb) toolbar.insert(button, -1) button.show() self._bg_palette = button.get_palette() button_grid = Gtk.Grid() row = 0 for bg in BGDICT.keys(): if bg == 'custom': button = ToolButton('view-source') else: button = ToolButton(bg) button.connect('clicked', self._load_bg_cb, None, bg) eventbox = Gtk.EventBox() eventbox.connect('button_press_event', self._load_bg_cb, bg) label = Gtk.Label(BGDICT[bg][0]) eventbox.add(label) label.show() button_grid.attach(button, 0, row, 1, 1) button.show() button_grid.attach(eventbox, 1, row, 1, 1) eventbox.show() row += 1 self._bg_palette.set_content(button_grid) button_grid.show() def _button_palette_cb(self, button): palette = button.get_palette() if palette: if not palette.is_up(): palette.popup(immediate=True, state=palette.SECONDARY) else: palette.popdown(immediate=True) def can_close(self): # Let everyone know we are leaving... if hasattr(self, '_bounce_window') and \ self._bounce_window.we_are_sharing(): self._playing = False self.send_event('l|%s' % (json_dump([self.nick]))) return True def _setup_canvas(self): canvas = Gtk.DrawingArea() canvas.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self.set_canvas(canvas) canvas.show() return canvas def _load_bg_cb(self, widget, event, bg): if bg == 'custom': chooser(self, 'Image', self._new_background_from_journal) else: self._bounce_window.set_background(BGDICT[bg][1]) def _load_ball_cb(self, widget, event, ball): if ball == 'custom': chooser(self, 'Image', self._new_ball_from_journal) else: self._bounce_window.ball.new_ball( os.path.join(activity.get_bundle_path(), 'images', ball + '.svg')) self._bounce_window.set_background(BGDICT[BALLDICT[ball][1]][1]) self._current_ball = ball def _reset_ball(self): ''' If we switch back from sector mode, we need to restore the ball ''' if self._bounce_window.mode != 'sectors': return if self._current_ball == 'custom': # TODO: Reload custom ball self._current_ball = 'soccerball' self._bounce_window.ball.new_ball( os.path.join(activity.get_bundle_path(), 'images', self._current_ball + '.svg')) def _new_ball_from_journal(self, dsobject): ''' Load an image from the Journal. ''' self._bounce_window.ball.new_ball_from_image( dsobject.file_path, os.path.join(activity.get_activity_root(), 'tmp', 'custom.png')) def _new_background_from_journal(self, dsobject): ''' Load an image from the Journal. ''' self._bounce_window.new_background_from_image(None, dsobject=dsobject) def _fraction_cb(self, arg=None): ''' Set fraction mode ''' self._reset_ball() self._bounce_window.mode = 'fractions' def _percent_cb(self, arg=None): ''' Set percent mode ''' self._reset_ball() self._bounce_window.mode = 'percents' def _sector_cb(self, arg=None): ''' Set sector mode ''' self._bounce_window.mode = 'sectors' def _add_fraction_cb(self, arg=None): ''' Read entries and add a fraction to the list ''' try: numerator = int(self.numerator.get_text().strip()) except ValueError: self.numerator.set_text('NAN') numerator = 0 try: denominator = int(self.denominator.get_text().strip()) except ValueError: self.denominator.set_text('NAN') denominator = 1 if denominator == 0: self.denominator.set_text('ZDE') if numerator > denominator: numerator = 0 if numerator > 0 and denominator > 1: fraction = '%d/%d' % (numerator, denominator) self._bounce_window.add_fraction(fraction) if 'custom' in self.metadata: # Save to Journal self.metadata['custom'] = '%s,%s' % (self.metadata['custom'], fraction) else: self.metadata['custom'] = fraction self.alert( _('New fraction'), _('Your fraction, %s, has been added to the program' % (fraction))) def reset_label(self, label): ''' update the challenge label ''' self._label.set_label(label) def alert(self, title, text=None): alert = NotifyAlert(timeout=5) alert.props.title = title alert.props.msg = text self.add_alert(alert) alert.connect('response', self._alert_cancel_cb) alert.show() def _alert_cancel_cb(self, alert, response_id): self.remove_alert(alert) # Collaboration-related methods def _setup_sharing(self): ''' Setup the Presence Service. ''' self.pservice = presenceservice.get_instance() self.initiating = None # sharing (True) or joining (False) owner = self.pservice.get_owner() self.owner = owner self._bounce_window.buddies.append(self.nick) self._player_colors = [self._colors] self._player_pixbufs = [ svg_str_to_pixbuf(generate_xo_svg(scale=0.8, colors=self._colors)) ] self._share = '' self.connect('shared', self._shared_cb) self.connect('joined', self._joined_cb) def _shared_cb(self, activity): ''' Either set up initial share...''' self._new_tube_common(True) def _joined_cb(self, activity): ''' ...or join an exisiting share. ''' self._new_tube_common(False) def _new_tube_common(self, sharer): ''' Joining and sharing are mostly the same... ''' if self.shared_activity is None: _logger.debug('Error: Failed to share or join activity ... \ shared_activity is null in _shared_cb()') return self.initiating = sharer self.waiting_for_fraction = not sharer 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) if sharer: _logger.debug('This is my activity: making a tube...') id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( SERVICE, {}) self._label.set_label(_('Wait for others to join.')) else: _logger.debug('I am joining an activity: waiting for a tube...') self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb) # display your XO on the toolbar self._player.set_from_pixbuf(self._player_pixbufs[0]) def _list_tubes_reply_cb(self, tubes): ''' Reply to a list request. ''' for tube_info in tubes: self._new_tube_cb(*tube_info) def _list_tubes_error_cb(self, e): ''' Log errors. ''' _logger.debug('Error: ListTubes() failed: %s', e) def _new_tube_cb(self, id, initiator, type, service, params, state): ''' Create a new tube. ''' _logger.debug( 'Newtube: ID=%d initator=%d type=%d service=%s params=%r state=%d', id, initiator, type, service, params, state) if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE): if state == telepathy.TUBE_STATE_LOCAL_PENDING: self.tubes_chan[ \ telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id) tube_conn = TubeConnection(self.conn, self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id, \ group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP]) self.chattube = ChatTube(tube_conn, self.initiating, \ self.event_received_cb) # Let the sharer know a new joiner has arrived. if self.waiting_for_fraction: self.send_event('j|%s' % (json_dump([self.nick, self._colors]))) def _setup_dispatch_table(self): self._processing_methods = { 'j': [self._new_joiner, 'new joiner'], 'b': [self._buddy_list, 'buddy list'], 'f': [self._receive_a_fraction, 'receive a fraction'], 't': [self._take_a_turn, 'take a turn'], 'l': [self._buddy_left, 'buddy left'] } def event_received_cb(self, event_message): ''' Data from a tube has arrived. ''' if len(event_message) == 0: return try: command, payload = event_message.split('|', 2) except ValueError: _logger.debug('Could not split event message %s', event_message) return _logger.debug('received an event %s|%s', command, payload) if self._playing: self._processing_methods[command][0](payload) def _buddy_left(self, payload): [nick] = json_load(payload) self._label.set_label(nick + ' ' + _('has left.')) if self.initiating: self._remove_player(nick) payload = json_dump( [self._bounce_window.buddies, self._player_colors]) self.send_event('b|%s' % (payload)) # Restart from sharer's turn self._bounce_window.its_my_turn() def _new_joiner(self, payload): ''' Someone has joined; sharer adds them to the buddy list. ''' [nick, colors] = json_load(payload) self._label.set_label(nick + ' ' + _('has joined.')) if self.initiating: self._append_player(nick, colors) payload = json_dump( [self._bounce_window.buddies, self._player_colors]) self.send_event('b|%s' % (payload)) if self._bounce_window.count == 0: # Haven't started yet... self._bounce_window.its_my_turn() def _remove_player(self, nick): if nick in self._bounce_window.buddies: i = self._bounce_window.buddies.index(nick) self._bounce_window.buddies.remove(nick) self._player_colors.remove(self._player_colors[i]) self._player_pixbufs.remove(self._player_pixbufs[i]) def _append_player(self, nick, colors): ''' Keep a list of players, their colors, and an XO pixbuf ''' if not nick in self._bounce_window.buddies: _logger.debug('appending %s to the buddy list', nick) self._bounce_window.buddies.append(nick) self._player_colors.append([str(colors[0]), str(colors[1])]) self._player_pixbufs.append( svg_str_to_pixbuf( generate_xo_svg(scale=0.8, colors=self._player_colors[-1]))) def _buddy_list(self, payload): '''Sharer sent the updated buddy list, so regenerate internal lists''' if not self.initiating: [buddies, colors] = json_load(payload) self._bounce_window.buddies = buddies[:] self._player_colors = colors[:] self._player_pixbufs = [] for colors in self._player_colors: self._player_pixbufs.append( svg_str_to_pixbuf( generate_xo_svg( scale=0.8, colors=[str(colors[0]), str(colors[1])]))) def send_a_fraction(self, fraction): ''' Send a fraction to other players. ''' payload = json_dump(fraction) self.send_event('f|%s' % (payload)) def _receive_a_fraction(self, payload): ''' Receive a fraction from another player. ''' fraction = json_load(payload) self._bounce_window.play_a_fraction(fraction) def _take_a_turn(self, nick): ''' If it is your turn, take it, otherwise, wait. ''' if nick == self.nick: self._bounce_window.its_my_turn() else: self._bounce_window.its_their_turn(nick) def send_event(self, entry): ''' Send event through the tube. ''' _logger.debug('sending event: %s', entry) if hasattr(self, 'chattube') and self.chattube is not None: self.chattube.SendText(entry) def set_player_on_toolbar(self, nick): ''' Display the XO icon of the player whose turn it is. ''' self._player.set_from_pixbuf( self._player_pixbufs[self._bounce_window.buddies.index(nick)]) self._player.set_tooltip_text(nick)
class AbiWordActivity(activity.Activity): def __init__(self, handle): activity.Activity.__init__(self, handle) # abiword uses the current directory for all its file dialogs os.chdir(os.path.expanduser('~')) # create our main abiword canvas self.abiword_canvas = DocumentView() self._new_instance = True toolbar_box = ToolbarBox() self.activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(self.activity_button, -1) separator = Gtk.SeparatorToolItem() separator.show() self.activity_button.props.page.insert(separator, 2) ExportButtonFactory(self, self.abiword_canvas) self.activity_button.show() edit_toolbar = ToolbarButton() edit_toolbar.props.page = EditToolbar(self, toolbar_box) edit_toolbar.props.icon_name = 'toolbar-edit' edit_toolbar.props.label = _('Edit') toolbar_box.toolbar.insert(edit_toolbar, -1) view_toolbar = ToolbarButton() view_toolbar.props.page = ViewToolbar(self.abiword_canvas) view_toolbar.props.icon_name = 'toolbar-view' view_toolbar.props.label = _('View') toolbar_box.toolbar.insert(view_toolbar, -1) # due to http://bugzilla.abisource.com/show_bug.cgi?id=13585 if self.abiword_canvas.get_version() != '3.0': self.speech_toolbar_button = ToolbarButton(icon_name='speak') toolbar_box.toolbar.insert(self.speech_toolbar_button, -1) self._init_speech() separator = Gtk.SeparatorToolItem() toolbar_box.toolbar.insert(separator, -1) text_toolbar = ToolbarButton() text_toolbar.props.page = TextToolbar(self.abiword_canvas) text_toolbar.props.icon_name = 'format-text' text_toolbar.props.label = _('Text') toolbar_box.toolbar.insert(text_toolbar, -1) para_toolbar = ToolbarButton() para_toolbar.props.page = ParagraphToolbar(self.abiword_canvas) para_toolbar.props.icon_name = 'paragraph-bar' para_toolbar.props.label = _('Paragraph') toolbar_box.toolbar.insert(para_toolbar, -1) insert_toolbar = ToolbarButton() insert_toolbar.props.page = InsertToolbar(self.abiword_canvas) insert_toolbar.props.icon_name = 'insert-table' insert_toolbar.props.label = _('Table') toolbar_box.toolbar.insert(insert_toolbar, -1) image = ToolButton('insert-picture') image.set_tooltip(_('Insert Image')) self._image_id = image.connect('clicked', self._image_cb) toolbar_box.toolbar.insert(image, -1) palette = image.get_palette() content_box = Gtk.VBox() palette.set_content(content_box) image_floating_checkbutton = Gtk.CheckButton(_('Floating')) image_floating_checkbutton.connect( 'toggled', self._image_floating_checkbutton_toggled_cb) content_box.pack_start(image_floating_checkbutton, True, True, 0) content_box.show_all() self.floating_image = False separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_size_request(0, -1) separator.set_expand(True) separator.show() toolbar_box.toolbar.insert(separator, -1) stop = StopButton(self) toolbar_box.toolbar.insert(stop, -1) toolbar_box.show_all() self.set_toolbar_box(toolbar_box) # add a overlay to be able to show a icon while joining a shared doc overlay = Gtk.Overlay() overlay.add(self.abiword_canvas) overlay.show() self._connecting_box = ConnectingBox() overlay.add_overlay(self._connecting_box) self.set_canvas(overlay) # we want a nice border so we can select paragraphs easily self.abiword_canvas.set_show_margin(True) # Read default font face and size client = GConf.Client.get_default() self._default_font_face = client.get_string( '/desktop/sugar/activities/write/font_face') if not self._default_font_face: self._default_font_face = 'Sans' self._default_font_size = client.get_int( '/desktop/sugar/activities/write/font_size') if self._default_font_size == 0: self._default_font_size = 12 # activity sharing self.participants = {} self.joined = False self.connect('shared', self._shared_cb) if self.shared_activity: # we are joining the activity logger.error('We are joining an activity') # display a icon while joining self._connecting_box.show() # disable the abi widget self.abiword_canvas.set_sensitive(False) self._new_instance = False self.connect('joined', self._joined_cb) self.shared_activity.connect('buddy-joined', self._buddy_joined_cb) self.shared_activity.connect('buddy-left', self._buddy_left_cb) if self.get_shared(): self._joined_cb(self) else: # we are creating the activity logger.error("We are creating an activity") self.abiword_canvas.zoom_width() self.abiword_canvas.show() self.connect_after('map-event', self.__map_activity_event_cb) self.abiword_canvas.connect('size-allocate', self.size_allocate_cb) def _init_speech(self): import speech from speechtoolbar import SpeechToolbar if speech.supported: self.speech_toolbar = SpeechToolbar(self) self.speech_toolbar_button.set_page(self.speech_toolbar) self.speech_toolbar_button.show() def size_allocate_cb(self, abi, alloc): GObject.idle_add(abi.queue_draw) def __map_activity_event_cb(self, event, activity): # set custom keybindings for Write # we do it later because have problems if done before - OLPC #11049 logger.error('Loading keybindings') keybindings_file = os.path.join(get_bundle_path(), 'keybindings.xml') self.abiword_canvas.invoke_ex( 'com.abisource.abiword.loadbindings.fromURI', keybindings_file, 0, 0) # set default font if self._new_instance: self.abiword_canvas.select_all() logging.error('Setting default font to %s %d in new documents', self._default_font_face, self._default_font_size) self.abiword_canvas.set_font_name(self._default_font_face) self.abiword_canvas.set_font_size(str(self._default_font_size)) self.abiword_canvas.moveto_bod() self.abiword_canvas.select_bod() if hasattr(self.abiword_canvas, 'toggle_rulers'): # this is not available yet on upstream abiword self.abiword_canvas.view_print_layout() self.abiword_canvas.toggle_rulers(False) self.abiword_canvas.grab_focus() def get_preview(self): if not hasattr(self.abiword_canvas, 'render_page_to_image'): return activity.Activity.get_preview(self) from gi.repository import GdkPixbuf pixbuf = self.abiword_canvas.render_page_to_image(1) pixbuf = pixbuf.scale_simple(style.zoom(300), style.zoom(225), GdkPixbuf.InterpType.BILINEAR) preview_data = [] def save_func(buf, lenght, data): data.append(buf) return True pixbuf.save_to_callbackv(save_func, preview_data, 'png', [], []) preview_data = ''.join(preview_data) return preview_data def _shared_cb(self, activity): logger.error('My Write activity was shared') self._sharing_setup() self.shared_activity.connect('buddy-joined', self._buddy_joined_cb) self.shared_activity.connect('buddy-left', self._buddy_left_cb) channel = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES] logger.error('This is my activity: offering a tube...') id = channel.OfferDBusTube('com.abisource.abiword.abicollab', {}) logger.error('Tube address: %s', channel.GetDBusTubeAddress(id)) def _sharing_setup(self): logger.debug("_sharing_setup()") if self.shared_activity is None: logger.error('Failed to share or join activity') return 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.tube_id = None self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal( 'NewTube', self._new_tube_cb) def _list_tubes_reply_cb(self, tubes): for tube_info in tubes: self._new_tube_cb(*tube_info) def _list_tubes_error_cb(self, e): logger.error('ListTubes() failed: %s', e) def _joined_cb(self, activity): logger.error("_joined_cb()") if not self.shared_activity: self._enable_collaboration() return self.joined = True logger.error('Joined an existing Write session') self._sharing_setup() logger.error('This is not my activity: waiting for a tube...') self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb) self._enable_collaboration() def _enable_collaboration(self): """ when communication established, hide the download icon and enable the abi widget """ self.abiword_canvas.zoom_width() self.abiword_canvas.set_sensitive(True) self._connecting_box.hide() def _new_tube_cb(self, id, initiator, type, service, params, state): logger.error('New tube: ID=%d initiator=%d type=%d service=%s ' 'params=%r state=%d', id, initiator, type, service, params, state) if self.tube_id is not None: # We are already using a tube return if type != telepathy.TUBE_TYPE_DBUS or \ service != "com.abisource.abiword.abicollab": return channel = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES] if state == telepathy.TUBE_STATE_LOCAL_PENDING: channel.AcceptDBusTube(id) # look for the initiator's D-Bus unique name initiator_dbus_name = None dbus_names = channel.GetDBusNames(id) for handle, name in dbus_names: if handle == initiator: logger.error('found initiator D-Bus name: %s', name) initiator_dbus_name = name break if initiator_dbus_name is None: logger.error('Unable to get the D-Bus name of the tube initiator') return cmd_prefix = 'com.abisource.abiword.abicollab.olpc.' # pass this tube to abicollab address = channel.GetDBusTubeAddress(id) if self.joined: logger.error('Passing tube address to abicollab (join): %s', address) self.abiword_canvas.invoke_ex(cmd_prefix + 'joinTube', address, 0, 0) # The intiator of the session has to be the first passed # to the Abicollab backend. logger.error('Adding the initiator to the session: %s', initiator_dbus_name) self.abiword_canvas.invoke_ex(cmd_prefix + 'buddyJoined', initiator_dbus_name, 0, 0) else: logger.error('Passing tube address to abicollab (offer): %s', address) self.abiword_canvas.invoke_ex(cmd_prefix + 'offerTube', address, 0, 0) self.tube_id = id channel.connect_to_signal('DBusNamesChanged', self._on_dbus_names_changed) self._on_dbus_names_changed(id, dbus_names, []) def _on_dbus_names_changed(self, tube_id, added, removed): """ We call com.abisource.abiword.abicollab.olpc.buddy{Joined,Left} according members of the D-Bus tube. That's why we don't add/remove buddies in _buddy_{joined,left}_cb. """ logger.error('_on_dbus_names_changed') # if tube_id == self.tube_id: cmd_prefix = 'com.abisource.abiword.abicollab.olpc' for handle, bus_name in added: logger.error('added handle: %s, with dbus_name: %s', handle, bus_name) self.abiword_canvas.invoke_ex(cmd_prefix + '.buddyJoined', bus_name, 0, 0) self.participants[handle] = bus_name def _on_members_changed(self, message, added, removed, local_pending, remote_pending, actor, reason): logger.error("_on_members_changed") for handle in removed: bus_name = self.participants.pop(handle, None) if bus_name is None: # FIXME: that shouldn't happen so probably hide another bug. # Should be investigated continue cmd_prefix = 'com.abisource.abiword.abicollab.olpc' logger.error('removed handle: %d, with dbus name: %s', handle, bus_name) self.abiword_canvas.invoke_ex(cmd_prefix + '.buddyLeft', bus_name, 0, 0) def _buddy_joined_cb(self, activity, buddy): logger.error('buddy joined with object path: %s', buddy.object_path()) def _buddy_left_cb(self, activity, buddy): logger.error('buddy left with object path: %s', buddy.object_path()) def read_file(self, file_path): logging.debug('AbiWordActivity.read_file: %s, mimetype: %s', file_path, self.metadata['mime_type']) if self._is_plain_text(self.metadata['mime_type']): self.abiword_canvas.load_file('file://' + file_path, 'text/plain') else: # we pass no mime/file type, let libabiword autodetect it, # so we can handle multiple file formats self.abiword_canvas.load_file('file://' + file_path, '') self.abiword_canvas.zoom_width() self._new_instance = False def write_file(self, file_path): logging.debug('AbiWordActivity.write_file: %s, mimetype: %s', file_path, self.metadata['mime_type']) # if we were editing a text file save as plain text if self._is_plain_text(self.metadata['mime_type']): logger.debug('Writing file as type source (text/plain)') self.abiword_canvas.save('file://' + file_path, 'text/plain', '') else: #if the file is new, save in .odt format if self.metadata['mime_type'] == '': self.metadata['mime_type'] = 'application/rtf' # Abiword can't save in .doc format, save in .rtf instead if self.metadata['mime_type'] == 'application/msword': self.metadata['mime_type'] = 'application/rtf' self.abiword_canvas.save('file://' + file_path, self.metadata['mime_type'], '') # due to http://bugzilla.abisource.com/show_bug.cgi?id=13585 if self.abiword_canvas.get_version() != '3.0': self.metadata['fulltext'] = self.abiword_canvas.get_content( 'text/plain', None)[:3000] def _is_plain_text(self, mime_type): # These types have 'text/plain' in their mime_parents but we need # use it like rich text if mime_type in ['application/rtf', 'text/rtf', 'text/html']: return False from sugar3 import mime mime_parents = mime.get_mime_parents(self.metadata['mime_type']) return self.metadata['mime_type'] in ['text/plain', 'text/csv'] or \ 'text/plain' in mime_parents def _image_floating_checkbutton_toggled_cb(self, checkbutton): self.floating_image = checkbutton.get_active() def _image_cb(self, button): try: chooser = ObjectChooser(self, what_filter='Image', filter_type=FILTER_TYPE_GENERIC_MIME, show_preview=True) except: # for compatibility with older versions chooser = ObjectChooser(self, what_filter='Image') try: result = chooser.run() if result == Gtk.ResponseType.ACCEPT: logging.debug('ObjectChooser: %r', chooser.get_selected_object()) jobject = chooser.get_selected_object() if jobject and jobject.file_path: self.abiword_canvas.insert_image(jobject.file_path, self.floating_image) finally: chooser.destroy() del chooser
class FractionBounceActivity(activity.Activity): def __init__(self, handle): ''' Initiate activity. ''' super(FractionBounceActivity, self).__init__(handle) self.nick = profile.get_nick_name() if profile.get_color() is not None: self._colors = profile.get_color().to_string().split(',') else: self._colors = ['#A0FFA0', '#FF8080'] self.max_participants = 4 # sharing self._playing = True self._setup_toolbars() canvas = self._setup_canvas() # Read any custom fractions from the project metadata if 'custom' in self.metadata: custom = self.metadata['custom'] else: custom = None self._current_ball = 'soccerball' self._toolbar_was_expanded = False # Initialize the canvas self._bounce_window = Bounce(canvas, activity.get_bundle_path(), self) Gdk.Screen.get_default().connect('size-changed', self._configure_cb) # Restore any custom fractions if custom is not None: fractions = custom.split(',') for f in fractions: self._bounce_window.add_fraction(f) self._bounce_window.buddies.append(self.nick) self._player_colors = [self._colors] self._player_pixbufs = [ svg_str_to_pixbuf(generate_xo_svg(scale=0.8, colors=self._colors)) ] def on_activity_joined_cb(me): logging.debug('activity joined') self._player.set_from_pixbuf(self._player_pixbufs[0]) self.connect('joined', on_activity_joined_cb) def on_activity_shared_cb(me): logging.debug('activity shared') self._player.set_from_pixbuf(self._player_pixbufs[0]) self._label.set_label(_('Wait for others to join.')) self.connect('shared', on_activity_shared_cb) self._collab = CollabWrapper(self) if self.shared_activity: # We're joining if not self.get_shared(): self._label.set_label(_('Wait for the sharer to start.')) actions = { 'j': self._new_joiner, 'b': self._buddy_list, 'f': self._receive_a_fraction, 't': self._take_a_turn, 'l': self._buddy_left, } def on_message_cb(collab, buddy, msg): logging.debug('on_message_cb buddy %r msg %r' % (buddy, msg)) if self._playing: actions[msg.get('action')](msg.get('data')) self._collab.connect('message', on_message_cb) def on_joined_cb(collab, msg): logging.debug('joined') self.send_event('j', [self.nick, self._colors]) self._collab.connect('joined', on_joined_cb, 'joined') def on_buddy_joined_cb(collab, buddy, msg): logging.debug('on_buddy_joined_cb buddy %r' % (buddy.props.nick)) self._collab.connect('buddy_joined', on_buddy_joined_cb, 'buddy_joined') def on_buddy_left_cb(collab, buddy, msg): logging.debug('on_buddy_left_cb buddy %r' % (buddy.props.nick)) self._collab.connect('buddy_left', on_buddy_left_cb, 'buddy_left') self._collab.setup() def set_data(self, blob): pass def get_data(self): return None def close(self, **kwargs): aplay.close() activity.Activity.close(self, **kwargs) def _configure_cb(self, event): if Gdk.Screen.width() < 1024: self._label.set_size_request(275, -1) self._label.set_label('') self._separator.set_expand(False) else: self._label.set_size_request(500, -1) self._separator.set_expand(True) self._bounce_window.configure_cb(event) if self._toolbar_expanded(): self._bounce_window.bar.bump_bars('up') self._bounce_window.ball.ball.move_relative( (0, -style.GRID_CELL_SIZE)) def _toolbar_expanded(self): if self._activity_button.is_expanded(): return True elif self._custom_toolbar_button.is_expanded(): return True return False def _update_graphics(self, widget): # We need to catch opening and closing of toolbars and ignore # switching between open toolbars. if self._toolbar_expanded(): if not self._toolbar_was_expanded: self._bounce_window.bar.bump_bars('up') self._bounce_window.ball.ball.move_relative( (0, -style.GRID_CELL_SIZE)) self._toolbar_was_expanded = True else: if self._toolbar_was_expanded: self._bounce_window.bar.bump_bars('down') self._bounce_window.ball.ball.move_relative( (0, style.GRID_CELL_SIZE)) self._toolbar_was_expanded = False def _setup_toolbars(self): custom_toolbar = Gtk.Toolbar() toolbox = ToolbarBox() self._toolbar = toolbox.toolbar self._activity_button = ActivityToolbarButton(self) self._activity_button.connect('clicked', self._update_graphics) self._toolbar.insert(self._activity_button, 0) self._activity_button.show() self._custom_toolbar_button = ToolbarButton(label=_('Custom'), page=custom_toolbar, icon_name='view-source') self._custom_toolbar_button.connect('clicked', self._update_graphics) custom_toolbar.show() self._toolbar.insert(self._custom_toolbar_button, -1) self._custom_toolbar_button.show() self._load_standard_buttons(self._toolbar) self._separator = Gtk.SeparatorToolItem() self._separator.props.draw = False self._separator.set_expand(True) self._toolbar.insert(self._separator, -1) self._separator.show() stop_button = StopButton(self) stop_button.props.accelerator = _('<Ctrl>Q') self._toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbox) toolbox.show() self._load_custom_buttons(custom_toolbar) def _load_standard_buttons(self, toolbar): fraction_button = RadioToolButton(group=None) fraction_button.set_icon_name('fraction') fraction_button.set_tooltip(_('fractions')) fraction_button.connect('clicked', self._fraction_cb) toolbar.insert(fraction_button, -1) fraction_button.show() sector_button = RadioToolButton(group=fraction_button) sector_button.set_icon_name('sector') sector_button.set_tooltip(_('sectors')) sector_button.connect('clicked', self._sector_cb) toolbar.insert(sector_button, -1) sector_button.show() percent_button = RadioToolButton(group=fraction_button) percent_button.set_icon_name('percent') percent_button.set_tooltip(_('percents')) percent_button.connect('clicked', self._percent_cb) toolbar.insert(percent_button, -1) percent_button.show() self._player = Gtk.Image() self._player.set_from_pixbuf( svg_str_to_pixbuf( generate_xo_svg(scale=0.8, colors=['#282828', '#282828']))) self._player.set_tooltip_text(self.nick) toolitem = Gtk.ToolItem() toolitem.add(self._player) self._player.show() toolbar.insert(toolitem, -1) toolitem.show() self._label = Gtk.Label(_("Click the ball to start.")) self._label.set_line_wrap(True) if Gdk.Screen.width() < 1024: self._label.set_size_request(275, -1) else: self._label.set_size_request(500, -1) self.toolitem = Gtk.ToolItem() self.toolitem.add(self._label) self._label.show() toolbar.insert(self.toolitem, -1) self.toolitem.show() def _load_custom_buttons(self, toolbar): self.numerator = Gtk.Entry() self.numerator.set_text('') self.numerator.set_tooltip_text(_('numerator')) self.numerator.set_width_chars(3) toolitem = Gtk.ToolItem() toolitem.add(self.numerator) self.numerator.show() toolbar.insert(toolitem, -1) toolitem.show() label = Gtk.Label(' / ') toolitem = Gtk.ToolItem() toolitem.add(label) label.show() toolbar.insert(toolitem, -1) toolitem.show() self.denominator = Gtk.Entry() self.denominator.set_text('') self.denominator.set_tooltip_text(_('denominator')) self.denominator.set_width_chars(3) toolitem = Gtk.ToolItem() toolitem.add(self.denominator) self.denominator.show() toolbar.insert(toolitem, -1) toolitem.show() button = ToolButton('list-add') button.set_tooltip(_('add new fraction')) button.props.sensitive = True button.props.accelerator = 'Return' button.connect('clicked', self._add_fraction_cb) toolbar.insert(button, -1) button.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(False) toolbar.insert(separator, -1) separator.show() button = ToolButton('soccerball') button.set_tooltip(_('choose a ball')) button.props.sensitive = True button.connect('clicked', self._button_palette_cb) toolbar.insert(button, -1) button.show() self._ball_palette = button.get_palette() button_grid = Gtk.Grid() row = 0 for ball in BALLDICT.keys(): if ball == 'custom': button = ToolButton('view-source') else: button = ToolButton(ball) button.connect('clicked', self._load_ball_cb, None, ball) eventbox = Gtk.EventBox() eventbox.connect('button_press_event', self._load_ball_cb, ball) label = Gtk.Label(BALLDICT[ball][0]) eventbox.add(label) label.show() button_grid.attach(button, 0, row, 1, 1) button.show() button_grid.attach(eventbox, 1, row, 1, 1) eventbox.show() row += 1 self._ball_palette.set_content(button_grid) button_grid.show() button = ToolButton('insert-picture') button.set_tooltip(_('choose a background')) button.props.sensitive = True button.connect('clicked', self._button_palette_cb) toolbar.insert(button, -1) button.show() self._bg_palette = button.get_palette() button_grid = Gtk.Grid() row = 0 for bg in BGDICT.keys(): if bg == 'custom': button = ToolButton('view-source') else: button = ToolButton(bg) button.connect('clicked', self._load_bg_cb, None, bg) eventbox = Gtk.EventBox() eventbox.connect('button_press_event', self._load_bg_cb, bg) label = Gtk.Label(BGDICT[bg][0]) eventbox.add(label) label.show() button_grid.attach(button, 0, row, 1, 1) button.show() button_grid.attach(eventbox, 1, row, 1, 1) eventbox.show() row += 1 self._bg_palette.set_content(button_grid) button_grid.show() def _button_palette_cb(self, button): palette = button.get_palette() if palette: if not palette.is_up(): palette.popup(immediate=True) else: palette.popdown(immediate=True) def can_close(self): # Let everyone know we are leaving... if hasattr(self, '_bounce_window') and \ self._bounce_window.we_are_sharing(): self._playing = False self.send_event('l', self.nick) return True def _setup_canvas(self): canvas = Gtk.DrawingArea() canvas.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self.set_canvas(canvas) canvas.show() return canvas def _load_bg_cb(self, widget, event, bg): if bg == 'custom': chooser(self, 'Image', self._new_background_from_journal) else: self._bounce_window.set_background(BGDICT[bg][1]) def _load_ball_cb(self, widget, event, ball): if ball == 'custom': chooser(self, 'Image', self._new_ball_from_journal) else: self._bounce_window.ball.new_ball( os.path.join(activity.get_bundle_path(), 'images', ball + '.svg')) self._bounce_window.set_background(BGDICT[BALLDICT[ball][1]][1]) self._current_ball = ball def _reset_ball(self): ''' If we switch back from sector mode, we need to restore the ball ''' if self._bounce_window.mode != 'sectors': return if self._current_ball == 'custom': # TODO: Reload custom ball self._current_ball = 'soccerball' self._bounce_window.ball.new_ball( os.path.join(activity.get_bundle_path(), 'images', self._current_ball + '.svg')) def _new_ball_from_journal(self, dsobject): ''' Load an image from the Journal. ''' self._bounce_window.ball.new_ball_from_image( dsobject.file_path, os.path.join(activity.get_activity_root(), 'tmp', 'custom.png')) def _new_background_from_journal(self, dsobject): ''' Load an image from the Journal. ''' self._bounce_window.new_background_from_image(None, dsobject=dsobject) def _fraction_cb(self, arg=None): ''' Set fraction mode ''' self._reset_ball() self._bounce_window.mode = 'fractions' def _percent_cb(self, arg=None): ''' Set percent mode ''' self._reset_ball() self._bounce_window.mode = 'percents' def _sector_cb(self, arg=None): ''' Set sector mode ''' self._bounce_window.mode = 'sectors' def _add_fraction_cb(self, arg=None): ''' Read entries and add a fraction to the list ''' try: numerator = int(self.numerator.get_text().strip()) except ValueError: self.numerator.set_text('NAN') numerator = 0 try: denominator = int(self.denominator.get_text().strip()) except ValueError: self.denominator.set_text('NAN') denominator = 1 if denominator == 0: self.denominator.set_text('ZDE') if numerator > denominator: numerator = 0 if numerator > 0 and denominator > 1: fraction = '%d/%d' % (numerator, denominator) self._bounce_window.add_fraction(fraction) if 'custom' in self.metadata: # Save to Journal self.metadata['custom'] = '%s,%s' % (self.metadata['custom'], fraction) else: self.metadata['custom'] = fraction self.alert( _('New fraction'), _('Your fraction, %s, has been added to the program' % (fraction))) def reset_label(self, label): ''' update the challenge label ''' self._label.set_label(label) def alert(self, title, text=None): alert = NotifyAlert(timeout=5) alert.props.title = title alert.props.msg = text self.add_alert(alert) alert.connect('response', self._alert_cancel_cb) alert.show() def _alert_cancel_cb(self, alert, response_id): self.remove_alert(alert) # Collaboration-related methods def _buddy_left(self, nick): self._label.set_label(nick + ' ' + _('has left.')) if self._collab.props.leader: self._remove_player(nick) self.send_event('b', [self._bounce_window.buddies, self._player_colors]) # Restart from sharer's turn self._bounce_window.its_my_turn() def _new_joiner(self, payload): ''' Someone has joined; sharer adds them to the buddy list. ''' [nick, colors] = payload self._label.set_label(nick + ' ' + _('has joined.')) if self._collab.props.leader: self._append_player(nick, colors) self.send_event('b', [self._bounce_window.buddies, self._player_colors]) if self._bounce_window.count == 0: # Haven't started yet... self._bounce_window.its_my_turn() def _remove_player(self, nick): if nick in self._bounce_window.buddies: i = self._bounce_window.buddies.index(nick) self._bounce_window.buddies.remove(nick) self._player_colors.remove(self._player_colors[i]) self._player_pixbufs.remove(self._player_pixbufs[i]) def _append_player(self, nick, colors): ''' Keep a list of players, their colors, and an XO pixbuf ''' if nick not in self._bounce_window.buddies: _logger.debug('appending %s to the buddy list', nick) self._bounce_window.buddies.append(nick) self._player_colors.append([str(colors[0]), str(colors[1])]) self._player_pixbufs.append( svg_str_to_pixbuf( generate_xo_svg(scale=0.8, colors=self._player_colors[-1]))) def _buddy_list(self, payload): '''Sharer sent the updated buddy list, so regenerate internal lists''' if not self._collab.props.leader: [buddies, colors] = payload self._bounce_window.buddies = buddies[:] self._player_colors = colors[:] self._player_pixbufs = [] for colors in self._player_colors: self._player_pixbufs.append( svg_str_to_pixbuf( generate_xo_svg( scale=0.8, colors=[str(colors[0]), str(colors[1])]))) def send_a_fraction(self, fraction): ''' Send a fraction to other players. ''' self.send_event('f', fraction) def _receive_a_fraction(self, payload): ''' Receive a fraction from another player. ''' self._bounce_window.play_a_fraction(payload) def _take_a_turn(self, nick): ''' If it is your turn, take it, otherwise, wait. ''' if nick == self.nick: # TODO: disambiguate self._bounce_window.its_my_turn() else: self._bounce_window.its_their_turn(nick) def send_event(self, action, data): ''' Send event through the tube. ''' _logger.debug('send_event action=%r data=%r' % (action, data)) self._collab.post({'action': action, 'data': data}) def set_player_on_toolbar(self, nick): ''' Display the XO icon of the player whose turn it is. ''' self._player.set_from_pixbuf( self._player_pixbufs[self._bounce_window.buddies.index(nick)]) self._player.set_tooltip_text(nick)
def make_toolbar(self): # toolbar with the new toolbar redesign toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() toolbarview = Gtk.Toolbar() langtoolbar_button = ToolbarButton( label=_('Filter'), page=toolbarview, icon_name='filter') langtoolbar_button.show() toolbar_box.toolbar.insert(langtoolbar_button, -1) tool = ToolButton('grammar') tool.set_tooltip(_('Langue française')) tool.connect('clicked', self.filter_french) tool.show() toolbarview.insert(tool, -1) tool = ToolButton('calculator') tool.set_tooltip(_('Mathématiques')) tool.connect('clicked', self.filter_math) tool.show() toolbarview.insert(tool, -1) tool = ToolButton('earth') tool.set_tooltip(_('Science')) tool.connect('clicked', self.filter_science) tool.show() toolbarview.insert(tool, -1) tool = ToolButton('institution') tool.set_tooltip(_('Instruction civique et histoire géographie')) tool.connect('clicked', self.filter_civism) tool.show() toolbarview.insert(tool, -1) toolbarview.show() box_search_item = Gtk.ToolItem() self.search_entry = Gtk.Entry() self.search_entry.connect('changed', self.text_filter) self.search_entry.set_size_request(300, -1) box_search_item.add(self.search_entry) self.search_entry.show() box_search_item.show() toolbar_box.toolbar.insert(box_search_item, -1) favorite_button = ToolButton(self.favorite_status) favorite_button.set_tooltip('Filter on favorite') favorite_button.connect('clicked', self.favorite) toolbar_box.toolbar.insert(favorite_button, -1) favorite_button.show() self.favorite_button = favorite_button settings_button = ToolButton('settings') settings_button.set_tooltip('Settings') settings_button.connect('clicked', self.settings) toolbar_box.toolbar.insert(settings_button, -1) settings_button.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show()
class LogActivity(activity.Activity): def __init__(self, handle): activity.Activity.__init__(self, handle) self._autosearch_timer = None # Paths to watch: ~/.sugar/someuser/logs, /var/log paths = [] paths.append(env.get_profile_path('logs')) paths.append('/var/log') # Additional misc files. ext_files = [] ext_files.append(os.path.expanduser('~/.bash_history')) self.viewer = MultiLogView(paths, ext_files) self.set_canvas(self.viewer) self.viewer.grab_focus() self._build_toolbox() # Get Sugar's clipboard self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.show() self._configure_cb(None) Gdk.Screen.get_default().connect('size-changed', self._configure_cb) def _build_toolbox(self): toolbar_box = ToolbarBox() self.max_participants = 1 activity_button = ActivityToolbarButton(self) activity_toolbar = activity_button.page self._toolbar = toolbar_box.toolbar self._toolbar.insert(activity_button, -1) self._secondary_toolbar = Gtk.Toolbar() self._secondary_toolbar_button = ToolbarButton( page=self._secondary_toolbar, icon_name='system-search') self._secondary_toolbar.show() self._toolbar.insert(self._secondary_toolbar_button, -1) self._secondary_toolbar_button.hide() show_list = ToggleToolButton('view-list') show_list.set_active(True) show_list.set_tooltip(_('Show list of files')) show_list.connect('toggled', self._list_toggled_cb) self._toolbar.insert(show_list, -1) show_list.show() copy = CopyButton() copy.connect('clicked', self.__copy_clicked_cb) self._toolbar.insert(copy, -1) wrap_btn = ToggleToolButton("format-wrap") wrap_btn.set_tooltip(_('Word Wrap')) wrap_btn.connect('clicked', self._wrap_cb) self._toolbar.insert(wrap_btn, -1) self.search_entry = iconentry.IconEntry() self.search_entry.set_size_request(Gdk.Screen.width() / 3, -1) self.search_entry.set_icon_from_name( iconentry.ICON_ENTRY_PRIMARY, 'entry-search') self.search_entry.add_clear_button() self.search_entry.connect('activate', self._search_entry_activate_cb) self.search_entry.connect('changed', self._search_entry_changed_cb) self._search_item = Gtk.ToolItem() self._search_item.add(self.search_entry) self._toolbar.insert(self._search_item, -1) self._search_prev = ToolButton('go-previous-paired') self._search_prev.set_tooltip(_('Previous')) self._search_prev.connect('clicked', self._search_prev_cb) self._toolbar.insert(self._search_prev, -1) self._search_next = ToolButton('go-next-paired') self._search_next.set_tooltip(_('Next')) self._search_next.connect('clicked', self._search_next_cb) self._toolbar.insert(self._search_next, -1) self._update_search_buttons() self.collector_palette = CollectorPalette(self) collector_btn = ToolButton('log-export') collector_btn.set_palette(self.collector_palette) collector_btn.connect('clicked', self._logviewer_cb) collector_btn.show() activity_toolbar.insert(collector_btn, -1) self._delete_btn = ToolButton('list-remove') self._delete_btn.set_tooltip(_('Delete Log File')) self._delete_btn.connect('clicked', self._delete_log_cb) self._toolbar.insert(self._delete_btn, -1) self._separator = Gtk.SeparatorToolItem() self._separator.set_expand(True) self._separator.set_draw(False) self._toolbar.insert(self._separator, -1) self._stop_btn = StopButton(self) self._toolbar.insert(self._stop_btn, -1) toolbar_box.show_all() self.set_toolbar_box(toolbar_box) def _configure_cb(self, event=None): for control in [self._stop_btn, self._separator, self._delete_btn]: if control in self._toolbar: self._toolbar.remove(control) if Gdk.Screen.width() < Gdk.Screen.height(): self._secondary_toolbar_button.show() self._secondary_toolbar_button.set_expanded(True) self._remove_controls(self._toolbar) self._add_controls(self._secondary_toolbar) else: self._secondary_toolbar_button.set_expanded(False) self._secondary_toolbar_button.hide() self._remove_controls(self._secondary_toolbar) self._add_controls(self._toolbar) for control in [self._delete_btn, self._separator, self._stop_btn]: if control not in self._toolbar: self._toolbar.insert(control, -1) def _remove_controls(self, toolbar): for control in [self._search_item, self._search_prev, self._search_next]: if control in toolbar: toolbar.remove(control) def _add_controls(self, toolbar): for control in [self._search_item, self._search_prev, self._search_next]: if control not in toolbar: toolbar.insert(control, -1) control.show() def _list_toggled_cb(self, widget): if widget.get_active(): self.viewer.list_scroll.show() else: self.viewer.list_scroll.hide() def __copy_clicked_cb(self, button): if self.viewer.active_log: self.viewer.active_log.copy_clipboard(self.clipboard) def _wrap_cb(self, button): if button.get_active(): self.viewer._textview.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) else: self.viewer._textview.set_wrap_mode(Gtk.WrapMode.NONE) def _search_entry_activate_cb(self, entry): if self._autosearch_timer: GLib.source_remove(self._autosearch_timer) self.viewer.set_search_text(entry.props.text) self._update_search_buttons() def _search_entry_changed_cb(self, entry): if self._autosearch_timer: GLib.source_remove(self._autosearch_timer) self._autosearch_timer = GLib.timeout_add(_AUTOSEARCH_TIMEOUT, self.__autosearch_cb) def __autosearch_cb(self): self._autosearch_timer = None self.search_entry.activate() return False def _search_prev_cb(self, button): self.viewer.search_next('backward') self._update_search_buttons() def _search_next_cb(self, button): self.viewer.search_next('forward') self._update_search_buttons() def _update_search_buttons(self,): if len(self.viewer.search_text) == 0: self._search_prev.props.sensitive = False self._search_next.props.sensitive = False else: prev_result = self.viewer.get_next_result('backward') next_result = self.viewer.get_next_result('forward') self._search_prev.props.sensitive = prev_result is not None self._search_next.props.sensitive = next_result is not None def _delete_log_cb(self, widget): if self.viewer.active_log: logfile = self.viewer.active_log.logfile try: os.remove(logfile) except OSError, err: notify = NotifyAlert() notify.props.title = _('Error') notify.props.msg = _('%(error)s when deleting %(file)s') % \ {'error': err.strerror, 'file': logfile} notify.connect('response', _notify_response_cb, self) self.add_alert(notify)
def _setup_toolbars(self): """ Setup the toolbars.. """ project_toolbar = Gtk.Toolbar() custom_slide_toolbar = Gtk.Toolbar() custom_stator_toolbar = Gtk.Toolbar() edit_toolbar = Gtk.Toolbar() # no sharing self.max_participants = 1 toolbox = ToolbarBox() # Activity toolbar activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() project_toolbar_button = ToolbarButton(page=project_toolbar, icon_name="sliderule") project_toolbar.show() toolbox.toolbar.insert(project_toolbar_button, -1) project_toolbar_button.show() custom_slide_toolbar_button = ToolbarButton(page=custom_slide_toolbar, icon_name="custom-slide") custom_slide_toolbar.show() toolbox.toolbar.insert(custom_slide_toolbar_button, -1) custom_slide_toolbar_button.show() custom_stator_toolbar_button = ToolbarButton(page=custom_stator_toolbar, icon_name="custom-stator") custom_stator_toolbar.show() toolbox.toolbar.insert(custom_stator_toolbar_button, -1) custom_stator_toolbar_button.show() edit_toolbar_button = ToolbarButton(label=_("Edit"), page=edit_toolbar, icon_name="toolbar-edit") edit_toolbar_button.show() toolbox.toolbar.insert(edit_toolbar_button, -1) edit_toolbar_button.show() self.set_toolbar_box(toolbox) toolbox.show() toolbar = toolbox.toolbar # Add the buttons to the toolbars self._function_combo = combo_factory( FUNCTIONS, project_toolbar, self._function_combo_cb, default=FC_multiply, tooltip=_("select function") ) self.top_button = button_factory("C", project_toolbar, self._dummy_cb, tooltip=_("active slide")) self._slide_combo = combo_factory( SLIDE_TABLE, project_toolbar, self._slide_combo_cb, default=C_slide, tooltip=_("select slide") ) self.bottom_button = button_factory("D", project_toolbar, self._dummy_cb, tooltip=_("active stator")) self._stator_combo = combo_factory( STATOR_TABLE, project_toolbar, self._stator_combo_cb, default=D_slide, tooltip=_("select stator") ) separator_factory(project_toolbar) self.realign_button = button_factory("realign", project_toolbar, self.realign_cb, tooltip=_("realign slides")) self._offset_function = [] self._calculate_function = [] self._label_function = [] self._domain_min = [] self._domain_max = [] self._step_size = [] self.custom = [] ENTRY = ["C", "D"] ENTRY_TOOLBAR = [custom_slide_toolbar, custom_stator_toolbar] ENTRY_BUTTON = ["custom-slide", "custom-stator"] ENTRY_TOOLTIP = [_("create custom slide"), _("create custom stator")] ENTRY_CALLBACK = [self._custom_slide_cb, self._custom_stator_cb] for i in range(2): self._offset_function.append( entry_factory(DEFINITIONS[ENTRY[i]][0], ENTRY_TOOLBAR[i], tooltip=_("position function"), max=10) ) self._calculate_function.append( entry_factory(DEFINITIONS[ENTRY[i]][1], ENTRY_TOOLBAR[i], tooltip=_("result function"), max=10) ) self._label_function.append( entry_factory(DEFINITIONS[ENTRY[i]][2], ENTRY_TOOLBAR[i], tooltip=_("label function"), max=10) ) self._domain_min.append( entry_factory(DEFINITIONS[ENTRY[i]][3], ENTRY_TOOLBAR[i], tooltip=_("domain minimum"), max=4) ) self._domain_max.append( entry_factory(DEFINITIONS[ENTRY[i]][4], ENTRY_TOOLBAR[i], tooltip=_("domain maximum"), max=4) ) self._step_size.append( entry_factory(DEFINITIONS[ENTRY[i]][5], ENTRY_TOOLBAR[i], tooltip=_("step size"), max=4) ) self.custom.append( button_factory(ENTRY_BUTTON[i], ENTRY_TOOLBAR[i], ENTRY_CALLBACK[i], tooltip=ENTRY_TOOLTIP[i]) ) copy = button_factory("edit-copy", edit_toolbar, self._copy_cb, tooltip=_("Copy"), accelerator="<Ctrl>c") paste = button_factory("edit-paste", edit_toolbar, self._paste_cb, tooltip=_("Paste"), accelerator="<Ctrl>v") separator_factory(toolbox.toolbar, True, False) stop_button = StopButton(self) stop_button.props.accelerator = "<Ctrl>q" toolbox.toolbar.insert(stop_button, -1) stop_button.show() # workaround to #2050 edit_toolbar_button.set_expanded(True) # start with project toolbar enabled project_toolbar_button.set_expanded(True)
class Dimensions(activity.Activity): ''' Dimension matching game ''' def __init__(self, handle): ''' Initialize the Sugar activity ''' super(Dimensions, self).__init__(handle) self.ready_to_play = False self._prompt = '' self._read_journal_data() self._sep = [] self._setup_toolbars() self._setup_canvas() if self.shared_activity: # We're joining if not self.get_shared(): xocolors = XoColor(profile.get_color().to_string()) share_icon = Icon(icon_name='zoom-neighborhood', xo_color=xocolors) self._joined_alert = Alert() self._joined_alert.props.icon = share_icon self._joined_alert.props.title = _('Please wait') self._joined_alert.props.msg = _('Starting connection...') self.add_alert(self._joined_alert) # Wait for joined signal self.connect("joined", self._joined_cb) self._setup_presence_service() if not hasattr(self, '_saved_state'): self._saved_state = None self.vmw.new_game(show_selector=True) else: self.vmw.new_game(saved_state=self._saved_state, deck_index=self._deck_index) self.ready_to_play = True if self._editing_word_list: self.vmw.editing_word_list = True self.vmw.edit_word_list() elif self._editing_custom_cards: self.vmw.editing_custom_cards = True self.vmw.edit_custom_card() Gdk.Screen.get_default().connect('size-changed', self._configure_cb) self._configure_cb(None) def _select_game_cb(self, button, card_type): ''' Choose which game we are playing. ''' if self.vmw.joiner(): # joiner cannot change level return # self.vmw.card_type = card_type self._prompt = PROMPT_DICT[card_type] self._load_new_game(card_type) def _load_new_game(self, card_type=None, show_selector=True): if not self.ready_to_play: return # self._notify_new_game(self._prompt) GObject.idle_add(self._new_game, card_type, show_selector) def _new_game(self, card_type, show_selector=True): if card_type == 'custom' and self.vmw.custom_paths[0] is None: self.image_import_cb() else: self.tools_toolbar_button.set_expanded(False) self.vmw.new_game(show_selector=show_selector) def _robot_cb(self, button=None): ''' Toggle robot assist on/off ''' if self.vmw.robot: self.vmw.robot = False self.robot_button.set_tooltip(_('Play with the computer.')) self.robot_button.set_icon_name('robot-off') elif not self.vmw.editing_word_list: self.vmw.robot = True self.robot_button.set_tooltip( _('Stop playing with the computer.')) self.robot_button.set_icon_name('robot-on') def _level_cb(self, button, level): ''' Cycle between levels ''' if self.vmw.joiner(): # joiner cannot change level return self.vmw.level = level # self.level_label.set_text(self.calc_level_label(self.vmw.low_score, # self.vmw.level)) self._load_new_game(show_selector=False) def calc_level_label(self, low_score, play_level): ''' Show the score. ''' if low_score[play_level] == -1: return LEVEL_LABELS[play_level] else: return '%s (%d:%02d)' % \ (LEVEL_LABELS[play_level], int(low_score[play_level] / 60), int(low_score[play_level] % 60)) def image_import_cb(self, button=None): ''' Import custom cards from the Journal ''' self.vmw.editing_custom_cards = True self.vmw.editing_word_list = False self.vmw.edit_custom_card() if self.vmw.robot: self._robot_cb(button) def _number_card_O_cb(self, button, numberO): ''' Choose between O-card list for numbers game. ''' if self.vmw.joiner(): # joiner cannot change decks return self.vmw.numberO = numberO self.vmw.card_type = 'number' self._load_new_game() def _number_card_C_cb(self, button, numberC): ''' Choose between C-card list for numbers game. ''' if self.vmw.joiner(): # joiner cannot change decks return self.vmw.numberC = numberC self.vmw.card_type = 'number' self._load_new_game() def _edit_words_cb(self, button): ''' Edit the word list. ''' self.vmw.editing_word_list = True self.vmw.editing_custom_cards = False self.vmw.edit_word_list() if self.vmw.robot: self._robot_cb(button) def _read_metadata(self, keyword, default_value, json=False): ''' If the keyword is found, return stored value ''' if keyword in self.metadata: data = self.metadata[keyword] else: data = default_value if json: try: return jloads(data) except: pass return data def _read_journal_data(self): ''' There may be data from a previous instance. ''' self._play_level = int(self._read_metadata('play_level', 0)) self._robot_time = int(self._read_metadata('robot_time', ROBOT_TIMER_DEFAULT)) self._card_type = self._read_metadata('cardtype', MODE) self._low_score = [int(self._read_metadata('low_score_beginner', -1)), int(self._read_metadata('low_score_intermediate', -1)), int(self._read_metadata('low_score_expert', -1))] self._all_scores = self._read_metadata( 'all_scores', '{"pattern": [], "word": [], "number": [], "custom": []}', True) self._numberO = int(self._read_metadata('numberO', PRODUCT)) self._numberC = int(self._read_metadata('numberC', HASH)) self._matches = int(self._read_metadata('matches', 0)) self._robot_matches = int(self._read_metadata('robot_matches', 0)) self._total_time = int(self._read_metadata('total_time', 0)) self._deck_index = int(self._read_metadata('deck_index', 0)) self._word_lists = [[self._read_metadata('mouse', _('mouse')), self._read_metadata('cat', _('cat')), self._read_metadata('dog', _('dog'))], [self._read_metadata('cheese', _('cheese')), self._read_metadata('apple', _('apple')), self._read_metadata('bread', _('bread'))], [self._read_metadata('moon', _('moon')), self._read_metadata('sun', _('sun')), self._read_metadata('earth', _('earth'))]] self._editing_word_list = bool(int(self._read_metadata( 'editing_word_list', 0))) self._editing_custom_cards = bool(int(self._read_metadata( 'editing_custom_cards', 0))) if self._card_type == 'custom': self._custom_object = self._read_metadata('custom_object', None) if self._custom_object is None: self._card_type = MODE self._custom_jobject = [] for i in range(9): self._custom_jobject.append(self._read_metadata( 'custom_' + str(i), None)) def _write_scores_to_clipboard(self, button=None): ''' SimpleGraph will plot the cululative results ''' jscores = '' c = 0 for key in self.vmw.all_scores.keys(): for data in self.vmw.all_scores[key]: jscores += '%s: %s\n' % (str(c + 1), data[1]) c += 1 clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) clipboard.set_text(jscores, -1) def _setup_toolbars(self): ''' Setup the toolbars.. ''' tools_toolbar = Gtk.Toolbar() numbers_toolbar = Gtk.Toolbar() toolbox = ToolbarBox() self.activity_toolbar_button = ActivityToolbarButton(self) toolbox.toolbar.insert(self.activity_toolbar_button, 0) self.activity_toolbar_button.show() self.numbers_toolbar_button = ToolbarButton( page=numbers_toolbar, icon_name='number-tools') if MODE == 'number': numbers_toolbar.show() toolbox.toolbar.insert(self.numbers_toolbar_button, -1) self.numbers_toolbar_button.show() self.tools_toolbar_button = ToolbarButton( page=tools_toolbar, icon_name='view-source') self.button_pattern = button_factory( 'new-pattern-game', toolbox.toolbar, self._select_game_cb, cb_arg='pattern', tooltip=_('New game')) self._set_extras(toolbox.toolbar) self._sep.append(separator_factory(toolbox.toolbar, True, False)) stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>q' toolbox.toolbar.insert(stop_button, -1) stop_button.show() button_factory('score-copy', self.activity_toolbar_button, self._write_scores_to_clipboard, tooltip=_('Export scores to clipboard')) self.set_toolbar_box(toolbox) toolbox.show() if MODE == 'word': self.words_tool_button = button_factory( 'word-tools', tools_toolbar, self._edit_words_cb, tooltip=_('Edit word lists.')) self.import_button = button_factory( 'image-tools', tools_toolbar, self.image_import_cb, tooltip=_('Import custom cards')) self.button_custom = button_factory( 'new-custom-game', tools_toolbar, self._select_game_cb, cb_arg='custom', tooltip=_('New custom game')) self.button_custom.set_sensitive(False) if MODE == 'number': self._setup_number_buttons(numbers_toolbar) def _setup_number_buttons(self, numbers_toolbar): self.product_button = radio_factory( 'product', numbers_toolbar, self._number_card_O_cb, cb_arg=PRODUCT, tooltip=_('product'), group=None) NUMBER_O_BUTTONS[PRODUCT] = self.product_button self.roman_button = radio_factory( 'roman', numbers_toolbar, self._number_card_O_cb, cb_arg=ROMAN, tooltip=_('Roman numerals'), group=self.product_button) NUMBER_O_BUTTONS[ROMAN] = self.roman_button self.word_button = radio_factory( 'word', numbers_toolbar, self._number_card_O_cb, cb_arg=WORD, tooltip=_('word'), group=self.product_button) NUMBER_O_BUTTONS[WORD] = self.word_button self.chinese_button = radio_factory( 'chinese', numbers_toolbar, self._number_card_O_cb, cb_arg=CHINESE, tooltip=_('Chinese'), group=self.product_button) NUMBER_O_BUTTONS[CHINESE] = self.chinese_button self.mayan_button = radio_factory( 'mayan', numbers_toolbar, self._number_card_O_cb, cb_arg=MAYAN, tooltip=_('Mayan'), group=self.product_button) NUMBER_O_BUTTONS[MAYAN] = self.mayan_button self.incan_button = radio_factory( 'incan', numbers_toolbar, self._number_card_O_cb, cb_arg=INCAN, tooltip=_('Quipu'), group=self.product_button) NUMBER_O_BUTTONS[INCAN] = self.incan_button separator_factory(numbers_toolbar, False, True) self.hash_button = radio_factory( 'hash', numbers_toolbar, self._number_card_C_cb, cb_arg=HASH, tooltip=_('hash marks'), group=None) NUMBER_C_BUTTONS[HASH] = self.hash_button self.dots_button = radio_factory( 'dots', numbers_toolbar, self._number_card_C_cb, cb_arg=DOTS, tooltip=_('dots in a circle'), group=self.hash_button) NUMBER_C_BUTTONS[DOTS] = self.dots_button self.star_button = radio_factory( 'star', numbers_toolbar, self._number_card_C_cb, cb_arg=STAR, tooltip=_('points on a star'), group=self.hash_button) NUMBER_C_BUTTONS[STAR] = self.star_button self.dice_button = radio_factory( 'dice', numbers_toolbar, self._number_card_C_cb, cb_arg=DICE, tooltip=_('dice'), group=self.hash_button) NUMBER_C_BUTTONS[DICE] = self.dice_button self.lines_button = radio_factory( 'lines', numbers_toolbar, self._number_card_C_cb, cb_arg=LINES, tooltip=_('dots in a line'), group=self.hash_button) NUMBER_C_BUTTONS[LINES] = self.lines_button def _configure_cb(self, event): self._vbox.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self._vbox.show() if Gdk.Screen.width() < Gdk.Screen.height(): for sep in self._sep: sep.hide() else: for sep in self._sep: sep.show() def _robot_selection_cb(self, widget): if self._robot_palette: if not self._robot_palette.is_up(): self._robot_palette.popup(immediate=True, state=self._robot_palette.SECONDARY) else: self._robot_palette.popdown(immediate=True) return def _setup_robot_palette(self): self._robot_palette = self._robot_time_button.get_palette() self._robot_timer_menu = {} for seconds in ROBOT_TIMER_VALUES: self._robot_timer_menu[seconds] = { 'menu_item': MenuItem(), 'label': ROBOT_TIMER_LABELS[seconds], 'icon': image_from_svg_file( 'timer-%d.svg' % (seconds)), 'icon-selected': image_from_svg_file( 'timer-%d-selected.svg' % (seconds)) } self._robot_timer_menu[seconds]['menu_item'].set_label( self._robot_timer_menu[seconds]['label']) if seconds == ROBOT_TIMER_DEFAULT: self._robot_timer_menu[seconds]['menu_item'].set_image( self._robot_timer_menu[seconds]['icon-selected']) else: self._robot_timer_menu[seconds]['menu_item'].set_image( self._robot_timer_menu[seconds]['icon']) self._robot_timer_menu[seconds]['menu_item'].connect( 'activate', self._robot_selected_cb, seconds) self._robot_palette.menu.append( self._robot_timer_menu[seconds]['menu_item']) self._robot_timer_menu[seconds]['menu_item'].show() def _robot_selected_cb(self, button, seconds): self.vmw.robot_time = seconds if hasattr(self, '_robot_time_button') and \ seconds in ROBOT_TIMER_VALUES: self._robot_time_button.set_icon_name('timer-%d' % seconds) for time in ROBOT_TIMER_VALUES: if time == seconds: self._robot_timer_menu[time]['menu_item'].set_image( self._robot_timer_menu[time]['icon-selected']) else: self._robot_timer_menu[time]['menu_item'].set_image( self._robot_timer_menu[time]['icon']) def _set_extras(self, toolbar): self.robot_button = button_factory( 'robot-off', toolbar, self._robot_cb, tooltip=_('Play with the computer')) self._robot_time_button = button_factory( 'timer-15', toolbar, self._robot_selection_cb, tooltip=_('robot pause time')) self._setup_robot_palette() self._sep.append(separator_factory(toolbar, False, True)) self.beginner_button = radio_factory( 'beginner', toolbar, self._level_cb, cb_arg=BEGINNER, tooltip=_('beginner'), group=None) LEVEL_BUTTONS[BEGINNER] = self.beginner_button self.intermediate_button = radio_factory( 'intermediate', toolbar, self._level_cb, cb_arg=INTERMEDIATE, tooltip=_('intermediate'), group=self.beginner_button) LEVEL_BUTTONS[INTERMEDIATE] = self.intermediate_button self.expert_button = radio_factory( 'expert', toolbar, self._level_cb, cb_arg=EXPERT, tooltip=_('expert'), group=self.beginner_button) LEVEL_BUTTONS[EXPERT] = self.expert_button 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) def _setup_canvas(self): ''' Create a canvas in a Gtk.Fixed ''' self.fixed = Gtk.Fixed() self.fixed.connect('size-allocate', self._fixed_resize_cb) self.fixed.show() self.set_canvas(self.fixed) self._vbox = Gtk.VBox(False, 0) self._vbox.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self.fixed.put(self._vbox, 0, 0) self._vbox.show() self._canvas = Gtk.DrawingArea() self._canvas.set_size_request(int(Gdk.Screen.width()), int(Gdk.Screen.height())) self._canvas.show() self.show_all() self._vbox.pack_end(self._canvas, True, True, 0) self._vbox.show() self.show_all() self.vmw = Game(self._canvas, parent=self, card_type=MODE) self.vmw.level = self._play_level LEVEL_BUTTONS[self._play_level].set_active(True) self.vmw.card_type = self._card_type self.vmw.robot = False self.vmw.robot_time = self._robot_time self.vmw.low_score = self._low_score self.vmw.all_scores = self._all_scores self.vmw.numberO = self._numberO self.vmw.numberC = self._numberC self.vmw.matches = self._matches self.vmw.robot_matches = self._robot_matches self.vmw.total_time = self._total_time self.vmw.buddies = [] self.vmw.word_lists = self._word_lists self.vmw.editing_word_list = self._editing_word_list if hasattr(self, '_custom_object') and self._custom_object is not None: self.vmw._find_custom_paths(datastore.get(self._custom_object)) for i in range(9): if hasattr(self, '_custom_jobject') and \ self._custom_jobject[i] is not None: self.vmw.custom_paths[i] = datastore.get( self._custom_jobject[i]) self.button_custom.set_sensitive(True) return self._canvas def write_file(self, file_path): ''' Write data to the Journal. ''' if hasattr(self, 'vmw'): self.metadata['play_level'] = self.vmw.level self.metadata['low_score_beginner'] = int(self.vmw.low_score[0]) self.metadata['low_score_intermediate'] = int( self.vmw.low_score[1]) self.metadata['low_score_expert'] = int(self.vmw.low_score[2]) self.metadata['all_scores'] = jdumps(self.vmw.all_scores) print jdumps(self.vmw.all_scores) self.metadata['robot_time'] = self.vmw.robot_time self.metadata['numberO'] = self.vmw.numberO self.metadata['numberC'] = self.vmw.numberC self.metadata['cardtype'] = self.vmw.card_type self.metadata['matches'] = self.vmw.matches self.metadata['robot_matches'] = self.vmw.robot_matches self.metadata['total_time'] = int(self.vmw.total_time) self.metadata['deck_index'] = self.vmw.deck.index self.metadata['mouse'] = self.vmw.word_lists[0][0] self.metadata['cat'] = self.vmw.word_lists[0][1] self.metadata['dog'] = self.vmw.word_lists[0][2] self.metadata['cheese'] = self.vmw.word_lists[1][0] self.metadata['apple'] = self.vmw.word_lists[1][1] self.metadata['bread'] = self.vmw.word_lists[1][2] self.metadata['moon'] = self.vmw.word_lists[2][0] self.metadata['sun'] = self.vmw.word_lists[2][1] self.metadata['earth'] = self.vmw.word_lists[2][2] self.metadata['editing_word_list'] = self.vmw.editing_word_list self.metadata['mime_type'] = 'application/x-visualmatch' f = file(file_path, 'w') f.write(self._dump()) f.close() else: _logger.debug('Deferring saving to %s' % file_path) def _dump(self): ''' Dump game data to the journal.''' data = [] for i in self.vmw.grid.grid: if i is None or self.vmw.editing_word_list: data.append(None) else: data.append(i.index) for i in self.vmw.clicked: if i.spr is None or self.vmw.deck.spr_to_card(i.spr) is None or \ self.vmw.editing_word_list: data.append(None) else: data.append(self.vmw.deck.spr_to_card(i.spr).index) for i in self.vmw.deck.cards: if i is None or self.vmw.editing_word_list: data.append(None) else: data.append(i.index) for i in self.vmw.match_list: if self.vmw.deck.spr_to_card(i) is not None: data.append(self.vmw.deck.spr_to_card(i).index) for i in self.vmw.word_lists: for j in i: data.append(j) return self._data_dumper(data) def _data_dumper(self, data): io = StringIO() jdump(data, io) return io.getvalue() def read_file(self, file_path): ''' Read data from the Journal. ''' f = open(file_path, 'r') self._load(f.read()) f.close() def _load(self, data): ''' Load game data from the journal. ''' saved_state = self._data_loader(data) if len(saved_state) > 0: self._saved_state = saved_state def _data_loader(self, data): json_data = jloads(data) return json_data def _notify_new_game(self, prompt): ''' Called from New Game button since loading a new game can be slooow!! ''' alert = NotifyAlert(3) alert.props.title = prompt alert.props.msg = _('A new game is loading.') def _notification_alert_response_cb(alert, response_id, self): self.remove_alert(alert) alert.connect('response', _notification_alert_response_cb, self) self.add_alert(alert) alert.show() def _new_help_box(self, name, button=None): help_box = Gtk.VBox() help_box.set_homogeneous(False) help_palettes[name] = help_box if button is not None: help_buttons[name] = button help_windows[name] = Gtk.ScrolledWindow() help_windows[name].set_size_request( int(Gdk.Screen.width() / 3), Gdk.Screen.height() - style.GRID_CELL_SIZE * 3) help_windows[name].set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) help_windows[name].add_with_viewport(help_palettes[name]) help_palettes[name].show() return help_box def _setup_toolbar_help(self): ''' Set up a help palette for the main toolbars ''' help_box = self._new_help_box('main-toolbar') add_section(help_box, _('Dimensions'), icon='activity-dimensions') add_paragraph(help_box, _('Tools'), icon='view-source') if MODE == 'pattern': add_paragraph(help_box, _('Game'), icon='new-pattern-game') elif MODE == 'number': add_paragraph(help_box, PROMPT_DICT['number'], icon='new-number-game') add_paragraph(help_box, _('Numbers'), icon='number-tools') elif MODE == 'word': add_paragraph(help_box, PROMPT_DICT['word'], icon='new-word-game') add_paragraph(help_box, _('Play with the computer'), icon='robot-off') add_paragraph(help_box, _('robot pause time'), icon='timer-60') add_paragraph(help_box, _('beginner'), icon='beginner') add_paragraph(help_box, _('intermediate'), icon='intermediate') add_paragraph(help_box, _('expert'), icon='expert') add_section(help_box, _('Dimensions'), icon='activity-dimensions') add_paragraph(help_box, _('Export scores to clipboard'), icon='score-copy') add_section(help_box, _('Tools'), icon='view-source') add_section(help_box, _('Import image cards'), icon='image-tools') add_paragraph(help_box, PROMPT_DICT['custom'], icon='new-custom-game') if MODE == 'word': add_section(help_box, _('Edit word lists.'), icon='word-tools') if MODE == 'number': add_section(help_box, _('Numbers'), icon='number-tools') add_paragraph(help_box, _('product'), icon='product') add_paragraph(help_box, _('Roman numerals'), icon='roman') add_paragraph(help_box, _('word'), icon='word') add_paragraph(help_box, _('Chinese'), icon='chinese') add_paragraph(help_box, _('Mayan'), icon='mayan') add_paragraph(help_box, _('Quipu'), icon='incan') add_paragraph(help_box, _('hash marks'), icon='hash') add_paragraph(help_box, _('dots in a circle'), icon='dots') add_paragraph(help_box, _('points on a star'), icon='star') add_paragraph(help_box, _('dice'), icon='dice') add_paragraph(help_box, _('dots in a line'), icon='lines') def _setup_presence_service(self): ''' Setup the Presence Service. ''' self.pservice = presenceservice.get_instance() self.initiating = None # sharing (True) or joining (False) owner = self.pservice.get_owner() self.owner = owner self.vmw.buddies.append(self.owner) self._share = '' self.connect('shared', self._shared_cb) self.connect('joined', self._joined_cb) def _shared_cb(self, activity): ''' Either set up initial share...''' if self.shared_activity is None: _logger.error('Failed to share or join activity ... \ shared_activity is null in _shared_cb()') return self.initiating = True self.waiting_for_deck = 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.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal( 'NewTube', self._new_tube_cb) _logger.debug('This is my activity: making a tube...') self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( SERVICE, {}) def _joined_cb(self, activity): ''' ...or join an exisiting share. ''' if self.shared_activity is None: _logger.error('Failed to share or join activity ... \ shared_activity is null in _shared_cb()') return if self._joined_alert is not None: self.remove_alert(self._joined_alert) self._joined_alert = None 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.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal( 'NewTube', self._new_tube_cb) _logger.debug('I am joining an activity: waiting for a tube...') self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb) self.waiting_for_deck = True self.button_pattern.set_sensitive(False) self.robot_button.set_sensitive(False) self._robot_time_button.set_sensitive(False) self.beginner_button.set_sensitive(False) self.intermediate_button.set_sensitive(False) self.expert_button.set_sensitive(False) def _list_tubes_reply_cb(self, tubes): ''' Reply to a list request. ''' for tube_info in tubes: self._new_tube_cb(*tube_info) def _list_tubes_error_cb(self, e): ''' Log errors. ''' _logger.error('ListTubes() failed: %s', e) def _new_tube_cb(self, id, initiator, type, service, params, state): ''' Create a new tube. ''' _logger.debug('New tube: ID=%d initator=%d type=%d service=%s ' 'params=%r state=%d', id, initiator, type, service, params, state) if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE): if state == telepathy.TUBE_STATE_LOCAL_PENDING: self.tubes_chan[ telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id) tube_conn = TubeConnection( self.conn, self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id, group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP]) self.chattube = ChatTube(tube_conn, self.initiating, self.event_received_cb) if self.waiting_for_deck: self._send_event('j') def event_received_cb(self, text): ''' Data is passed as tuples: cmd:text ''' if text[0] == 'B': e, card_index = text.split(':') self.vmw.add_to_clicked( self.vmw.deck.index_to_card(int(card_index)).spr) elif text[0] == 'r': self.vmw.clean_up_match() elif text[0] == 'R': self.vmw.clean_up_no_match(None) elif text[0] == 'S': e, card_index = text.split(':') i = int(card_index) self.vmw.process_click(self.vmw.clicked[i].spr) self.vmw.process_selection(self.vmw.clicked[i].spr) elif text[0] == 'j': if self.initiating: # Only the sharer 'shares'. self._send_event('P:' + str(self.vmw.level)) self._send_event('X:' + str(self.vmw.deck.index)) self._send_event('M:' + str(self.vmw.matches)) self._send_event('C:' + self.vmw.card_type) self._send_event('D:' + str(self._dump())) elif text[0] == 'J': # Force a request for current state. self._send_event('j') self.waiting_for_deck = True elif text[0] == 'C': e, text = text.split(':') self.vmw.card_type = text elif text[0] == 'P': e, text = text.split(':') self.vmw.level = int(text) # self.level_label.set_text(self.calc_level_label( # self.vmw.low_score, self.vmw.level)) LEVEL_BUTTONS[self.vmw.level].set_active(True) elif text[0] == 'X': e, text = text.split(':') self.vmw.deck.index = int(text) elif text[0] == 'M': e, text = text.split(':') self.vmw.matches = int(text) elif text[0] == 'D': if self.waiting_for_deck: e, text = text.split(':') self._load(text) self.waiting_for_deck = False self.vmw.new_game(self._saved_state, self.vmw.deck.index) def _send_event(self, entry): ''' Send event through the tube. ''' if hasattr(self, 'chattube') and self.chattube is not None: self.chattube.SendText(entry)
def __init__(self, handle): '''Set up the Acoustic Tape Measure activity.''' super(AcousticMeasureActivity, self).__init__(handle) #self.set_title(_('Acoustic Tape Measure Activity')) self._logger = logging.getLogger('acousticmeasure-activity') GObject.threads_init() try: self._logger.debug("locale: " + locale.setlocale(locale.LC_ALL, '')) except locale.Error: self._logger.error("setlocale failed") # top toolbar with share and close buttons: from sugar3.graphics.toolbarbox import ToolbarBox from sugar3.graphics.toolbarbox import ToolbarButton from sugar3.activity.widgets import ShareButton from sugar3.activity.widgets import StopButton from sugar3.activity.widgets import ActivityButton from sugar3.activity.widgets import TitleEntry toolbar_box = ToolbarBox() activity_button = ActivityButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() title_entry = TitleEntry(self) toolbar_box.toolbar.insert(title_entry, -1) title_entry.show() try: from sugar3.activity.widgets import DescriptionItem description_item = DescriptionItem(self) toolbar_box.toolbar.insert(description_item, -1) description_item.show() except: pass share_button = ShareButton(self) toolbar_box.toolbar.insert(share_button, -1) share_button.show() separator = Gtk.SeparatorToolItem() toolbar_box.toolbar.insert(separator, -1) separator.show() self._t_h_bar = atm_toolbars.TempToolbar() tb = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self._t_h_bar.show_all() adj_button = ToolbarButton(page=self._t_h_bar, icon_name='preferences-system') toolbar_box.toolbar.insert(adj_button, -1) adj_button.show() self._smoot_bar = smoot_toolbar.SmootToolbar(self) self._smoot_bar.show_all() custom_button = ToolbarButton(page=self._smoot_bar, icon_name='view-source') toolbar_box.toolbar.insert(custom_button, -1) custom_button.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() toolbar = toolbar_box.toolbar if not self.powerd_running(): try: bus = dbus.SystemBus() proxy = bus.get_object('org.freedesktop.ohm', '/org/freedesktop/ohm/Keystore') self.ohm_keystore = dbus.Interface( proxy, 'org.freedesktop.ohm.Keystore') except dbus.DBusException, e: self._logger.warning("Error setting OHM inhibit: %s" % e) self.ohm_keystore = None