# Copyright 2009 Autodesk, Inc.  All rights reserved.
# Use of this software is subject to the terms of the Autodesk license agreement 
# provided at the time of installation or download, or which otherwise accompanies
# this software in either electronic or hard copy form.
#
# Script description:
# Allow edition of MoBu ActionScript.txt that maps a Python action to a script. To change
# the shortcut that is mapped to an action use the KeyboardMapper.py script (or edit
# a keyboard file).
#
# Topic: FBConfigFile, FBSpread, FBConfigFile
# 

from pyfbsdk import *
from pyfbsdk_additions import *

import os
import os.path
import mbutils

TOOL_NAME = "Action Script Manager"
ACTION_SCRIPT_PATH = os.path.join(mbutils.GetConfigPath(), "Scripts")
ACTION_SCRIPT_FILE = os.path.join(ACTION_SCRIPT_PATH, "ActionScript.txt")

class ActionScriptMgr(FBTool):
    def RowClicked(self,control,event):
        # Populate path edit box
        if self.path_spread.GetRow(event.Row).RowSelected:
            self.current_row = event.Row
        else:
            self.current_row = -1
        path = self.path_spread.GetCellValue(event.Row, 0)

        # Do not update the path edit if the selected row has no path. It makes
        # path manipulation easier 
        if path:
            self.path_edit.Text = path

    def Browse(self,control,event):
        filepopup = pyfbsdk.FBFilePopup()
        filepopup.Caption = "Select a script"
        filepopup.Style = pyfbsdk.FBFilePopupStyle.kFBFilePopupOpen
        filepopup.Filter = "*.py"
        result = filepopup.Execute()
        if result:
            self.path_edit.Text = os.path.join(filepopup.Path,filepopup.FileName)
        del filepopup

    def Add(self,control,event):
        if self.current_row == -1:
            return
        self.path_spread.SetCellValue(self.current_row,0,self.path_edit.Text)
        self.UpdateScript(self.current_row)

    def Remove(self,control,event):
        # Unbind the selected row's path
        if self.current_row == -1:
            return
        self.path_spread.SetCellValue(self.current_row,0,"")
        self.UpdateScript(self.current_row)

    def UpdateScript(self,row):
        config = FBConfigFile("ActionScript.txt",ACTION_SCRIPT_PATH)

        spread_row = self.path_spread.GetRow(row)
        key = spread_row.Caption
        value = self.path_spread.GetCellValue(row,0)
        if value:
            # Convert it to relative path as it is more portable if
            # the script is inside MotionBuilder tree
            value = os.path.relpath(value,ACTION_SCRIPT_PATH)
        config.Set("ScriptFiles",key,value)

    def CellChanged(self,control,event):
        # User has edited a path by modifying the cell himself: update the relevant binding
        self.UpdateScript(event.Row)

    def Populate(self):
        # All relative paths inside ActionScript.txt are relative to ActionScrip.txt path
        # so set the current working dir as ACTION_SCRIPT_PATH
        old_cwd = os.getcwd()
        os.chdir(ACTION_SCRIPT_PATH)

        self.current_row = -1
        self.nb_row = 0
        config = FBConfigFile("ActionScript.txt",ACTION_SCRIPT_PATH)
        for i in range(12):
            key = "Script%d" % (i + 1)
            value = config.Get("ScriptFiles",key)
            self.path_spread.RowAdd(key,self.nb_row)
            if value:
                self.path_spread.SetCellValue(self.nb_row,0,os.path.abspath(value))
            self.nb_row += 1
        os.chdir(old_cwd)

    def __init__(self):
         # init base class
        FBTool.__init__(self,TOOL_NAME)

        AddTool(self)

        x = FBAddRegionParam(0,FBAttachType.kFBAttachLeft,"")
        y = FBAddRegionParam(0,FBAttachType.kFBAttachTop,"")
        w = FBAddRegionParam(0,FBAttachType.kFBAttachRight,"")
        h = FBAddRegionParam(0,FBAttachType.kFBAttachBottom,"")
        self.AddRegion("main","main", x, y, w, h)

        vbox = VBoxLayout()
        self.SetControl("main",vbox)

        widget_height = 30
        button_width = 60

        l = FBLabel()
        l.Caption = "Action Scripts"
        vbox.Add(l, widget_height)

        self.path_spread = FBSpread()
        self.path_spread.Caption = "Actions"
        self.path_spread.ColumnAdd("Path")
        self.path_spread.GetColumn(0).Width = 550
        self.path_spread.OnRowClick.Add(self.RowClicked)
        self.path_spread.OnCellChange.Add(self.CellChanged)
        vbox.AddRelative(self.path_spread,1.0)

        hbox = HBoxLayout()

        self.path_edit = FBEdit()
        hbox.AddRelative(self.path_edit,1.0)

        b = FBButton()
        b.Caption = "Browse..."
        b.OnClick.Add(self.Browse)
        hbox.Add(b, button_width)

        vbox.Add(hbox,widget_height)

        hbox = HBoxLayout()
        b = FBButton()
        b.Caption = "Set"
        b.OnClick.Add(self.Add)
        hbox.Add(b, button_width)

        b = FBButton()
        b.Caption = "Remove"
        b.OnClick.Add(self.Remove)
        hbox.Add(b, button_width)

        # Notify user that motionbuiler reads the ActionScript.txt file on startup only.
        l = FBLabel()
        l.Caption = "You will need to restart MotionBuilder for changes to takes place!"
        l.Style = FBTextStyle.kFBTextStyleBold
        hbox.Add(l, 400)

        vbox.Add(hbox,widget_height)

        self.StartSizeX = 800
        self.StartSizeY = 425

        # Populate Datas
        self.Populate()

# This call is only useful in  Development to ensure a recreation of the tool each time   
#DestroyToolByName(TOOL_NAME)

# this snippet of code ensure our tool will only be created once,
# even if this script is "imported" from other scripts.
if TOOL_NAME in ToolList:
    tool = ToolList[TOOL_NAME]
    ShowTool(tool)
else:
    tool=ActionScriptMgr()

    # This call is only useful in Development to ensure we show the tool when created
    #ShowTool(tool)