# L-41 MCS 260 Fri 22 Apr 2016 : cantor.py

"""
The Cantor set is defined by taking out recursively
the middle of a line segment.
"""

from tkinter import Tk, Canvas, ALL
from tkinter import Button, IntVar, Scale

class CantorSet(object):
    """
    GUI to draw a Cantor set on canvas.
    """
    def __init__(self, wdw, N):
        """
        A Cantor set with N levels.
        """
        wdw.title('a cantor set')
        self.dim = 3**N+20
        self.n = IntVar()
        self.scl = Scale(wdw, orient='horizontal', \
            from_=0, to=N, tickinterval=1, \
            length=self.dim, variable=self.n, \
            command=self.draw_set)
        self.scl.grid(row=0, column=0)
        self.scl.set(0)
        self.cnv = Canvas(wdw, width=self.dim, \
            height=self.dim//3, bg='white')
        self.cnv.grid(row=1, column=0)
        self.btt = Button(wdw, text="clear canvas", \
            command=self.clear_canvas)
        self.btt.grid(row=2, column=0)

    def cantor(self, lft, rgt, hgt, txt, lvl):
        """
        Draws a line from lft to rgt, at height hgt
        txt is a string, int(txt) equals the number
        of times the middle third must be removed
        lvl is level of recursion, start at lvl = int(txt).
        """
        if lvl == 0:           # draw line segment
            self.cnv.create_line(lft, hgt, rgt, hgt, width=2)
        else:
            nlf = (2*lft+rgt)//3
            nrg = (lft+2*rgt)//3
            self.cantor(lft, nlf, hgt+30, txt, lvl-1)
            self.cantor(nrg, rgt, hgt+30, txt, lvl-1)
        if lvl == int(txt):      # put text string
            xctr = self.dim//2
            if txt == '0':
                self.cnv.create_text(xctr, hgt-10, text=txt)
            else:
                self.cnv.create_text(xctr, hgt+lvl*30, text=txt)

    def draw_set(self, val):
        """
        Draws a Cantor set.
        """
        nbr = int(val)
        self.cantor(10, self.dim-10, 30, val, nbr)

    def clear_canvas(self):
        """
        Clears the entire canvas.
        """
        self.cnv.delete(ALL)

def main():
    """
    Instantiates the GUI object
    and launches the main event loop.
    """
    top = Tk()
    CantorSet(top, 6)
    top.mainloop()

if __name__ == "__main__":
    main()
