# -*- coding: utf-8 -*- """ toolbox.py Create Oficina Toolbar in Sugar Copyright 2007, NATE-LSI-EPUSP Oficina is developed in Brazil at Escola Politécnica of Universidade de São Paulo. NATE is part of LSI (Integrable Systems Laboratory) and stands for Learning, Work and Entertainment Research Group. Visit our web page: www.lsi.usp.br/nate Suggestions, bugs and doubts, please email oficina@lsi.usp.br Oficina is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. Oficina is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Oficina; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. The copy of the GNU General Public License is found in the COPYING file included in the source distribution. Authors: Joyce Alessandra Saul (joycealess@gmail.com) Andre Mossinato (andremossinato@gmail.com) Nathalia Sautchuk Patrício (nathalia.sautchuk@gmail.com) Pedro Kayatt (pekayatt@gmail.com) Rafael Barbolo Lopes (barbolo@gmail.com) Alexandre A. Gonçalves Martinazzo (alexandremartinazzo@gmail.com) Colaborators: Bruno Gola (brunogola@gmail.com) Group Manager: Irene Karaguilla Ficheman (irene@lsi.usp.br) Cientific Coordinator: Roseli de Deus Lopes (roseli@lsi.usp.br) """ from gettext import gettext as _ import gtk, logging from sugar.activity.activity import ActivityToolbox, EditToolbar from sugar.graphics.toolcombobox import ToolComboBox from sugar.graphics.toolbutton import ToolButton from sugar.graphics.toggletoolbutton import ToggleToolButton from sugar.graphics.combobox import ComboBox from sugar.graphics.palette import Palette from sugar.graphics.menuitem import MenuItem #Create toolbars for the activity class Toolbox(ActivityToolbox): ## The Constructor def __init__(self, activity): ActivityToolbox.__init__(self, activity) # creating toolbars for Draw activity self._edit_toolbar = DrawEditToolbar(activity) self.add_toolbar(_('Edit'), self._edit_toolbar) self._edit_toolbar.show() self._tools_toolbar = ToolsToolbar(activity) self.add_toolbar(_('Tools'), self._tools_toolbar) self._tools_toolbar.show() self._shapes_toolbar = ShapesToolbar(activity) self.add_toolbar(_('Shapes'), self._shapes_toolbar) self._shapes_toolbar.show() self._text_toolbar = TextToolbar(activity) self.add_toolbar(_('Text'), self._text_toolbar) self._text_toolbar.show() self._image_toolbar = ImageToolbar(activity) self.add_toolbar(_('Image'), self._image_toolbar) self._image_toolbar.show() self._effects_toolbar = EffectsToolbar(activity) self.add_toolbar(_('Effects'), self._effects_toolbar) self._effects_toolbar.show() #self._view_toolbar = ViewToolbar(activity) #self.add_toolbar(_('View'), self._view_toolbar) #self._view_toolbar.show() self.set_current_toolbar(2) ##Make the Edit Toolbar class DrawEditToolbar(EditToolbar): ## The Constructor def __init__(self, activity): EditToolbar.__init__(self) self._activity = activity self.undo.set_tooltip(_('Undo')) self.redo.set_tooltip(_('Redo')) self.copy.set_tooltip(_('Copy')) self.paste.set_tooltip(_('Paste')) separator = gtk.SeparatorToolItem() separator.set_draw(True) self.insert(separator, -1) separator.show() self._clear_all = ToolButton('edit-clear') self.insert(self._clear_all, -1) self._clear_all.show() self._clear_all.set_tooltip(_('Clear')) self.undo.connect('clicked', self._undo_cb) self.redo.connect('clicked', self._redo_cb) self.copy.connect('clicked', self._copy_cb) self.paste.connect('clicked', self._paste_cb) self._clear_all.connect('clicked', self._clear_all_cb) self._activity._area.connect('undo', self._on_signal_undo_cb) self._activity._area.connect('redo', self._on_signal_redo_cb) self._activity._area.connect('selected', self._on_signal_copy_cb) self._activity._area.connect('action-saved', self._on_signal_action_saved_cb) def _undo_cb(self, widget, data=None): self._activity._area.undo() def _redo_cb(self, widget, data=None): self._activity._area.redo() def _copy_cb(self, widget, data=None): self._activity._area.copy() def _paste_cb(self, widget, data=None): self._activity._area.past() def _on_signal_undo_cb(self, widget, data=None): self._verify_sensitive_buttons() def _on_signal_redo_cb(self, widget, data=None): self._verify_sensitive_buttons() def _on_signal_copy_cb(self, widget, data=None): self._verify_sensitive_buttons() def _on_signal_action_saved_cb(self, widget, data=None): self._verify_sensitive_buttons() ##define when a button is active def _verify_sensitive_buttons(self): self.undo.set_sensitive( self._activity._area.can_undo() ) self.redo.set_sensitive( self._activity._area.can_redo() ) self.copy.set_sensitive( self._activity._area.is_selected() ) #TODO: it is not possible to verify these yet. #self.copy.set_sensitive( self._activity._area.can_copy() ) #self.paste.set_sensitive( self._activity._area.can_paste() ) def _clear_all_cb(self, widget, data=None): self._activity._area.clear() ##Determine Tools of the Toolbar class ToolsToolbar(gtk.Toolbar): #Tool default definitions _TOOL_PENCIL = { 'name' : 'pencil', 'size' : 2, 'fill color' : None, 'stroke color' : None, 'shape' : 'circle', 'fill' : True, 'sides' : None, 'points' : None } _TOOL_BRUSH = { 'name' : 'brush', 'size' : 5, 'fill color' : None, 'stroke color' : None, 'shape' : 'circle', 'fill' : True, 'sides' : None, 'points' : None } ##The Constructor _TOOL_ERASER = { 'name' : 'eraser', 'size' : 20, 'fill color' : None, 'stroke color' : None, 'shape' : 'circle', 'fill' : True, 'sides' : None, 'points' : None } _TOOL_POLYGON = { 'name' : 'polygon', 'size' : 2, 'fill color' : None, 'stroke color' : None, 'shape' : 'circle', 'fill' : True, 'sides' : None, 'points' : None } _TOOL_BUCKET = { 'name' : 'bucket', 'size' : None, 'fill color' : None, 'stroke color' : None, 'shape' : None, 'fill' : None, 'sides' : None, 'points' : None } _TOOL_MARQUEE_ELLIPTICAL = { 'name' : 'marquee-elliptical', 'size' : None, 'fill color' : None, 'stroke color' : None, 'shape' : None, 'fill' : None, 'sides' : None, 'points' : None } _TOOL_MARQUEE_FREEFORM = { 'name' : 'marquee-freeform', 'size' : None, 'fill color' : None, 'stroke color' : None, 'shape' : None, 'fill' : None, 'sides' : None, 'points' : None } _TOOL_MARQUEE_RECTANGULAR = { 'name' : 'marquee-rectangular', 'size' : None, 'fill color' : None, 'stroke color' : None, 'shape' : None, 'fill' : None, 'sides' : None, 'points' : None } _TOOL_MARQUEE_SMART = { 'name' : 'marquee-smart', 'size' : None, 'fill color' : None, 'stroke color' : None, 'shape' : None, 'fill' : None, 'sides' : None, 'points' : None } def __init__(self, activity): gtk.Toolbar.__init__(self) # FIXME: This should be a file picker instead of a combobox self._activity = activity self._icon_stroke = ToolButton('icon-stroke') self.insert(self._icon_stroke, -1) self._icon_stroke.show() self._icon_stroke.set_tooltip(_('Tool Color')) # Changing widget: using toolbox.ButtonStrokeColor instead of toolbox.ComboStrokeColors ''' self._stroke_color = ComboStrokeColors(activity) self.insert(self._stroke_color, -1) self._stroke_color.show() ''' self._stroke_color = ButtonStrokeColor(activity) self._stroke_color.show() # self._stroke_color.set_tooltip(_('Stroke Color')) item = gtk.ToolItem() item.add(self._stroke_color) self.insert(item, -1) item.show() # self._stroke_size = ComboStrokeSize(activity) # self.insert(self._stroke_size, -1) # self._stroke_size.show() separator = gtk.SeparatorToolItem() separator.set_draw(True) self.insert(separator, -1) separator.show() self._tool_pencil = ToolButton('tool-pencil') self.insert(self._tool_pencil, -1) self._tool_pencil.show() self._tool_pencil.set_tooltip(_('Pencil')) try: self._configure_palette(self._tool_pencil, self._TOOL_PENCIL) except: logging.debug('Could not create palette for tool Pencil') self._tool_brush = ToolButton('tool-brush') self.insert(self._tool_brush, -1) self._tool_brush.show() self._tool_brush.set_tooltip(_('Brush')) try: self._configure_palette(self._tool_brush, self._TOOL_BRUSH) except: logging.debug('Could not create palette for tool Brush') self._tool_eraser = ToolButton('tool-eraser') self.insert(self._tool_eraser, -1) self._tool_eraser.show() self._tool_eraser.set_tooltip(_('Eraser')) try: self._configure_palette(self._tool_eraser, self._TOOL_ERASER) except: logging.debug('Could not create palette for tool Eraser') self._tool_polygon = ToolButton('tool-polygon') self.insert(self._tool_polygon, -1) self._tool_polygon.show() self._tool_polygon.set_tooltip(_('Polygon')) try: self._configure_palette(self._tool_polygon, self._TOOL_POLYGON) except: logging.debug('Could not create palette for tool Polygon') self._tool_bucket = ToolButton('tool-bucket') self.insert(self._tool_bucket, -1) self._tool_bucket.show() self._tool_bucket.set_tooltip(_('Bucket')) separator = gtk.SeparatorToolItem() separator.set_draw(True) self.insert(separator, -1) separator.show() """ self._tool_marquee_elliptical = ToolButton('tool-marquee-elliptical') self.insert(self._tool_marquee_elliptical, -1) self._tool_marquee_elliptical.show() self._tool_marquee_elliptical.set_tooltip(_('Elliptical Marquee')) self._tool_marquee_freeform = ToolButton('tool-marquee-freeform') self.insert(self._tool_marquee_freeform, -1) self._tool_marquee_freeform.show() self._tool_marquee_freeform.set_tooltip(_('Freeform Marquee')) self._tool_marquee_smart = ToolButton('tool-marquee-smart') self.insert(self._tool_marquee_smart, -1) self._tool_marquee_smart.show() self._tool_marquee_smart.set_tooltip(_('Smart Marquee')) """ self._tool_marquee_rectangular = ToolButton('tool-marquee-rectangular') self.insert(self._tool_marquee_rectangular, -1) self._tool_marquee_rectangular.show() self._tool_marquee_rectangular.set_tooltip(_('Rectangular Marquee')) self._icon_stroke.connect('clicked', self._on_icon_stroke_clicked) # New connect method # Using dictionnaries to control tool's properties self._tool_polygon.connect('clicked', self.set_tool, self._TOOL_POLYGON) self._tool_pencil.connect('clicked', self.set_tool, self._TOOL_PENCIL) self._tool_brush.connect('clicked', self.set_tool, self._TOOL_BRUSH) self._tool_eraser.connect('clicked', self.set_tool, self._TOOL_ERASER) self._tool_bucket.connect('clicked', self.set_tool, self._TOOL_BUCKET) #self._tool_marquee_elliptical.connect('clicked', self.set_tool, self._TOOL_MARQUEE_ELLIPTICAL) #self._tool_marquee_freeform.connect('clicked', self.set_tool, self._TOOL_MARQUEE_FREEFORM) self._tool_marquee_rectangular.connect('clicked', self.set_tool, self._TOOL_MARQUEE_RECTANGULAR) #self._tool_marquee_smart.connect('clicked', self.set_tool, self._TOOL_MARQUEE_SMART) def _configure_palette(self, widget, tool=None): """Set palette for a tool @param self -- gtk.Toolbar @param widget - the widget which Palette will be set, a ToolButton object @param tool - the reference tool for Palette creation. Its values are restricted to Class constants """ logging.debug('setting a palette for %s', tool['name']) palette = widget.get_palette() if tool is None: raise TypeError # We can set size when using either Pencil, Free Polygon, Brush or Eraser if tool['name'] is self._TOOL_PENCIL['name'] or \ tool['name'] is self._TOOL_POLYGON['name'] or \ tool['name'] is self._TOOL_BRUSH['name'] or \ tool['name'] is self._TOOL_ERASER['name']: size_spinbutton = gtk.SpinButton() size_spinbutton.show() black = gtk.gdk.Color(0,0,0) size_spinbutton.modify_text(gtk.STATE_NORMAL, black) # This is where we set restrictions for size: # Initial value, minimum value, maximum value, step adj = gtk.Adjustment(tool['size'], 1.0, 100.0, 1.0) size_spinbutton.set_adjustment(adj) size_spinbutton.set_numeric(True) label = gtk.Label(_('Size: ')) label.show() palette.action_bar.pack_start(label) palette.action_bar.pack_start(size_spinbutton) size_spinbutton.connect('value-changed', self._on_value_changed, tool) # User is able to choose Shapes for 'Brush' and 'Eraser' if tool['name'] is self._TOOL_BRUSH['name'] or \ tool['name'] is self._TOOL_ERASER['name']: # Changing to gtk.RadioButton # item_1 = MenuItem(_('Square'), 'rectangle') # item_2 = MenuItem(_('Circle'), 'ellipse') # # logging.debug('Menu Items created') # # for menu_item in palette.menu.get_children(): # palette.menu.remove(menu_item) # # palette.menu.append(item_1) # palette.menu.append(item_2) # # item_1.connect('activate', self.set_shape, tool, 'square') # item_2.connect('activate', self.set_shape, tool, 'circle') # # item_1.show() # item_2.show() # TODO: insert images to represent shapes item1 = gtk.RadioButton(None, _('Circle')) item1.show() item1.set_active(True) item2 = gtk.RadioButton(item1, _('Square')) item2.show() item1.connect('toggled', self._on_toggled, tool, 'circle') item2.connect('toggled', self._on_toggled, tool, 'square') label = gtk.Label(_('Shape')) label.show() vbox = gtk.VBox() vbox.show() vbox.pack_start(label) vbox.pack_start(item1) vbox.pack_start(item2) #palette.action_bar.pack_start(vbox) palette.set_content(vbox) separator = gtk.HSeparator() vbox.pack_end(separator1) separator.show() # User is able to fill or not a polygon, and its fill color if tool['name'] is self._TOOL_POLYGON['name']: # Creating a CheckButton named "Fill". fill_checkbutton = gtk.CheckButton(_('Fill')) fill_checkbutton.show() #fill_checkbutton.set_active(self._activity._area.fill) fill_checkbutton.set_active(self._TOOL_POLYGON['fill']) fill_checkbutton.connect('toggled', self._on_fill_checkbutton_toggled, widget, self._TOOL_POLYGON) palette.set_content(fill_checkbutton) # Creating Fill Color Button label = gtk.Label(_('Fill Color')) label.show() colorbutton = ButtonFillColor(self._activity) colorbutton.show() palette.action_bar.pack_start(label) palette.action_bar.pack_start(colorbutton) colorbutton.connect_after('color-set', self._on_color_set, self._TOOL_POLYGON) def set_shape(self, widget=None, tool=None, shape=None): """ Set a tool shape according to user choice at Tool Palette @param self -- gtk.Toolbar @param widget -- The connected widget, if any; necessary in case this method is used in a connect() @param tool -- A dictionnary to determine which tool is been using @param shape -- Determine which shape Brush and Erase will use """ tool['shape'] = shape self.set_tool(tool=tool) def set_tool(self, widget=None, tool=None): """ Set tool to the Area object. Configures tool's color and size. @param self -- gtk.Toolbar @param widget -- The connected widget, if any; necessary in case this method is used in a connect() @param tool -- A dictionnary to determine which tool is been using """ # New method to set tools; using dict # Color must be allocated; if not, it will be displayed as black new_color = self._stroke_color.get_color() tool['stroke color'] = self._stroke_color.alloc_color(new_color) self._activity._area.set_tool(tool) # Moving this to Area #setting cursor # try: # pixbuf = gtk.gdk.pixbuf_new_from_file('./images/' + tool['name'] + '.png') # cursor = gtk.gdk.Cursor(gtk.gdk.display_get_default() , pixbuf, 6, 21) # except: # cursor = None # # self._activity._area.window.set_cursor(cursor) def _on_icon_stroke_clicked(self, widget, data=None): self._stroke_color.clicked() def _on_fill_checkbutton_toggled(self, checkbutton, button=None, tool=None): logging.debug('Checkbutton is Active: %s', checkbutton.get_active() ) # New method for setting tools #self._activity._area.fill = checkbutton.get_active() tool['fill'] = checkbutton.get_active() self.set_tool(tool=tool) def _on_fill_checkbutton_map(self, checkbutton, data=None): """ Update checkbutton condition to agree with Area.Area object; this prevents tools to have fill checked but be drawed not filled. @param self -- gtk.Toolbar @param checkbutton @param data """ self._activity._area.fill = checkbutton.get_active() def _on_color_set(self, colorbutton, tool): logging.debug('toolbox.ToolsToolbar._on_color_set') # Color must be allocated; if not, it will be displayed as black new_color = colorbutton.get_color() tool['fill color'] = colorbutton.alloc_color(new_color) self.set_tool(tool=tool) def _on_value_changed(self, spinbutton, tool): size = spinbutton.get_value_as_int() tool['size'] = size self.set_tool(tool=tool) def _on_toggled(self, radiobutton, tool, shape): if radiobutton.get_active(): self.set_shape(tool=tool, shape=shape) ''' ##Class to manage Fill colors class ComboFillColors(ToolComboBox): ## The Constructor def __init__(self, activity): ToolComboBox.__init__(self) self._activity = activity self._fill_color = self.combo self._fill_color.append_item(self.alloc_color('#000000'), 'Black') self._fill_color.append_item(self.alloc_color('#ffffff'), 'White') self._fill_color.append_item(self.alloc_color('#800000'), 'Maroon') self._fill_color.append_item(self.alloc_color('#ff0000'), 'Red') self._fill_color.append_item(self.alloc_color('#808000'), 'Olive') self._fill_color.append_item(self.alloc_color('#ffff00'), 'Yellow') self._fill_color.append_item(self.alloc_color('#008000'), 'Green') self._fill_color.append_item(self.alloc_color('#00ff00'), 'Lime') self._fill_color.append_item(self.alloc_color('#008080'), 'Teal') self._fill_color.append_item(self.alloc_color('#00ffff'), 'Aqua') self._fill_color.append_item(self.alloc_color('#000080'), 'Navy') self._fill_color.append_item(self.alloc_color('#0000ff'), 'Blue') self._fill_color.append_item(self.alloc_color('#800080'), 'Purple') self._fill_color.append_item(self.alloc_color('#ff00ff'), 'Fuchsia') self._fill_color.set_active(0) self._fill_color.connect('changed', self._combo_changed_cb) def alloc_color(self, color): """Alloc new color. @param self -- gtk.Toolbar @param color -- hexadecimal number @return gdk.Color object """ colormap = self.get_colormap() _COLOR_ = colormap.alloc_color(color, True, True) return _COLOR_ def _combo_changed_cb(self, combo): color = self.get_color() self.set_fill_color(color) def set_fill_color(self, color): """Set the fill color in Area @param self -- gtk.Toolbar @param color -- a gdk.Color object """ self._activity._area._set_fill_color(color) def get_color(self): """Get the fill color from combobox @param self -- gtk.Toolbar @return gdk.Color object """ model = self.combo.get_model() active = self.combo.get_active() return model[active][0] ##Class to manage Stroke colors class ComboStrokeColors(ToolComboBox): ##The Constructor def __init__(self, activity): ToolComboBox.__init__(self) self._activity = activity self._stroke_color = self.combo self._stroke_color.append_item(self.alloc_color('#000000'), 'Black') self._stroke_color.append_item(self.alloc_color('#ffffff'), 'White') self._stroke_color.append_item(self.alloc_color('#800000'), 'Maroon') self._stroke_color.append_item(self.alloc_color('#ff0000'), 'Red') self._stroke_color.append_item(self.alloc_color('#808000'), 'Olive') self._stroke_color.append_item(self.alloc_color('#ffff00'), 'Yellow') self._stroke_color.append_item(self.alloc_color('#008000'), 'Green') self._stroke_color.append_item(self.alloc_color('#00ff00'), 'Lime') self._stroke_color.append_item(self.alloc_color('#008080'), 'Teal') self._stroke_color.append_item(self.alloc_color('#00ffff'), 'Aqua') self._stroke_color.append_item(self.alloc_color('#000080'), 'Navy') self._stroke_color.append_item(self.alloc_color('#0000ff'), 'Blue') self._stroke_color.append_item(self.alloc_color('#800080'), 'Purple') self._stroke_color.append_item(self.alloc_color('#ff00ff'), 'Fuchsia') self._stroke_color.set_active(0) self._stroke_color.connect('changed', self._combo_changed_cb) def alloc_color(self, color): """Alloc new color. @param self -- gtk.Toolbar @param color -- hexadecimal number @return gdk.Color object """ colormap = self.get_colormap() _COLOR_ = colormap.alloc_color(color, True, True) return _COLOR_ def _combo_changed_cb(self, combo): color = self.get_color() self.set_stroke_color(color) def get_color(self): """Get the fill color from combobox @param self -- gtk.Toolbar @return a gdk.Color object """ model = self.combo.get_model() active = self.combo.get_active() return model[active][0] def set_stroke_color(self, color): """Set the fill color in Area @param self -- gtk.Toolbar @param color -- a gdk.Color object """ self._activity._area._set_stroke_color(color) ''' ##Class to manage Stroke Size class ComboStrokeSize(ToolComboBox): _ACTION_1 = 1 _ACTION_2 = 2 _ACTION_3 = 3 _ACTION_5 = 5 _ACTION_10 = 10 _ACTION_20 = 20 _ACTION_50 = 50 _ACTION_100 = 100 """ _ACTION_500 = 500 _ACTION_1000 = 1000 _ACTION_5000 = 5000 _ACTION_10000 = 10000 _ACTION_100000 = 100000 """ ##The Constructor def __init__(self, activity): ToolComboBox.__init__(self) self._activity = activity self._stroke_size = self.combo self._stroke_size.append_item(self._ACTION_1, _('1')) self._stroke_size.append_item(self._ACTION_2, _('2')) self._stroke_size.append_item(self._ACTION_3, _('3')) self._stroke_size.append_item(self._ACTION_5, _('5')) self._stroke_size.append_item(self._ACTION_10, _('10')) self._stroke_size.append_item(self._ACTION_20, _('20')) self._stroke_size.append_item(self._ACTION_50, _('50')) self._stroke_size.append_item(self._ACTION_100, _('100')) """ self._stroke_size.append_item(self._ACTION_500, _('500')) self._stroke_size.append_item(self._ACTION_1000, _('1000')) self._stroke_size.append_item(self._ACTION_5000, _('5000')) self._stroke_size.append_item(self._ACTION_10000, _('10000')) self._stroke_size.append_item(self._ACTION_100000, _('100000')) """ self._stroke_size.set_active(1) self._stroke_size.connect('changed', self._combo_changed_cb) def _combo_changed_cb(self, combo): # model = combo.get_model() # active = combo.get_active() # self.set_stroke_size(model[active][0]) size = self.get_size() self.set_stroke_size(size) def set_stroke_size(self, size): self._activity._area.configure_line(size) def get_size(self): model = self.combo.get_model() active = self.combo.get_active() return model[active][0] ##Class to manage the Fill Color of a Button class ButtonFillColor(gtk.ColorButton): ##The Constructor def __init__(self, activity): gtk.ColorButton.__init__(self) self._activity = activity self.connect('color-set', self._color_button_cb) def _color_button_cb(self, widget): color = self.get_color() self.set_fill_color(color) def alloc_color(self, color): colormap = self._activity._area.get_colormap() return colormap.alloc_color(color.red, color.green, color.blue) def set_fill_color(self, color): new_color = self.alloc_color(color) self._activity._area._set_fill_color(new_color) ##Class to manage the Stroke Color of a Button class ButtonStrokeColor(gtk.ColorButton): ##The Constructor def __init__(self, activity): gtk.ColorButton.__init__(self) self._activity = activity self.connect('color-set', self._color_button_cb) def _color_button_cb(self, widget): color = self.get_color() self.set_stroke_color(color) def alloc_color(self, color): colormap = self._activity._area.get_colormap() return colormap.alloc_color(color.red, color.green, color.blue) def set_stroke_color(self, color): new_color = self.alloc_color(color) self._activity._area._set_stroke_color(new_color) ##Make the Shapes Toolbar class ShapesToolbar(gtk.Toolbar): _SHAPE_ARROW = 'arrow' _SHAPE_CURVE = 'curve' _SHAPE_ELLIPSE = 'ellipse' _SHAPE_FREEFORM = 'freeform' _SHAPE_HEART = 'heart' _SHAPE_LINE = 'line' _SHAPE_PARALLELOGRAM = 'parallelogram' _SHAPE_POLYGON = 'polygon_regular' _SHAPE_RECTANGLE = 'rectangle' _SHAPE_STAR = 'star' _SHAPE_TRAPEZOID = 'trapezoid' _SHAPE_TRIANGLE = 'triangle' ##The Constructor def __init__(self, activity): gtk.Toolbar.__init__(self) self._activity = activity self._icon_fill = ToolButton('icon-fill') self.insert(self._icon_fill, -1) self._icon_fill.show() self._icon_fill.set_tooltip(_('Fill Color')) self._fill_color = ButtonFillColor(activity) self._fill_color.show() item = gtk.ToolItem() item.add(self._fill_color) self.insert(item, -1) item.show() self._icon_stroke = ToolButton('icon-stroke') self.insert(self._icon_stroke, -1) self._icon_stroke.show() self._icon_stroke.set_tooltip(_('Stroke Color')) self._stroke_color = ButtonStrokeColor(activity) self._stroke_color.show() item = gtk.ToolItem() item.add(self._stroke_color) self.insert(item, -1) item.show() self._stroke_size = ComboStrokeSize(activity) self.insert(self._stroke_size, -1) self._stroke_size.show() separator = gtk.SeparatorToolItem() separator.set_draw(True) self.insert(separator, -1) separator.show() self._shape_ellipse = ToolButton('tool-shape-ellipse') self.insert(self._shape_ellipse, -1) self._shape_ellipse.show() self._shape_ellipse.set_tooltip(_('Ellipse')) try: self._configure_palette_shape_ellipse() except: logging.debug('Could not create palette for Shape Ellipse') self._shape_rectangle = ToolButton('tool-shape-rectangle') self.insert(self._shape_rectangle, -1) self._shape_rectangle.show() self._shape_rectangle.set_tooltip(_('Rectangle')) try: self._configure_palette_shape_rectangle() except: logging.debug('Could not create palette for Shape Ellipse') self._shape_line = ToolButton('tool-shape-line') self.insert(self._shape_line, -1) self._shape_line.show() self._shape_line.set_tooltip(_('Line')) self._shape_polygon = ToolButton('tool-shape-polygon') self.insert(self._shape_polygon, -1) self._shape_polygon.show() self._shape_polygon.set_tooltip(_('Polygon')) try: self._configure_palette_shape_polygon() except: logging.debug('Could not create palette for Regular Polygon') """ self._shape_freeform = ToolButton('tool-shape-freeform') self.insert(self._shape_freeform, -1) self._shape_freeform.show() self._shape_freeform.set_tooltip(_('Freeform')) """ self._shape_heart = ToolButton('tool-shape-heart') self.insert(self._shape_heart, -1) self._shape_heart.show() self._shape_heart.set_tooltip(_('Heart')) try: self._configure_palette_shape_heart() except: logging.debug('Could not create palette for Shape Heart') self._shape_parallelogram = ToolButton('tool-shape-parallelogram') self.insert(self._shape_parallelogram, -1) self._shape_parallelogram.show() self._shape_parallelogram.set_tooltip(_('Parallelogram')) try: self._configure_palette_shape_parallelogram() except: logging.debug('Could not create palette for Shape Parallelogram') self._shape_arrow = ToolButton('tool-shape-arrow') self.insert(self._shape_arrow, -1) self._shape_arrow.show() self._shape_arrow.set_tooltip(_('Arrow')) try: self._configure_palette_shape_arrow() except: logging.debug('Could not create palette for Shape Arrow') self._shape_star = ToolButton('tool-shape-star') self.insert(self._shape_star, -1) self._shape_star.show() self._shape_star.set_tooltip(_('Star')) try: self._configure_palette_shape_star() except: logging.debug('Could not create palette for Shape Star') self._shape_trapezoid = ToolButton('tool-shape-trapezoid') self.insert(self._shape_trapezoid, -1) self._shape_trapezoid.show() self._shape_trapezoid.set_tooltip(_('Trapezoid')) try: self._configure_palette_shape_trapezoid() except: logging.debug('Could not create palette for Shape Trapezoid') self._shape_triangle = ToolButton('tool-shape-triangle') self.insert(self._shape_triangle, -1) self._shape_triangle.show() self._shape_triangle.set_tooltip(_('Triangle')) try: self._configure_palette_shape_triangle() except: logging.debug('Could not create palette for Shape Triangle') self._icon_stroke.connect('clicked', self._on_icon_stroke_clicked) self._icon_fill.connect('clicked', self._on_icon_fill_clicked) self._shape_arrow.connect('clicked', self.set_tool, self._SHAPE_ARROW) self._shape_ellipse.connect('clicked', self.set_tool, self._SHAPE_ELLIPSE) #self._shape_freeform.connect('clicked', self.set_tool, self._SHAPE_FREEFORM) self._shape_heart.connect('clicked', self.set_tool, self._SHAPE_HEART) self._shape_line.connect('clicked', self.set_tool, self._SHAPE_LINE) self._shape_parallelogram.connect('clicked', self.set_tool, self._SHAPE_PARALLELOGRAM) self._shape_polygon.connect('clicked', self.set_tool, self._SHAPE_POLYGON) self._shape_rectangle.connect('clicked', self.set_tool, self._SHAPE_RECTANGLE) self._shape_star.connect('clicked', self.set_tool, self._SHAPE_STAR) self._shape_trapezoid.connect('clicked', self.set_tool, self._SHAPE_TRAPEZOID) self._shape_triangle.connect('clicked', self.set_tool, self._SHAPE_TRIANGLE) def set_tool(self, widget, tool): # setting tool self._activity._area.tool = tool # setting size and color size = self._stroke_size.get_size() self._stroke_size.set_stroke_size(size) stroke_color = self._stroke_color.get_color() self._stroke_color.set_stroke_color(stroke_color) fill_color = self._fill_color.get_color() self._fill_color.set_fill_color(fill_color) #setting cursor try: pixbuf = gtk.gdk.pixbuf_new_from_file('./images/' + tool + '.png') cursor = gtk.gdk.Cursor(gtk.gdk.display_get_default() , pixbuf, 6, 21) except: cursor = None self._activity._area.window.set_cursor(cursor) def _on_icon_stroke_clicked(self, widget, data=None): self._stroke_color.clicked() def _on_icon_fill_clicked(self, widget, data=None): self._fill_color.clicked() def _on_value_changed(self, spinbutton, data=None): self._activity._area.polygon_sides = spinbutton.get_value_as_int() if data is self._SHAPE_POLYGON: self.set_tool(self._shape_polygon, self._SHAPE_POLYGON) elif data is self._SHAPE_STAR: self.set_tool(self._shape_star, self._SHAPE_STAR) def _on_fill_checkbutton_toggled(self, checkbutton, button=None): logging.debug('Checkbutton is Active: %s', checkbutton.get_active() ) self._activity._area.fill = checkbutton.get_active() try: button.emit('clicked') except: pass def _configure_palette_shape_ellipse(self): logging.debug('Creating palette to shape ellipse') self._create_simple_palette(self._shape_ellipse) def _configure_palette_shape_rectangle(self): logging.debug('Creating palette to shape rectangle') self._create_simple_palette(self._shape_rectangle) def _configure_palette_shape_polygon(self): logging.debug('Creating palette to shape polygon') self._create_simple_palette(self._shape_polygon) palette = self._shape_polygon.get_palette() spin = gtk.SpinButton() spin.show() # When inserted in a Palette, a spinbutton does not display text in black black = gtk.gdk.Color(0,0,0) spin.modify_text(gtk.STATE_NORMAL, black) # This is where we set restrictions for Regular Polygon: # Initial value, minimum value, maximum value, step try: initial = float(self._activity._area.polygon_sides) except: initial = 5.0 adj = gtk.Adjustment(initial, 3.0, 50.0, 1.0) spin.set_adjustment(adj) spin.set_numeric(True) label = gtk.Label(_('Sides: ')) label.show() palette.action_bar.pack_start(label) palette.action_bar.pack_start(spin) spin.connect('value-changed', self._on_value_changed, self._SHAPE_POLYGON) def _configure_palette_shape_heart(self): logging.debug('Creating palette to shape heart') self._create_simple_palette(self._shape_heart) def _configure_palette_shape_parallelogram(self): logging.debug('Creating palette to shape parallelogram') self._create_simple_palette(self._shape_parallelogram) def _configure_palette_shape_arrow(self): logging.debug('Creating palette to shape arrow') self._create_simple_palette(self._shape_arrow) def _configure_palette_shape_star(self): logging.debug('Creating palette to shape star') self._create_simple_palette(self._shape_star) palette = self._shape_star.get_palette() spin = gtk.SpinButton() spin.show() # When inserted in a Palette, a spinbutton does not display text in black black = gtk.gdk.Color(0,0,0) spin.modify_text(gtk.STATE_NORMAL, black) # This is where we set restrictions for Star: # Initial value, minimum value, maximum value, step try: initial = float(self._activity._area.polygon_sides) except: initial = 5.0 adj = gtk.Adjustment(initial, 3.0, 50.0, 1.0) spin.set_adjustment(adj) spin.set_numeric(True) label = gtk.Label(_('Points: ')) label.show() palette.action_bar.pack_start(label) palette.action_bar.pack_start(spin) # It is connected to the same method that Regular Polygon's Palette is because they use the same property in Area spin.connect('value-changed', self._on_value_changed, self._SHAPE_STAR) def _configure_palette_shape_trapezoid(self): logging.debug('Creating palette to shape trapezoid') self._create_simple_palette(self._shape_trapezoid) def _configure_palette_shape_triangle(self): logging.debug('Creating palette to shape triangle') self._create_simple_palette(self._shape_triangle) def _create_simple_palette(self, button): """ Create a simple palette with an CheckButton named "Fill". Most tools use only this. @param self -- gtk.Toolbar @param button -- a ToolButton to associate the palette. """ palette = button.get_palette() fill_checkbutton = gtk.CheckButton(_('Fill')) fill_checkbutton.show() fill_checkbutton.set_active(self._activity._area.fill) fill_checkbutton.connect('toggled', self._on_fill_checkbutton_toggled, button) fill_checkbutton.connect('map', self._on_fill_checkbutton_map) # widget.connect_after('clicked', self._on_fill_checkbutton_after_clicked, fill_checkbutton) palette.set_content(fill_checkbutton) def _on_fill_checkbutton_map(self, checkbutton, data=None): """ Update checkbutton condition to agree with Area.Area object; this prevents tools to have fill checked but be drawed not filled. @param self -- gtk.Toolbar @param checkbutton @param data """ self._activity._area.fill = checkbutton.get_active() # def _on_fill_checkbutton_after_clicked(self, widget, checkbutton): # # Trying to prevent same condition described at self._on_fill_checkbutton_map # self._activity._area.fill = checkbutton.get_active() ##Make the Text Toolbar class TextToolbar(gtk.Toolbar): _ACTION_TEXT = 'text' ##The Constructor def __init__(self, activity): gtk.Toolbar.__init__(self) self._activity = activity self._text = ToolButton('text') self.insert(self._text, -1) self._text.show() self._text.set_tooltip(_('Type')) self._text.connect('clicked', self.set_tool, self._ACTION_TEXT) self._text_color = ButtonFillColor(activity) self._text_color.show() item = gtk.ToolItem() item.add(self._text_color) self.insert(item, -1) item.show() separator = gtk.SeparatorToolItem() separator.set_draw(True) self.insert(separator, -1) separator.show() """ #FIXME: this button is not connected to the right callback self._bold = ToggleToolButton('format-text-bold') self.insert(self._bold, -1) self._bold.show() self._bold.connect('clicked', test_connect, activity, 'bold') #FIXME: this button is not connected to the right callback self._italic = ToggleToolButton('format-text-italic') self.insert(self._italic, -1) self._italic.show() self._italic.connect('clicked', test_connect, activity, 'italic') #FIXME: this button is not connected to the right callback self._underline = ToggleToolButton('format-text-underline') self.insert(self._underline, -1) self._underline.show() self._underline.connect('clicked', test_connect, activity, 'underline') # Displays a few colors in a ComboBox # TODO: User's choice is done when clicking at the first Combo item # TODO: Keep previous choices at the list self._text_color = ComboBox() self._text_color.append_text('red') #FIXME: must use a gtk.ToolItem to use 'insert' method #self.insert(self._text_color, -1) self._text_color.show() """ def set_tool(self, widget, tool): #FIXME: this callback must change as others buttons get enabled self._activity._area.tool = tool color = self._text_color.get_color() self._text_color.set_fill_color(color) # setting cursor pixbuf = gtk.gdk.pixbuf_new_from_file('./images/text.png') cursor = gtk.gdk.Cursor(gtk.gdk.display_get_default() , pixbuf, 6, 21) self._activity._area.window.set_cursor(cursor) ##Make the Images Toolbar class ImageToolbar(gtk.Toolbar): _OBJECT_HEIGHT = 'height' _OBJECT_INSERT = 'insert' _OBJECT_ROTATE_LEFT = 'rotate-left' _OBJECT_ROTATE_RIGHT = 'rotate-right' _OBJECT_WIDTH = 'width' ##The Constructor def __init__(self, activity): gtk.Toolbar.__init__(self) self._object_insert = ToolButton('object-insert') self.insert(self._object_insert, -1) self._object_insert.show() self._object_insert.set_tooltip(_('Insert Image')) separator = gtk.SeparatorToolItem() separator.set_draw(True) self.insert(separator, -1) separator.show() """ self._object_rotate_left = ToolButton('object-rotate-left') self.insert(self._object_rotate_left, -1) self._object_rotate_left.show() self._object_rotate_left.set_tooltip(_('Rotate Left')) self._object_rotate_right = ToolButton('object-rotate-right') self.insert(self._object_rotate_right, -1) self._object_rotate_right.show() self._object_rotate_right.set_tooltip(_('Rotate Right')) """ self._object_height = ToolButton('object-height') self.insert(self._object_height, -1) self._object_height.show() self._object_height.set_tooltip(_('Height')) self._object_width = ToolButton('object-width') self.insert(self._object_width, -1) self._object_width.show() self._object_width.set_tooltip(_('Width')) self._configure_palette_resize(self._object_height, 'object-height', activity) self._configure_palette_resize(self._object_width, 'object-width', activity) # self._object_height.connect('clicked', self.resize, activity, 'object-height', self._OBJECT_HEIGHT) self._object_insert.connect('clicked', self.insertImage, activity) #self._object_rotate_left.connect('clicked', self.rotate_left, activity) #self._object_rotate_right.connect('clicked', set_tool, activity, 'object-rotate-right', self._OBJECT_ROTATE_RIGHT) # self._object_width.connect('clicked', self.resize, activity, 'object-width', self._OBJECT_WIDTH) def rotate_left(self, widget, activity): #activity._area._rotate_left(widget) pass def _resize(self, spinButton, tool, activity): size = spinButton.get_value_as_int() if activity._area.tool == 'marquee-rectangular' and activity._area.selmove: if tool == "object-height": activity._area.d.resizeSelection(activity._area,1., float(size)/100) elif tool == "object-width": activity._area.d.resizeSelection(activity._area,float(size)/100, 1.) def _configure_palette_resize(self, widget, tool, activity): """Set palette for a tool - width or height @param self -- gtk.Toolbar @param widget - the widget which Palette will be set, a ToolButton object @param tool @param activity """ logging.debug('setting a palette for %s', tool) palette = widget.get_palette() spin = gtk.SpinButton() spin.show() # When inserted in a Palette, a spinbutton does not display text in black black = gtk.gdk.Color(0,0,0) spin.modify_text(gtk.STATE_NORMAL, black) # This is where we set restrictions for Resizing: # Initial value, minimum value, maximum value, step initial = float(100) adj = gtk.Adjustment(initial, 10.0, 500.0, 1.0) spin.set_adjustment(adj) spin.set_numeric(True) label = gtk.Label(_('Resize (%): ')) label.show() palette.action_bar.pack_start(label) palette.action_bar.pack_start(spin) spin.connect('value-changed', self._resize, tool, activity) def insertImage(self, widget, activity): # TODO: add a filter to display images only. dialog = gtk.FileChooserDialog(title=(_('Open File...')), action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) dialog.show_all() logging.debug('Importing image from file') response = dialog.run() if response == gtk.RESPONSE_OK: file_path = dialog.get_filename() logging.debug('file selected') logging.debug(file_path) #file_path = decode_path((file_path,))[0] #open(activity, file_path) activity._area.loadImage(file_path,widget,True) elif response == gtk.RESPONSE_CANCEL: logging.debug('Closed, no files selected') dialog.destroy() ##Make the Effects Tools Toolbar class EffectsToolbar(gtk.Toolbar): _EFFECT_GRAYSCALE = 'grayscale' _EFFECT_RAINBOW = 'rainbow' ##The Constructor def __init__(self, activity): gtk.Toolbar.__init__(self) self._activity = activity self._effect_grayscale = ToolButton('effect-grayscale') self.insert(self._effect_grayscale, -1) self._effect_grayscale.show() self._effect_grayscale.set_tooltip(_('Grayscale')) self._effect_rainbow = ToolButton('effect-raindow') self.insert(self._effect_rainbow, -1) self._effect_rainbow.show() self._effect_rainbow.set_tooltip(_('Rainbow')) self._configure_palette(self._effect_rainbow, self._EFFECT_RAINBOW) separator = gtk.SeparatorToolItem() self.insert(separator, -1) separator.show() """ #FIXME: Must be implemented self._black_and_white = ToolButton('black_and_white') self.insert(self._black_and_white, -1) self._black_and_white.show() self._black_and_white.connect('clicked', test_connect, activity, 'effect-black-and-white') self._black_and_white.set_tooltip(_('Black and White')) self._invert_colors = ToolButton('invert_colors') self.insert(self._invert_colors, -1) self._invert_colors.show() self._invert_colors.connect('clicked', test_connect, activity, 'invert-colors') self._invert_colors.set_tooltip(_('Invert Colors')) """ self._effect_grayscale.connect('clicked', self.grayscale) self._effect_rainbow.connect('clicked', self.rainbow) ##Make the colors be in grayscale def grayscale(self, widget): self._activity._area.grayscale(widget) ##Like the brush, but change it color when painting def rainbow(self, widget): self._activity._area.tool = self._EFFECT_RAINBOW # setting cursor try: pixbuf = gtk.gdk.pixbuf_new_from_file('./images/rainbow.png') cursor = gtk.gdk.Cursor(gtk.gdk.display_get_default() , pixbuf, 6, 21) except: cursor = None self._activity._area.window.set_cursor(cursor) def _configure_palette(self, widget, tool=None): """Set palette for a tool @param self -- gtk.Toolbar @param widget - the widget which Palette will be set @param tool - the reference tool for Palette creation. Its values are restricted to Class constants """ logging.debug('setting a palette for %s', tool) palette = widget.get_palette() if tool is None: return elif tool is self._EFFECT_RAINBOW: spin = gtk.SpinButton() spin.show() black = gtk.gdk.Color(0,0,0) #white = gtk.gdk.Color(255,255,255) #spin.modify_base(gtk.STATE_NORMAL, black) #spin.modify_base(gtk.STATE_ACTIVE, white) spin.modify_text(gtk.STATE_NORMAL, black) # This is where we set restrictions for Rainbow: # Initial value, minimum value, maximum value, step adj = gtk.Adjustment(5.0, 1.0, 100.0, 1.0) spin.set_adjustment(adj) spin.set_numeric(True) label = gtk.Label(_('Size: ')) label.show() palette.action_bar.pack_start(label) palette.action_bar.pack_start(spin) spin.connect('value-changed', self._on_value_changed) def _on_value_changed(self, spinbutton, data=None): size = spinbutton.get_value_as_int() self._activity._area.configure_line(size) self.rainbow(self._effect_rainbow) ##Make the View Toolbar class ViewToolbar(gtk.Toolbar): _ACTION_1000 = 0 _ACTION_500 = 1 _ACTION_200 = 2 _ACTION_150 = 3 _ACTION_100 = 4 _ACTION_50 = 5 _ACTION_25 = 6 _ACTION_10 = 7 ##The Constructor def __init__(self, activity): gtk.Toolbar.__init__(self) tool_item = ToolComboBox() self._view_percent = tool_item.combo self._view_percent.append_item(self._ACTION_1000, _('1000')) self._view_percent.append_item(self._ACTION_500, _('500')) self._view_percent.append_item(self._ACTION_200, _('200')) self._view_percent.append_item(self._ACTION_150, _('150')) self._view_percent.append_item(self._ACTION_100, _('100')) self._view_percent.append_item(self._ACTION_50, _('50')) self._view_percent.append_item(self._ACTION_25, _('25')) self._view_percent.append_item(self._ACTION_10, _('10')) self._view_percent.set_active(0) self._view_percent.connect('changed', self._combo_changed_cb) self.insert(tool_item, -1) tool_item.show() separator = gtk.SeparatorToolItem() self.insert(separator, -1) separator.show() self._zoom_plus = ToolButton('zoom-plus') self.insert(self._zoom_plus, -1) self._zoom_plus.show() self._zoom_plus.set_tooltip(_('ZOOM +')) self._zoom_minus = ToolButton('zoom-minus') self.insert(self._zoom_minus, -1) self._zoom_minus.show() self._zoom_minus.set_tooltip(_('ZOOM -')) ''' # FIXME: these callbacks are not implemented self._zoom_plus.connect('clicked', test_connect, activity, 'zoom_plus') self._zoom_minus.connect('clicked', test_connect, activity, 'zoom_minus') ''' def _combo_changed_cb(self, combo): if combo == self._view_percent: print 'treeeter'