Ticket #1829: 0001-Added-Label-Thought-Support.patch

File 0001-Added-Label-Thought-Support.patch, 17.4 KB (added by jasg, 14 years ago)
  • new file icons/label-mode.svg

    From b854758c74a87cb87b1ff8ca25ad115f0e0e5572 Mon Sep 17 00:00:00 2001
    From: Jorge Saldivar <jsaldivar@paraguayeduca.org>, Martin Abente <mabente@paraguayeduca.org>
    Date: Mon, 15 Mar 2010 11:23:15 -0300
    Subject: [PATCH] Added Label Thought Support
    
    ---
     icons/label-mode.svg |   73 +++++++++++++++++
     labyrinthactivity.py |   15 +++-
     src/ImageThought.py  |    2 +-
     src/LabelThought.py  |  215 ++++++++++++++++++++++++++++++++++++++++++++++++++
     src/MMapArea.py      |   26 +++++--
     5 files changed, 319 insertions(+), 12 deletions(-)
     create mode 100644 icons/label-mode.svg
     create mode 100644 src/LabelThought.py
    
    diff --git a/icons/label-mode.svg b/icons/label-mode.svg
    new file mode 100644
    index 0000000..361ec68
    - +  
     1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
     2<svg
     3   xmlns:dc="http://purl.org/dc/elements/1.1/"
     4   xmlns:cc="http://creativecommons.org/ns#"
     5   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
     6   xmlns:svg="http://www.w3.org/2000/svg"
     7   xmlns="http://www.w3.org/2000/svg"
     8   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
     9   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
     10   enable-background="new 0 0 55 54.696"
     11   height="54.696px"
     12   version="1.1"
     13   viewBox="0 0 55 54.696"
     14   width="55px"
     15   x="0px"
     16   xml:space="preserve"
     17   y="0px"
     18   id="svg2"
     19   sodipodi:version="0.32"
     20   inkscape:version="0.47pre4 r22446"
     21   sodipodi:docname="label-mode.svg"
     22   inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
     23     id="metadata22"><rdf:RDF><cc:Work
     24         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
     25           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
     26     id="defs20"><inkscape:perspective
     27   sodipodi:type="inkscape:persp3d"
     28   inkscape:vp_x="0 : 27.348 : 1"
     29   inkscape:vp_y="0 : 1000 : 0"
     30   inkscape:vp_z="55 : 27.348 : 1"
     31   inkscape:persp3d-origin="27.5 : 18.232 : 1"
     32   id="perspective24" />
     33       
     34
     35               
     36               
     37        </defs><sodipodi:namedview
     38     inkscape:window-height="735"
     39     inkscape:window-width="1264"
     40     inkscape:pageshadow="2"
     41     inkscape:pageopacity="0.0"
     42     guidetolerance="10.0"
     43     gridtolerance="10.0"
     44     objecttolerance="10.0"
     45     borderopacity="1.0"
     46     bordercolor="#666666"
     47     pagecolor="#ffffff"
     48     id="base"
     49     showgrid="true"
     50     inkscape:zoom="8.4466873"
     51     inkscape:cx="27.5"
     52     inkscape:cy="27.348"
     53     inkscape:window-x="0"
     54     inkscape:window-y="4"
     55     inkscape:current-layer="svg2"
     56     inkscape:window-maximized="0"><inkscape:grid
     57       type="xygrid"
     58       id="grid2820" /></sodipodi:namedview><g
     59     id="g2817"
     60     transform="translate(0,2)"
     61     style="fill:#ffffff"><rect
     62       y="38.695999"
     63       x="21"
     64       height="5"
     65       width="18"
     66       id="rect2822"
     67       style="fill:#ffffff;fill-opacity:1;stroke:none" /><rect
     68       y="4.6959991"
     69       x="17"
     70       height="39"
     71       width="6"
     72       id="rect2824"
     73       style="fill:#ffffff;fill-opacity:1;stroke:none" /></g></svg>
     74 No newline at end of file
  • labyrinthactivity.py

    diff --git a/labyrinthactivity.py b/labyrinthactivity.py
    index d212c8c..954fbb4 100644
    a b class LabyrinthActivity(activity.Activity): 
    274274            activity_toolbar.share.props.visible = False
    275275            toolbox.set_current_toolbar(1)
    276276
    277         self.mods = [None] * 4
     277        self.mods = [None] * 6
    278278
    279279        self.mods[0] = RadioToolButton(named_icon='select-mode')
    280280        self.mods[0].set_tooltip(_('Edit mode'))
    class LabyrinthActivity(activity.Activity): 
    304304        self.mods[3].connect('clicked', self.__mode_cb, MMapArea.MODE_IMAGE)
    305305        target_toolbar.insert(self.mods[3], tool_offset + 3)
    306306
     307        self.mods[5] = RadioToolButton(named_icon='label-mode')
     308        self.mods[5].set_tooltip(_('Label mode'))
     309        self.mods[5].set_accelerator(_('<ctrl>a'))
     310        self.mods[5].set_group(self.mods[0])
     311        self.mods[5].connect('clicked', self.__mode_cb, MMapArea.MODE_LABEL)
     312        target_toolbar.insert(self.mods[5], tool_offset + 4)
     313
    307314        separator = gtk.SeparatorToolItem()
    308         target_toolbar.insert(separator, tool_offset + 4)
     315        target_toolbar.insert(separator, tool_offset + 5)
    309316
    310317        tool = ToolButton('link')
    311318        tool.set_tooltip(_('Link/unlink two selected thoughts'))
    312319        tool.set_accelerator(_('<ctrl>l'))
    313320        tool.connect('clicked', self.__link_cb)
    314         target_toolbar.insert(tool, tool_offset + 5)
     321        target_toolbar.insert(tool, tool_offset + 6)
    315322
    316323        tool = ToolButton('edit-delete')
    317324        tool.set_tooltip(_('Erase selected thought(s)'))
    318325        tool.connect('clicked', self.__delete_cb)
    319         target_toolbar.insert(tool, tool_offset + 6)
     326        target_toolbar.insert(tool, tool_offset + 7)
    320327
    321328        self.show_all()
    322329        self._mode = MMapArea.MODE_TEXT
  • src/ImageThought.py

    diff --git a/src/ImageThought.py b/src/ImageThought.py
    index 0b3e15e..964aa99 100644
    a b class ImageThought (ResizableThought): 
    100100                utils.export_thought_outline (context, self.ul, self.lr, self.background_color, self.am_selected, self.am_primary, utils.STYLE_NORMAL,
    101101                                                                          (move_x, move_y))
    102102                if self.pic:
    103             raw_pixels = self.pic.get_pixels_array()
     103                        raw_pixels = self.pic.get_pixels_array()
    104104                        if hasattr(context, "set_source_pixbuf"):
    105105                                context.set_source_pixbuf (self.pic, self.pic_location[0]+move_x, self.pic_location[1]+move_y)
    106106                        elif hasattr(context, "set_source_surface"):
  • new file src/LabelThought.py

    diff --git a/src/LabelThought.py b/src/LabelThought.py
    new file mode 100644
    index 0000000..af89073
    - +  
     1#! /usr/bin/env python
     2# LabelThoughts.py
     3# This file is part of Labyrinth
     4#
     5# Copyright (C) 2010 - Jorge Saldivar <jsaldivar@paraguayeduca.org>
     6#                      Martin Abente <mabente@paraguayeduca.org>
     7#
     8# Labyrinth is free software; you can redistribute it and/or modify
     9# it under the terms of the GNU General Public License as published by
     10# the Free Software Foundation; either version 2 of the License, or
     11# (at your option) any later version.
     12#
     13# Labyrinth is distributed in the hope that it will be useful,
     14# but WITHOUT ANY WARRANTY; without even the implied warranty of
     15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
     16# GNU General Public License for more details.
     17#
     18# You should have received a copy of the GNU General Public License
     19# along with Labyrinth; if not, write to the Free Software
     20# Foundation, Inc., 51 Franklin St, Fifth Floor,
     21# Boston, MA  02110-1301  USA
     22#
     23
     24import gtk
     25import pango
     26import utils
     27import xml.dom
     28
     29from BaseThought import *
     30from TextThought import TextThought
     31
     32class LabelThought (TextThought):
     33    def __init__ (self, coords, pango_context, thought_number, save, undo, loading, background_color, foreground_color, name="label_thought"):
     34        super (LabelThought, self).__init__(coords, pango_context, thought_number, save, undo, loading, background_color, foreground_color, name)
     35        self.edge = True
     36
     37    def can_be_parent(self):
     38        return False
     39
     40    def draw (self, context):
     41        self.recalc_edges ()
     42        if self.edge:
     43            ResizableThought.draw(self, context)
     44        if self.creating:
     45            return
     46        (textx, texty) = (self.min_x, self.min_y)
     47        if self.am_primary:
     48            r, g, b = utils.primary_colors["text"]
     49        elif (self.foreground_color):
     50            r, g, b = utils.gtk_to_cairo_color(self.foreground_color)
     51        else:
     52            r, g ,b = utils.gtk_to_cairo_color(utils.default_colors["text"])
     53        context.set_source_rgb (r, g, b)
     54        self.layout.set_alignment(pango.ALIGN_CENTER)
     55        context.move_to (textx, texty)
     56        context.show_layout (self.layout)
     57        if self.editing:
     58            if self.preedit:
     59                (strong, weak) = self.layout.get_cursor_pos (self.index + self.preedit[2])
     60            else:
     61                (strong, weak) = self.layout.get_cursor_pos (self.index)
     62            (startx, starty, curx,cury) = strong
     63            startx /= pango.SCALE
     64            starty /= pango.SCALE
     65            curx /= pango.SCALE
     66            cury /= pango.SCALE
     67            context.move_to (textx + startx, texty + starty)
     68            context.line_to (textx + startx, texty + starty + cury)
     69            context.stroke ()
     70        context.set_source_rgb (0,0,0)
     71        context.stroke ()
     72
     73    def update_save (self):
     74        next = self.element.firstChild
     75        while next:
     76            m = next.nextSibling
     77            if next.nodeName == "attribute":
     78                self.element.removeChild (next)
     79                next.unlink ()
     80            next = m
     81
     82        if self.text_element.parentNode is not None:
     83            self.text_element.replaceWholeText (self.text)
     84        text = self.extended_buffer.get_text ()
     85        if text:
     86            self.extended_buffer.update_save()
     87        else:
     88            try:
     89                self.element.removeChild(self.extended_buffer.element)
     90            except xml.dom.NotFoundErr:
     91                pass
     92        self.element.setAttribute ("cursor", str(self.index))
     93        self.element.setAttribute ("ul-coords", str(self.ul))
     94        self.element.setAttribute ("lr-coords", str(self.lr))
     95        self.element.setAttribute ("identity", str(self.identity))
     96        self.element.setAttribute ("background-color", utils.color_to_string(self.background_color))
     97        self.element.setAttribute ("foreground-color", utils.color_to_string(self.foreground_color))
     98        self.element.setAttribute ("edge", str(self.edge))
     99        if self.am_selected:
     100                self.element.setAttribute ("current_root", "true")
     101        else:
     102            try:
     103                self.element.removeAttribute ("current_root")
     104            except xml.dom.NotFoundErr:
     105                pass
     106        if self.am_primary:
     107            self.element.setAttribute ("primary_root", "true");
     108        else:
     109            try:
     110                self.element.removeAttribute ("primary_root")
     111            except xml.dom.NotFoundErr:
     112                pass
     113        doc = self.element.ownerDocument
     114        it = self.attributes.get_iterator()
     115        while (1):
     116            r = it.range()
     117            for x in it.get_attrs():
     118                if x.type == pango.ATTR_WEIGHT and x.value == pango.WEIGHT_BOLD:
     119                    elem = doc.createElement ("attribute")
     120                    self.element.appendChild (elem)
     121                    elem.setAttribute("start", str(r[0]))
     122                    elem.setAttribute("end", str(r[1]))
     123                    elem.setAttribute("type", "bold")
     124                elif x.type == pango.ATTR_STYLE and x.value == pango.STYLE_ITALIC:
     125                    elem = doc.createElement ("attribute")
     126                    self.element.appendChild (elem)
     127                    elem.setAttribute("start", str(r[0]))
     128                    elem.setAttribute("end", str(r[1]))
     129                    elem.setAttribute("type", "italics")
     130                elif x.type == pango.ATTR_UNDERLINE and x.value == pango.UNDERLINE_SINGLE:
     131                    elem = doc.createElement ("attribute")
     132                    self.element.appendChild (elem)
     133                    elem.setAttribute("start", str(r[0]))
     134                    elem.setAttribute("end", str(r[1]))
     135                    elem.setAttribute("type", "underline")
     136                elif x.type == pango.ATTR_FONT_DESC:
     137                    elem = doc.createElement ("attribute")
     138                    self.element.appendChild (elem)
     139                    elem.setAttribute("start", str(r[0]))
     140                    elem.setAttribute("end", str(r[1]))
     141                    elem.setAttribute("type", "font")
     142                    elem.setAttribute("value", x.desc.to_string ())
     143            if not it.next():
     144                break
     145
     146    def load (self, node, tar):
     147        self.index = int (node.getAttribute ("cursor"))
     148        self.end_index = self.index
     149        tmp = node.getAttribute ("ul-coords")
     150        self.ul = utils.parse_coords (tmp)
     151        tmp = node.getAttribute ("lr-coords")
     152        self.lr = utils.parse_coords (tmp)
     153
     154        self.width = self.lr[0] - self.ul[0]
     155        self.height = self.lr[1] - self.ul[1]
     156
     157        self.identity = int (node.getAttribute ("identity"))
     158        try:
     159            tmp = node.getAttribute ("background-color")
     160            self.background_color = gtk.gdk.color_parse(tmp)
     161            tmp = node.getAttribute ("foreground-color")
     162            self.foreground_color = gtk.gdk.color_parse(tmp)
     163        except ValueError:
     164            pass
     165
     166        self.am_selected = node.hasAttribute ("current_root")
     167        self.am_primary = node.hasAttribute ("primary_root")
     168       
     169        if node.getAttribute ("edge") == "True":
     170            self.edge = True
     171        else:
     172            self.edge = False
     173
     174        for n in node.childNodes:
     175            if n.nodeType == n.TEXT_NODE:
     176                self.text = n.data
     177            elif n.nodeName == "Extended":
     178                self.extended_buffer.load(n)
     179            elif n.nodeName == "attribute":
     180                attrType = n.getAttribute("type")
     181                start = int(n.getAttribute("start"))
     182                end = int(n.getAttribute("end"))
     183
     184                if attrType == "bold":
     185                    attr = pango.AttrWeight(pango.WEIGHT_BOLD, start, end)
     186                elif attrType == "italics":
     187                    attr = pango.AttrStyle(pango.STYLE_ITALIC, start, end)
     188                elif attrType == "underline":
     189                    attr = pango.AttrUnderline(pango.UNDERLINE_SINGLE, start, end)
     190                elif attrType == "font":
     191                    font_name = str(n.getAttribute("value"))
     192                    pango_font = pango.FontDescription (font_name)
     193                    attr = pango.AttrFontDesc (pango_font, start, end)
     194                self.attributes.change(attr)
     195            else:
     196                print "Unknown: "+n.nodeName
     197        self.rebuild_byte_table ()
     198        self.recalc_edges()
     199
     200    def enter(self):
     201        if self.editing:
     202            return
     203        self.orig_text = self.text
     204        self.editing = True
     205        self.edge = True
     206
     207    def leave(self):
     208        if not self.editing:
     209            return
     210        ResizableThought.leave(self)
     211        self.editing = False
     212        self.end_index = self.index
     213        self.emit ("update_links")
     214        self.edge = False
     215        self.recalc_edges ()
  • src/MMapArea.py

    diff --git a/src/MMapArea.py b/src/MMapArea.py
    index a0a16df..5fdcf87 100644
    a b  
    2121#
    2222
    2323import math
    24 
    2524import time
    2625import gtk
    2726import pango
    import xml.dom.minidom as dom 
    3534
    3635import Links
    3736import TextThought
     37import LabelThought
    3838import ImageThought
    3939import DrawingThought
    4040import ResourceThought
    MODE_TEXT = 1 
    5353MODE_IMAGE              = 2
    5454MODE_DRAW               = 3
    5555MODE_RESOURCE   = 4
     56MODE_LABEL              = 5
    5657
    5758VIEW_LINES = 0
    5859VIEW_BEZIER = 1
    class MMapArea (gtk.DrawingArea): 
    534535                else:
    535536                        map(lambda x : x.unselect(), self.selected)
    536537                        self.selected = [thought]
    537                 self.current_root = []
     538                if thought.can_be_parent():
     539                        self.current_root = []
    538540                for x in self.selected:
    539541                        if x.can_be_parent():
    540542                                self.current_root.append(x)
    class MMapArea (gtk.DrawingArea): 
    723725
    724726                if type == MODE_TEXT:
    725727                        thought = TextThought.TextThought (coords, self.pango_context, self.nthoughts, self.save, self.undo, loading, self.background_color, self.foreground_color)
     728                elif type == MODE_LABEL:
     729                        thought = LabelThought.LabelThought (coords, self.pango_context, self.nthoughts, self.save, self.undo, loading, self.background_color, self.foreground_color)
    726730                elif type == MODE_IMAGE:
    727731                        thought = ImageThought.ImageThought (coords, self.pango_context, self.nthoughts, self.save, self.undo, loading, self.background_color, self.foreground_color)
    728732                elif type == MODE_DRAW:
    class MMapArea (gtk.DrawingArea): 
    10221026                for node in top_element.childNodes:
    10231027                        if node.nodeName == "thought":
    10241028                                self.load_thought (node, MODE_TEXT, tar)
     1029                        elif node.nodeName == "label_thought":
     1030                                self.load_thought (node, MODE_LABEL, tar)
    10251031                        elif node.nodeName == "image_thought":
    10261032                                self.load_thought (node, MODE_IMAGE, tar)
    10271033                        elif node.nodeName == "drawing_thought":
    class MMapArea (gtk.DrawingArea): 
    11671173        def link_menu_cb (self):
    11681174                if len (self.selected) != 2:
    11691175                        return
     1176                if not self.selected[0].can_be_parent() or \
     1177                        not self.selected[1].can_be_parent():
     1178                                return
    11701179                lnk = None
    11711180                for l in self.links:
    11721181                        if l.connects (self.selected[0], self.selected[1]):
    class MMapArea (gtk.DrawingArea): 
    12251234
    12261235                if not thought:
    12271236                        return True
    1228                 if not self.primary:
    1229                         self.make_primary (thought)
    1230                         self.select_thought (thought, None)
     1237                if not self.primary and \
     1238                        thought.can_be_parent():
     1239                                self.make_primary (thought)
     1240                                self.select_thought (thought, None)
    12311241                else:
    12321242                        self.emit ("change_buffer", thought.extended_buffer)
    12331243                        self.hookup_im_context (thought)
    class MMapArea (gtk.DrawingArea): 
    12351245                        self.undo.block ()
    12361246                        if not self.current_root:
    12371247                                self.current_root.append(self.primary)
    1238                         for x in self.current_root:
    1239                                 self.create_link (x, None, thought)
     1248                        if thought.can_be_parent():
     1249                                for x in self.current_root:
     1250                                        if x.can_be_parent():
     1251                                                self.create_link (x, None, thought)
    12401252                        for x in self.selected:
    12411253                                x.unselect ()
    12421254                        self.selected = [thought]