Exemplo n.º 1
0
 def adjust_fonts(self, event):
   new_font = Font(**self.fonts['normal'].configure())
   size = orig_size = new_font['size']
   desired_total_height = event.height
   orig_row_height = new_font.metrics('linespace')
   orig_row_height += self.LS_EXTRA
   orig_total_height = self.N_ROWS * orig_row_height
   if orig_total_height < desired_total_height:
     a, compfname, final_neg_adjust = 1, '__gt__', True
   elif orig_total_height > desired_total_height:
     a, compfname, final_neg_adjust = -1, '__lt__', False
   else:
     return
   prev_total_height = orig_total_height
   while True:
     if a < 0 and size <= self.MIN_FONT_SIZE:
       size = self.MIN_FONT_SIZE
       break
     size += a
     new_font.configure(size=size)
     new_row_height = new_font.metrics('linespace')
     new_row_height += self.LS_EXTRA
     new_total_height = self.N_ROWS * new_row_height
     if new_total_height == prev_total_height:
       size -= a
       break
     compf = getattr(new_total_height, compfname)
     if compf(desired_total_height):
       if final_neg_adjust and size > self.MIN_FONT_SIZE:
         size -= a
       break
     prev_total_height = new_total_height
   if size != orig_size:
     self.fonts['normal'].configure(size=size)
     self.fonts['bold'].configure(size=size)
Exemplo n.º 2
0
 def displayAutomata(self):
     for item in self.canvasitems:
         self.automataCanvas.delete(item)
     if self.selectedButton == 0:
         header = "e-NFA"
         automata = self.nfa
         if self.dotFound:
             image = self.nfaimg
             imagefile = self.nfaimagefile
     elif self.selectedButton == 1:
         header = "DFA"
         automata = self.dfa
         if self.dotFound:
             image = self.dfaimg
             imagefile = self.dfaimagefile
     elif self.selectedButton == 2:
         header = "Minimized DFA"
         automata = self.minDFA
         if self.dotFound:
             image = self.mindfaimg
             imagefile = self.mindfaimagefile
     font = Font(family="times", size=20)
     (w, h) = (font.measure(header), font.metrics("linespace"))
     headerheight = h + 10
     itd = self.automataCanvas.create_text(10,
                                           10,
                                           text=header,
                                           font=font,
                                           anchor=NW)
     self.canvasitems.append(itd)
     [text, linecount] = automata.getPrintText()
     font = Font(family="times", size=13)
     (w, h) = (font.measure(text), font.metrics("linespace"))
     textheight = headerheight + linecount * h + 20
     itd = self.automataCanvas.create_text(10,
                                           headerheight + 10,
                                           text=text,
                                           font=font,
                                           anchor=NW)
     self.canvasitems.append(itd)
     if self.dotFound:
         itd = self.automataCanvas.create_image(10,
                                                textheight,
                                                image=image,
                                                anchor=NW)
         self.canvasitems.append(itd)
         totalwidth = imagefile.size[0] + 10
         totalheight = imagefile.size[1] + textheight + 10
     else:
         totalwidth = self.cwidth + 10
         totalheight = textheight + 10
     if totalheight < self.cheight:
         totalheight = self.cheight
     if totalwidth < self.cwidth:
         totalwidth = self.cwidth
     self.automataCanvas.config(scrollregion=(0, 0, totalwidth,
                                              totalheight))
Exemplo n.º 3
0
    def __init__(
        self,
        master: Union[tk.Frame, tk.Tk],
        x: int,
        y: int,
        horizontal_anchor: HorizontalAnchor,
        vertical_anchor: VerticalAnchor,
        txt: str,
        font: tkf.Font,
        txt_color: str,
        color: str,
    ):
        super().__init__(
            master=master,
            text=txt,
            font=font,
            padx=0,
            pady=0,
            fg=txt_color,
            bg=color,
            bd=0,
        )

        txt_width = font.measure(txt)
        txt_height = font.metrics("linespace")
        xloc, yloc = self._get_position(
            horizontal_anchor,
            vertical_anchor,
            x,
            y,
            txt_width,
            txt_height
        )
        self.place(x=xloc, y=yloc)
Exemplo n.º 4
0
    def render(self, data, node_name):
        # Figure out what size the text we want is.
        label_txt = data.get('label', None)
        font = Font(family="Helvetica", size=12)
        h = font.metrics("linespace") + 1

        if label_txt:
            w = font.measure(label_txt) + 2
        else:
            w = font.measure("....") + 2
        self.config(width=w, height=h)
        marker_options = {
            'fill': data.get('color', 'blue'),
            'outline': 'white'
        }

        if data.get('circle', None):
            self.create_oval(0, 0, w, h, **marker_options)
            self.config(width=w, height=h)
            if label_txt:
                self.create_text(w / 2,
                                 h / 2,
                                 text=label_txt,
                                 font=font,
                                 fill="white")
        else:
            self.create_rectangle(0, 0, w, h, **marker_options)
            if label_txt:
                self.create_text(w / 2,
                                 h / 2,
                                 text=label_txt,
                                 font=font,
                                 fill="white")
Exemplo n.º 5
0
        def text_extents(self, style, text):
            """
            The text extents are calculated using tkinter.Font
            """
            with InternalWindow() as window:
                font_type = ""
                if style["bold"]:
                    font_type += "bold"
                if style["italic"]:
                    if len(font_type) > 0:
                        font_type += " "
                    font_type += "italic"

                # Create the new font object.
                font = Font(window, (style["font"], -int(style["size"]*FONT_SCALING), font_type))
                # Query the data
                width = font.measure(text)
                metrics = font.metrics()

            return {
                "width": width / float(FONT_SCALING),
                "height": metrics["linespace"] / float(FONT_SCALING),
                "ascent": metrics["ascent"] / float(FONT_SCALING),
                "descent": metrics["descent"] / float(FONT_SCALING)
            }
Exemplo n.º 6
0
    def render(self, data, node_name):
        label_txt = data.get('label', None)
        font = Font(family="Helvetica", size=12)
        h = font.metrics("linespace") + 6
        if label_txt:
            w = font.measure(label_txt) + 8
        else:
            w = font.measure("....") + 2
        self.config(width=w, height=h)
        marker_options = {
            'fill': data.get('color', 'orange'),
            'outline': 'orange'
        }

        if data.get('circle', False) or data.get('type', 'NOTLAN') == 'LAN':
            self.create_oval(0, 0, w - 1, h - 1, **marker_options)
            self.config(width=w, height=h)
            if label_txt:
                self.create_text((w) / 2, (h) / 2,
                                 text=label_txt,
                                 font=font,
                                 fill="black")
        else:
            self.create_rectangle(0, 0, w, h, **marker_options)
            if label_txt:
                self.create_text(w / 2,
                                 h / 2,
                                 text=label_txt,
                                 font=font,
                                 fill="black")
Exemplo n.º 7
0
 def label_pos(self, pos, label=None, horizontal=False):
     """Calculate label start position (top-right if vertical, top-center if horizontal)"""
     xscale = turtle.getscreen().xscale
     yscale = turtle.getscreen().yscale
     font_family, font_size = self.font
     font = Font(family=font_family, size=font_size)
     line_height = font.metrics('linespace') / yscale
     height = (label.count('\n') + 1) * line_height
     return -8 / xscale if horizontal else pos, \
            pos - 0.5 * height if horizontal else -height - 6 / yscale
Exemplo n.º 8
0
 def label_size(self, label):
     """Calculate label size"""
     font_family, font_size = self.font
     font = Font(family=font_family, size=font_size)
     width = 0
     lines = 0
     for line in label.split('\n'):
         width = max(width, font.measure(line))
         lines += 1
     xscale = turtle.getscreen().xscale
     yscale = turtle.getscreen().yscale
     return width / xscale, font.metrics('linespace') * lines / yscale
Exemplo n.º 9
0
class ProgressPopup(tk.Toplevel):
    '''Displays progress with progressbar'''
    def __init__(self, title, steps=100):
        tk.Toplevel.__init__(self)
        self.fixed_font = Font(size=10)
        self.line_height = self.fixed_font.metrics("linespace")

        self.title(title)
        tk.Label(self, text=title).grid(row=0,
                                        column=0,
                                        sticky='w',
                                        padx=5,
                                        pady=20,
                                        columnspan=2)
        self.progress = ttk.Progressbar(self,
                                        orient='horizontal',
                                        length=200,
                                        mode='determinate',
                                        maximum=100)
        self.progress.grid(row=1, column=0, sticky='ew', padx=5, columnspan=2)

        self.scrollbar = tk.Scrollbar(self)
        self.scrollbar.grid(row=2, column=1, sticky='nesw', pady=10)

        self.log = tk.Canvas(self,
                             background='#FFFFFF',
                             width=500,
                             height=150,
                             yscrollcommand=self.scrollbar.set)
        self.log.grid(row=2, column=0, sticky='nesw', pady=10)
        self.log.line_number = 0

        self.scrollbar.config(command=self.log.yview)

        self.grab_set()

        self.step = 100.0 / steps

    def next(self):
        self.progress['value'] += self.step
        self.update()

    def log_message(self, line):
        self.log.create_text(0, (self.line_height * self.log.line_number),
                             font=self.fixed_font,
                             text=line,
                             anchor='nw')
        self.log.line_number += 1
        self.log.configure(scrollregion=self.log.bbox('all'))
        self.log.yview_moveto(1)

        self.update()
Exemplo n.º 10
0
Arquivo: event.py Projeto: SlamaFR/AP1
def taille_texte(chaine, police='Helvetica', taille='24'):
    """
    Donne la largeur et la hauteur en pixel nécessaires pour afficher
    ``chaine`` dans la police et la taille données.

    :param str chaine: chaîne à mesurer
    :param police: police de caractères (défaut : `Helvetica`)
    :param taille: taille de police (défaut 24)
    :return: couple (w, h) constitué de la largeur et la hauteur de la chaîne
        en pixels (int), dans la police et la taille données.
    """
    font = Font(family=police, size=taille)
    return font.measure(chaine), font.metrics("linespace")
Exemplo n.º 11
0
class ConversationTreeview(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent)

        self.font = Font(font='TkDefaultFont')
        self.font_height = self.font.metrics('linespace')
        self.style = ttk.Style(self)
        self.style.configure('Treeview',
                             rowheight=((self.font_height * 2) + 10))

        self.scrollbar = ttk.Scrollbar(self)
        self.tree = ttk.Treeview(self, columns=(
            'Tweet',
            'Author',
        ))
        self.scrollbar.configure(command=self.tree.yview)
        self.tree.configure(yscrollcommand=self.scrollbar.set)

        self.tree.column('#1', width=140, stretch=0)
        self.tree.column('#2', width=100, stretch=0)

        self.tree.heading('#0', text='Tweet')
        self.tree.heading('#1', text='Author')
        self.tree.heading('#2', text='Sentiment')

        self.tree.pack(side='left', fill='both', expand=True)
        self.scrollbar.pack(side='right', fill='y')

    def __clear(self):
        self.tree.delete(*self.tree.get_children())

    def wrap_text(self, text):
        text_length = len(text)
        if not text_length > 50:
            return text

        line1 = []
        line2 = []

        for word in text.split():
            if len(' '.join(line1) + ' ' + word) < (text_length / 2):
                line1.append(word)
            else:
                line2.append(word)

        return ' '.join(line1) + '\n' + ' '.join(line2)

    def update(self, conversations):
        self.__clear()

        for convo in conversations:
            root_tweet_text = self.wrap_text(convo.tweets[0])
            root_tw = self.tree.insert(
                '',
                'end',
                text=root_tweet_text,
                values=[convo.authors[0], convo.conversation_sentiment])
            for i in range(1, convo.number_of_turns()):
                if convo.sentiment_diffs[i - 1] <= 0:
                    sent_diff = '+' + str(
                        round(abs(convo.sentiment_diffs[i - 1]), 5))
                else:
                    sent_diff = '-' + str(
                        round(convo.sentiment_diffs[i - 1], 5))
                tweet_text = self.wrap_text(convo.tweets[i])
                self.tree.insert(root_tw,
                                 'end',
                                 text=tweet_text,
                                 values=[convo.authors[i], sent_diff])
Exemplo n.º 12
0
    def create_blocks_fst(self):
        text_height = Font.metrics(self.myFont, 'linespace')
        top_line = 20

        # block for Expr
        self.canvas.create_polygon(self.command_block_coords(
            50, top_line, text_height + 15, 110),
                                   fill='violet red',
                                   outline='purple',
                                   tags='expr_block')
        self.canvas.create_polygon(self.inside_block_coords(
            55, top_line + 10, text_height, 90),
                                   fill='light pink',
                                   tags='expr_block')
        top_line += text_height + 25

        # block for return command
        txt_len = Font.measure(self.myFont, 'return')
        self.canvas.create_polygon(self.command_block_coords(
            50, top_line, text_height + 15, 10 + txt_len + 20 + txt_len),
                                   fill='violet red',
                                   outline='purple',
                                   tags='return_block')
        self.canvas.create_text(57,
                                top_line + 8,
                                anchor=NW,
                                text='return',
                                tags='return_block',
                                font=self.myFont)
        self.canvas.create_polygon(self.inside_block_coords(
            52 + 1.3 * txt_len, top_line + 10, text_height, txt_len),
                                   fill='light pink',
                                   tags='return_block')
        top_line += text_height + 25

        # block for variable assignment command
        txt_len = Font.measure(self.myFont, 'variable')
        txt2_len = Font.measure(self.myFontBold, '=')
        self.canvas.create_polygon(self.command_block_coords(
            50, top_line, text_height + 15,
            10 + txt_len + 15 + txt2_len + 15 + txt_len + 10),
                                   fill='violet red',
                                   outline='purple',
                                   tags='variable_block')
        self.canvas.create_polygon(self.inside_block_coords(
            60, top_line + 10, text_height, txt_len + 5),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='variable_block')
        self.canvas.create_text(67,
                                top_line + 10,
                                anchor=NW,
                                text="variable",
                                tags='variable_block',
                                font=self.myFont)
        self.canvas.create_text(67 + txt_len + 8,
                                top_line + 10,
                                anchor=NW,
                                text="=",
                                tags='variable_block',
                                font=self.myFontBold)
        self.canvas.create_polygon(self.inside_block_coords(
            67 + txt_len + 8 + txt2_len + 5, top_line + 10, text_height,
            txt_len),
                                   fill='light pink',
                                   tags='variable_block')
        top_line += text_height + 25

        # block for if statement
        txt_len = Font.measure(self.myFont, 'if')
        self.canvas.create_polygon(self.control_block_coords(
            50, top_line, text_height + 15,
            10 + txt_len + 15 + 8 * txt_len + 15, 25)[0],
                                   fill='orange',
                                   outline='chocolate',
                                   tags='if_block')
        self.canvas.create_polygon(self.control_block_coords(
            50, top_line, text_height + 15,
            10 + txt_len + 10 + 9 * txt_len + 15, 25)[1],
                                   fill='orange',
                                   outline='chocolate',
                                   tags='if_block')
        self.canvas.create_text(67,
                                top_line + 10,
                                anchor=NW,
                                text='if',
                                tags='if_block',
                                font=self.myFont)
        self.canvas.create_polygon(self.inside_block_coords(
            67 + 2 * txt_len, top_line + 9, text_height, 8 * txt_len),
                                   fill='peachpuff',
                                   tags='if_block')

        top_line += text_height + 75

        # block for while statement
        txt_len = Font.measure(self.myFont, 'while')
        self.canvas.create_polygon(self.control_block_coords(
            50, top_line, text_height + 15, 10 + txt_len + 15 + txt_len + 25,
            25)[0],
                                   fill='orange',
                                   outline='chocolate',
                                   tags='while_block')
        self.canvas.create_polygon(self.control_block_coords(
            50, top_line, text_height + 15, 10 + txt_len + 15 + txt_len + 25,
            25)[1],
                                   fill='orange',
                                   outline='chocolate',
                                   tags='while_block')
        self.canvas.create_text(60,
                                top_line + 10,
                                anchor=NW,
                                text='while',
                                tags='while_block',
                                font=self.myFont)
        self.canvas.create_polygon(self.inside_block_coords(
            65 + txt_len, top_line + 9, text_height, 55),
                                   fill='peachpuff',
                                   tags='while_block')

        top_line += text_height + 75

        txt_len = Font.measure(self.myFont, 'print()')
        self.canvas.create_polygon(self.inside_block_coords(
            50, top_line, text_height + 4, txt_len + 30 + txt_len),
                                   fill='limegreen',
                                   outline='green',
                                   tags='print')
        self.canvas.create_text(65,
                                top_line + 2,
                                anchor=NW,
                                text="print(",
                                tags='print',
                                font=self.myFont)
        self.canvas.create_polygon(self.inside_block_coords(
            60 + txt_len, top_line + 2, text_height, txt_len),
                                   fill='lightgreen',
                                   tags='print')
        self.canvas.create_text(70 + 2 * txt_len,
                                top_line + 2,
                                anchor=NW,
                                text=")",
                                tags='print',
                                font=self.myFont)

        top_line += text_height + 15

        # complete print block
        self.canvas.create_polygon(self.command_block_coords(
            50, top_line, 2 * text_height + 5, 135),
                                   fill='violet red',
                                   outline='purple',
                                   tags='print_complete')
        self.canvas.create_polygon(self.inside_block_coords(
            55, top_line + 10, text_height + 4, txt_len + 30 + txt_len),
                                   fill='limegreen',
                                   outline='green',
                                   tags='print_complete')
        self.canvas.create_text(65,
                                top_line + 12,
                                anchor=NW,
                                text="print(",
                                tags='print_complete',
                                font=self.myFont)
        self.canvas.create_polygon(self.inside_block_coords(
            60 + txt_len, top_line + 12, text_height, txt_len),
                                   fill='lightgreen',
                                   tags='print_complete')
        self.canvas.create_text(70 + 2 * txt_len,
                                top_line + 12,
                                anchor=NW,
                                text=")",
                                tags='print_complete',
                                font=self.myFont)
        top_line += text_height + 25

        # right side column
        # equals statement block
        top_line = 20
        txt_len = Font.measure(self.myFontBold, ' == ')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height + 4,
            15 + 2 * 1.2 * txt_len + txt_len + 15),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='equals')
        self.canvas.create_polygon(self.inside_block_coords(
            310, top_line + 2, text_height, 1.2 * txt_len),
                                   fill='sky blue',
                                   tags='equals')
        self.canvas.create_text(312 + 1.2 * txt_len + 10,
                                top_line + 2,
                                anchor=NW,
                                text="==",
                                tags='equals',
                                font=self.myFontBold)
        self.canvas.create_polygon(self.inside_block_coords(
            310 + 1.2 * txt_len + txt_len + 10, top_line + 2, text_height,
            1.2 * txt_len),
                                   fill='sky blue',
                                   tags='equals')
        top_line += text_height + 15

        # not equal statement block
        txt_len = Font.measure(self.myFontBold, ' != ')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height + 4,
            15 + 2 * 1.5 * txt_len + txt_len + 15),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='not_equal')
        self.canvas.create_polygon(self.inside_block_coords(
            310, top_line + 2, text_height, 1.5 * txt_len),
                                   fill='sky blue',
                                   tags='not_equal')
        self.canvas.create_text(312 + 1.5 * txt_len + 10,
                                top_line + 2,
                                anchor=NW,
                                text="!=",
                                tags='not_equal',
                                font=self.myFontBold)
        self.canvas.create_polygon(self.inside_block_coords(
            310 + 1.5 * txt_len + txt_len + 10, top_line + 2, text_height,
            1.5 * txt_len),
                                   fill='sky blue',
                                   tags='not_equal')
        top_line += text_height + 15

        # grater than block
        txt_len = Font.measure(self.myFontBold, ' > ')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height + 4,
            15 + 2 * 2 * txt_len + txt_len + 15),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='greater')
        self.canvas.create_polygon(self.inside_block_coords(
            310, top_line + 2, text_height, 2 * txt_len),
                                   fill='sky blue',
                                   tags='greater')
        self.canvas.create_text(312 + 2 * txt_len + 10,
                                top_line + 2,
                                anchor=NW,
                                text=">",
                                tags='greater',
                                font=self.myFontBold)
        self.canvas.create_polygon(self.inside_block_coords(
            310 + 2 * txt_len + txt_len + 10, top_line + 2, text_height,
            2 * txt_len),
                                   fill='sky blue',
                                   tags='greater')
        top_line += text_height + 15

        # smaller than block
        txt_len = Font.measure(self.myFontBold, ' < ')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height + 4,
            15 + 2 * 2 * txt_len + txt_len + 15),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='smaller')
        self.canvas.create_polygon(self.inside_block_coords(
            310, top_line + 2, text_height, 2 * txt_len),
                                   fill='sky blue',
                                   tags='smaller')
        self.canvas.create_text(312 + 2 * txt_len + 10,
                                top_line,
                                anchor=NW,
                                text="<",
                                tags='smaller',
                                font=self.myFontBold)
        self.canvas.create_polygon(self.inside_block_coords(
            310 + 2 * txt_len + txt_len + 10, top_line + 2, text_height,
            2 * txt_len),
                                   fill='sky blue',
                                   tags='smaller')
        top_line += text_height + 15

        # grater or equal block
        txt_len = Font.measure(self.myFontBold, ' >= ')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height + 4,
            15 + 2 * 1.2 * txt_len + txt_len + 15),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='greater_or_equal')
        self.canvas.create_polygon(self.inside_block_coords(
            310, top_line + 2, text_height, 1.2 * txt_len),
                                   fill='sky blue',
                                   tags='greater_or_equal')
        self.canvas.create_text(312 + 1.2 * txt_len + 10,
                                top_line,
                                anchor=NW,
                                text=">=",
                                tags='greater_or_equal',
                                font=self.myFontBold)
        self.canvas.create_polygon(self.inside_block_coords(
            310 + 1.2 * txt_len + txt_len + 10, top_line + 2, text_height,
            1.2 * txt_len),
                                   fill='sky blue',
                                   tags='greater_or_equal')
        top_line += text_height + 15

        # smaller or equal block
        txt_len = Font.measure(self.myFontBold, ' <= ')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height + 4,
            15 + 2 * 1.2 * txt_len + txt_len + 15),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='smaller_or_equal')
        self.canvas.create_polygon(self.inside_block_coords(
            310, top_line + 2, text_height, 1.2 * txt_len),
                                   fill='sky blue',
                                   tags='smaller_or_equal')
        self.canvas.create_text(312 + 1.2 * txt_len + 10,
                                top_line,
                                anchor=NW,
                                text="<=",
                                tags='smaller_or_equal',
                                font=self.myFontBold)
        self.canvas.create_polygon(self.inside_block_coords(
            310 + 1.2 * txt_len + txt_len + 10, top_line + 2, text_height,
            1.2 * txt_len),
                                   fill='sky blue',
                                   tags='smaller_or_equal')
        top_line += text_height + 15

        # or block
        txt_len = Font.measure(self.myFontBold, ' or ')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height + 4,
            15 + 2 * 1.7 * txt_len + txt_len + 15),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='or')
        self.canvas.create_polygon(self.inside_block_coords(
            310, top_line + 2, text_height, 1.7 * txt_len),
                                   fill='sky blue',
                                   tags='or')
        self.canvas.create_text(312 + 1.7 * txt_len + 10,
                                top_line,
                                anchor=NW,
                                text="or",
                                tags='or',
                                font=self.myFont)
        self.canvas.create_polygon(self.inside_block_coords(
            310 + 1.7 * txt_len + txt_len + 10, top_line + 2, text_height,
            1.7 * txt_len),
                                   fill='sky blue',
                                   tags='or')
        top_line += text_height + 15

        # and block
        txt_len = Font.measure(self.myFont, 'and ')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height + 4,
            15 + 2 * 1.2 * txt_len + txt_len + 15),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='and')
        self.canvas.create_polygon(self.inside_block_coords(
            310, top_line + 2, text_height, 1.2 * txt_len),
                                   fill='sky blue',
                                   tags='and')
        self.canvas.create_text(310 + 1.2 * txt_len + 12,
                                top_line + 2,
                                anchor=NW,
                                text="and",
                                tags='and',
                                font=self.myFont)
        self.canvas.create_polygon(self.inside_block_coords(
            312 + 1.2 * txt_len + txt_len + 10, top_line + 2, text_height,
            1.2 * txt_len),
                                   fill='sky blue',
                                   tags='and')
        top_line += text_height + 15

        # not block
        txt_len = Font.measure(self.myFont, 'not ')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height + 4, 10 + txt_len + 10 + 1.6 * txt_len),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='not')
        self.canvas.create_text(312,
                                top_line + 2,
                                anchor=NW,
                                text='not',
                                tags='not',
                                font=self.myFont)
        self.canvas.create_polygon(self.inside_block_coords(
            312 + txt_len, top_line + 2, text_height, 1.6 * txt_len),
                                   fill='sky blue',
                                   tags='not')
        top_line += text_height + 15

        # block for variable
        txt_len = Font.measure(self.myFont, 'variable')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height, txt_len + 20),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='variable')
        self.canvas.create_text(315,
                                top_line,
                                anchor=NW,
                                text="variable",
                                tags='variable',
                                font=self.myFont)

        # None block
        txt_len = Font.measure(self.myFont, 'None')
        self.canvas.create_polygon(self.inside_block_coords(
            400, top_line, text_height, txt_len + 20),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='none')
        self.canvas.create_text(415,
                                top_line,
                                anchor=NW,
                                text="None",
                                tags='none',
                                font=self.myFont)

        top_line += text_height + 15

        # block for creating number
        txt_len = Font.measure(self.myFont, 'number')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height, txt_len + 20),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='number')
        self.canvas.create_text(315,
                                top_line,
                                anchor=NW,
                                text="number",
                                tags='number',
                                font=self.myFont)

        # True block
        txt_len = Font.measure(self.myFont, 'True')
        self.canvas.create_polygon(self.inside_block_coords(
            400, top_line, text_height, txt_len + 20),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='true')
        self.canvas.create_text(415,
                                top_line,
                                anchor=NW,
                                text="True",
                                tags='true',
                                font=self.myFont)
        top_line += text_height + 15

        # block for creating string
        txt_len = Font.measure(self.myFont, 'string')
        self.canvas.create_polygon(self.inside_block_coords(
            300, top_line, text_height, txt_len + 20),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='string')
        self.canvas.create_text(315,
                                top_line,
                                anchor=NW,
                                text="string",
                                tags='string',
                                font=self.myFont)

        # False block
        txt_len = Font.measure(self.myFont, 'False')
        self.canvas.create_polygon(self.inside_block_coords(
            400, top_line, text_height, txt_len + 25),
                                   fill='dodger blue',
                                   outline='steel blue',
                                   tags='false')
        self.canvas.create_text(415,
                                top_line,
                                anchor=NW,
                                text="False",
                                tags='false',
                                font=self.myFont)
Exemplo n.º 13
0
clue_rect_default_height = 75

x_pad = 20  # the amount to pad before starting the clue number
x_num_pad = 5  # the amount to pad between the clue number and the clue
y_pad = 5  # the amount to pad (top and bottom) between the end
# of the clue box and the bounding box of the clue text

clue_rect_top_y = 0  # zero to start.  bottom_y + 1 in the loop
for key, value in down_clues.items():
    print(key, value)

    clue_number = key
    clue_text = value
    clue_text_length = rfont.measure(clue_text)
    clue_num_length = rfont.measure(clue_number)
    clue_text_height = rfont.metrics("linespace")
# print("clue_text_length:", clue_text_length)
# col_left_x, row_top_y, col_right_x, row_bot_y

# clue_rect_bottom_y = clue_rect_top_y + clue_rect_default_height
# clue_text_line_len = clue_right_x - (clue_left_x + (x_pad*2) + clue_num_length + x_num_pad + clue_top_y + y_pad)

# cr = list_canvas.create_rectangle(clue_left_x, clue_top_y, clue_right_x, clue_bottom_y, fill="light grey")
# cn = list_canvas.create_text(clue_left_x + x_pad, clue_top_y + y_pad, text=clue_number, font=bfont, anchor = "nw")
# ct = list_canvas.create_text(clue_left_x + x_pad + clue_num_length + x_num_pad, clue_top_y + y_pad, text=clue_text, font=rfont, anchor = "nw", width=clue_text_line_len)
# bb = list_canvas.bbox(ct)
# x0, y0, x1, y1 = list_canvas.coords(cr)
# y1 = bb[3] + y_pad
# list_canvas.coords(cr, x0, y0, x1, y1)
# clue_rect_top_y = clue_rect_bottom_y + 1
# if key == 1: break
    alldata = view_data()
    for row in alldata:
        print(row[1:])
        vocablist.insert('', 'end', values=row[1:])


header = ['Vocab JP', 'Vocab Thai', 'Description', 'Image']

vocablist = ttk.Treeview(AllVocab, columns=header, show='headings', height=10)
vocablist.pack(fill=BOTH)

for hd in header:
    vocablist.heading(hd, text=hd)

font = Font(family='Angsana New', size=20)
font.metrics()
fontheight = font.metrics()['linespace']

style = ttk.Style()
style.configure("Treeview.Heading", font=('Arial', 15))
style.configure("Treeview", font=font, rowheight=fontheight)

BUpdate = ttk.Button(AllVocab, text='Update', command=update_data)
BUpdate.pack()


def del_item():

    q = messagebox.askyesno('Confirm', 'คุณต้องการลบใช่หรือไม่?')
    print(q)
Exemplo n.º 15
0
class SearchBox(Frame):
    '''A Treeview widget on top, Entry on bottom, using queues for
     interaction with outside functions'''
    def __init__(self, parent=None, db=DB, fdict={}):
        Frame.__init__(self, parent)
        self.Tests = Tests
        self.db = db
        self.fdict = dbm.open(self.db, 'c')
        #self.fdict['**']=''
        self.db_update = False
        #will hold the query to be processed
        self.query = None
        self.drives = self.get_drives()
        self.start_func = StartFunc(
        )  #platform dependent double-click response

        self.results = iter(
            ())  #initiating query results as an empty generator
        self.total_width = self.winfo_screenwidth(
        )  #to adjust column widths relative to screen size
        #Remember scorch mode
        self.scorch = False
        self.encoding = ENCODING

        #for scorch mode
        #self.keylist=self.fdict.keys()
        self.keylist_index = 0
        self.keylist_counter = 0

        #keystroke indicator
        self.counter = 0

        #queues for passing search queries and results
        self.query_queue = Queue()
        self.result_queue = Queue()

        #for usage by db generating function
        self.dbinit_queue = Queue()

        #--Search Results panel at top
        self.panel = Treeview(columns=('Path', 'Size', 'Date'))
        self.panel.pack(expand=True, fill='both')
        self.panel.heading('#0', text='Name')
        self.panel.heading(0, text='Path')
        self.panel.heading(1, text='Size')
        self.panel.heading(2, text='Date Modified')

        #--Starting geometry of the search panel
        try:  #start maximized
            self.panel.master.attributes('-zoomed', 1)
        except:
            self.panel.master.state('zoomed')

        self.panel_width = self.panel.winfo_width()
        #Name - 2/5-----Path - 2/5-----Size -1/25-----Date -4/25
        # '#0' is the 'Name' column
        self.panel.column('#0', width=int(self.total_width * 0.4))
        self.panel.column('Path', width=int(self.total_width * 0.4))
        self.panel.column('Size', width=int(self.total_width * 0.06))
        self.panel.column('Date', width=int(self.total_width * 0.14))

        #--Panel font, style
        self.font = Font(family='Helvetica', size=11)
        '''TkDefaultFont - {'family': 'Segoe UI',  'overstrike': 0, 'size': 9, 
                       'slant': 'roman', 'underline': 0, 'weight': normal'}'''
        self.style = Style()

        #linespace - adjust the row height to the font, doesn't happen on its own in tkinter
        self.style.configure('SearchBox.Treeview',
                             font=self.font,
                             rowheight=self.font.metrics('linespace'))
        self.panel.config(style='SearchBox.Treeview')

        #alternating background colors
        self.panel.tag_configure('color1',
                                 background='gray85')  #, foreground='white')
        self.panel.tag_configure('color2',
                                 background='gray90')  #, foreground='white')
        #'dark sea green', 'wheat3', 'black'

        #--App title and icon, currently transparent
        self.panel.master.title('Jiffy')
        self.icon = PhotoImage(height=16, width=16)
        self.icon.blank()  #transparent icon, works on all but Py35/Win

        #loading the transparent icon. black on Py35/Win
        try:
            self.master.wm_iconphoto('True', self.icon)
        except:
            #For some reason this jammed Python 3.5 with Tk 8.6 on Windows
            self.tk.call('wm', 'iconphoto', self.master._w, self.icon)

        #--A string variable to monitor input to the Entry box
        self.entry_var = StringVar()
        #self.entry_var.set('Type to search. [F5 - Refresh Database]. [F12 - Scorch Mode]')
        # [Ctrl-O - Options]. [Ctrl-I - Info]
        self.entry_var.trace('w', self.update_query)

        #--Entry line on the bottom
        self.entry_box = Entry(textvariable=self.entry_var)
        #keep it as a single line on all window sizes
        self.entry_box.pack(side='bottom', fill='x')

        #--Widget Bindings
        #self.master.bind('<Ctrl-Z>', self.quit)  #alternative to Alt-F4
        self.master.bind('<Control-equal>', self.scaleup)
        self.master.bind('<Control-Button-4>', self.scaleup)
        self.master.bind('<Control-minus>', self.scaledown)
        self.master.bind('<Control-Button-5>', self.scaledown)
        self.master.bind('<Control-MouseWheel>', self.scale_mouse)

        self.panel.bind('<Double-1>', self.doubleclick)
        self.panel.bind('<Return>', self.doubleclick)

        #allow scrolling and typing without switching focus
        self.entry_box.bind('<MouseWheel>', self.scroll_from_entry)
        self.entry_box.bind('<Button-4>', self.scroll_from_entry)
        self.entry_box.bind('<Button-5>', self.scroll_from_entry)

        self.master.bind('<F5>', self.make_database)
        #self.master.bind('<F12>', self.scorch_mode)

        #--Starting up with entry box active
        self.entry_box.focus_set()

        #--Generating a starting message based on existence of a database
        if not self.fdict:
            self.panel.insert('',
                              'end',
                              text='No cache database found',
                              values=('Hit F5 to generate database', ))
        else:
            self.panel.insert(
                '',
                'end',
                text='Type to search.   [F5 - Refresh Database]',
                values=('[Ctrl - +/-/MouseWheel - Adjust font size]', ))
        # [Ctrl-O - Options]. [Ctrl-I - Info]
        #self.panel.insert('', 'end', text='Scorch Mode is faster but uses more memory', values=('Loads the entire database into RAM',))

        self.update_searchbox()
        #Initializing the query managing function in a separate thread (upgrade to pool?)
        thread.start_new_thread(
            TMakeSearch, (self.fdict, self.query_queue, self.result_queue))

    ##GUI functionality--------------------------------------------------------
    #O change to initiation from parameter to SearchBox for more modularity
    def get_drives(event):
        return GetDrives()

    def scroll_from_entry(self, event):
        '''Scroll results without deactivating entry box, called from entry_box'''

        self.panel.yview_scroll(1, 'units')

    def scaleup(self, event):
        '''The Treeview widget won't auto-adjust the row height, 
        so requires manual resetting upon font changing'''
        self.font['size'] += 1
        self.style.configure('SearchBox.Treeview',
                             rowheight=self.font.metrics('linespace') + 1)

    def scaledown(self, event):
        self.font['size'] -= 1
        self.style.configure('SearchBox.Treeview',
                             rowheight=self.font.metrics('linespace') + 1)

    def scale_mouse(self, event):
        self.scaleup(event) if event.delta > 0 else self.scaledown(event)

    def doubleclick(self, event):
        '''Invoke default app on double-click or Enter'''

        #getting file/folder name and removing '[' and ']' for folders
        selection = self.panel.item(self.panel.focus())
        filename = selection['text']
        #remove folder indicating square brackets
        if filename[0] == '[':
            filename = filename[1:-2]

        #SPLIT_TOKEN='\\' if 'win' in sys.platform else '/'
        full_path = selection['values'][0] + SPLIT_TOKEN + filename
        self.start_func(full_path)

    def quit(self, event):
        '''Currently Alt-F4 exits program, in case I want to add more shortcuts.
        Also add thread closing management here'''

        self.master.destroy()

    ##Cheese: update_database()->is_sb_generated(), trace_results(), update_query()
    def make_database(self, event):
        '''Using a thread to generate the dictionary to prevent GUI freezing'''

        #* dbm might not be thread safe - best might be to restart TMakeSearch
        self.gtime = time()  # for testing
        self.entry_var.set('Updating Database')
        self.entry_box.icursor('end')

        #Resulting dicitionay will be passed via dbinint_queue
        thread.start_new_thread(RecursiveCreateDict,
                                (self.drives, self.dbinit_queue, self.fdict))

        #Wait for the dictionary to be generated
        self.is_db_generated()

    def is_db_generated(self):
        '''Update database if available or sleep and try again'''

        if not self.dbinit_queue.empty():
            #A new dictionary was passed

            #retrieving new dict
            self.newdict, self.unsearched = self.dbinit_queue.get()
            #Messaging TMakeSearch to stop querying the dictionary
            self.db_update = True
            self.query_queue.put(None)
            sleep(0.11)  #TMakeSearch takes 0.1s naps. Check further '''

            if whichdb(self.db) == ('dbhash'):
                '''For dumbdbm, this jams the app, as does manual updating. it's
                not dumb, it's just not worthy'''
                self.fdict.update(self.newdict)
            else:
                for key in self.newdict:
                    self.fdict[key] = self.newdict[key]
            print('fdict is created')
            self.db_update = False
            #save new database
            self.fdict.sync()
            print('fdict synced')

            #Open a new TMakeSearch with the updated database
            #thread.start_new_thread(TMakeSearch, (self.fdict, self.query_queue, self.result_queue))

            #Cleaning up
            self.newdict.clear()
            self.newdict = None

            self.gtime = time() - self.gtime
            #to read about {}.format              #also, a label may be simpler
            self.entry_var.set('Database generation time- ' + str(self.gtime) +
                               's. Type to search. [F5 - Refresh Database]')

            #Pass a signal to close TMakeSearch, then reopen it
            self.query_queue.put(True)
            thread.start_new_thread(
                TMakeSearch, (self.fdict, self.query_queue, self.result_queue))

            self.entry_box.icursor(0)
            #self.loading.destroy()
            self.panel.delete(*self.panel.get_children())
            self.panel.insert(
                '',
                0,
                text='Scorch Mode is faster but uses more memory',
                values=('Loads database into RAM', ))
            #self.keylist=fdict.keys()   #for scorch mode
            self.counter = 0
            #self.IS_1ST_PRESS=True
            #for testing
            #print time()-self.start
            #print self.dict_size()
        else:
            self.after(100, self.is_db_generated)

    def update_searchbox(self):
        '''Update GUI with new result batches '''

        self.even = True
        #for splitting size and date from the keys
        self.separator = ' * '.encode(self.encoding)
        while not self.result_queue.empty():
            qresult = self.result_queue.get()
            #print ('is_batch_recieved:', qresult)
            #if qcounter==self.counter:  #currently assuming results will arrive by querying order
            #break
        try:
            #if nothing in queue this will raise an error, saves a preemptive if clause
            self.results, self.is_new = qresult
            if Tests.is_batch_recieved:
                print('is_batch_recieved:', self.results)
        except:
            pass  #no new results
            if Tests.is_batch_recieved:
                print('is_batch_recieved: no new results')
        else:
            #if self.panel.get_children()!=():
            #results for a newer query, erase old results
            if self.is_new:
                self.panel.delete(*self.panel.get_children())

            for key in self.results:
                try:
                    name, size, date = key.decode(self.encoding).split(u'*')
                    #name, size, date=key.split(self.separator)
                    if Tests.is_result_parsed:
                        print(name)
                except:
                    if Tests.is_result_parsed:
                        print('parsing issue with', key)
                else:
                    path = self.fdict[key].decode(self.encoding)
                    '''if 'win' in sys.platform and top[0] is u'/':
                        top=u'C:\\'+top[1:] '''
                    color = 'color1' if self.even else 'color2'
                    self.even = not self.even
                    self.panel.insert('',
                                      'end',
                                      text=name,
                                      values=(path, size, date),
                                      tags=(color, ))

        self.after(60, self.update_searchbox)

    def update_query(self, x=None, y=None, z=None):
        '''Invoked by StringVar().trace() method, which passes 3 arguments that are honorably ditched '''

        #Deactivate while switching dictionaries
        if self.db_update:
            pass

        #Cleaning up for 1st keystroke or after a message in the Entry box
        if not self.counter:
            '''Entry box needs to be cleaned, the new char put in and the cursor
           placed after it'''
            #get&set the 1st search char. user may've changed cursor location b4 typing
            self.entry_var.set(
                self.entry_var.get()[self.entry_box.index(INSERT) - 1])
            #move cursor after the first char
            self.entry_box.icursor(1)

        #counter goes up either way
        self.counter += 1
        self.query = self.entry_var.get()
        self.query_queue.put(self.query)
        if Tests.is_query_sent:
            print(self.query)
            print(self.counter)

    ##Not in use ----------------------------------------------------------------

    def trace_query(self):
        '''If I opt for periodically checking the StringVar'''

        if self.counter:  #when counter=0 there's a message/notification in the entry box
            if self.query != self.entry_var.get():
                self.query = self.entry_var.get()
                self.query_queue.put(self.query)

        self.after(100, self.trace_query)

    def trace_and_update(self):
        ''' In-GUI implementation of query searching, uses a list for iterating 
        over the keys'''
        '''works smoother when results are generated quickly, but with
        sparse results GUI becomes unresponsive for short whiles. Relevant
        only if results are guaranteed to be generated swiftly'''

        #print self.query
        #if new query, resetting search parameters and GUI
        if self.query != self.entry_var.get():
            self.keylist_counter = 0
            self.query = self.entry_var.get()
            self.search_list = self.query.lower().split()
            self.panel.delete(*self.panel.get_children())

        self.insertion_counter = 0
        self.keylist_index = self.keylist_counter
        for key in self.keylist[self.keylist_index:]:
            filename = key.split('*')[0].lower()
            #If a match, parse and add to the Treeview
            if self.all(token in filename for token in self.search_list):
                name, size, date = key.split('*')
                self.panel.insert('',
                                  'end',
                                  text=name,
                                  values=(self.fdict[key], size, date))
                self.insertion_counter += 1
            self.keylist_counter += 1

            if self.insertion_counter >= self.INSERTIONS_PER_CYCLE:  #50  ##or not dict_counter:
                break  #nap time

        self.after(60, self.trace_and_update)
Exemplo n.º 16
0
statusBar_lab.pack(side='left', padx=2, expand='yes', fill='both')
if root._windowingsystem != 'aqua':
    foo = ttk.Sizegrip(statusBar)
    foo.pack(side='left', padx=2)
statusBar.pack(side='bottom', fill='x', pady=2)

##set textheight 30
##catch {
##    set textheight [expr {
##	([winfo screenheight .] * 0.7) /
##	[font metrics mainFont -displayof . -linespace]
##    }]
##}
textheight = 30
try:
    textheight = root.winfo_screenheight() * 0.7 / mainFont.metrics('linespace', displayof='.')
except:
    pass

##ttk::frame .textFrame
##scrollbar .s -orient vertical -command {.t yview} -takefocus 1
##pack .s -in .textFrame -side right -fill y
##text .t -yscrollcommand {.s set} -wrap word -width 70 -height $textheight \
##	-font mainFont -setgrid 1 -highlightthickness 0 \
##	-padx 4 -pady 2 -takefocus 0
##pack .t -in .textFrame -expand y -fill both -padx 1
##pack .textFrame -expand yes -fill both
##if {[tk windowingsystem] eq "aqua"} {
##    pack configure .statusBar.lab -padx {10 18} -pady {4 6}
##    pack configure .statusBar -pady 0
##    .t configure -padx 10 -pady 0
Exemplo n.º 17
0
class CanvasElem(object):
    '''CanvasElem keeps track of a canvas element, possibly with text.'''
    
    STD_FONTS = [ {'family':'Bookman Old Style', 'size':14},\
                  {'family':'Century', 'size':14}, \
                  {'family':'Courier', 'size':14}]
    
    #Changes the script-name of the gate to the display-name of the gate
    GATE_MASKS = {'h':'H', 'x':'X', 'y':'Y', 'z':'Z', 'rx':'Rx', 'ry':'Ry',\
                 'rz':'Rz', 's':'S', 'ph':'S','t':'T', 'tdag':'T^', 'measure':'M', 'prepz':'|0>'}
    #All the gates that have a special drawing style
    SPECIAL_GATES = ('cnot', 'cx', 'toffoli', 'swap', 'cphase', 'cz', 'cr','c-x','c-z','class_cx','class_cz')
    SPECIAL_NODES = ('circ','oplus','cross')
    #Determine the radius of the associated nodes of the special gates
    RADII = {'circ':5, 'oplus': 9, 'cross':6 }
    
    #Determine the width of the boxes around the gates
    BORDER_WIDTH = 3
    
    #Determine the margins around the gates.
    MARGINS = (0,0) #(5,5)
    
    def __init__(self, canvas, gate=None, aspect = (-1,-1), bbox=None, font_dict=None,\
                 special_node = None, draw_rect = True):
        self.canvas = canvas
        
        self.aspect = aspect
        self.bbox = bbox

        #Keep track of the actual drawing coordinates
        self.draw_x = -1
        self.draw_y = -1
        self.draw_w = -1
        self.draw_h = -1
        self.text_x = -1
        self.text_y = -1
        
        #Keep track of the min dimensions of the bbox such that the contents can be displayed correctly
        self.min_w = -1
        self.min_h = -1
        
        #Keep track of the attachment points to which other elements can attach themselves.
        self.attachments = {'left':-1, 'right':-1, 'top':-1, 'bottom':-1}
        
        #Keep track of the text within the rectangle
        self.text = None
        #Set the font
        self.font = None
        if font_dict:
            self.font = Font(family=font_dict['family'], size=font_dict['size'])
        else:
            for font_dict in self.STD_FONTS:
                try:
                    self.font = Font(family=font_dict['family'],size=font_dict['size'])
                    if self.font:
                        break
                except Exception as e:
                    pass
            else:
                raise ValueError(f'{self.__str__()} cannot produce any font, none worked!')
        
        #Keep track of the canvas elements
        self.rect_canvas = None
        self.text_canvas = None
        self.special_node = special_node
        self.specials_canvas = []
        
        #Keep track of whether we need to draw the rectangle
        self.draw_rect = draw_rect
        
        #Update the current gate, and the associated text
        self.set_gate(gate)
        
    def find_min_size(self):
        '''Finds the minimum size of the rectangle needed to contain the text'''
        if self.special_node:
            #self.min_w = max(2 * self.RADIUS, self.font.measure('x'), self.font.measure('o'))
            #self.min_h = max(2 * self.RADIUS, self.font.metrics('linespace'))
            self.min_w = self.min_h = 2 * self.RADII[self.special_node]
            
        #If we are an element with actual text inside, compute how large the text is
        elif self.text:
            min_w = self.font.measure(self.text) + self.draw_rect*self.BORDER_WIDTH*2
            min_h = self.font.metrics('linespace') + self.draw_rect*self.BORDER_WIDTH*2
            #Take into account the aspect ratio in self.aspect
            if not -1 in self.aspect:
                #We must have w/h = aspect[0]/aspect[1] => w  = h * aspect[0]/aspect[1]
                #Either stretch w, or stretch h
                if min_h * self.aspect[0]/self.aspect[1] > min_w:
                    self.min_w = int( min_h * self.aspect[0]/self.aspect[1] )
                    self.min_h = int(min_h)
                else:
                    self.min_w = int(min_w)
                    self.min_h = int( min_w * self.aspect[1]/self.aspect[0] )
            else:
                self.min_w = int(min_w)
                self.min_h = int(min_h)
            
            
    def set_bbox(self,bbox):
        self.bbox = bbox
        
    def set_gate(self,gate):
        self.gate = gate
        if self.gate in self.GATE_MASKS.keys():
            self.text = self.GATE_MASKS[self.gate]
        #If the gate is a special gate, suppress the text. Otherwise, set it.
        elif self.gate in self.SPECIAL_GATES:
            self.text = None
        else:
            self.text = self.gate
            
        self.find_min_size()

    def find_draw_coords(self):
        '''Finds the coordinates to draw with, and sets up the attachment points'''
        if self.bbox is None:
            raise ValueError(f'{self.__str__()} cannot find draw coords because bbox is None!')
        
        #Do NOT include margins if we are building a special node
        if self.special_node:
            want_width = self.min_w
            want_height = self.min_h
        else:
            want_width = self.min_w + 2 * self.MARGINS[0]
            want_height = self.min_h + 2 * self.MARGINS[1]

        self.draw_w = want_width if want_width < self.bbox['w'] else self.bbox['w']
        self.draw_h = want_height if want_height < self.bbox['h'] else self.bbox['h']

        self.draw_x = int( self.bbox['x'] + (self.bbox['w'] - self.draw_w)/2 )
        self.draw_y = int( self.bbox['y'] + (self.bbox['h'] - self.draw_h)/2 )

        self.text_x = int( self.draw_x + self.draw_w/2 )
        self.text_y = int( self.draw_y + self.draw_h/2 )

        self.attachments['left'] = self.draw_x
        self.attachments['right'] = self.draw_x + self.draw_w
        self.attachments['top'] = self.draw_y
        self.attachments['bottom'] = self.draw_y + self.draw_h

        
    def draw(self):
        '''Draws the element on the canvas'''
        #First, find the coords at which we should draw.
        self.find_draw_coords()
        
        #If we are a normal node:
        if self.special_node is None:
            #If we should draw a rectangle:
            if self.draw_rect:
                self.rect_canvas = self.canvas.create_rectangle(self.draw_x,self.draw_y,\
                                        self.draw_x+self.draw_w,self.draw_y+self.draw_h,width=self.BORDER_WIDTH)
            
            #If we are a measurement device
            if self.gate == 'measure':
                self.specials_canvas += self.draw_measurement()
            #If we have text:
            elif self.text:
                self.text_canvas = self.canvas.create_text(self.text_x,self.text_y,font=self.font, justify=tk.CENTER,\
                                                          text=self.text)
        
        else: #We are special: we need to draw either a circ, an oplus or a cross
            def node(xy, r, circ=False, fill=False, plus=False, cross=False):
                out = []
                if circ:
                    out.append(self.canvas.create_oval( xy[0]-r, xy[1]-r, xy[0]+r, xy[1]+r, fill='black' if fill else '', width=1.5) )
                if plus:
                    out.append(self.canvas.create_line( xy[0], xy[1]-r, xy[0], xy[1]+r, width=2 ) )
                    out.append(self.canvas.create_line( xy[0]-r, xy[1], xy[0]+r, xy[1], width=2 ) )
                if cross:
                    out.append(self.canvas.create_line( xy[0]-r, xy[1]-r, xy[0]+r, xy[1]+r, width=2.5 ) )
                    out.append(self.canvas.create_line( xy[0]-r, xy[1]+r, xy[0]+r, xy[1]-r, width=2.5 ) )
                return out
            
            mid_x = int( self.bbox['x'] + self.bbox['w']/2 )
            mid_y = int( self.bbox['y'] + self.bbox['h']/2 )
            
            if self.special_node == 'circ':
                self.specials_canvas += node((mid_x,mid_y), self.RADII['circ'], circ=True, fill=True )
            elif self.special_node == 'oplus':
                self.specials_canvas += node((mid_x,mid_y), self.RADII['oplus'], circ=True, plus=True)
            else:
                self.specials_canvas += node((mid_x,mid_y), self.RADII['cross'], cross=True)
                
    def draw_measurement(self):
        '''Draws a measurement device'''
        mid_x = int(self.draw_x + self.draw_w/2)
        mid_y = int(self.draw_y + 3*self.draw_h/5)
        radius = int( (self.draw_w/2) * 7/10 )
        arc = self.canvas.create_arc( mid_x-radius, mid_y-radius, mid_x+radius, mid_y+radius,\
                                     start=0, extent=180, width=2, style=tk.ARC  )
        end_x = int(self.draw_x + self.draw_w * 8.5/10 )
        end_y = int(self.draw_y + self.draw_h * 1.5/10 )
        arrow = self.canvas.create_line(mid_x, mid_y, end_x, end_y, arrow=tk.LAST, width=2 )
        
        return arc, arrow

    def __str__(self):
        return f'R.D. DRAW(x={self.draw_x},y={self.draw_y},w={self.draw_w},h={self.draw_h},text={self.text})'
    
    def __repr__(self):
        return self.__str__()
Exemplo n.º 18
0
class PitchDisplay:
    def __init__(self, mainWindow, threshold=10):
        self.frame = mainWindow.right_frame
        self.mainWindow = mainWindow

        self.threshold = threshold

        self.font = Font(size=20)
        self.pitchOffset = self.font.metrics('linespace') * 0.75

        self._pitchValue = '---'  # default display
        self._centsValue = -50
        self._hertzValue = 0
        self._octaveValue = ''

        self._span = 75  # Size of tuner arc in degrees, starting at vertical

        self.canvas = Canvas(self.frame,
                             bg=Colors.background,
                             bd=0,
                             highlightthickness=0)
        self.canvas.pack(fill=BOTH, expand=True)
        self.canvas.bind("<Configure>", self.configure)

        self.top_frame = Frame(self.canvas,
                               height=35,
                               bg=Colors.background,
                               bd=0,
                               highlightthickness=0)
        #self.top_frame.pack_propagate(0)
        self.top_frame.pack(side='top', fill=tk.X, anchor=tk.N)

        self.rec_frame = Frame(self.top_frame,
                               width=80,
                               height=35,
                               bg=Colors.background,
                               bd=0,
                               highlightthickness=0)
        self.rec_frame.pack_propagate(0)
        self.rec_frame.pack(anchor='w', side=tk.LEFT)

        self.light = IndicatorLight(self.rec_frame, 35)
        self.light.pack(anchor='w', side='left')

        self.time_label = Label(self.rec_frame,
                                text='00:00',
                                anchor='e',
                                justify=RIGHT,
                                fg=Colors.text,
                                bg=Colors.background)
        self.time_label.pack(side='right')

        self.score_label = RoundedLabel(self.top_frame,
                                        "Score: 0%",
                                        Colors.score_label,
                                        Colors.background,
                                        height=35,
                                        width=110)
        self.score_label.pack(side='right')
        #self.score_label.set_text("adfasdf")

        self.showsHertz = BooleanVar()

        style = ttk.Style()
        style.configure("Pitch.TCheckbutton",
                        background=Colors.background,
                        foreground=Colors.text)
        style.map('Pitch.TCheckbutton',
                  foreground=[('active', Colors.text)],
                  background=[('pressed', '!focus', '#232323'),
                              ('active', Colors.aux)])

        c = ttk.Checkbutton(self.canvas,
                            text="Show Hertz",
                            variable=self.showsHertz,
                            takefocus=False,
                            command=self.display_default_gui,
                            style="Pitch.TCheckbutton")
        c.pack(anchor='e', side='bottom')

        self._last_time = 0
        self._clearing = False

        self.display_default_gui()

    def pause(self):
        self.light.stop()
        self.canvas.itemconfig(self.help_text,
                               text='Press \'space\' to accept audio input')
        self._clearing = True

    def resume(self):
        self.light.start_flashing()
        self.canvas.itemconfig(self.help_text,
                               text='Press \'space\' to pause audio input')

    def cents_to_angle(self, cents):
        return cents / 50 * self._span

    def configure(self, event):
        self.display_default_gui()

    def display_score(self, score):
        self.score_label.set_text(f"Score: {round(score)}%")

    def display_current_gui(self):
        pitch_and_octave = self._pitchValue + self._octaveValue
        self.canvas.itemconfig(self.current_pitch_display,
                               text=pitch_and_octave)
        if self.showsHertz.get():
            self.canvas.itemconfig(self.hertzDisplay, text=self._hertzValue)
        self.update_line(self._centsValue)
        if not self._clearing and abs(self._centsValue) <= self.threshold:
            self.canvas.itemconfig(self.green_arc, fill=Colors.green)
        else:
            self.canvas.itemconfig(self.green_arc, fill="#ccffbf")

    def display_default_gui(self):
        self.canvas.delete("all")
        self.width = self.frame.winfo_width()
        self.height = self.frame.winfo_height()
        min_dimension = min(self.width, self.height)
        self.radius = 0.4 * min_dimension
        self.centerX = self.width / 2
        self.centerY = self.height / 2 + 15

        self.current_pitch_display = self.canvas.create_text(self.centerX,
                                                             self.centerY +
                                                             self.pitchOffset,
                                                             font=self.font,
                                                             text='---',
                                                             fill=Colors.text)
        if self.showsHertz.get():
            self.hertzDisplay = self.canvas.create_text(self.centerX,
                                                        self.centerY +
                                                        2 * self.pitchOffset,
                                                        font="Ubuntu 14",
                                                        text='',
                                                        fill=Colors.text)

        self.help_text = self.canvas.create_text(
            self.width / 2,
            self.height - 35,
            text='Press \'space\' to accept audio input',
            fill=Colors.text)

        x0 = self.centerX - self.radius
        y0 = self.centerY - self.radius
        x1 = self.centerX + self.radius
        y1 = self.centerY + self.radius

        # rect = self.canvas.create_rectangle(x0, y0, x1, y1)

        rStart = 90 - self._span
        rSpan = 2 * self._span
        yStart = 90 - self.cents_to_angle(
            self.mainWindow.controller.yellow_threshold)
        ySpan = 2 * (90 - yStart)
        gStart = 90 - self.cents_to_angle(self.threshold)
        gSpan = 2 * self.cents_to_angle(self.threshold)

        self.red_arc = self.canvas.create_arc(x0, y0, x1, y1)
        self.canvas.itemconfig(self.red_arc,
                               start=rStart,
                               fill="#ffbfbf",
                               extent=rSpan,
                               outline='')

        self.yellow_arc = self.canvas.create_arc(x0, y0, x1, y1)
        self.canvas.itemconfig(self.yellow_arc,
                               start=yStart,
                               fill="#fffeb0",
                               extent=ySpan,
                               outline='')

        self.green_arc = self.canvas.create_arc(x0, y0, x1, y1)
        self.canvas.itemconfig(self.green_arc,
                               start=gStart,
                               fill="#ccffbf",
                               extent=gSpan,
                               outline='')

        self.line = self.canvas.create_line(0,
                                            0,
                                            0,
                                            0,
                                            fill=Colors.tuner_needle,
                                            width=4,
                                            arrow=FIRST,
                                            arrowshape=(self.radius, 10, 5))
        self.update_line(-50)

    def update_line(self, cents):
        deg = self.cents_to_angle(cents)
        theta = radians(deg)
        dx = self.radius * sin(theta)
        dy = self.radius * cos(theta)
        self.canvas.coords(self.line, self.centerX, self.centerY,
                           self.centerX + dx, self.centerY - dy)

    def set_threshold(self, thresh):
        self.threshold = thresh
        self.display_default_gui()

    def update_pitch(self, value):  # event as parameter
        self._pitchValue = value

    def update_hertz(self, value):
        self._hertzValue = value

    def update_cents(self, value):
        self._centsValue = value

    def update_octave(self, value):
        self._octaveValue = value

    def set_time(self, total_seconds):
        minutes = total_seconds // 60
        seconds = total_seconds % 60
        display_string = '{:02}:{:02}'.format(minutes, seconds)
        self.time_label.config(text=display_string)

    def update_data(self, hz, data):  #TODO: remove data parameter?
        if hz != 0:
            self._clearing = False
            midi = hz_to_midi(hz)
            if data.midi_range[0] <= midi <= data.midi_range[1]:
                pitch_class = midi_to_pitch_class(midi)
                desired_hz = closest_in_tune_frequency(hz)
                cent = cents(desired_hz, hz)
                name = data.key_signature.get_display_for(pitch_class)
                self.update_cents(cent)
                self.update_hertz(f"{round(hz)} Hz")
                self.update_octave(f"{get_octave(midi)}")
                self.update_pitch(name)
                self.display_current_gui()
                self._last_time = time.time()
        else:
            self.clear()

        self.set_time(data.timer.get())  # TODO move timer

    def clear(self):
        self._clearing = True
        if self._centsValue != -50 and time.time() - self._last_time > 1.5:
            self.update_cents(max(-50, self._centsValue - 3))
            self.update_pitch('---')
            self.update_hertz('')
            self.update_octave('')
            self.display_current_gui()
        elif self._centsValue == -50:  # clearing animation has finished
            self._clearing = False

    def needs_update(self):
        return self._clearing
Exemplo n.º 19
0
class TextEditor(Frame, CaretObserver, TextObserver):
    def update_text(self, text: str):
        self.update_status_bar()
        self.redisplay()

    def update_caret_location(self, loc: Location):
        self.update_status_bar()
        self.redisplay()

    def __init__(self, text_editor_model: TextEditorModel):
        super().__init__()

        # TODO extract
        self._minimalWidth = 555
        self._minimalHeight = 700
        self._xMargin = 10
        self._numberSpacing = 50
        self._yMargin = 20
        self._font = Font(size=12, family="Purisa")
        self._canvasTextColor = flat_colors.FlatUiColors.CLOUDS
        self._canvasBackgroundColor = flat_colors.FlatUiColors.PETER_RIVER
        self._canvasHighlightColor = flat_colors.FlatUiColors.EMERALD

        # TODO extract
        self._caretShownDelay = 300
        self._caretHiddenDelay = 5000
        self._caretColor = flat_colors.FlatUiColors.MIDNIGHT_BLUE

        self.__processed_selection = []

        self._model = text_editor_model
        self._model._caretObservers.add(self)
        # using an anonymous class:
        # self._model._observers.add(type("Pero", (CaretObserver, object),
        #                                 {"updateCaretLocation": lambda _, __: self.redisplay()})())

        self._clipboardStack = ClipboardStack()

        self._pluginsDirectory = "./plugins/"
        self._pluginsModuleName = "plugins"
        self._plugins = self._load_plugins()

        self.init_menubar()
        self.init_toolbar()
        self.init_statusbar()
        self.init_canvas()

    def _load_plugins(self):
        plugins = []
        for file in os.listdir(self._pluginsDirectory):
            if file.endswith(".py"):
                print(file)
                # try:
                spec = importlib.util.spec_from_file_location(
                    self._pluginsModuleName, self._pluginsDirectory + file)
                module = importlib.util.module_from_spec(spec)
                spec.loader.exec_module(module)
                for name, obj in inspect.getmembers(
                        module, lambda x: inspect.isclass(x) and issubclass(x, Plugin) and not inspect.isabstract(x)):
                    plugins.append(obj())
                # except:
                #     pass

        return plugins

    def init_menubar(self):
        menubar = Menu(self.master)
        self.master.config(menu=menubar)

        file_menu = Menu(menubar)
        file_menu.add_command(label="Open", underline=0, command=self.open_file)
        file_menu.add_command(label="Save", underline=0, command=self.save_file)
        file_menu.add_command(label="Exit", underline=0, command=self.on_exit)
        menubar.add_cascade(label="File", underline=0, menu=file_menu)

        edit_menu = Menu(menubar)
        edit_menu.add_command(label="Undo", command=self.undo, state=DISABLED)
        UndoManager.get_instance().attach_undo_observer(
            type("UndoManagerStackObserver1", (UndoManagerStackObserver, object),
                 {"stack_empty": lambda _, e: edit_menu.entryconfig(1, state=DISABLED if e else NORMAL)})())

        edit_menu.add_command(label="Redo", command=self.redo, state=DISABLED)
        UndoManager.get_instance().attach_redo_observer(
            type("UndoManagerStackObserver2", (UndoManagerStackObserver, object),
                 {"stack_empty": lambda _, e: edit_menu.entryconfig(2, state=DISABLED if e else NORMAL)})())

        edit_menu.add_command(label="Cut", command=self.cut, state=DISABLED)
        self._model.attach_selection_observer(
            type("SelectionObserverCut", (SelectionObserver, object),
                 {"update_selection": lambda _, e: edit_menu.entryconfig(3, state=DISABLED if not e else NORMAL)})())

        edit_menu.add_command(label="Copy", command=self.copy, state=DISABLED)
        self._model.attach_selection_observer(
            type("SelectionObserverCopy", (SelectionObserver, object),
                 {"update_selection": lambda _, e: edit_menu.entryconfig(4, state=DISABLED if not e else NORMAL)})())

        edit_menu.add_command(label="Paste", command=self.paste, state=DISABLED)
        self._clipboardStack.attach_clipboard_observer(
            type("ClipboardObserverPaste", (ClipboardObserver, object),
                 {"update_clipboard": lambda _, e: edit_menu.entryconfig(5, state=DISABLED if not e else NORMAL)})())

        edit_menu.add_command(label="Paste and Take", command=self.paste_and_take)
        self._clipboardStack.attach_clipboard_observer(
            type("ClipboardObserverPasteAndTake", (ClipboardObserver, object),
                 {"update_clipboard": lambda _, e: edit_menu.entryconfig(6, state=DISABLED if not e else NORMAL)})())

        edit_menu.add_command(label="Delete selection", command=self.delete_selection, state=DISABLED)
        self._model.attach_selection_observer(
            type("SelectionObserverDelete", (SelectionObserver, object),
                 {"update_selection": lambda _, e: edit_menu.entryconfig(7, state=DISABLED if not e else NORMAL)})())

        edit_menu.add_command(label="Clear document", command=self.clear_document)
        menubar.add_cascade(label="Edit", underline=0, menu=edit_menu)

        move_menu = Menu(menubar)
        move_menu.add_command(label="Caret to document start", command=self.caret_to_start)
        move_menu.add_command(label="Caret to document end", command=self.caret_to_end)
        menubar.add_cascade(label="Move", underline=0, menu=move_menu)

        plugins_menu = Menu(menubar)
        for plugin in self._plugins:
            plugins_menu.add_command(
                label=plugin.get_name(),
                command=lambda p=plugin: p.execute(self._model, UndoManager.get_instance(), self._clipboardStack))

        menubar.add_cascade(label="Plugins", underline=0, menu=plugins_menu)

    def init_toolbar(self):
        toolbar = Frame(self.master)

        undo = Button(toolbar, text="Undo", command=self.undo, state=DISABLED)
        undo.pack(side=LEFT, padx=2, pady=2)
        UndoManager.get_instance().attach_undo_observer(
            type("UndoManagerStackObserver3", (UndoManagerStackObserver, object),
                 {"stack_empty": lambda _, e: undo.config(state=DISABLED if e else NORMAL)})())

        redo = Button(toolbar, text="Redo", command=self.redo, state=DISABLED)
        redo.pack(side=LEFT, padx=2, pady=2)
        UndoManager.get_instance().attach_redo_observer(
            type("UndoManagerStackObserver4", (UndoManagerStackObserver, object),
                 {"stack_empty": lambda _, e: redo.config(state=DISABLED if e else NORMAL)})())

        copy = Button(toolbar, text="Copy", command=self.copy, state=DISABLED)
        copy.pack(side=LEFT, padx=2, pady=2)
        self._model.attach_selection_observer(
            type("SelectionObserverCopyTool", (SelectionObserver, object),
                 {"update_selection": lambda _, e: copy.config(state=DISABLED if not e else NORMAL)})())

        cut = Button(toolbar, text="Cut", command=self.cut, state=DISABLED)
        cut.pack(side=LEFT, padx=2, pady=2)
        self._model.attach_selection_observer(
            type("SelectionObserverCutTool", (SelectionObserver, object),
                 {"update_selection": lambda _, e: cut.config(state=DISABLED if not e else NORMAL)})())

        paste = Button(toolbar, text="Paste", command=self.cut, state=DISABLED)
        paste.pack(side=LEFT, padx=2, pady=2)
        self._clipboardStack.attach_clipboard_observer(
            type("ClipboardObserverPasteTool", (ClipboardObserver, object),
                 {"update_clipboard": lambda _, e: paste.config(state=DISABLED if not e else NORMAL)})())

        toolbar.pack(side=TOP, fill=X)

    def init_statusbar(self):
        self._statusbar = Label(self.master, bd=1, relief=SUNKEN, padx=6, pady=4, anchor=E)
        self._statusbar.pack(side=BOTTOM, fill=X)
        self.update_status_bar()

    def init_canvas(self):
        self.master.title("Lab 3 example")
        self.pack(fill=BOTH, expand=1)

        self._display_caret = True
        self._selecting_active = False
        self._canvas = Canvas(self, bg=self._canvasBackgroundColor,
                              scrollregion=(0, 0, self._minimalWidth, self._minimalHeight))
        self._vbar = Scrollbar(self, orient=VERTICAL)
        self._vbar.pack(side=RIGHT, fill=Y)
        self._vbar.config(command=self._canvas.yview)
        self._hbar = Scrollbar(self, orient=HORIZONTAL)
        self._hbar.pack(side=BOTTOM, fill=X)
        self._hbar.config(command=self._canvas.xview)
        self._canvas.config(xscrollcommand=self._hbar.set, yscrollcommand=self._vbar.set)
        self._canvas.pack(fill=BOTH, expand=1)

        self.redisplay()
        self._canvas.bind_all("<Key>", self.on_key_pressed)
        self._other_dialog_open = False
        self.after(self._caretShownDelay, self.on_timer)

    def redisplay(self, update_selection=False):
        # print("caret loc", self._model.get_caret_location().get(), "||| current row and column",
        #       self._model.find_caret(), "|||| sel", self._model.get_selection_range().get_start(),
        #       self._model.get_selection_range().get_end())
        row_height = self._font.metrics()["linespace"]
        (caret_row, caret_column) = self._model.find_caret()

        height = max(self._minimalHeight, len(
            list(self._model.all_lines())) * row_height + 2 * self._yMargin)
        width = max(self._minimalWidth, self._font.measure(
            max(list(self._model.all_lines()), key=len)) + self._numberSpacing + 2 * self._xMargin)
        self._canvas.delete("all")
        self._canvas.config(scrollregion=(0, 0, width, height))

        # TODO follow caret by scrolling left/right and up/down
        # deltaX =
        # deltaY =

        self._render_selection(update_selection)
        self._render_caret(caret_row, caret_column)

        for (i, line) in enumerate(self._model.all_lines()):
            self._canvas.create_text(self._xMargin, self._yMargin + row_height * i, font=self._font, text=str(i),
                                     anchor=NW, fill=self._canvasTextColor)
            self._canvas.create_text(self._xMargin + self._numberSpacing, self._yMargin + row_height * i,
                                     font=self._font, text=line, anchor=NW, fill=self._canvasTextColor)

    def update_selection(self, right_end_moved: bool):
        """
        Update the current selection in the TextEditorModel. If selecting is inactive, the selection will be reset to
        range [current_caret_location, current_caret_location]. Otherwise, the range will be updated in accordance with
        the new caret position.
        :param right_end_moved: was the caret at the right end of the selection
        """
        # TODO move to an more appropriate place
        new_caret_location = self._model.get_caret_location().get()
        if self._selecting_active:
            selection_before = self._model.get_selection_range()
            if right_end_moved:
                self._model.set_selection_range(LocationRange(selection_before.get_start().get(), new_caret_location))
            else:
                self._model.set_selection_range(LocationRange(new_caret_location, selection_before.get_end().get()))
        else:
            self._model.reset_selection()

    def on_timer(self):
        self._display_caret = not self._display_caret
        self.redisplay(True)
        self.after(self._caretShownDelay if not self._display_caret else self._caretShownDelay, self.on_timer)

    def on_exit(self):
        self.master.destroy()

    def get_x_y_of_line_start(self, row):
        return self._xMargin + self._numberSpacing, self._yMargin + self._font.metrics()["linespace"] * row

    def get_x_y_of_line_end(self, row):
        return (self._xMargin + self._numberSpacing + self._font.measure(self._model.get_line(row)),
                self._yMargin + self._font.metrics()["linespace"] * row)

    def get_x_y_at_caret_location(self, caret_location: Location):
        row, column = self._model.find_location(caret_location)
        return self.get_x_y_at_row_and_column(row, column)

    def get_x_y_at_row_and_column(self, row, column):
        xy_tuple = self.get_x_y_of_line_start(row)
        x, y = xy_tuple[0], xy_tuple[1]
        return x + self._font.measure(self._model.get_line(row)[:column]), y

    def row_height(self):
        return self._font.metrics()["linespace"]

    def _render_caret(self, caret_row, caret_column):
        color = self._caretColor if self._display_caret else self._canvasBackgroundColor
        x_start = self._xMargin + self._numberSpacing + self._font.measure(
            self._model.get_line(caret_row)[:caret_column])
        y_start = self._yMargin + self.row_height() * caret_row + 3
        self._canvas.create_line(x_start - 3, y_start, x_start + 3, y_start, fill=color)
        self._canvas.create_line(x_start, y_start, x_start, y_start + self._font.metrics()["linespace"] - 9, fill=color)
        self._canvas.create_line(x_start - 3, y_start + self._font.metrics()["linespace"] - 9, x_start + 3,
                                 y_start + self._font.metrics()["linespace"] - 9, fill=color)

    def _render_selection(self, update_selection=True):
        selection = self._model.get_selection_range()
        if selection.get_start().get() == selection.get_end().get():
            return

        if update_selection:
            self.__preprocess_selection(selection)

        for e in self.__processed_selection:
            self._canvas.create_rectangle(e[0][0], e[0][1], e[1][0], e[1][1] + self.row_height(),
                                          outline=self._canvasHighlightColor, fill=self._canvasHighlightColor)

    def __preprocess_selection(self, selection: LocationRange):
        sel_start_r, sel_start_c = self._model.find_location(selection.get_start())
        sel_end_r, sel_end_c = self._model.find_location(selection.get_end())

        if sel_start_r > sel_end_r or sel_start_r == sel_end_r and sel_start_c > sel_end_c:
            sel_start_r, sel_start_c, sel_end_r, sel_end_c = sel_end_r, sel_end_c, sel_start_r, sel_start_c

        if sel_start_r == sel_end_r:
            self.__processed_selection = [(self.get_x_y_at_row_and_column(sel_start_r, sel_start_c),
                                           self.get_x_y_at_row_and_column(sel_end_r, sel_end_c))]
        else:
            self.__processed_selection = [(self.get_x_y_at_row_and_column(sel_start_r, sel_start_c),
                                           self.get_x_y_of_line_end(sel_start_r))]
            self.__processed_selection += [(self.get_x_y_of_line_start(row), self.get_x_y_of_line_end(row)) for row in
                                           range(sel_start_r + 1, sel_end_r)]
            self.__processed_selection += [(self.get_x_y_of_line_start(sel_end_r),
                                            self.get_x_y_at_row_and_column(sel_end_r, sel_end_c))]

    def update_status_bar(self):
        ln, col = self._model.find_caret()
        total_rows = self._model.get_lines_count()
        self._statusbar['text'] = "Ln: {}, Col: {}\tTotal rows: {}".format(ln, col, total_rows)

    def on_key_pressed(self, e):
        if self._other_dialog_open:
            return
        keysym = e.keysym
        char = e.char

        # https://stackoverflow.com/questions/19861689/check-if-modifier-key-is-pressed-in-tkinter
        ctrl = (e.state & 0x4) != 0
        alt = (e.state & 0x8) != 0 or (e.state & 0x80) != 0
        shift = (e.state & 0x1) != 0
        self._selecting_active = shift

        # print(e.keysym, e.char, e.keycode, e.char.isprintable(), "%x" % e.state, ctrl, shift, alt)

        if keysym == "Left":
            self._display_caret = True
            caret_before = self._model.get_caret_location().get()
            self._model.move_caret_left()
            self.update_selection(caret_before == self._model.get_selection_range().get_end().get())
        elif keysym == "Right":
            self._display_caret = True
            caret_before = self._model.get_caret_location().get()
            self._model.move_caret_right()
            self.update_selection(caret_before == self._model.get_selection_range().get_end().get())
        elif keysym == "Up":
            self._display_caret = True
            caret_before = self._model.get_caret_location().get()
            self._model.move_caret_up()
            self.update_selection(caret_before == self._model.get_selection_range().get_end().get())
        elif keysym == "Down":
            self._display_caret = True
            caret_before = self._model.get_caret_location().get()
            self._model.move_caret_down()
            self.update_selection(caret_before == self._model.get_selection_range().get_end().get())
        elif keysym == "BackSpace":
            self._display_caret = True
            if self._model.get_selection_range().is_empty():
                action = self._model.execute_delete_before()
                if action is not None:
                    UndoManager.get_instance().push(action)
            else:
                self.delete_selection()
        elif keysym == "Delete":
            self._display_caret = True
            if self._model.get_selection_range().is_empty():
                action = self._model.execute_delete_after()
                if action is not None:
                    UndoManager.get_instance().push(action)
            else:
                self.delete_selection()
        elif keysym == "Return":
            # TODO what if None
            action1 = self.delete_selection(False)
            action2 = self._model.execute_insert_at_caret("\n")
            actions = [a for a in [action1, action2] if a is not None]
            if actions:
                UndoManager.get_instance().push(JumboEditAction(actions))
        elif keysym == "Escape":
            self._display_caret = True
            self.master.destroy()
        elif ctrl and keysym.lower() == "c":
            self.copy()
        elif ctrl and keysym.lower() == "x":
            self.cut()
        elif ctrl and keysym.lower() == "v":
            if shift:
                self.paste_and_take()
            else:
                self.paste()
        elif ctrl and keysym.lower() == "y":
            self.redo()
        elif ctrl and keysym.lower() == "z":
            self.undo()
        elif len(char) and char.isprintable():
            # TODO should LocationRange be immutable? Or how should I pass it around?
            action1 = self.delete_selection(False)
            action2 = self._model.execute_insert_at_caret(char)
            self._model.reset_selection()
            actions = [a for a in [action1, action2] if a is not None]
            if actions:
                UndoManager.get_instance().push(JumboEditAction(actions))

    def open_file(self):
        self._other_dialog_open = True
        try:
            f = filedialog.askopenfile(mode='r', defaultextension=".txt")
            if f is None:
                return
            text = "\n".join(f.readlines())
            self._model.set_text(text)
            f.close()
        finally:
            self._other_dialog_open = False

    def save_file(self):
        self._other_dialog_open = True
        try:
            f = filedialog.asksaveasfile(mode='w', defaultextension=".txt")
            if f is None:
                return
            text = "\n".join(self._model.all_lines())
            f.write(text)
            f.close()
        finally:
            self._other_dialog_open = False

    def undo(self):
        um = UndoManager.get_instance()
        if not um.is_undo_empty():
            um.undo()

    def redo(self):
        um = UndoManager.get_instance()
        if not um.is_redo_empty():
            um.redo()

    def copy(self):
        if not self._model.get_selection_range().is_empty():
            self._clipboardStack.push(self._model.get_selected_text())

    def cut(self):
        if not self._model.get_selection_range().is_empty():
            self._clipboardStack.push(self._model.get_selected_text())
            self.delete_selection()

    def paste(self):
        if self._clipboardStack.has_any():
            self.delete_selection()
            action = self._model.execute_insert_at_caret(self._clipboardStack.peek())
            if action is not None:
                UndoManager.get_instance().push(action)

    def paste_and_take(self):
        if self._clipboardStack.has_any():
            action1 = self.delete_selection(False)
            action2 = self._model.execute_insert_at_caret(self._clipboardStack.pop())
            actions = [a for a in [action1, action2] if a is not None]
            if actions:
                UndoManager.get_instance().push(JumboEditAction(actions))

    def delete_selection(self, push_action=True) -> EditAction:
        if self._model.get_selection_range().is_empty():
            return
        sel_left = self._model.get_selection_range().get_left()
        self._model.move_caret_to(sel_left)

        action = self._model.execute_delete_range(self._model.get_selection_range().clone())
        if push_action and action is not None:
            UndoManager.get_instance().push(action)
        self._model.set_selection_range(LocationRange(sel_left.get(), sel_left.get()))
        return action

    def clear_document(self):
        self._model.set_selection_range(LocationRange(0, self._model.get_caret_max()))
        self.delete_selection()

    def caret_to_start(self):
        self._model.move_caret_to(Location(0))

    def caret_to_end(self):
        self._model.move_caret_to(Location(self._model.get_caret_max()))
Exemplo n.º 20
0
    def __init__(self,
                 master,
                 columns,
                 data=None,
                 command=None,
                 sort=True,
                 select_mode=None,
                 heading_anchor=CENTER,
                 cell_anchor=W,
                 style=None,
                 height=None,
                 padding=None,
                 adjust_heading_to_content=False,
                 stripped_rows=None,
                 selection_background=None,
                 selection_foreground=None,
                 field_background=None,
                 heading_font=None,
                 heading_background=None,
                 heading_foreground=None,
                 cell_pady=2,
                 cell_background=None,
                 cell_foreground=None,
                 cell_font=None,
                 headers=True):

        self._stripped_rows = stripped_rows

        self._columns = columns

        self._number_of_rows = 0
        self._number_of_columns = len(columns)

        self.row = self.List_Of_Rows(self)
        self.column = self.List_Of_Columns(self)

        s = Style()

        if style is None:
            style_name = "Multicolumn_Listbox%s.Treeview" % self._style_index
            self._style_index += 1
        else:
            style_name = style

        style_map = {}
        if selection_background is not None:
            style_map["background"] = [('selected', selection_background)]

        if selection_foreground is not None:
            style_map["foeground"] = [('selected', selection_foreground)]

        if style_map:
            s.map(style_name, **style_map)

        style_config = {}
        if cell_background is not None:
            style_config["background"] = cell_background

        if cell_foreground is not None:
            style_config["foreground"] = cell_foreground

        if cell_font is None:
            font_name = s.lookup(style_name, "font")
            cell_font = nametofont(font_name)
        else:
            if not isinstance(cell_font, Font):
                if isinstance(cell_font, basestring):
                    cell_font = nametofont(cell_font)
                else:
                    if len(Font) == 1:
                        cell_font = Font(family=cell_font[0])
                    elif len(Font) == 2:
                        cell_font = Font(family=cell_font[0],
                                         size=cell_font[1])

                    elif len(Font) == 3:
                        cell_font = Font(family=cell_font[0],
                                         size=cell_font[1],
                                         weight=cell_font[2])
                    else:
                        raise ValueError(
                            "Not possible more than 3 values for font")

            style_config["font"] = cell_font

        self._cell_font = cell_font

        self._rowheight = cell_font.metrics("linespace") + cell_pady
        style_config["rowheight"] = self._rowheight

        if field_background is not None:
            style_config["fieldbackground"] = field_background

        s.configure(style_name, **style_config)

        heading_style_config = {}
        if heading_font is not None:
            heading_style_config["font"] = heading_font
        if heading_background is not None:
            heading_style_config["background"] = heading_background
        if heading_foreground is not None:
            heading_style_config["foreground"] = heading_foreground

        heading_style_name = style_name + ".Heading"
        s.configure(heading_style_name, **heading_style_config)

        treeview_kwargs = {"style": style_name}

        if height is not None:
            treeview_kwargs["height"] = height

        if padding is not None:
            treeview_kwargs["padding"] = padding

        if headers:
            treeview_kwargs["show"] = "headings"
        else:
            treeview_kwargs["show"] = ""

        if select_mode is not None:
            treeview_kwargs["selectmode"] = select_mode

        self.interior = Treeview(master, columns=columns, **treeview_kwargs)

        if command is not None:
            self._command = command
            self.interior.bind("<<TreeviewSelect>>", self._on_select)

        for i in range(0, self._number_of_columns):

            if sort:
                self.interior.heading(
                    i,
                    text=columns[i],
                    anchor=heading_anchor,
                    command=lambda col=i: self.sort_by(col, descending=False))
            else:
                self.interior.heading(i,
                                      text=columns[i],
                                      anchor=heading_anchor)

            if adjust_heading_to_content:
                self.interior.column(i, width=Font().measure(columns[i]))

            self.interior.column(i, anchor=cell_anchor)

        if data is not None:
            for row in data:
                self.insert_row(row)
Exemplo n.º 21
0
class DNAStrandInterface: 
    ## Valid DNA symbols.
    symbols = 'atcg'
    complSymbols = {
        'a':'t',
        't':'a',
        'c':'g',
        'g':'c'
    }
    def __init__(self, master = None, data1 = "", data2 = ""): 
        
        self.master = master 
        
        self.canResize = 0
        self.helpIsOpen = False

        #text fonts
        self.font = Font(family="Courier", size=22)
        self.widthOfChar = self.font.measure("a")
        self.heightOfChar = self.font.metrics("linespace")


        self.fontHelp = Font(family="Courier", size=12)
        self.widthOfCharHelp = self.fontHelp.measure("a")
        self.heightOfCharHelp = self.fontHelp.metrics("linespace")

        
        self.canvas = Canvas(master)
        self.recenter()
        
        self.dnaMoving = False

        self.x = 0
        self.y = 0
        
        self.getData()
        self.movement() 


    #initial scene to choose method of input data   
    def getData(self):
        self.buttonFile = Button(self.master, text = "Get data from file", command = self.getDataFile)
        self.buttonType = Button(self.master, text = "Type data", command = self.getDataType)
        
        self.buttonFile.place(relx=0.5, rely=0.4, anchor=CENTER)
        self.buttonType.place(relx=0.5, rely=0.6, anchor=CENTER)
        self.canvas.pack()

    #destroys initial scene
    def destroyInitMenu(self):  
        self.buttonFile.destroy()    
        self.buttonType.destroy()

    #get input from file
    #generates error if the path is invalid    
    def getEntryFileData(self):
        path = self.entryFile.get() 
        
        try:
            with open(path, 'r') as f:
                data1 = f.readline()
                if(len(data1) >= 1 and data1[len(data1)-1]=='\n'):
                    data1 = data1[:-1]
                data2 = f.readline()
                if(len(data2) >= 1 and data2[len(data2)-1]=='\n'):
                    data2 = data2[:-1]
                f.close()
                self.destroyDataFile()
                self.setData(data1, data2)
        except IOError as e:
            print("Invalid path")
            self.canvas.destroy()
            exit()

    #destroys data file scene
    def destroyDataFile(self):        
        self.entryFile.destroy()
        self.labelFile.destroy()
        self.buttonGetDataFile.destroy()    
    
    #creates data file scene
    def getDataFile(self):            
        self.destroyInitMenu()
        txt1 = "Path: "
        self.labelFile = Label(master, text=txt1, font = self.font)
        self.entryFile = Entry(self.master) 
        self.buttonGetDataFile = Button(self.master, text = "ENTER", command=self.getEntryFileData)
        
        self.buttonGetDataFile.place(relx=0.5, rely=0.7, anchor=CENTER)
        self.labelFile.place(relx=0.4, rely=0.5, anchor=CENTER)
        self.entryFile.place(relx=0.6, rely=0.5, anchor=CENTER)
        
    #creates data type scene
    def getDataType(self):            
        self.destroyInitMenu()
        txt1 = "DNA strand 1: "
        self.labelDna1 = Label(master, text=txt1, font = self.font)
        txt2 = "DNA strand 2: "
        self.labelDna2 = Label(master, text=txt2, font = self.font)
        self.entryDna1 = Entry(self.master) 
        self.entryDna2 = Entry(self.master) 
        self.buttonGetDataType = Button(self.master, text = "ENTER", command=self.getEntryData)
        self.labelDna1.place(relx=0.4, rely=0.2, anchor=CENTER)
        self.entryDna1.place(relx=0.7, rely=0.2, anchor=CENTER)
        self.labelDna2.place(relx=0.4, rely=0.4, anchor=CENTER)
        self.entryDna2.place(relx=0.7, rely=0.4, anchor=CENTER)
        self.buttonGetDataType.place(relx=0.5, rely=0.7, anchor=CENTER)
        self.canvas.pack()


    #destroys data type scene
    def destroyDataType(self):
        self.entryDna1.destroy()
        self.labelDna1.destroy()
        self.entryDna2.destroy()
        self.labelDna2.destroy()
        self.buttonGetDataType.destroy()

    #gets input from typing
    def getEntryData(self):
        data1 = self.entryDna1.get()
        data2 = self.entryDna2.get()
        self.destroyDataType()
        self.setData(data1, data2)

    #test if given data is valid
    def isValid(self, data):
        if(data == ""):
            return False
        valid = True
        for i in (data):
            flag = False
            for j in(self.symbols):
                if (i == j):
                    flag = True
                    break
            if flag == False:
                valid = False
                break
        return valid

    #generates error if given data is invalid
    def validateData(self, data1, data2):
        try:
            if self.isValid(data1) == False:
                raise ValueError('invalid givenData strand1')
            if self.isValid(data2) == False:
                raise ValueError('invalid givenData strand2')
        except ValueError as error:
                print(str(error))
                self.canvas.destroy()
                exit()


    #sets data1 and data2 and creates dna moving scene
    def setData(self, data1, data2):

        self.canResize = 0
        self.data1 = data1.replace('A','a').replace('T','t').replace('G','g').replace('C','c')
        self.data2 = data2.replace('A','a').replace('T','t').replace('G','g').replace('C','c')
        self.validateData(self.data1, self.data2)
        self.reset()

        #creates strands with the given data
        self.strand1 = self.canvas.create_text( 
                        self.center['x'], self.center['y'], text = self.data1, font = self.font )
        self.strand2 = self.canvas.create_text( 
                        self.center['x'] + self.x, self.center['y'] + self.y + self.widthOfChar, text = self.data2, font = self.font)
        
        #creates help message
        self.helpMSG = self.canvas.create_text( 
                         10 + len("h - help")*self.widthOfCharHelp/2.0, 10, text = "h - help", font = self.fontHelp, fill="red")
        self.helpList = ["Shift-L - shuffle", "Escape - exit", "m - got to position", "    of maximum matches", "right key - move right", "left key - move left", "upper key - move up", "down key - move down", "Tab - reset"] 
        self.helpPosX = [ 0, 0, 0, 0,(25*self.widthOfCharHelp), (25*self.widthOfCharHelp), (25*self.widthOfCharHelp), (25*self.widthOfCharHelp), (25*self.widthOfCharHelp)]
        self.helpPosY = [ 1, 2, 3, 4, 0, 1, 2, 3, 4]
        self.helpTexts = []
        for i in range(len(self.helpList)):
            self.helpTexts.append(self.canvas.create_text( 
                         10 + len(self.helpList[i])*self.widthOfCharHelp/2.0 + self.helpPosX[i], 10 + self.heightOfCharHelp*self.helpPosY[i] , text = "", font = self.fontHelp))

        
        self.recenter() 
        self.canvas.config(width=2560, height=1536)
        self.canvas.pack()
        self.dnaMoving = True
        
        


    #deals with help message
    def help(self, event):

        if(self.dnaMoving):
            msg =""
            if(self.helpIsOpen == True):
                msg = "h - help"
                for i in range(len(self.helpList)):
                    self.canvas.itemconfig(self.helpTexts[i], text = "")
            else:
                msg = "h - close help"
                for i in range(len(self.helpList)):
                    self.canvas.itemconfig(self.helpTexts[i], text = self.helpList[i])
                
            self.canvas.itemconfig(self.helpMSG, text = msg)
            self.canvas.coords(self.helpMSG, 10 + len(msg)*self.widthOfCharHelp/2.0, 10)           
            self.helpIsOpen = not self.helpIsOpen


        

    #recenters components
    def recenter(self):
        self.canvas.pack()
        self.center = {'y' : self.canvas.winfo_height()/2.0, 'x' : self.canvas.winfo_width()/2.0}
        
    #resizes window
    def resize(self, event):
        self.width = event.width  
        self.height = event.height
        
        if(self.canResize >= 1):
            self.canvas.config(width=self.width, height=self.height)
            self.canvas.pack()
            self.canResize = 0
        else:
            self.canResize += 1
        
    #sets strand2 relative position to the starting position
    def reset(self):
        self.x = (len(self.data2) - len(self.data1))*self.widthOfChar/(2.0)
        self.y = self.heightOfChar

    def callReset(self, event):
        if(self.dnaMoving):
            self.reset()

    
    #deals with the strands movements
    def movement(self):
        self.recenter()
        if(self.dnaMoving):
            self.canvas.coords(self.strand1, self.center['x'], self.center['y'])
            self.canvas.coords(self.strand2, self.center['x'] + self.x, self.center['y'] + self.y)
            
            x_strand2 = self.canvas.coords(self.strand2)[0] 
            y_strand2 = self.canvas.coords(self.strand2)[1]

            width_strand2 = len(self.data2)*self.widthOfChar
            height_strand2 = self.heightOfChar

            if(x_strand2 + width_strand2/2 <= 0 or x_strand2 - width_strand2/2 >= self.canvas.winfo_width()):
                self.reset()
            elif(y_strand2 + height_strand2/2 <= 0 or y_strand2 - height_strand2/2 >= self.canvas.winfo_height()):
                self.reset()
            
            self.matches()
  
        self.canvas.after(100, self.movement) 
    
    def left(self, event): 
        self.x += -5
        self.y += 0
    
    def right(self, event): 
        self.x += 5
        self.y += 0
    
    def up(self, event): 
        self.x += 0
        self.y += -5
    
 
    def down(self, event): 
        self.x += 0
        self.y += 5


    #returns if math of c1 and c2 is valid
    def charMatch(self, c1, c2):
        match = False
        if c1 in self.symbols:
            if c2 == self.complSymbols[c1]:
                match = True

        # If c1 is in the complement symbols dictionary and c2 is equal to the complement of c1 the match is valid
 
        return match
    
    def findMatchesWithRightShift(self, shift):       
        myStrand = self.data2
        otherStrand = self.data1

        mat = [False]*len(myStrand)
        
        myIndex = shift # right shift the other is equal to left shift myself
        otherIndex = 0

        # iterates through the letters of the strands testing matches
        i = 0
        while(otherIndex + i < len(otherStrand) and myIndex + i < len(myStrand)):
            c1 = otherStrand[otherIndex + i]
            c2 = myStrand[myIndex + i] 
            if (self.charMatch(c1, c2)== True):
                mat[myIndex + i] = True
            i+=1

        # iterates through the mat array inserting each modified character at its corresponding position in the matches string
        
        matches = ''
        for i in range(len(mat)):
            if (mat[i]==False):
                matches += (myStrand[i]).lower()
            else:
                matches += myStrand[i].upper()
        return matches
    
    def findMatchesWithLeftShift(self, shift):       
        myStrand = self.data2
        otherStrand = self.data1

        mat = [False]*len(myStrand)
        
        myIndex = 0
        otherIndex = shift

        # iterates through the letters of the strands testing matches
        i = 0
        while(otherIndex + i < len(otherStrand) and myIndex + i < len(myStrand)):
            c1 = otherStrand[otherIndex + i]
            c2 = myStrand[myIndex + i] 
            if (self.charMatch(c1, c2) == True):
                mat[myIndex + i] = True
            i+=1

        # iterates through the mat array inserting each modified character at its corresponding position in the matches string
        
        matches = ''
        for i in range(len(mat)):
            if (mat[i]==False):
                matches += (myStrand[i]).lower()
            else:
                matches += myStrand[i].upper()
        return matches
    
    def countMatchesWithRightShift(self, shift):       
        myStrand = self.data2
        otherStrand = self.data1

        count = 0
        
        myIndex = shift # right shift the other is equal to left shift myself
        otherIndex = 0

        # iterates through the letters of the strands testing matches
        i = 0
        while(otherIndex + i < len(otherStrand) and myIndex + i < len(myStrand)):
            c1 = otherStrand[otherIndex + i]
            c2 = myStrand[myIndex + i] 
            if (self.charMatch(c1, c2)== True):
                count += 1
            i+=1

        return count
    
    def countMatchesWithLeftShift(self, shift):       
        myStrand = self.data2
        otherStrand = self.data1

        count = 0
        
        myIndex = 0
        otherIndex = shift

        # iterates through the letters of the strands testing matches
        i = 0
        while(otherIndex + i < len(otherStrand) and myIndex + i < len(myStrand)):
            c1 = otherStrand[otherIndex + i]
            c2 = myStrand[myIndex + i] 
            if (self.charMatch(c1, c2) == True):
                count += 1
            i+=1

        return count

    def findMaxPossibleMatches(self, event):
        if(self.dnaMoving):
            countMax = -1
            posMax = -1

            limitShiftLeft = len(self.data1) - 1
            limitShiftRight = len(self.data2) - 1

            for shift in range(limitShiftLeft):
                matches = self.countMatchesWithLeftShift(shift)
                if (matches > countMax):
                    countMax = matches
                    posMax = shift

            for shift in range(limitShiftRight):
                matches = self.countMatchesWithRightShift(shift)
                if (matches> countMax):
                    countMax = matches
                    posMax = -shift
            
            self.reset()
            self.x += posMax*self.widthOfChar
            
        
    

    # tests matches and indicates them with uppercase letters
    def matches(self):
        self.canvas.pack()
        ini_x_strand2 = self.center['x'] + (len(self.data2) - len(self.data1))*self.widthOfChar/(2.0)
        x_strand2 = self.canvas.coords(self.strand2)[0]

        if(x_strand2 >= ini_x_strand2):
            shift = (int) (x_strand2 - ini_x_strand2) // self.widthOfChar
            self.canvas.itemconfig(self.strand2, text = self.findMatchesWithLeftShift(shift))
        else:
            shift = (int) (ini_x_strand2 - x_strand2) // self.widthOfChar
            self.canvas.itemconfig(self.strand2, text = self.findMatchesWithRightShift(shift))
    
    #shuffles letters of strand2
    def shuffle(self, event):
        if(self.dnaMoving):
            newData = list(self.data2)
            for i in range(0,len(newData) - 1):
                j = randint(i+1, len(newData)-1)
                newData[i], newData[j] = newData[j], newData[i]
            self.data2 = ''.join(newData)
            self.canvas.itemconfig(self.strand2, text = self.data2)
        
    #exits application
    def quit(self, event):
        self.canvas.destroy()
        exit()
Exemplo n.º 22
0
class Tree(Canvas):
    # do we have enough possible arguments?!?!?!
    def __init__(self,
                 master,
                 root_id,
                 root_label='',
                 get_contents_callback=None,
                 dist_x=15,
                 dist_y=15,
                 font=None,
                 text_offset=10,
                 line_flag=1,
                 expanded_icon=None,
                 collapsed_icon=None,
                 regular_icon=None,
                 plus_icon=None,
                 minus_icon=None,
                 node_class=Node,
                 drop_callback=None,
                 *args,
                 **kw_args):

        # pass args to superclass (new idiom from Python 2.2)
        Canvas.__init__(self, master, *args, **kw_args)

        #BNV Create the font and calc height
        self._active = None
        try:
            if font is None:
                self.font = Font(name="tree", exists=True)
            else:
                self.font = Font(name="tree", font=font, exists=True)
        except:
            if font is None: font = _DEFAULT_FONT
            try:
                self.font = Font(name="tree", font=font)
            except:
                self.font = font

        metrics = self.font.metrics()
        self.height = metrics["ascent"] + metrics["descent"]
        if dist_y < self.height: dist_y = self.height + 2

        # this allows to subclass Node and pass our class in
        self.node_class = node_class
        # keep track of node bindings
        self.bindings = {}
        # cheap mutex spinlock
        self.spinlock = 0
        # flag to see if there's been any d&d dragging
        self.drag = 0
        # default images (BASE64-encoded GIF files)
        if expanded_icon == None:
            self.expanded_icon=PhotoImage(
                data='R0lGODlhEAANAKIAAAAAAMDAwICAgP//////ADAwMAAAAAAA' \
                'ACH5BAEAAAEALAAAAAAQAA0AAAM6GCrM+jCIQamIbw6ybXNSx3GVB' \
                'YRiygnA534Eq5UlO8jUqLYsquuy0+SXap1CxBHr+HoBjoGndDpNAAA7')
        else:
            self.expanded_icon = expanded_icon
        if collapsed_icon == None:
            self.collapsed_icon=PhotoImage(
                data='R0lGODlhDwANAKIAAAAAAMDAwICAgP//////ADAwMAAAAAAA' \
                'ACH5BAEAAAEALAAAAAAPAA0AAAMyGCHM+lAMMoeAT9Jtm5NDKI4Wo' \
                'FXcJphhipanq7Kvu8b1dLc5tcuom2foAQQAyKRSmQAAOw==')
        else:
            self.collapsed_icon = collapsed_icon
        if regular_icon == None:
            self.regular_icon=PhotoImage(
                data='R0lGODlhCwAOAJEAAAAAAICAgP///8DAwCH5BAEAAAMALAAA' \
                'AAALAA4AAAIphA+jA+JuVgtUtMQePJlWCgSN9oSTV5lkKQpo2q5W+' \
                'wbzuJrIHgw1WgAAOw==')
        else:
            self.regular_icon = regular_icon
        if plus_icon == None:
            self.plus_icon=PhotoImage(
                data='R0lGODdhCQAJAPEAAAAAAH9/f////wAAACwAAAAACQAJAAAC' \
                'FIyPoiu2sJyCyoF7W3hxz850CFIA\nADs=')
        else:
            self.plus_icon = plus_icon
        if minus_icon == None:
            self.minus_icon=PhotoImage(
                data='R0lGODdhCQAJAPEAAAAAAH9/f////wAAACwAAAAACQAJAAAC' \
                'EYyPoivG614LAlg7ZZbxoR8UADs=')
        else:
            self.minus_icon = minus_icon
        # horizontal distance that subtrees are indented
        self.dist_x = dist_x
        # vertical distance between rows
        self.dist_y = dist_y
        # how far to offset text label
        self.text_offset = text_offset
        # flag controlling connecting line display
        self.line_flag = line_flag
        # called just before subtree expand/collapse
        self.get_contents_callback = get_contents_callback
        # called after drag'n'drop
        self.drop_callback = drop_callback
        # create root node to get the ball rolling
        self.root = node_class(parent_node=None,
                               label=root_label,
                               id=root_id,
                               expandable_flag=1,
                               collapsed_icon=self.collapsed_icon,
                               expanded_icon=self.expanded_icon,
                               x=dist_x,
                               y=dist_y,
                               parent_widget=self)
        # configure for scrollbar(s)
        x1, y1, x2, y2 = self.bbox('all')
        self.configure(scrollregion=(x1, y1, x2 + 5, y2 + 5))
        # add a cursor
        self.cursor_box = self.create_rectangle(0, 0, 0, 0)
        self.move_cursor(self.root)
        # make it easy to point to control
        #BNV
        #self.bind('<Enter>', self.PVT_mousefocus)
        self.bind('<Button-1>', self.PVT_mousefocus)
        # totally arbitrary yet hopefully intuitive default keybindings
        # stole 'em from ones used by microsoft tree control
        # page-up/page-down
        self.bind('<Next>', self.pagedown)
        self.bind('<Prior>', self.pageup)
        # arrow-up/arrow-down
        self.bind('<Down>', self.__next__)
        self.bind('<Up>', self.prev)
        # arrow-left/arrow-right
        self.bind('<Left>', self.ascendAndClose)
        # (hold this down and you expand the entire tree)
        self.bind('<Right>', self.descend)
        # home/end
        self.bind('<Home>', self.first)
        self.bind('<End>', self.last)
        # space bar
        self.bind('<Key-space>', self.toggle)
        self.bind('<Return>', self.select)
        # mouse wheel
        self.bind('<Button-4>', self.lineUp)
        self.bind('<Button-5>', self.lineDown)
        # middle button
        self.bind('<B2-Motion>', self.scanDrag)
        self.bind('<ButtonRelease-2>', self.scanRelease)
        self.scandrag = False

    # ----- PRIVATE METHODS (prefixed with "PVT_") -----
    # these methods are subject to change, so please try not to use them
    def PVT_mousefocus(self, event):
        """Soak up event argument when moused-over"""
        self.focus_set()

    # ----- PUBLIC METHODS -----
    def tag_bind(self, tag, seq, *args, **kw_args):
        """Keep track of callback bindings so we can delete them later. I
        shouldn't have to do this!!!!"""
        # pass args to superclass
        func_id = Canvas.tag_bind(self, tag, seq, *args, **kw_args)
        # save references
        self.bindings[tag] = self.bindings.get(tag, []) + [(seq, func_id)]

    def add_list(self,
                 list=None,
                 name=None,
                 id=None,
                 flag=0,
                 expanded_icon=None,
                 collapsed_icon=None):
        """Add node construction info to list"""
        n = Struct()
        n.name = name
        n.id = id
        n.flag = flag
        if collapsed_icon:
            n.collapsed_icon = collapsed_icon
        else:
            if flag:
                # it's expandable, use closed folder icon
                n.collapsed_icon = self.collapsed_icon
            else:
                # it's not expandable, use regular file icon
                n.collapsed_icon = self.regular_icon
        if flag:
            if expanded_icon:
                n.expanded_icon = expanded_icon
            else:
                n.expanded_icon = self.expanded_icon
        else:
            # not expandable, don't need an icon
            n.expanded_icon = None
        if list == None:
            list = []
        list.append(n)
        return list

    def add_node(self,
                 name=None,
                 id=None,
                 flag=0,
                 expanded_icon=None,
                 collapsed_icon=None):
        """Add a node during get_contents_callback()"""
        self.add_list(self.new_nodes, name, id, flag, expanded_icon,
                      collapsed_icon)

    def find_full_id(self, search):
        """Search for a node"""
        return self.root.PVT_find(search)

    # BNV
    def find_full_id_expand(self, search):
        node = self.root

        prev = None
        for id in search:
            node.expand()
            if isinstance(id, int):
                node = node.child_nodes[id]
            else:
                if prev is None:
                    pid = [id]
                else:
                    pid = [prev, id]
                node = node.PVT_find(pid)
                if node is None: break
            prev = id
        return node

    def cursor_node(self):
        """Return node under cursor"""
        return self.pos

    def see(self, *items):
        """Scroll (in a series of nudges) so items are visible"""
        x1, y1, x2, y2 = self.bbox(*items)
        while x2 > self.canvasx(0) + self.winfo_width():
            old = self.canvasx(0)
            self.xview('scroll', 1, 'units')
            # avoid endless loop if we can't scroll
            if old == self.canvasx(0):
                break
        while y2 > self.canvasy(0) + self.winfo_height():
            old = self.canvasy(0)
            self.yview('scroll', 1, 'units')
            if old == self.canvasy(0):
                break
        # done in this order to ensure upper-left of object is visible
        while x1 < self.canvasx(0):
            old = self.canvasx(0)
            self.xview('scroll', -1, 'units')
            if old == self.canvasx(0):
                break
        while y1 < self.canvasy(0):
            old = self.canvasy(0)
            self.yview('scroll', -1, 'units')
            if old == self.canvasy(0):
                break

    def move_cursor(self, node):
        """Move cursor to node"""
        self.pos = node
        x1, y1, x2, y2 = self.bbox(node.symbol, node.label)
        self.coords(self.cursor_box, x1 - 1, y1 - 1, x2 + 1, y2 + 1)
        self.see(node.symbol, node.label)

    def toggle(self, event=None):
        """Expand/collapse subtree"""
        self.pos.toggle_state()

    # BNV override routine for selection
    def select(self, event=None):
        """Select node"""
        self.pos.select()

    def next(self, event=None):
        """Move to next lower visible node"""
        self.move_cursor(self.pos.next_visible())

    def prev(self, event=None):
        """Move to next higher visible node"""
        self.move_cursor(self.pos.prev_visible())

    def ascend(self, event=None):
        """Move to immediate parent"""
        if self.pos.parent_node:
            # move to parent
            self.move_cursor(self.pos.parent_node)

    # BNV
    def ascendAndClose(self, event=None):
        """Close present if open and then move to immediate parent"""
        if self.pos.expandable_flag and self.pos.expanded_flag:
            self.pos.toggle_state()
        elif self.pos.parent_node:
            # move to parent
            self.move_cursor(self.pos.parent_node)

    def descend(self, event=None):
        """Move right, expanding as we go"""
        if self.pos.expandable_flag:
            self.pos.expand()
            if self.pos.child_nodes:
                # move to first subnode
                self.move_cursor(self.pos.child_nodes[0])
                return
        # if no subnodes, move to next sibling
        next(self)

    def first(self, event=None):
        """Go to root node"""
        # move to root node
        self.move_cursor(self.root)

    def last(self, event=None):
        """Go to last visible node"""
        # move to bottom-most node
        self.move_cursor(self.root.PVT_last())

    def pageup(self, event=None):
        """Previous page"""
        n = self.pos
        j = self.winfo_height() / self.dist_y
        for i in range(j - 3):
            n = n.prev_visible()
        self.yview('scroll', -1, 'pages')
        self.move_cursor(n)

    def pagedown(self, event=None):
        """Next page"""
        n = self.pos
        j = self.winfo_height() / self.dist_y
        for i in range(j - 3):
            n = n.next_visible()
        self.yview('scroll', 1, 'pages')
        self.move_cursor(n)

    # BNV
    def refresh(self):
        full_id = self.pos.full_id()
        self.root.refresh()
        node = self.find_full_id(full_id)
        if node is not None:
            self.move_cursor(node)
            Node.select(node)

    # BNV
    def lineUp(self, event=None):
        """Previous line"""
        self.yview('scroll', -1, 'units')

    # BNV
    def lineDown(self, event=None):
        """Next line"""
        self.yview('scroll', 1, 'units')

    # BNV
    def scanDrag(self, event):
        if self.scandrag:
            self.scan_dragto(event.x, event.y, 3)
        else:
            self.config(cursor="hand2")
            self.scan_mark(event.x, event.y)
            self.scandrag = True

    # BNV
    def scanRelease(self, event):
        self.scandrag = False
        self.config(cursor="")

    # ----- functions for drag'n'drop support -----
    def where(self, event):
        """Determine drag location in canvas coordinates. event.x & event.y
        don't seem to be what we want."""
        # where the corner of the canvas is relative to the screen:
        x_org = self.winfo_rootx()
        y_org = self.winfo_rooty()
        # where the pointer is relative to the canvas widget,
        # including scrolling
        x = self.canvasx(event.x_root - x_org)
        y = self.canvasy(event.y_root - y_org)
        return x, y

    def dnd_accept(self, source, event):
        """Accept dnd messages, i.e. we're a legit drop target, and we do
        implement d&d functions."""
        if not isinstance(source, Tree): return None
        self.target = None
        return self

    def dnd_enter(self, source, event):
        """Get ready to drag or drag has entered widget (create drag
        object)"""
        # this flag lets us know there's been drag motion
        self.drag = 1
        x, y = self.where(event)
        x1, y1, x2, y2 = source.widget.bbox(source.symbol, source.label)
        dx, dy = x2 - x1, y2 - y1
        # create dragging icon
        if source.expanded_flag:
            self.dnd_symbol = self.create_image(x,
                                                y,
                                                image=source.expanded_icon)
        else:
            self.dnd_symbol = self.create_image(x,
                                                y,
                                                image=source.collapsed_icon)
        self.dnd_label = self.create_text(x + self.text_offset,
                                          y,
                                          text=source.get_label(),
                                          justify='left',
                                          anchor='w')

    def dnd_motion(self, source, event):
        """Move drag icon"""
        self.drag = 1
        x, y = self.where(event)
        x1, y1, x2, y2 = self.bbox(self.dnd_symbol, self.dnd_label)
        self.move(self.dnd_symbol, x - x1 + source.x_off,
                  y - y1 + source.y_off)
        self.move(self.dnd_label, x - x1 + source.x_off, y - y1 + source.y_off)

    def dnd_leave(self, source, event):
        """Finish dragging or drag has left widget (destroy drag object)"""
        self.delete(self.dnd_symbol)
        self.delete(self.dnd_label)

    def dnd_commit(self, source, event):
        """Object has been dropped here"""
        # call our own dnd_leave() to clean up
        self.dnd_leave(source, event)
        # process pending events to detect target node
        # update_idletasks() doesn't do the trick if source & target are
        # on  different widgets
        self.update()
        if not self.target:
            # no target node
            return
        # we must update data structures based on the drop
        if self.drop_callback:
            try:
                # called with dragged node and target node
                # this is where a file manager would move the actual file
                # it must also move the nodes around as it wishes
                self.drop_callback(source, self.target)
            except:
                report_callback_exception()