From 1e622866f18294b956faa178c0a8675d3dac4315 Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Fri, 22 Feb 2013 20:16:03 +0000 Subject: changes in support of touch --- diff --git a/icons/move-active.svg b/icons/move-active.svg new file mode 100644 index 0000000..f33ba33 --- /dev/null +++ b/icons/move-active.svg @@ -0,0 +1,56 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/icons/move.svg b/icons/move.svg new file mode 100644 index 0000000..2e84448 --- /dev/null +++ b/icons/move.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + diff --git a/labyrinthactivity.py b/labyrinthactivity.py index 3340bc6..a17eb93 100644 --- a/labyrinthactivity.py +++ b/labyrinthactivity.py @@ -37,14 +37,16 @@ from sugar.datastore import datastore from port.tarball import Tarball try: - # >= 0.86 toolbars - from sugar.graphics.toolbarbox import ToolbarButton, ToolbarBox - from sugar.activity.widgets import ActivityToolbarButton - from sugar.activity.widgets import StopButton + from sugar.graphics.toolbarbox import ToolbarBox + HASTOOLBARBOX = True except ImportError: - # <= 0.84 toolbars + HASTOOLBARBOX = False pass +if HASTOOLBARBOX: + from sugar.graphics.toolbarbox import ToolbarButton + from sugar.activity.widgets import ActivityToolbarButton + from sugar.activity.widgets import StopButton # labyrinth sources are shipped inside the 'src' subdirectory sys.path.append(os.path.join(activity.get_bundle_path(), 'src')) @@ -128,14 +130,23 @@ class ViewToolbar(gtk.Toolbar): def __zoom_in_cb(self, button): self._main_area.scale_fac *= 1.2 self._main_area.invalidate() + if len(self._main_area.selected) == 1: + if hasattr(self._main_area.selected[0], 'textview'): + self._main_area.selected[0].remove_textview() def __zoom_out_cb(self, button): self._main_area.scale_fac /= 1.2 self._main_area.invalidate() + if len(self._main_area.selected) == 1: + if hasattr(self._main_area.selected[0], 'textview'): + self._main_area.selected[0].remove_textview() def __zoom_original_cb(self, button): self._main_area.scale_fac = 1.0 self._main_area.invalidate() + if len(self._main_area.selected) == 1: + if hasattr(self._main_area.selected[0], 'textview'): + self._main_area.selected[0].remove_textview() def __zoom_tofit_cb(self, button): bounds = self.__get_thought_bounds() @@ -143,6 +154,9 @@ class ViewToolbar(gtk.Toolbar): self._main_area.translation[1] = bounds['y'] self._main_area.scale_fac = bounds['scale'] self._main_area.invalidate() + if len(self._main_area.selected) == 1: + if hasattr(self._main_area.selected[0], 'textview'): + self._main_area.selected[0].remove_textview() def __get_thought_bounds(self): if len(self._main_area.thoughts) == 0: @@ -326,6 +340,7 @@ class TextAttributesToolbar(gtk.Toolbar): self._main_area.set_foreground_color(color) def change_active_font(self): + current_font_name = None current_font = str(self.__attribute_values()["font"]) for index, size in enumerate(self.__font_sizes): index_size = current_font.find(size) @@ -397,8 +412,7 @@ class LabyrinthActivity(activity.Activity): def __init__(self, handle): activity.Activity.__init__(self, handle) - try: - # Use new >= 0.86 toolbar design + if HASTOOLBARBOX: self.max_participants = 1 toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) @@ -447,9 +461,6 @@ class LabyrinthActivity(activity.Activity): toolbar_box.toolbar.insert(self.text_format_toolbar, -1) self._main_area.set_text_attributes(self.text_format_toolbar) - separator = gtk.SeparatorToolItem() - toolbar_box.toolbar.insert(separator, -1) - self.mods = [None] * 6 self.thought_toolbar = ToolbarButton() self.thought_toolbar.props.page = ThoughtsToolbar(self) @@ -457,22 +468,12 @@ class LabyrinthActivity(activity.Activity): self.thought_toolbar.props.label = _('Thought Type') toolbar_box.toolbar.insert(self.thought_toolbar, -1) - separator = gtk.SeparatorToolItem() - separator.props.draw = False - separator.set_expand(True) - separator.show() - toolbar_box.toolbar.insert(separator, -1) - target_toolbar = toolbar_box.toolbar - tool_offset = 6 - - tool = StopButton(self) - toolbar_box.toolbar.insert(tool, -1) toolbar_box.show_all() self.set_toolbar_box(toolbar_box) - except NameError: + else: # Use old <= 0.84 toolbar design toolbox = activity.ActivityToolbox(self) self.set_toolbox(toolbox) @@ -497,7 +498,6 @@ class LabyrinthActivity(activity.Activity): self.edit_toolbar.show() target_toolbar = self.edit_toolbar - tool_offset = 0 self._undo = UndoManager.UndoManager(self, self.edit_toolbar.undo.child, @@ -518,23 +518,39 @@ class LabyrinthActivity(activity.Activity): self.mods[0] = ToolButton('select-mode') self.mods[0].set_tooltip(_('Edit mode')) - self.mods[0].set_accelerator(_('e')) + # self.mods[0].set_accelerator(_('e')) self.mods[0].connect('clicked', self.mode_cb, MMapArea.MODE_NULL) - target_toolbar.insert(self.mods[0], tool_offset) - - #separator = gtk.SeparatorToolItem() - #target_toolbar.insert(separator, tool_offset + 5) + target_toolbar.insert(self.mods[0], -1) tool = ToolButton('link') tool.set_tooltip(_('Link/unlink two selected thoughts')) - tool.set_accelerator(_('l')) + # tool.set_accelerator(_('l')) tool.connect('clicked', self.__link_cb) - target_toolbar.insert(tool, tool_offset + 1) + target_toolbar.insert(tool, -1) + + self.move_button = ToolButton('move') + self.move_button.set_tooltip(_('Move selected though')) + # tool.set_accelerator(_('m')) + self.move_button.connect('clicked', self.__move_cb) + target_toolbar.insert(self.move_button, -1) + + separator = gtk.SeparatorToolItem() + target_toolbar.insert(separator, -1) tool = ToolButton('edit-delete') tool.set_tooltip(_('Erase selected thought(s)')) tool.connect('clicked', self.__delete_cb) - target_toolbar.insert(tool, tool_offset + 2) + target_toolbar.insert(tool, -1) + + if HASTOOLBARBOX: + separator = gtk.SeparatorToolItem() + separator.props.draw = False + separator.set_expand(True) + separator.show() + toolbar_box.toolbar.insert(separator, -1) + + tool = StopButton(self) + toolbar_box.toolbar.insert(tool, -1) self.show_all() self._mode = MMapArea.MODE_TEXT @@ -543,6 +559,10 @@ class LabyrinthActivity(activity.Activity): self.set_focus_child(self._main_area) def __build_main_canvas_area(self): + self.fixed = gtk.Fixed() + self.fixed.show() + self.set_canvas(self.fixed) + self._undo.block() self._main_area = MMapArea.MMapArea(self._undo) self._main_area.connect("set_focus", self.__main_area_focus_cb) @@ -553,12 +573,19 @@ class LabyrinthActivity(activity.Activity): self.__text_selection_cb) self._main_area.connect("thought_selection_changed", self.__thought_selected_cb) - self.set_canvas(self._main_area) + + self._vbox = gtk.VBox() + self._vbox.set_size_request(gtk.gdk.screen_width(), + gtk.gdk.screen_height()) + self._vbox.pack_end(self._main_area, True, True) + self.fixed.put(self._vbox, 0, 0) + self._vbox.show() self._undo.unblock() def __text_selection_cb(self, thought, start, end, text): """Update state of copy button based on text selection """ + logging.debug('text_selection_cb %d %d %s' % (start, end, text)) if start != end: self.__change_copy_state(True) self.text_format_toolbar.props.page.change_active_font() @@ -707,7 +734,9 @@ class LabyrinthActivity(activity.Activity): del fileObject def __main_area_focus_cb(self, arg, event, extended=False): - self._main_area.grab_focus() + # Don't steal focus from textview + # self._main_area.grab_focus() + pass def read_file(self, file_path): tar = Tarball(file_path) @@ -730,8 +759,6 @@ class LabyrinthActivity(activity.Activity): x, y = utils.parse_coords(tmp) self._main_area.translation = [x, y] - self.thought_toolbar.props.page.mods[self._mode].set_active(True) - tar.close() def write_file(self, file_path): @@ -745,6 +772,8 @@ class LabyrinthActivity(activity.Activity): tar.write('MANIFEST', manifest) self._main_area.save_thyself(tar) + self.mods[self._mode].set_active(True) + tar.close() def serialize_to_xml(self, doc, top_element): @@ -765,5 +794,9 @@ class LabyrinthActivity(activity.Activity): def __link_cb(self, widget): self._main_area.link_menu_cb() + def __move_cb(self, widget): + self.move_button.set_icon('move-active') + self._main_area.move_menu_cb(self.move_button) + def __delete_cb(self, widget): self._main_area.delete_selected_elements() diff --git a/src/MMapArea.py b/src/MMapArea.py index 838175a..37473a5 100644 --- a/src/MMapArea.py +++ b/src/MMapArea.py @@ -147,6 +147,7 @@ class MMapArea (gtk.DrawingArea): self.commit_handler = None self.title_change_handler = None self.moving = False + self.move_mode = False self.move_origin = None self.move_origin_new = None self.focus = None @@ -213,8 +214,11 @@ class MMapArea (gtk.DrawingArea): obj = self.find_object_at (coords) if obj: - if event.button == 3: - self.moving = not (event.state & gtk.gdk.CONTROL_MASK) + if event.button == 3 or self.move_mode: + if self.move_mode: + self.moving = True + else: + self.moving = not (event.state & gtk.gdk.CONTROL_MASK) if self.moving: self.set_cursor(gtk.gdk.FLEUR) self.move_origin = (coords[0], coords[1]) @@ -273,7 +277,10 @@ class MMapArea (gtk.DrawingArea): self.move_action = None self.moving = False + self.move_mode = False self.move_origin = None + if hasattr(self, 'move_button'): + self.move_button.set_icon('move') obj = self.find_object_at (coords) @@ -733,7 +740,7 @@ class MMapArea (gtk.DrawingArea): type = self.mode if type == MODE_TEXT: - thought = TextThought.TextThought (coords, self.pango_context, self.nthoughts, self.save, self.undo, loading, self.background_color, self.foreground_color) + thought = TextThought.TextThought (coords, self.pango_context, self.nthoughts, self.save, self.undo, loading, self.background_color, self.foreground_color, fixed=self.parent.parent, parent=self) elif type == MODE_LABEL: thought = LabelThought.LabelThought (coords, self.pango_context, self.nthoughts, self.save, self.undo, loading, self.background_color, self.foreground_color) elif type == MODE_IMAGE: @@ -774,6 +781,9 @@ class MMapArea (gtk.DrawingArea): else: action = None + if hasattr(thought, 'textview'): + thought.remove_textview() + if thought.element in self.element.childNodes: self.element.removeChild (thought.element) self.thoughts.remove (thought) @@ -1179,6 +1189,14 @@ class MMapArea (gtk.DrawingArea): return True return False + def move_menu_cb (self, move_button): + if len(self.selected) == 1: + if hasattr(self.selected[0], 'textview'): + self.selected[0].remove_textview() + self.move_mode = True + self.move_button = move_button + logging.debug('caching move button') + def link_menu_cb (self): if len (self.selected) != 2: return diff --git a/src/TextThought.py b/src/TextThought.py index 1fef255..d376da0 100644 --- a/src/TextThought.py +++ b/src/TextThought.py @@ -20,7 +20,14 @@ # Boston, MA 02110-1301 USA # +# In order to support an on-screen keyboard, a textview widget is used +# instead of capturing individual keyboard events. The down side to +# this is that the maintenance of text attributes is mangled. The good +# news is that much of the complexity disappears. +# --Walter Bender 2013 + import gtk +import gobject import pango import utils import os @@ -37,7 +44,7 @@ UNDO_REMOVE_ATTR=66 UNDO_REMOVE_ATTR_SELECTION=67 class TextThought (ResizableThought): - def __init__ (self, coords, pango_context, thought_number, save, undo, loading, background_color, foreground_color, name="thought"): + def __init__ (self, coords, pango_context, thought_number, save, undo, loading, background_color, foreground_color, name="thought", fixed=None, parent=None): super (TextThought, self).__init__(coords, save, name, undo, background_color, foreground_color) self.index = 0 @@ -56,6 +63,10 @@ class TextThought (ResizableThought): self.current_attrs = [] self.double_click = False self.orig_text = None + self._parent = parent + self._fixed = fixed + self.textview = None + self._textview_handler = None if prefs.get_direction () == gtk.TEXT_DIR_LTR: self.pango_context.set_base_dir (pango.DIRECTION_LTR) @@ -71,7 +82,7 @@ class TextThought (ResizableThought): self.all_okay = True - def index_from_bindex (self, bindex): + def index_from_bindex (self, bindex): if bindex == 0: return 0 index = 0 @@ -102,7 +113,7 @@ class TextThought (ResizableThought): self.attrlist = pango.AttrList () # TODO: splice instead of own method it = self.attributes.get_iterator() - + while 1: at = it.get_attrs() for x in at: @@ -123,7 +134,7 @@ class TextThought (ResizableThought): self.attrlist.splice(ins_style, self.index, len(ins_text)) else: show_text = self.text - + it = self.attributes.get_iterator() while(1): found = False @@ -199,13 +210,13 @@ class TextThought (ResizableThought): self.emit("update-attrs", bold, italics, underline, pango_font) return show_text - def recalc_text_edges (self): + def recalc_text_edges (self): if (not hasattr(self, "layout")): return del self.layout - + show_text = self.attrs_changed () - + r,g,b = utils.selected_colors["fill"] r *= 65536 g *= 65536 @@ -246,12 +257,12 @@ class TextThought (ResizableThought): self.ul = (self.lr[0] - margin[0] - margin[2] - text_w, tmp1) """ - def recalc_edges (self): + def recalc_edges (self): self.lr = (self.ul[0]+self.width, self.ul[1]+self.height) if not self.creating: self.recalc_text_edges() - def commit_text (self, context, string, mode, font_combo_box, font_sizes_combo_box): + def commit_text (self, context, string, mode, font_combo_box, font_sizes_combo_box): font_name = font_combo_box.get_active_text() font_size = font_sizes_combo_box.get_active_text() self.set_font(font_name, font_size) @@ -260,7 +271,7 @@ class TextThought (ResizableThought): self.emit ("title_changed", self.text) self.emit ("update_view") - def add_text (self, string): + def add_text (self, string): if self.index > self.end_index: left = self.text[:self.end_index] right = self.text[self.index:] @@ -276,12 +287,12 @@ class TextThought (ResizableThought): bleft = self.bytes[:self.b_f_i (self.index)] bright = self.bytes[self.b_f_i (self.end_index):] change = self.index - self.end_index + len(string) - else: + else: left = self.text[:self.index] right = self.text[self.index:] bleft = self.bytes[:self.b_f_i(self.index)] bright = self.bytes[self.b_f_i(self.index):] - change = len(string) + change = len(string) it = self.attributes.get_iterator() changes= [] @@ -317,7 +328,7 @@ class TextThought (ResizableThought): changes.append(x) if it.next() == False: break - + del self.attributes self.attributes = pango.AttrList() for x in changes: @@ -329,14 +340,14 @@ class TextThought (ResizableThought): self.index += len (string) self.bytes = bleft + str(len(string)) + bright self.bindex = self.b_f_i (self.index) - self.end_index = self.index + self.end_index = self.index - def draw (self, context): + def draw (self, context): self.recalc_edges () ResizableThought.draw(self, context) if self.creating: return - + (textx, texty) = (self.min_x, self.min_y) if self.am_primary: r, g, b = utils.primary_colors["text"] @@ -364,14 +375,21 @@ class TextThought (ResizableThought): context.set_source_rgb (0,0,0) context.stroke () - def process_key_press (self, event, mode): + def process_key_press (self, event, mode): + # Since we are using textviews, we don't use the + # keypress code anymore + if not self.editing: + return False + else: + return True + modifiers = gtk.accelerator_get_default_mod_mask () shift = event.state & modifiers == gtk.gdk.SHIFT_MASK handled = True clear_attrs = True if not self.editing: return False - + if (event.state & modifiers) & gtk.gdk.CONTROL_MASK: if event.keyval == gtk.keysyms.a: self.index = self.bindex = 0 @@ -410,7 +428,7 @@ class TextThought (ResizableThought): else: handled = False - if clear_attrs: + if clear_attrs: del self.current_attrs self.current_attrs = [] @@ -422,7 +440,7 @@ class TextThought (ResizableThought): return handled - def undo_text_action (self, action, mode): + def undo_text_action (self, action, mode): self.undo.block () if action.undo_type == UndoManager.DELETE_LETTER or action.undo_type == UndoManager.DELETE_WORD: real_mode = not mode @@ -442,7 +460,7 @@ class TextThought (ResizableThought): self.add_text (action.text) self.rebuild_byte_table () self.bindex = self.b_f_i (self.index) - + del self.attributes self.attributes = pango.AttrList() map(lambda a : self.attributes.change(a), attrs) @@ -452,7 +470,7 @@ class TextThought (ResizableThought): self.emit ("grab_focus", False) self.undo.unblock () - def delete_char (self): + def delete_char (self): if self.index == self.end_index == len (self.text): return if self.index > self.end_index: @@ -477,7 +495,7 @@ class TextThought (ResizableThought): changes= [] old_attrs = [] accounted = -change - + it = self.attributes.get_iterator() while (1): (start,end) = it.range() @@ -516,11 +534,11 @@ class TextThought (ResizableThought): changes.append(x) if it.next() == False: break - + del self.attributes self.attributes = pango.AttrList() map(lambda a : self.attributes.change(a), changes) - + self.undo.add_undo (UndoManager.UndoAction (self, UndoManager.DELETE_LETTER, self.undo_text_action, self.b_f_i (self.index), local_text, len(local_text), local_bytes, old_attrs, changes)) @@ -528,7 +546,7 @@ class TextThought (ResizableThought): self.bytes = bleft+bright self.end_index = self.index - def backspace_char (self): + def backspace_char (self): if self.index == self.end_index == 0: return if self.index > self.end_index: @@ -594,12 +612,11 @@ class TextThought (ResizableThought): changes.append(x) if it.next() == False: break - - + del self.attributes self.attributes = pango.AttrList() map(lambda a : self.attributes.change(a), changes) - + self.text = left+right self.bytes = bleft+bright self.end_index = self.index @@ -609,7 +626,7 @@ class TextThought (ResizableThought): if self.index < 0: self.index = 0 - def move_index_back (self, mod): + def move_index_back (self, mod): if self.index <= 0: self.index = 0 return @@ -617,7 +634,7 @@ class TextThought (ResizableThought): if not mod: self.end_index = self.index - def move_index_forward (self, mod): + def move_index_forward (self, mod): if self.index >= len(self.text): self.index = len(self.text) return @@ -625,7 +642,7 @@ class TextThought (ResizableThought): if not mod: self.end_index = self.index - def move_index_up (self, mod): + def move_index_up (self, mod): tmp = self.text.decode () lines = tmp.splitlines () if len (lines) == 1: @@ -659,7 +676,7 @@ class TextThought (ResizableThought): if not mod: self.end_index = self.index - def move_index_down (self, mod): + def move_index_down (self, mod): tmp = self.text.decode () lines = tmp.splitlines () if len (lines) == 1: @@ -683,7 +700,7 @@ class TextThought (ResizableThought): if not mod: self.end_index = self.index - def move_index_horizontal(self, mod, home=False): + def move_index_horizontal(self, mod, home=False): lines = self.text.splitlines () loc = 0 line = 0 @@ -698,12 +715,18 @@ class TextThought (ResizableThought): return line += 1 - def process_button_down (self, event, coords): + def process_button_down (self, event, coords): + if not self._parent.move_mode and self.textview is None: + self._create_textview() + if self.textview is not None: + self.textview.grab_focus() + if ResizableThought.process_button_down(self, event, coords): return True - if not self.editing: - return False + # With textview, we are always editing + # if not self.editing: + # return False modifiers = gtk.accelerator_get_default_mod_mask () @@ -722,6 +745,7 @@ class TextThought (ResizableThought): self.index = len(self.text) self.end_index = 0 # and mark all self.double_click = True + elif event.button == 2: x = int ((coords[0] - self.min_x)*pango.SCALE) y = int ((coords[1] - self.min_y)*pango.SCALE) @@ -734,15 +758,87 @@ class TextThought (ResizableThought): if os.name != 'nt': clip = gtk.Clipboard (selection="PRIMARY") self.paste_text (clip) - + del self.current_attrs - self.current_attrs = [] + self.current_attrs = [] self.recalc_edges() self.emit ("update_view") + logging.debug('calling selection_changed') self.selection_changed() - def process_button_release (self, event, transformed): + def _create_textview(self): + # When the button is pressed inside a text thought, + # create a textview (necessary for invoking the + # on-screen keyboard) instead of processing the text + # by grabbing keyboard events. + if self.textview is None: + self.textview = gtk.TextView() + margin = utils.margin_required (utils.STYLE_NORMAL) + x, y, w, h = self._textview_rescale() + self.textview.set_size_request(w, h) + self._fixed.put(self.textview, x, y) + self.textview.set_justification(gtk.JUSTIFY_CENTER) + self.textview.modify_font( + pango.FontDescription(utils.default_font)) + self.textview.get_buffer().set_text(self.text) + self.textview.show() + if self._textview_handler is None: + self._textview_handler = self.textview.connect( + 'focus-out-event', self._textview_focus_out_cb) + ''' + self.copy_handler = self.textview.connect( + 'copy-clipboard', self._textview_copy_cb) + self.paste_handler = self.textview.connect( + 'paste-clipboard', self._textview_paste_cb) + self.select_handler = self.textview.connect( + 'select-all', self._textview_select_cb) + ''' + self.textview.grab_focus() + self._fixed.show() + + def _textview_rescale(self): + margin = utils.margin_required(utils.STYLE_NORMAL) + w = int((self.width - margin[0] - margin[2]) \ + * self._parent.scale_fac) + h = int((self.height - margin[1] - margin[3]) \ + * self._parent.scale_fac) + xo = gtk.gdk.screen_width() \ + * (1. - self._parent.scale_fac) / 2. + yo = gtk.gdk.screen_height() \ + * (1. - self._parent.scale_fac) / 2. + x = (self.ul[0] + margin[0]) * self._parent.scale_fac + y = (self.ul[1] + margin[1]) * self._parent.scale_fac + return int(x + xo), int(y + yo), int(w), int(h) + + def _textview_copy_cb(self, widget=None, event=None): + logging.debug('copy') + return False + + def _textview_paste_cb(self, widget=None, event=None): + logging.debug('paste') + return False + + def _textview_select_cb(self, widget=None, event=None): + logging.debug('select all') + return False + + def _textview_focus_out_cb(self, widget=None, event=None): + self._textview_process() + return False + + def _textview_process(self): + self.index = 0 + self.end_index = len(self.text) + self.delete_char() + bounds = self.textview.get_buffer().get_bounds() + self.add_text(self.textview.get_buffer().get_text( + bounds[0], bounds[1], True)) + self.emit ("title_changed", self.text) + self.emit ("update_view") + return False + + def process_button_release (self, event, transformed): if self.orig_size: if self.creating: orig_size = self.width >= MIN_SIZE or self.height >= MIN_SIZE @@ -757,15 +853,21 @@ class TextThought (ResizableThought): self.double_click = False return ResizableThought.process_button_release(self, event, transformed) - def selection_changed (self): + def selection_changed (self): (start, end) = (min(self.index, self.end_index), max(self.index, self.end_index)) + logging.debug('emit text_selection_changed') self.emit ("text_selection_changed", start, end, self.text[start:end]) - def handle_motion (self, event, transformed): + def handle_motion (self, event, transformed): if ResizableThought.handle_motion(self, event, transformed): self.recalc_edges() return True + if self.textview is not None and self.ul is not None: + x, y, w, h = self._textview_rescale() + self.textview.set_size_request(w, h) + self._fixed.move(self.textview, x, y) + if not self.editing or self.resizing: return False @@ -784,7 +886,7 @@ class TextThought (ResizableThought): return False - def export (self, context, move_x, move_y): + def export (self, context, move_x, move_y): utils.export_thought_outline (context, self.ul, self.lr, self.background_color, self.am_selected, self.am_primary, utils.STYLE_NORMAL, (move_x, move_y)) @@ -867,7 +969,7 @@ class TextThought (ResizableThought): if not it.next(): break - def rebuild_byte_table (self): + def rebuild_byte_table (self): # Build the Byte table del self.bytes self.bytes = '' @@ -941,12 +1043,14 @@ class TextThought (ResizableThought): self.recalc_edges() def copy_text (self, clip): + logging.debug('copy text') if self.end_index > self.index: clip.set_text (self.text[self.index:self.end_index]) else: clip.set_text (self.text[self.end_index:self.index]) def cut_text (self, clip): + logging.debug('cut text') if self.end_index > self.index: clip.set_text (self.text[self.index:self.end_index]) else: @@ -958,6 +1062,7 @@ class TextThought (ResizableThought): self.emit ("update_view") def paste_text (self, clip): + logging.debug('paste text') text = clip.wait_for_text() if not text: return @@ -968,7 +1073,7 @@ class TextThought (ResizableThought): self.bindex = self.bindex_from_index (self.index) self.emit ("update_view") - def delete_surroundings(self, imcontext, offset, n_chars, mode): + def delete_surroundings(self, imcontext, offset, n_chars, mode): # TODO: Add in Attr stuff orig = len(self.text) left = self.text[:offset] @@ -979,7 +1084,7 @@ class TextThought (ResizableThought): new = len(self.text) if self.index > len(self.text): self.index = len(self.text) - + change = old - new changes = [] old_attrs = [] @@ -1025,7 +1130,7 @@ class TextThought (ResizableThought): changes.append(x) if it.next() == False: break - + del self.attributes self.attributes = pango.AttrList() map(lambda x : self.attributes.change(x), changes) @@ -1037,14 +1142,14 @@ class TextThought (ResizableThought): self.bindex = self.bindex_from_index (self.index) self.emit ("update_view") - def preedit_changed (self, imcontext, mode): + def preedit_changed (self, imcontext, mode): self.preedit = imcontext.get_preedit_string () if self.preedit[0] == '': self.preedit = None self.recalc_edges () self.emit ("update_view") - def retrieve_surroundings (self, imcontext, mode): + def retrieve_surroundings (self, imcontext, mode): imcontext.set_surrounding (self.text, -1, self.bindex) return True @@ -1071,18 +1176,18 @@ class TextThought (ResizableThought): self.recalc_edges() self.emit("update_view") self.undo.unblock() - - def create_attribute(self, attribute, start, end): + + def create_attribute(self, attribute, start, end): if attribute == 'bold': return pango.AttrWeight(pango.WEIGHT_BOLD, start, end) elif attribute == 'italic': return pango.AttrStyle(pango.STYLE_ITALIC, start, end) elif attribute == 'underline': return pango.AttrUnderline(pango.UNDERLINE_SINGLE, start, end) - - def set_attribute(self, active, attribute): - if not self.editing: - return + + def set_attribute(self, active, attribute): + # if not self.editing: + # return if attribute == 'bold': pstyle, ptype, pvalue = (pango.WEIGHT_NORMAL, pango.ATTR_WEIGHT, pango.WEIGHT_BOLD) @@ -1090,14 +1195,14 @@ class TextThought (ResizableThought): pstyle, ptype, pvalue = (pango.STYLE_NORMAL, pango.ATTR_STYLE, pango.STYLE_ITALIC) elif attribute == 'underline': pstyle, ptype, pvalue = (pango.UNDERLINE_NONE, pango.ATTR_UNDERLINE, pango.UNDERLINE_SINGLE) - + index, end_index = (self.index, self.end_index) init = min(index, end_index) end = max(index, end_index) if not active: attr = pango.AttrStyle(pstyle, init, end) - #if index == end_index: + #if index == end_index: # self.current_attrs.change(attr) #else: self.attributes.change(attr) @@ -1116,11 +1221,11 @@ class TextThought (ResizableThought): self.undo_attr_cb,\ attr)) return - + it = self.attributes.get_iterator() old_attrs = self.attributes.copy() changed = [] - + while True: r = it.range() if r[0] <= init and r[1] >= end: @@ -1135,7 +1240,7 @@ class TextThought (ResizableThought): if not it.next(): break - + del self.attributes self.attributes = pango.AttrList() map(lambda x : self.attributes.change(x), changed) @@ -1149,15 +1254,15 @@ class TextThought (ResizableThought): old_attrs, self.attributes.copy())) else: - if index == end_index: + if index == end_index: attr = self.create_attribute(attribute, index, end_index) self.undo.add_undo(UndoManager.UndoAction(self, UNDO_ADD_ATTR, self.undo_attr_cb, attr)) self.current_attrs.append(attr) #self.attributes.insert(attr) - else: - attr = self.create_attribute(attribute, init, end) + else: + attr = self.create_attribute(attribute, init, end) old_attrs = self.attributes.copy() self.attributes.change(attr) self.undo.add_undo(UndoManager.UndoAction(self, UNDO_ADD_ATTR_SELECTION, @@ -1165,34 +1270,36 @@ class TextThought (ResizableThought): old_attrs, self.attributes.copy())) self.recalc_edges() + self.remove_textview() - def set_bold (self, active): + def set_bold (self, active): self.set_attribute(active, 'bold') - - def set_italics (self, active): + + def set_italics (self, active): self.set_attribute(active, 'italic') - def set_underline (self, active): + def set_underline (self, active): self.set_attribute(active, 'underline') - def set_font (self, font_name, font_size): - if not self.editing: - return - + def set_font (self, font_name, font_size): + # With textview, we are always editing + # if not self.editing: + # return + start = min(self.index, self.end_index) end = max(self.index, self.end_index) - - pango_font = pango.FontDescription(font_name+" "+font_size) - + + pango_font = pango.FontDescription(font_name+" "+font_size) + attr = pango.AttrFontDesc (pango_font, start, end) if start == end: self.undo.add_undo(UndoManager.UndoAction(self, UNDO_ADD_ATTR, self.undo_attr_cb, attr)) - try: + try: self.current_attrs.change(attr) - except AttributeError: + except AttributeError: self.current_attrs.append(attr) else: old_attrs = self.attributes.copy() @@ -1203,19 +1310,31 @@ class TextThought (ResizableThought): self.attributes.copy())) self.recalc_edges() - def inside(self, inside): + def inside(self, inside): + # FIXME: with switch to textview, we don't need cursor update if self.editing: + if self.textview is not None: + self.textview.grab_focus() self.emit ("change_mouse_cursor", gtk.gdk.XTERM) else: ResizableThought.inside(self, inside) - def enter(self): + def enter(self): if self.editing: return self.orig_text = self.text self.editing = True - def leave(self): + def remove_textview(self): + if self.textview is not None: + self._textview_process() + self._textview_handler = None + self.textview.hide() + self.textview.destroy() + self.textview = None + + def leave(self): + self.remove_textview() if not self.editing: return ResizableThought.leave(self) -- cgit v0.9.1