0

我正在使用 Tkinter/Python3 开发 Devanagari/Indic 编辑器,并且对 Text 小部件字体渲染有疑问。

梵文(以及所有印度语言文字)是一个字母音节,辅音组(“簇”)和元音符号形成一个音节。辅音使用 Unicode ZWJ 字符连接,Tex​​t 小部件负责呈现(元音变音符号可能会重新排序)。出现在辅音之后的元音字符使用变音符号形式而不是它们的完整形式。请参阅 Microsoft 的以下说明。

为梵文脚本开发 OpenType 字体

天城文音节- 天城文 > 书写系统的有效正字法“单位”。音节由辅音字母、独立>元音和从属元音组成。在文本序列中,这些字符 > 按音序存储(尽管它们在显示时可能不按音序表示)。音节一经定形,便不可分。 光标不能定位在音节内。>本文档中讨论的转换不跨越音节边界。

当不使用鼠标拖动选择文本时,我会注意 Python 事件处理程序,以便 INSERT 和 CURRENT 光标永远不会位于音节内的字符位置,因此不会显示元音变音符号和辅音半形式。

但是,在处理鼠标拖动(用于文本选择)时,我感到很困惑。我似乎无法弄清楚如何在拖动(B1-Motion)事件期间禁止鼠标光标移动到音节之间的字符位置。

self.editorText.mark_set ("my_index", "@%d,%d" % (event.x, event.y)) 用来获取拖动索引,然后使用我的例程寻找音节左侧和外部的第一个字符位置。但这只是行不通。

请参阅下面有关字体渲染问题的图片...

梵文文本正确显示

鼠标拖动光标进入音节并弄乱显示

任何帮助表示赞赏!

-PP

import tkinter as tk
import tkinter.ttk as ttk
from tkinter import font

reverse = {}
ucode = {}
varna = {}
enc1 = {}
enc2 = {}
first_vowel = ''

allLines  = """VIRAMA  Special          2381                    -       
p       Consonant           2346                    -       
r       Consonant           2352                    -       
A       Vowel               2310                    2366    
aa      Vowel               2310                    2366    
u       Vowel               2313                    2369   
D       Consonant           2337                    -      
ai      Vowel               2320                    2376   
g       Consonant           2327                    -     
n       Consonant           2344                    -       
ZWNJ    JoinerSpecial       8204                    -   
ZWJ     JoinerSpecial       8205                    -   
"""

#default EditorText height in pixels
editorTextWinfoHeightPixels = 1
editorTextFontHeightPixels = 1

class klasse(object):
    def __init__(self, master):

        self.top_line_number = 1
        self.bottom_line_number = 20
        self.last_line_number = 1
        self.current_line_number = 1
        self.current_char_position = 0
        self.previous_linelength = 0
        self.current_linelength = 0

        self.ieSelection = ''
        self.ieSelectionLength = 0
        self.dragLineStart = 0
        self.dragLineEnd = 0
        self.dragCharStart = 0
        self.dragCharEnd = 0
        self.numCopiedLines = 0

        self.fonts=list(font.families())
        self.fonts.sort()
        maxFontNameLength = len(max(self.fonts))

        self.frame = tk.Frame(root)

        self.editorFrame = tk.Frame(self.frame)
        self.editorFrame.pack(side="left", fill="both", expand="yes")
        self.editorText = tk.Text(self.editorFrame, exportselection="true")
        self.editorText.pack(side="top", fill="both", expand="yes", padx=2)

        self.editorText.config( wrap="word", # use word wrapping
               undo=True,
               font=('Arial', 20))        

        self.editorText.see(tk.INSERT)
        self.editorText.focus()

        self.editorText.bindtags((self.editorText))
        self.editorText.bind('<B1-Motion>', self.handleMouseDrag)
        self.editorText.bind('<Button-1>', self.mouseButtonCallback)
        self.frame.pack(fill="both", expand="yes")

        self.bottom_line_number = int(301/editorTextFontHeightPixels)
        self.editorText.insert("insert", chr(2346))
        self.editorText.insert("insert", chr(2381))
        self.editorText.insert("insert", chr(2352))
        self.editorText.insert("insert", chr(2366))
        self.editorText.insert("insert", chr(2313))
        self.editorText.insert("insert", chr(2337))
        self.editorText.insert("insert", chr(2346))
        self.editorText.insert("insert", chr(2366))
        #self.editorText.insert("insert", chr(2376))
        self.editorText.insert("insert", chr(2327))
        self.editorText.insert("insert", chr(2344))


    def handleMouseDrag (self, event):

        [start_line_number, start_char_position] = self.editorText.index('current').split('.')
        start_line_number = int(start_line_number)
        start_char_position = int(start_char_position)

        self.editorText.mark_set ("anirb_index", "@%d,%d" % (event.x, event.y))

        [temp_current_line_number, temp_current_char_position] = self.editorText.index('anirb_index').split('.')
        temp_current_line_number = int(temp_current_line_number)
        temp_current_char_position = int(temp_current_char_position)


        if temp_current_line_number > start_line_number or\
                (temp_current_line_number == start_line_number and temp_current_char_position > start_char_position):
        #forward selection
            self.editorText.mark_set ("sel.first", str(start_line_number)+'.'+str(start_char_position))
            self.editorText.mark_set ("sel.last", str(temp_current_line_number)+'.'+str(temp_current_char_position))

        else:
        #backward selection
            self.editorText.mark_set ("sel.first", str(temp_current_line_number)+'.'+str(temp_current_char_position))
            self.editorText.mark_set ("sel.last", str(start_line_number)+'.'+str(start_char_position))

        if self.editorText.tag_ranges ("sel") != []:
            self.editorText.tag_remove ("sel", "1.0", "end")

        self.current_line_number = temp_current_line_number
        self.current_char_position = temp_current_char_position

        self.editorText.tag_add ("sel", "sel.first", "sel.last")
        self.editorText.tag_config ("sel", background="darkblue", foreground="white")
        self.editorText.mark_set ("insert", "sel.last")

    def mouseSettle (self, callingWidget, mouseCursorIndex):
        global ucode

        current_char = ''

        [temp_current_line_number, temp_current_char_position] = mouseCursorIndex

        while (1):
            if temp_current_char_position == 0:
                break

            curr_char_index = str(temp_current_line_number) + '.' + str(temp_current_char_position)

            prev_char_index = str(temp_current_line_number) + '.' + str(temp_current_char_position - 1)
            char_to_left = self.editorText.get (prev_char_index, curr_char_index)

            if char_to_left != '':
                char_to_left = ord(char_to_left)

            next_char_index = str(temp_current_line_number) + '.' + str(temp_current_char_position + 1)

            current_char = self.editorText.get (curr_char_index, next_char_index)

            if current_char != '':
                current_char = ord(current_char)

            if current_char not in ucode.keys() or current_char == '':
                ucode[current_char] = "null"

            if char_to_left not in ucode.keys() or char_to_left == '':
                ucode[char_to_left] = "null"

            if ("consonant" in ucode[current_char] and "special" not in ucode[char_to_left]) or \
                (ucode[current_char] == "null" and "special" not in ucode[char_to_left]) or \
                ucode[char_to_left] == "vowel" or \
                ucode[char_to_left] == "standalone" or \
                ucode[char_to_left] == "null":

                break

            temp_current_char_position -= 1

        #endwhile 

        return temp_current_char_position

    #enddef


    #left mouse button click in editorText widget
    def mouseButtonCallback (self, event=None):

        global ucode

        [self.current_line_number, temp_current_char_position] = self.editorText.index('current').split('.')
        self.current_line_number = int(self.current_line_number)
        temp_current_char_position = int(temp_current_char_position)
        self.current_linelength = len(self.editorText.get (str(self.current_line_number)+'.0', str(self.current_line_number)+'.end'))

        if temp_current_char_position >= self.current_linelength:
            self.current_char_position = self.current_linelength
        else:
            #mouseSettle will return the new character position for INSERT cursor
            self.current_char_position = self.mouseSettle (0, [self.current_line_number, temp_current_char_position])

        self.editorText.mark_set ("insert", str(self.current_line_number)+'.'+str(self.current_char_position))
        self.editorText.mark_set ("current", str(self.current_line_number)+'.'+str(self.current_char_position))

        #remove all selection
        if self.editorText.tag_ranges ("sel") != []:
            self.editorText.tag_remove ("sel", "1.0", "end")

        difference = self.bottom_line_number - self.top_line_number

        if self.bottom_line_number < self.current_line_number:
            self.bottom_line_number = self.current_line_number
            self.top_line_number = self.bottom_line_number - difference
        if self.top_line_number > self.current_line_number:
            top_line_number = self.current_line_number
            self.bottom_line_number = self.top_line_number + difference

    #in case user clicked on a partially visible line at the top or bottom adjust those
        self.editorText.see(tk.INSERT)
        self.editorText.focus()


def parse ():
    global reverse
    global ucode
    global enc1
    global enc2
    global varna
    global first_vowel

    for line in allLines.split('\n'):
        #split on the comment character
        lineList = line.split('#')
        line = lineList[0] #whatever came before the comment character
        if line.lstrip() == '':
            continue
        lineList = line.split()
        #discard comments
        if len(lineList) == 4:
            (key, v, e1, e2) =  lineList
            print ("key is ---", key)
            if e1 == "-":
                e1 = ''
            if e2 == "-":
                e2 = ''
        elif len(lineList) > 0 and len(lineList) < 4:
            print('Error: Illegal Map ')

        varna[key] = v.lower()
        enc1[key] = e1.lower()
        enc2[key] = e2.lower()

        if varna[key] == "vowel" and enc2[key] == '':
            first_vowel = key

        #now create the hashes that characterize each 16-bit unicode character
        if "+" not in e1 and e1 != '':
            ucode[int(e1)] = v.lower()
            #this is the reverse map of enc1 to the latin input character (key)
            reverse[int(e1)] = key

        if "+" not in e2 and e2 != '':
            ucode[int(e2)] = v.lower()
            #this is the reverse map of enc2 to the latin input character (key)
            reverse[int(e2)] = key




parse()
counter = 0
root = tk.Tk()
app = klasse(root)
root.minsize (900, 350)
root.mainloop()
4

0 回答 0