Текстовый виджет Tkinter для визуализации шрифтов Devanagari (Windows 10, Python 3)

Я работаю над редактором Devanagari/Indic с помощью Tkinter/Python3 и у меня есть вопрос по визуализации шрифта виджета Text.

Деванагари (и все сценарии на индийском языке) - это алфавитный алфавит, а группы согласных ("кластеры") и гласные знаки образуют слог. Согласные объединяются с использованием символа Unicode ZWJ, а за визуализацию отвечает виджет Текст (возможно, диакритические знаки гласные могут быть переупорядочены). Гласные символы, встречающиеся после согласного, используют диакритическую форму, а не их полные формы. Смотрите следующее описание от Microsoft.

Разработка шрифтов OpenType для скрипта деванагари

Деванагари слог - Эффективная орфографическая "единица" системы письма Деванагари. Слоги состоят из согласных букв, независимых> гласных и зависимых гласных. В текстовой последовательности эти символы хранятся> в фонетическом порядке (хотя они могут не отображаться в фонетическом порядке> при отображении). Как только слог сформирован, он неделим. Курсор не может быть расположен внутри слога. Преобразования>, обсуждаемые в этом документе, не пересекают границы слогов.

Когда вы не выделяете текст с помощью перетаскивания мышью, я стараюсь в обработчиках событий Python, чтобы курсоры INSERT и CURRENT никогда не находились в позициях символов, попадающих в слог, так что диалектические и согласные полуформы не отображаются.

Тем не менее, я в тупик, когда дело доходит до обработки перетаскивания мыши (для выделения текста). Кажется, я не могу понять, как запретить курсору мыши во время события перетаскивания (движение B1) перемещаться в позиции символов между слогами.

я использую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()

0 ответов

Другие вопросы по тегам