styletext.py :  » GUI » Sketch » skencil-0.6.17 » Plugins » Objects » Lib » multilinetext » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » GUI » Sketch 
Sketch » skencil 0.6.17 » Plugins » Objects » Lib » multilinetext » styletext.py
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


from ScrolledText import ScrolledText
from iterator import Style,StyletextError,Pool
from string import atoi,replace,split

class StyleText(ScrolledText):

    def __init__(self, master, **kw):
        apply(ScrolledText.__init__, (self, master), kw)

        self.pool = Pool(self)
        self.sorts = {}
        self.sorts_order = []

        self.clip_text = ''
        self.clip_styling = []

        # XXX force-mechanism should be moved to TextEditor
        self.style_force = []

        self._patch_tk()
        self.bind('<Control-c>', self.copyevent)
        self.bind('<Control-v>', self.pasteevent)

        self.bind('<Alt-p>', lambda e, s=self:s.pool.dump())
        self.bind('<Alt-t>', lambda e, s=self:s.tag_dump())
        self.bind('<Alt-m>', lambda e, s=self:s.mark_dump())
        self.bind('<Alt-g>', lambda e, s=self:s.styling_dump())
        self.bind('<Alt-s>', lambda e, s=self:s.print_current_style())
        self.bind('<Alt-f>', lambda e, s=self:s.fontify('1.0','end'))

    def _patch_tk(self):
        insert_tcl = self.register(self.insert)
        delete_tcl = self.register(self.delete)

        tclstr = """
        rename _w _old_w

        proc _w { command args } {
            if { $command == "insert" } {
                set ret [ eval "insert_tcl $args" ]
            } elseif {$command == "delete"} {
                set ret [ eval "delete_tcl $args" ]
            } else {
                set ret [ eval "_old_w $command $args" ]
            }
            return $ret
        }
        """
        self._old_w = '.old'+self._w
        tclstr = replace(tclstr, '_old_w', self._old_w)
        tclstr = replace(tclstr, '_w', self._w)
        tclstr = replace(tclstr, 'insert_tcl', insert_tcl)
        tclstr = replace(tclstr, 'delete_tcl', delete_tcl)
        self.tk.eval(tclstr)

    def copyevent(self, event):
        range = self.tag_ranges('sel')
        if len(range) !=2:
            return
        self.clip_text = apply(self.get, range)
        self.clip_styling = apply(self.styling_get, range)

    def pasteevent(self, event):
        self.delselection()
        index = self.index('insert')
        self.insert(index, self.clip_text)
        self.styling_apply(index, self.clip_styling)

    def delselection(self):
        sel = self.tag_ranges('sel')
        if len(sel) == 2:
            apply(self.delete, sel)

    def register_sort(self, sortid, function, default):
        defaultstyle = apply(Style,(),{sortid : default})
        self.sorts[sortid] = (function, defaultstyle)
        self.sorts_order.insert(0, sortid)

    def print_current_style(self,event=None):
        print "_____ current style %s ______" % self.index('insert')
        for style in self.style_get('insert'):
            print self.index('insert'),"\t", style

    def mark_dump(self):
        list = []
        for name in self.mark_names():
            list.append((self.index(name), name))
        list.sort()


        print "============== mark dump ================="
        for pos, name in list:
#            if name[0] == '_':
                print pos,"\t", name

    def tag_dump(self):
        print "============== tag dump ==================="
        names = list(self.tag_names())
        out = []
        for tag in names:
            ranges = self.tag_ranges(tag)
            if len(ranges)>0:
                out.append((ranges, tag))
        out.sort()
        for ranges, tag in out:
            print tag,"\t\t", ranges

    def delete(self, index1, index2=None):
        index1 = self.index(index1)
        it = self.pool.iterator()
        self.tk.call(self._old_w, 'delete', index1, index2)

        # remove all tag changes which became obsolete.
        # Obsolete means, (1) the tag is at or after 'end' or (2) there
        # is another tag of the same sort at the same index position.
        it.before(index1)
        it.next()
        dict = {}
        while (not it.outofboundary) and self.compare(it, '==', index1):
            sort = it.current.sort
            if dict.has_key(sort):
                it.delete()
            else:
                dict[sort] = 1
                it.next()
        it.i = len(self.pool)-1
        it._update()
        while (not it.outofboundary) and self.compare(it, '>=', 'end'):
            it.delete()

    def insert(self, index, chars, *tagsnstyles):
        tags = []
        styles = self.style_force
        for arg in tagsnstyles:
            if type(arg).__name__ == 'string':
                tags = tags + arg
            elif hasattr(arg, 'is_Style'):
                styles.append(arg)
            else:
                raise StyletextError(
                    "arguments should be tags and styles: %s" % arg)

        begin = self.index(index)
        self.tk.call((self._old_w, 'insert', index, chars) + tuple(tags))

        end = self.index('%s + %dc' % (begin, len(chars)))
        for style in styles:
            self.style_add(style, begin, end, supressfontify=1)
        self.fontify("%s linestart - 1 lines" % begin, "%s lineend" % end)
        self.style_force = []

    def style_get(self, index, sort = None):
        '''Returns the style of type sort at position index.

        If sort is not given, returns a complete list of all styles.
        '''
        it = self.pool.iterator()
        it.before(index)

        if sort is not None:
            # look for a style of type 'sort'
            if it.outofboundary:
                return self.sorts[sort][1]
            while not it.is_first() and not it.current.sort == sort:
                it.prev()
            if it.current.sort == sort:
                return it.current
            else:
                return self.sorts[sort][1]
        else:

            dict = {}
            if not it.outofboundary:
                dict[it.current.sort] = it.current
                while (not it.is_first()) and len(dict)<len(self.sorts):
                    it.prev()
                    if not dict.has_key(it.current.sort):
                        dict[it.current.sort] = it.current
            # if incomplete: fill up with defaults
            for sort in self.sorts.keys():
                if not dict.has_key(sort):
                    dict[sort] = self.sorts[sort][1]
            ret = []

            # keep the order as given in self.sorts.keys()
            for sort in self.sorts_order:
                ret.append(dict[sort])
            return ret

    def style_get_range(self, begin, end, sort=None):
        '''returns all styles between begin and end.

        If sort is given, only those of type sort are returned.
        '''
        styles = self.style_get(begin+'+1 chars')
        it = self.pool.iterator()
        it.before(begin+'+1 chars')
        while  not it.is_last():
            it.next()
            if self.compare(it.id,'>=', end):
                break
            try:
                i = styles.index(it.current)
            except:
                styles.append(it.current)
        return styles

    def style_removeall(self):
        for mark in self.mark_names():
            if mark[0] == '_':
                self.mark_unset(mark)
        self.pool = Pool(self)
        self.fontify('1.0','end')

    def styling_get(self, begin, end):
        it = self.pool.iterator()
        styles = self.style_get(begin+"+ 1 chars")
        styling = []
        for style in styles:
            styling.append((style, begin))
        it.before(begin)
        # need to replace befores when there a style at
        while 1:
            if it.i >= len(self.pool):
                break
            elif it.i >= 0:
                if self.compare(it, '>', end):
                    break
                elif self.compare(it, '>', begin):
                    style = it.current
                    styling.append((style, self.index(it)))
            it.next()
        #
        end = self.index(end)
        styling.append((None, end))

        # relocate indizes
        ret = []
        bline, bchar = map(atoi, split(begin, '.'))
        for style, indexstr in styling:
            line, char = map(atoi, split(indexstr, '.'))
            if line == bline:
                char = char-bchar
            line = line-bline
            ret.append((style, line, char))

        return ret

    def styling_apply(self, index, styling):
        if styling is None or len(styling) == 0:
            return
        index = self.index(index)
        iline, ichar = map(atoi, split(index, '.'))
        it = self.pool.iterator()

        # determine end
        tmp, eline, echar = styling[-1]
        if eline == 0:
            echar = echar+ichar
        eline = eline+iline
        end = "%i.%i" % (eline, echar)

        i = 0
        for style, line, char in styling[:-1]:
            i = i+1
            if line == 0:
                char = char+ichar
            line = line+iline
            indexstr = "%i.%i" % (line, char)
            if i<4:
                self.style_add(style, index, end, supressfontify=1)
            else:
                # insert it
                it.insert_right(style, indexstr)
        self.fontify(index, end)


    def styling_dump(self):
        range = self.tag_ranges('sel')
        if len(range) != 2:
            return
        print apply(self.styling_get, range)

    def fontify(self, begin, end):
        for name in self.tag_names():
            if name[0]=='_':
                self.tag_remove(name, begin, end)

        styles = self.style_get(begin)
        dict = {}

        for style in styles:
            name = name+style._signature_
            dict[style.sort] = style.options

        it = self.pool.iterator()
        it.before(begin) # last style change before' begin'
        a = begin
        while self.compare(a,'<',end):
            if it.is_last():
                b = end
            else:
                it.next()
                b = it.id

            options = {}
            name = '_'+str(dict)
            self.tag_add(name,a, b)
            _dict = dict.copy()

            for sort in self.sorts_order:
                func = self.sorts[sort][0]
                apply(func, (options, _dict))

            self.tag_configure(name, options)

            if not it.outofboundary:
                dict[it.current.sort] = it.current.options
            a = b

    def style_add(self, style, begin, end, supressfontify=0):
        if self.compare(begin,'>=',end):
            return
        it = self.pool.iterator()

        # this is the simplest, definitly not the fastest solution
        ostyle_begin = self.style_get(begin, style.sort)
        ostyle_end = self.style_get(end+' +1 chars', style.sort)

        # delete all style changes of sort "style.sort" between "begin" and
        # "end"
        it.before(begin)
        it.next()
        while (not it.outofboundary) and  self.compare(it,'<=',end):
            if it.current.sort == style.sort:
                it.delete()
            else:
                it.next()
        if ostyle_begin != style:
            it.insert_left(style, begin)
        if ostyle_end != style:
            it.insert_right(ostyle_end, end)

        if not supressfontify:
            self.fontify(begin, end)

    # for older Tkinter version (those coming with Python 1.5.2) add
    # some missing Text methods
    def mark_next(self, index):
        """Return the name of the next mark after INDEX."""
        return self.tk.call(self._w, 'mark', 'next', index) or None

    def mark_previous(self, index):
        """Return the name of the previous mark before INDEX."""
        return self.tk.call(self._w, 'mark', 'previous', index) or None


if __name__=='__main__':
    from Tkinter import *
    tk = Tk()
    text = StyleText(tk, background='white')
    text.pack(fill=BOTH, expand=1)
    text.insert(END,'01234567890abcdefghijkl\n')
    text.insert(END,'01234567890abcdefghijkl\n')
    text.insert(END,'01234567890abcdefghijkl\n')

    import sys
    sys.path.append('/usr/lib/sketch-0.6.12/')
    from Sketch.Graphics import font

    class font_families:
        def __init__(self):
            self.family_to_fonts = font.make_family_to_fonts()
            self.families = self.family_to_fonts.keys()
            self.families.sort()

        def xlfd(self, **kw):
            fonts = self.family_to_fonts[kw['family']]
            for name in fonts:
                family, attrs, xlfd_start, encoding = font.fontmap[name]
                if attrs == kw['attr']:
                    return font.xlfd_template % \
                                      (xlfd_start, kw['size'], encoding)

            kw['attr'] = 'Roman'
            return apply(self.xlfd, (), kw)

        def ps(self, **kw):
            props = {}
            props.update(DEFAULT)
            props.update(kw)

            fonts = self.family_to_fonts[props['family']]
            for name in fonts:
                family, attrs, xlfd_start, encoding = font.fontmap[name]
                if attrs == props['attr']:
                    return name
            return ''

    font.read_font_dirs()
    FONTS = font_families()

    def FamilySort(tagoptions, dict):
        return tagoptions

    def AttrSort(tagoptions, dict):
        return tagoptions

    def SizeSort(tagoptions, dict):
        xfont = apply(FONTS.xlfd, (), dict)
        tagoptions['font'] = xfont
        return tagoptions

    text.register_sort('family', FamilySort, 'Times' )
    text.register_sort('attr', AttrSort, 'Roman')
    text.register_sort('size', SizeSort, 12)
    
 
    text.style_add(Style(size=24),'1.5','2.13')
    text.pool.dump()
    text.style_add(Style(size=72),'1.4','2.14')
    text.pool.dump()

    raw_input()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.