#!/usr/bin/env python22

#
# gui design study: starmap with internal or external dialogs
#                   for planet/starship data
#

from Tkinter import *
from random import randint

class Star:
    def __init__( self, x, y, id, name=None ):
        self.x  = x
        self.y  = y
        self.id   = id
        self.nameTemplates = ['cvcvc', 'cvcc','vcvc']
        self.consonants='bcdfghjklmnpqrstvwxyz'
        self.vocals = 'aeiou'
        if name == None:
            self.name = self.createName()
        else:
            self.name = name

    def getXY(self):
        return (self.x, self.y)

    def createName(self):  # code for fun and glory :-)
        name = ""
        r = randint(0,len(self.nameTemplates)-1)
        template = self.nameTemplates[ r ]
        for char in template:
            if char == 'c':
                s = randint(0,len(self.consonants)-1)
                name = name + self.consonants[s]
            else:
                s = randint(0,len(self.vocals)-1)
                name = name + self.vocals[s]
        return name.capitalize()

# eof class star


class StarObjects:
    def __init__(self):
        self.stars = []

    def append(self,star):
        self.stars.append(star)

    def __iter__(self):
        return iter(self.stars)

# eof class StarObjects

class TestDialog:
    def __init__(self, canvas, planetID, planetName, x, y):
        self.canvas  = canvas
        self.planetID   = planetID
        self.planetName = planetName
        lineHeight = 10  # the height of a text line in the dialog
        w = 80
        h = 9 * lineHeight
        self.objects = []  # stores the IDs of the canvas objects building this dialog

        # tow line -- a line from the mini dialog to the dialogs star:
        self.towline = self.canvas.create_line(x, y, x+(w/2), y+(h/2), fill="red")

        id = self.canvas.create_rectangle( x, y, x+w, y+h, width=1,outline="black", fill="orange" )
        self.objects.append( id )  # base rectangle

        id = self.canvas.create_rectangle( x, y, x+w, y+lineHeight, width=1,outline="black", fill="lightblue", tags="sdlg" )
        self.objects.append( id )  # title bar

        id = self.canvas.create_text( x+(w/2), y+(lineHeight/2), font=("Helvetica", 10), text=planetName, fill="black")
        self.objects.append( id )  # title

        # close-button:
        id = self.canvas.create_rectangle( x+2, y+2, x+lineHeight-2, y+lineHeight-2, width=1,outline="black", fill="black", tags="DlgClose" )
        self.objects.append( id )  # close button

        id = self.canvas.create_text( x+22, y+15, font=("Helvetica", 10), text="N: 230kt", fill="black")
        self.objects.append( id )  # title
        id = self.canvas.create_text( x+22, y+25, font=("Helvetica", 10), text="T: 142kt", fill="black")
        self.objects.append( id )  # title
        id = self.canvas.create_text( x+22, y+35, font=("Helvetica", 10), text="D: 123kt", fill="black")
        self.objects.append( id )  # title
        id = self.canvas.create_text( x+22, y+45, font=("Helvetica", 10), text="M:  23kt", fill="black")
        self.objects.append( id )  # title

    def moveRel( self, dx, dy ):
        for ele in self.objects:
            self.canvas.move( ele, dx, dy )
        coords = self.canvas.coords( self.towline )
        self.canvas.coords( self.towline, coords[0], coords[1], coords[2]+dx, coords[3]+dy )

    def close( self ):
        for ele in self.objects:
            self.canvas.delete( ele )
        self.canvas.delete( self.towline )

    def hasElementID( self, id ):
        for ele in self.objects:
          if ele == id:
              return 1
        return 0

# class TestDialog


# ---------------------------------------------------
class TestDialogContainer:
    def __init__(self):
        self.dialogs = []

    def deleteByButtonID( self, recID ):
        for dlg in self.dialogs:
            if dlg.hasElementID( recID ):
                print "deleting dialog..."
                dlg.close()
                return (1==1)
        return (1==2)

    def deleteAll( self ):
        for dlg in self.dialogs:
            dlg.close()

    def append( self, ele ):
        self.dialogs.append( ele )

    def moveDlgRelByID( self, id, dx, dy ):
      for dlg in self.dialogs:
        if dlg.hasElementID( id ):
          dlg.moveRel( dx, dy )
          return 1
      return 0

# container
# --------------------------------------------------

class Gui:
    def __init__(self):
        self.frame = Tk()
        self.frame.title('starmap design study 2')
        self.status = StringVar()
        self.miniDialogs = TestDialogContainer()

        self.dlg_moved = 0
        self.dlg_id  = 0
        self.dlg_old_x   = 0
        self.dlg_old_y   = 0
        self.dlg_new_x   = 0
        self.dlg_new_y   = 0

        statusBar = Label(self.frame, textvariable=self.status, bd=1, relief=SUNKEN, anchor=W)
        statusBar.pack(side=BOTTOM, fill=X)
        menubar = Menu(self.frame)
        filemenu = Menu(menubar)
        filemenu.add_separator()
        filemenu.add_command(label="Quit", command=self.quit)
        menubar.add_cascade(label="File", menu=filemenu)
        self.frame.config( menu=menubar )
        self.frame.bind("<Control-x>", self.quit)
        # adding a drawing area:
        self.canvas = Canvas( self.frame, width=450, height=350, bg="black" )
        self.canvas.pack( side=TOP )
        # generating some test data:
        self.starObjects = StarObjects()
        for i in range(15):
            x,y = randint(1,450), randint(1,350)
            star = Star( x, y, randint(1,100) )
            self.starObjects.append( star )
        # stores for storing the assignment of starIDs and ovals:
        self.oval2star = dict()
        # paint:
        self.canvas.create_line(1, 45,450, 45,fill="white")
        self.canvas.create_line(1,245,450,245,fill="white")
        self.canvas.create_line( 90, 1, 90,350,fill="white")
        self.canvas.create_line(290, 1,290,350,fill="white")
        self.paint()
        # click event:
        self.canvas.tag_bind ("DnD"     , "<ButtonPress-1>", self.click1)
        self.canvas.tag_bind ("sdlg"    , "<ButtonPress-1>", self.star_dlg_click)
        self.canvas.tag_bind ("sdlg"    , "<ButtonRelease-1>", self.star_dlg_unclick)
        self.canvas.tag_bind ("DlgClose", "<ButtonPress-1>", self.dlgClose)

    def paint(self):
        rStar = 4
        for star in self.starObjects:
            x,y  = star.getXY()
            name = star.name
            ovalID = self.canvas.create_oval( x-(2*rStar),y-(2*rStar),x,y,width=1,outline="black", fill="green", tags="DnD" )
            self.oval2star[ovalID] = star
            self.canvas.create_text (x, y+10, font =("Helvetica", 10), text=name, fill="green")


    def star_dlg_click(self, event):
        dlg_id, = self.canvas.find_withtag( CURRENT )
        # print "star_dlg_click ",event.x,event.y        
        self.dlg_id    = dlg_id
        self.dlg_old_x = event.x
        self.dlg_old_y = event.y
        event.widget.bind( "<Motion>", self.star_dlg_motion )

    def star_dlg_motion( self, event ):
        self.dlg_new_x = event.x
        self.dlg_new_y = event.y
        dx = self.dlg_new_x - self.dlg_old_x
        dy = self.dlg_new_y - self.dlg_old_y
        self.dlg_old_x = self.dlg_new_x
        self.dlg_old_y = self.dlg_new_y
        self.miniDialogs.moveDlgRelByID( self.dlg_id, dx, dy )
        self.dlg_moved = 1

    def star_dlg_unclick( self, event ):
       event.widget.unbind( "<Motion>" )
       #if self.dlg_moved:
       #   dx = self.dlg_new_x - self.dlg_old_x
       #   dy = self.dlg_new_y - self.dlg_old_y
       #   self.miniDialogs.moveDlgRelByID( self.dlg_id, dx, dy )
       self.dlg_moved = 0

    def click1(self, event):
        oval_id, = self.canvas.find_withtag( CURRENT )
        star = self.oval2star[ oval_id ]
        self.setStatusBar( "Star: " + star.name + " (" + str(star.id) + ")" )
        dlg = TestDialog( self.canvas, star.id, star.name, event.x, event.y )
        self.miniDialogs.append( dlg )

    def dlgClose( self, event ):
        current, = self.canvas.find_withtag( CURRENT )
        print "clicked on dlgClose ", current
        self.miniDialogs.deleteByButtonID( current )

    def quit( self, event=None ):
        self.frame.quit()

    def setStatusBar( self, title ):
        self.status.set(title)

    def mainloop( self ):
        self.setStatusBar("OK.")
        self.frame.mainloop()


if __name__ == "__main__":
    gui = Gui()
    gui.mainloop()
