commit 01f099754e133bbee3cf40762d55c0db11fca2e4
Author: Yuyang Guo <yuyang@yuyang-VirtualBox.(none)>
Date:   Tue Feb 12 16:29:28 2013 -0500

    Partially done GUI rewriting GUI
    now can only add and kill scouts freely but can do nothing else

diff --git a/scout/scoutsim/GUI.py b/scout/scoutsim/GUI.py
new file mode 100755
index 0000000..8caeb9d
--- /dev/null
+++ b/scout/scoutsim/GUI.py
@@ -0,0 +1,311 @@
+#!/usr/bin/python
+
+# Behavior GUI
+
+# shell subprocess libs
+import subprocess
+import shlex  #for converting string commands to tokens
+
+# GUI libs
+import wx
+import wx.lib.intctrl
+import wx.lib.agw.floatspin
+
+# not sure why these 2 are here
+import string
+import signal
+
+# ros imports for spawning and killing scout
+import rospy
+import roslib
+roslib.load_manifest("scoutsim")
+
+# scoutsim imports
+from scoutsim.srv import *
+
+from collections import defaultdict
+
+# each scout is represented by this class
+class Scout(object):
+    numOfScouts = 0 # class variable keeping track of scouts
+    
+    def __init__(self, x=0, y=0, theta=0, name=u"",
+                       Scouts=None, oninit = False):
+        print (len(name))
+        Scout.numOfScouts += 1 # reverted if not successful
+        if len(name) == 0:
+            # automatically give name according to numOfScouts
+            name = self.autoNameGen(Scouts)
+        # set vars
+        self.name = name
+        self.behavior = "chilling"
+        self.process =  None# used to keep track of all processes
+                        # related to this scout  
+        self.valid = False
+        # these vars are right now just the original position
+        # but when ODOMETRY is done, we could actually use them
+        self.x, self.y = x, y 
+        self.theta = theta
+        
+        # spawn the scout if it is not scout1 (automatically spawned)
+        if (not oninit): 
+            if (self.SpawnInSimulator()):
+                # spawned correctly
+                self.valid = True
+            else:
+                Scout.numOfScouts -= 1;
+        
+
+    def autoNameGen(self, Scouts):
+        i = 1
+        while (True):
+            if not (("scout%d"%i) in Scouts):
+                return "scout%d"%i
+            i+=1
+
+
+        # update the classvariable
+        
+
+    def SpawnInSimulator(self):
+        print "trying to spawn scout!!!"
+        try:
+            # ros spawn routine
+            rospy.wait_for_service('/spawn');
+            service = rospy.ServiceProxy('/spawn', Spawn);
+            response = service(self.x, self.y, self.theta, self.name)
+            return True
+        except rospy.ServiceException as Error:
+            print "things are bad!!!"
+            print Error
+            return False
+    
+    def changeBehavior(self, behavior):
+        self.behavior = behavior
+
+        # WARNING: Check this but ROS kills the old behavior for us
+            # kill the old behavior
+#        if self.process != None:
+#            self.process.terminate() #TODO: this kills the process
+#                                     #      but maybe not the rosnode
+#                                     #      change to "rosnode kill" instead
+#        # make sure the old behavior is terminated before we run the new one
+#        self.process.wait()
+        
+        # do rosprocess calls for new behavior
+        roscommand = shlex.split("rosrun libscout libscout %s %s"%
+                                            (self.name, self.behavior))
+        subprocess.Popen(roscommand, shell=False)
+
+    def killSelf(self):
+        # terminate its current behavior
+        if self.process != None:
+            self.process.terminate() # TODO: same here, try "rosnode kill"
+            self.process.wait()
+        # ros call to kill scout in simulator
+        try:
+            rospy.wait_for_service("/kill")
+            service = rospy.ServiceProxy("/kill", Kill)
+            response = service(self.name)
+            Scout.numOfScouts -= 1
+            self.valid = False
+        except rospy.ServiceException, e:
+            print "warning: kill scout unsuccessful" # TODO: change to alert
+            self.valid = True
+        # remove from the class
+
+
+# a wrapper for wx Frame
+class Window(wx.App):
+    def __init__(self, title=""):
+        super(Window, self).__init__()
+        self.initUIFrame()
+
+    def initUIFrame(self):
+        self.GUIFrame = GUI(None, "hallo!")
+
+
+# actual GUI frame
+class GUI(wx.Frame):
+    def __init__(self, parent, title):
+        super(GUI, self).__init__(parent, title=title,
+            style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER, size=(600, 600))
+        
+        # open up scoutsim race
+        command = shlex.split("rosrun scoutsim scoutsim_node race")
+        self.simWindowProcess = subprocess.Popen(command, shell=False)
+        #rospy.wait_for_service('/spawn') #don't know why this is here
+        
+        # register call back for on close cleanup
+        self.Bind(wx.EVT_CLOSE, self.onClose) 
+
+
+        self.initData()
+        self.initUI()
+        self.Show(True)     
+    
+    # do clean up after user close the window
+    def onClose(self, event):
+        print "Cleaning up all Processes"
+        
+        # kill all the behavior processes
+        for scout in self.scouts:
+            process = self.scouts[scout].process
+            if (process != None):
+                process.terminate()
+
+        # kill the scout sim window
+        self.simWindowProcess.terminate()
+        print "done"
+        self.Destroy()
+
+    def initData(self):
+        self.scouts = {}
+        self.scouts["scout1"] = Scout(x=0, y=0, theta=0, name="scout1",
+                                      Scouts = self.scouts, oninit=True)
+        #TODO: these arguments are not right...fix them!!!
+
+    # addButton callback
+    def addScout(self, x_wx, y_wx, theta_wx, name_wx):
+        # x, y, theta, name are given as wx Inputs
+        x = x_wx.GetValue()
+        y = y_wx.GetValue()
+        theta = theta_wx.GetValue()
+        name = name_wx.GetValue()
+        print "in GUI trying to add scout!"
+        newSc = Scout(x, y, theta, name, self.scouts)
+        if (newSc.valid):
+            # successful
+            self.scouts[newSc.name] = newSc
+            self.addScoutBox(newSc.name)
+            # alert user spawn successful
+            wx.MessageBox(u"Scout '%s' created successfully at (%d,%d,%d\u00B0)"
+                            %(newSc.name, newSc.x, newSc.y, newSc.theta), 
+                            "Scout Created", wx.OK | wx.ICON_INFORMATION)
+
+        else:
+            #failed to create scout
+            wx.MessageBox("Scout Creation failed :( Check for duplicate name",
+                            "Add Scout failed", wx.OK | wx.ICON_ERROR)
+
+    def removeScout(self, name):
+        sct = self.scouts[name]
+        print "removing scout %s"%name
+        sct.killSelf()
+        if (sct.valid == False):
+            # successful, remove from the dictionary
+            del self.scouts[name]
+            # refresh the display
+            print self.mainArea.Hide(self.sizer[name])
+            print self.mainArea.Remove(self.sizer[name])
+            del self.sizer[name]
+            self.window.Layout()
+            self.window.Refresh()
+            self.window.Update()
+        else:
+            raise Exception
+
+    ############################ UI stuff here ###########################
+    
+    def initUI(self):
+        self.initAddScoutArea()
+
+    # the labels and input boxes for adding a scout through GUI
+    def initAddScoutArea(self):
+        # all the layout stuff copied over: using grid layout
+        # button callbacks are changed
+        self.totalCols = 8
+        self.window = wx.ScrolledWindow(self, style=wx.VSCROLL)
+        self.mainArea = wx.GridSizer(cols=1)
+        sizer = wx.FlexGridSizer(rows=4, cols=self.totalCols, hgap=5, vgap=5)
+
+        # Labels
+        blankText = wx.StaticText(self.window, label="")
+        newScout = wx.StaticText(self.window, label="New Scout")
+        newScoutName = wx.StaticText(self.window, label="Name:")
+        startXTitle = wx.StaticText(self.window, label="X:")
+        startYTitle = wx.StaticText(self.window, label="Y:")
+        startThetaTitle = wx.StaticText(self.window, label="Rad:")
+
+        # Inputs
+        newScoutInput = wx.TextCtrl(self.window)
+        startX = wx.lib.agw.floatspin.FloatSpin(self.window, min_val=0, digits=5)
+        startY = wx.lib.agw.floatspin.FloatSpin(self.window, min_val=0, digits=5)
+        startTheta = wx.lib.agw.floatspin.FloatSpin(self.window, min_val=0, digits=5)
+        addButton = wx.Button(self.window, id=wx.ID_ADD)
+
+        # Pretty Stuff
+        hLine = wx.StaticLine(self.window, size=(600, 5))
+        bottomHLine = wx.StaticLine(self.window, size=(600, 5))
+        
+        # Row 0: just the label add scout
+        sizer.Add(newScout)
+        for i in range(7):
+            sizer.AddStretchSpacer(1)
+        # Row 1: input(name), x coord, y coord, rad, 
+        sizer.AddMany([newScoutName, (newScoutInput, 0, wx.EXPAND), startXTitle,
+            startX, startYTitle, startY, startThetaTitle, startTheta])
+        # Row 2: just the add button to the right
+        for i in range(7):
+            sizer.AddStretchSpacer(1)
+        sizer.Add(addButton)
+        # Row 3
+        
+        # Events
+        addButton.Bind(wx.EVT_BUTTON, lambda event: self.addScout(
+            startX, startY, startTheta, newScoutInput))
+
+        sizer.AddGrowableCol(idx=1)
+        self.mainArea.Add(sizer, proportion=1, flag=wx.ALL|wx.EXPAND, border=10)
+        self.window.SetSizer(self.mainArea)
+        self.sizer = defaultdict()
+        self.window.Layout()
+        
+        # make the scout1's controller
+        self.addScoutBox("scout1");
+        
+    # copied over from old GUI
+    def addScoutBox(self, name):
+        self.sizer[name] = wx.FlexGridSizer(rows=2, cols=5, hgap=5, vgap=5)
+        # Labels
+        scoutName = wx.StaticText(self.window, label="Scout: " + name)
+        behaviorLabel = wx.StaticText(self.window, label="Behavior: ")
+        currBehaviorLabel = wx.StaticText(self.window,
+            label="  |  Current Behavior: Slacking off")
+
+        # Inputs
+        # drop down menue
+        scoutChoices = wx.Choice(self.window) #choices=GetBehaviors())
+        #   buttons
+        pauseButton = wx.ToggleButton(self.window, label="Pause")
+        runButton = wx.Button(self.window, label="Run")
+        killButton = wx.Button(self.window, label="Kill")
+        teleopButton = wx.ToggleButton(self.window, label="Teleop")
+
+        # row 0
+        self.sizer[name].Add(scoutName)
+        self.sizer[name].Add(currBehaviorLabel, wx.EXPAND | wx.ALIGN_RIGHT)
+        self.sizer[name].AddStretchSpacer(1)
+        self.sizer[name].AddStretchSpacer(1)
+        self.sizer[name].Add(killButton, wx.ALIGN_RIGHT)
+
+        # row 1
+        self.sizer[name].Add(behaviorLabel)
+        self.sizer[name].Add(scoutChoices, wx.EXPAND)
+        self.sizer[name].Add(runButton)
+        self.sizer[name].Add(pauseButton, wx.ALIGN_RIGHT)
+        self.sizer[name].Add(teleopButton) 
+        # Events
+        killButton.Bind(wx.EVT_BUTTON, lambda event: self.removeScout(name))
+
+        self.mainArea.Add(self.sizer[name], proportion=1,
+            flag=wx.ALL | wx.EXPAND, border=10)
+        self.window.Layout()
+        return True
+
+
+
+if __name__ == '__main__':
+    # open up GUI
+    window = Window(title="Colony Scout Manager")
+    window.MainLoop()
