Interactive/TaskUICustom.py

# (C) Copyright 2011 Autodesk, Inc.  All rights reserved.
#
# This computer source code and related instructions and comments are
# the unpublished confidential and proprietary information of
# Autodesk, Inc. and are protected under applicable copyright and
# trade secret law.  They may not be disclosed to, copied or used by
# any third party without the prior written consent of Autodesk, Inc.

# Task UI, from Edit Menu.  You must have collapse* and expand* tif files
# either installed or in your preferences\Images directory.

kAnchorCorner = "TopLeft"    # Also, "BottomLeft", "TopRight", "BottomRight".
                             # If choosing one of the Top anchors, make
                             # sure you leave enough offset for the menubar
                             # and titlebar, or you will not see the image
                             # other than in full screen or borderless.
kAnchorOffset = (0,4)        # Offset from a corner, in pixels
kAnchorPercentage = (0.5,0.0)# 0 is bottom and left, 1 is top and right.
kImageSize = (24,17)         # Image will be rescaled to match


from UI                 import ControlState, getID, ImageButton, FindImages
from RTFapi             import NodeRef, ExternalDataAccess
from UserCustomization  import UserCustomBase, CustomInfo
from awSupportApi       import ApplicationSettings
from MessageInterpreter import MessageInterpreter
from Application        import theApplication
from UiSelector         import OverlayUiNew
from Modes              import ScreenMode

import os

class MyImageButton(ImageButton):
    def __init__(self, clickCallback, imagesToUse):
        assert(callable(clickCallback))
        ImageButton.__init__(self)
        self.myClickCallback = clickCallback
        self.setImages(imagesToUse)
        self.setSize(kImageSize)
        self.setDraggable(False)
        self.setVisible(True)

    def doRelease(self, uiEvent):
        ImageButton.doRelease(self, uiEvent)
        atX, atY = uiEvent.getPosition()
        x = int(round(atX))
        y = int(round(atY))
        self.myClickCallback(x, y)

    def detachCallbacks(self):
        self.myClickCallback = None


class TaskUIUi(OverlayUiNew):
    kTaskUiUniqueId = "TaskUICustom.TaskUI"

    def __init__(self):
        OverlayUiNew.__init__(self)
        self.myImagesC = None
        self.myImagesE = None
        self.myWidth = 0
        self.myHeight = 0
        self.getRoot().setUniqueId(getID(self.kTaskUiUniqueId))
        self.myPosition = kAnchorOffset
        self.myShowCollapse = False
        self.doCreate()


    def doCreate(self):
        self.__recomputePosition()
        images = self.__loadImages()
        self.myTaskUI = MyImageButton( self.__onHeaderClick, images )
        self.getControls().append(self.myTaskUI)
        for control in self.getControls():
            self.getRoot().insertChild(NodeRef(control.getNode().get()))


    def doCleanup(self):
        self.myTaskUI.detachCallbacks()
        self.getRoot().removeChild(NodeRef(self.myTaskUI.getNode().get()))
        self.myTaskUI = None


    def doLayout(self, position, size):
        self.layoutCommon(position, size)


    def __loadImages(self):
        if self.myImagesC is None and self.myImagesE is None:
            app = ApplicationSettings.instance()
            dir = os.path.join(app.getUserPreferencesDirectory(),"Images")
            app.addDirectoryToSearchPath(ApplicationSettings.kImages,dir)

        if self.myShowCollapse:
            if self.myImagesC is None:
                self.myImagesC = FindImages({ControlState.kNormal    : "collapse_idle.tif",
                                             ControlState.kHighlight : "collapse_roll.tif",
                                             ControlState.kPress     : "collapse_press.tif"})
            images = self.myImagesC
        else:
            if self.myImagesE is None:
                self.myImagesE = FindImages({ControlState.kNormal    : "expand_idle.tif",
                                             ControlState.kHighlight : "expand_roll.tif",
                                             ControlState.kPress     : "expand_press.tif"})
            images = self.myImagesE
        return images


    def __onHeaderClick(self, x, y):
        if self.myShowCollapse:
            self.sendMessage( 'UI_SHOW_MENUBAR', (False,) )
        else:
            self.sendMessage( 'UI_SHOW_MENUBAR', (True,) )
        self.myShowCollapse = not self.myShowCollapse
        self.myTaskUI.setImages(self.__loadImages())


    def __recomputePosition(self):
        self.myPosition = self.anchorToAbsolute(kAnchorCorner,
                                                kAnchorPercentage[0],
                                                kAnchorPercentage[1],
                                                kAnchorOffset, kImageSize)


    def __setPosition(self):
        if self.isVisible():
            self.myTaskUI.setPosition(self.myPosition)
            self.myTaskUI.doLayout()


    def __setVisibility(self, visible):
        if visible != self.isVisible():
            self.setVisible(visible)
            if visible:
                self.__setPosition()
        

    def anchorToAbsolute( self, anchor, percW, percH, loc, sz ):
        x = loc[0]
        y = loc[1]
        if "BottomLeft" == anchor:
            x += percW*self.myWidth
            y += percH*self.myHeight
        elif "BottomRight" == anchor:
            x = (1.0-percW)*self.myWidth - sz[0] - x
            y += percH*self.myHeight
        elif "TopLeft" == anchor:
            x += percW*self.myWidth
            y = (1.0-percH)*self.myHeight - sz[1] - y
        elif "TopRight" == anchor:
            x = (1.0-percW)*self.myWidth - sz[0] - x
            y = (1.0-percH)*self.myHeight - sz[1] - y
        return (x,y)

    def CUSTOM_OVERLAY_SET_MODE( self, message):
        (which, visible) = message.data
        if which == self.kTaskUiUniqueId:
            self.__setVisibility(visible)

    # We do not mind showing this interface together with everything else,
    # so we do not need to listen to the other _UI_SET_MODE messages.

    def APPLICATION_VIEW_POSITION_AND_SIZE_CHANGED( self, message ):
        # If the window resizes, reposition
        (x, y, self.myWidth, self.myHeight, s) = message.data
        d = theApplication.getDisplay()
        if d:
            (self.myWidth, self.myHeight) = d.getWindowSize()
        self.__recomputePosition()
        self.__setPosition()


class TaskUI( UserCustomBase ):
    def __init__( self ):
        self.myInterpreter = LocalInterpreter()
        self.myUniqueTaskId = None

    def getInterpreter( self, isInteractive ):
        if isInteractive:
            return self.myInterpreter
        return None

    def getCustomUi( self ):
        ui = TaskUIUi()
        self.myUniqueTaskId = ui.kTaskUiUniqueId
        self.myInterpreter.myId = self.myUniqueTaskId
        self.myInterpreter.ShowPending()
        return (self.myUniqueTaskId,ui)

    def appendMenuItems( self, id, menu ):
        if 'Edit' == id:
            menu.AppendSeparator()
            self.__myTaskShowId = menu.appendItem(_( 'Show Task UI' ),
                                                    self.__onTaskShow )
            self.__myTaskHideId = menu.appendItem(_( 'Hide Task UI' ),
                                                    self.__onTaskHide )

    def setRecommended(self,event):
        self.__myInterpreter.setRecommended()

    def enableMenuStates( self, id, enableStates ):
        if 'Edit' == id:
            enableStates[self.__myTaskShowId] = True
            enableStates[self.__myTaskHideId] = True

    def __onTaskShow( self, event ):
        self.myInterpreter.TaskShow(True)

    def __onTaskHide( self, event ):
        self.myInterpreter.TaskShow(False)


class LocalInterpreter( MessageInterpreter ):

    def __init__( self ):
        MessageInterpreter.__init__( self )
        self.myShowing = False
        self.mySkip = 2
        self.myId = None

    def TaskShow(self,show):
        if not self.myId:
            return
        if show:
            self.sendMessage( 'CUSTOM_OVERLAY_SET_MODE', (self.myId,True,) )
            self.sendMessage( 'UI_SHOW_MENUBAR', (False,) )
            self.sendMessage( 'DISPLAY_SCALEFORM_SHOW', (True,) )
        else:
            self.sendMessage( 'CUSTOM_OVERLAY_SET_MODE', (self.myId,False,) )
            self.sendMessage( 'UI_SHOW_MENUBAR', (True,) )
            self.sendMessage( 'DISPLAY_SCALEFORM_SHOW', (False,) )
        self.myShowing = show

    def INITIALIZATION_COMPLETE(self,message):
        self.ShowPending()

    def WINDOW_SHOW_BORDERS(self,message):
        (show,) = message.data
        self.forceHide(not show)

    def SCREEN_SET_MODE(self,message):
        (screenMode,) = message.data
        self.forceHide(ScreenMode.kFullScreen == screenMode)

    def ShowPending(self):
        self.mySkip -= 1
        if self.mySkip <= 0:
            self.TaskShow(True)

    def forceHide(self,forcing):
        if not self.myId:
            return
        if self.myShowing:
            if forcing:
                self.sendMessage('CUSTOM_OVERLAY_SET_MODE', (self.myId,False,))
            else:
                self.sendMessage('CUSTOM_OVERLAY_SET_MODE', (self.myId,True,))


    def setRecommended(self):
        self.sendMessage( 'EXTERNAL_DATA_ACCESS_ASSOCIATE_UPDATE',(ExternalDataAccess.kEnvironments,"","",) )
        self.sendMessage( 'EXTERNAL_DATA_ACCESS_ASSOCIATE_UPDATE',(ExternalDataAccess.kRecentFiles,"","",) )
        pass

    def APPLICATION_PREFERENCES_LOADED(self,message):
        self.setRecommended()

    def APPLICATION_RECENT_FILES_UPDATED(self,message):
        self.setRecommended()

    def MODEL_IMPORT_DISPLAYED_ALL(self,message):
        self.setRecommended()

    def APPLICATION_CLOSE_SCENE( self, message ):
        self.setRecommended()


def instantiate():
    return TaskUI()


def info():
    customInfo = CustomInfo()
    customInfo.vendor = 'Autodesk'
    customInfo.version = '1.0'
    customInfo.api = '2013'
    customInfo.shortInfo = "Task UI control."
    customInfo.longInfo = \
"""
"""
    return customInfo