# -= ml_colorControl.py =-
#                __   by Morgan Loomis
#     ____ ___  / /  http://morganloomis.com
#    / __ `__ \/ /  Revision 2
#   / / / / / / /  2018-02-17
#  /_/ /_/ /_/_/  _________
#               /_________/
# 
#     ______________
# - -/__ License __/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
# 
# Copyright 2018 Morgan Loomis
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy of 
# this software and associated documentation files (the "Software"), to deal in 
# the Software without restriction, including without limitation the rights to use, 
# copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
# Software, and to permit persons to whom the Software is furnished to do so, 
# subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in all 
# copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# 
#     ___________________
# - -/__ Installation __/- - - - - - - - - - - - - - - - - - - - - - - - - - 
# 
# Copy this file into your maya scripts directory, for example:
#     C:/Documents and Settings/user/My Documents/maya/scripts/ml_colorControl.py
# 
# Run the tool in a python shell or shelf button by importing the module, 
# and then calling the primary function:
# 
#     import ml_colorControl
#     ml_colorControl.ui()
# 
# 
#     __________________
# - -/__ Description __/- - - - - - - - - - - - - - - - - - - - - - - - - - - 
# 
# Color selections of nodes as a gradient. Choose a first and last color, and the
# intermediate colors will be generated by offsetting hsv.
# 
#     ____________
# - -/__ Usage __/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
# 
# Set the first and last color using the swatch. Select nodes in the order that
# you want the gradient to run. Finally press the "Color Selected Nodes" button.
# If you can't decide on a color, try a random one.
# 
# 
#     ___________________
# - -/__ Requirements __/- - - - - - - - - - - - - - - - - - - - - - - - - - 
# 
# This script requires the ml_utilities module, which can be downloaded here:
#     https://raw.githubusercontent.com/morganloomis/ml_tools/master/ml_utilities.py
# 
#                                                             __________
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /_ Enjoy! _/- - -

__author__ = 'Morgan Loomis'
__license__ = 'MIT'
__category__ = 'None'
__revision__ = 2

import colorsys, random
from functools import partial

import maya.cmds as mc
from maya import OpenMaya

try:
    import ml_utilities as utl
    utl.upToDateCheck(32)
except ImportError:
    result = mc.confirmDialog( title='Module Not Found', 
                message='This tool requires the ml_utilities module. Once downloaded you will need to restart Maya.', 
                button=['Download Module','Cancel'], 
                defaultButton='Cancel', cancelButton='Cancel', dismissString='Cancel' )
    
    if result == 'Download Module':
        mc.showHelp('http://morganloomis.com/tool/ml_utilities/',absolute=True)


def ui():
    '''Launch the UI
    '''
    mc.optionVar( sv=('colorManagementColorPickerColorSpaceSelection','Display Space') )
    win = ColorControlUI()
    win.buildMainLayout()
    win.finish()


class ColorControlUI(utl.MlUi):
    '''Inherited from MlUi
    '''

    def __init__(self):

        super(ColorControlUI, self).__init__('ml_colorControl',
                                               'Color Controls',
                                               width=400,
                                               height=175,
                                               info='''Color control curves or other nodes.
Color a selected list of nodes as a gradient from one color to another.
Set the first and last color, make a selection, and press the button.''')
        self.colorSliders = []
        self.buildWindow()


    def buildMainLayout(self):
        '''Build the main part of the ui
        '''

        #tabs = mc.tabLayout()

        #tab1 = mc.columnLayout(adj=True)
        #self.swatch_selected = self.colorControlLayout()
        #mc.button(label='Color Selected', command=self.colorSelected)
        #mc.setParent('..')

        #tab2 = mc.columnLayout(adj=True)
        self.swatch_range1 = self.colorControlLayout(label='First Selected')
        self.swatch_range2 = self.colorControlLayout(label='Last Selected')
        mc.separator(horizontal=True, height=10)
        mc.button(label='Color Selected Nodes', command=self.colorSelectedRange)
        #mc.setParent('..')

        #tab3 = mc.columnLayout(adj=True)
        #self.positionWidgets = {}
        #for xyz in 'XYZ':
            #for m in ['Min','Max']:
                #self.positionWidgets[m+xyz] = self.colorControlLayout(label='{} {}'.format(m,xyz))

        mc.setParent('..')

        #mc.tabLayout( tabs, edit=True, tabLabel=((tab1, 'Color Control'), (tab2, 'Color Range')) )


    def colorControlLayout(self, label=''):
        mc.rowLayout( numberOfColumns=4,
                      columnWidth4=(150, 200, 90, 80),
                      adjustableColumn=2,
                      columnAlign=(1, 'right'),
                      columnAttach=[(1, 'both', 0),
                                    (2, 'both', 0),
                                    (3, 'both', 0),
                                    (4, 'both', 0)] )
        mc.text(label=label)
        colorSlider = mc.colorSliderGrp( label='', adj=2, columnWidth=((1,1),(3,1)))
        mc.button(label='From Selected',
                  ann='Get the color of the selected object.',
                  command=partial(self.setFromSelected, colorSlider))
        mc.button(label='Randomize',
                  ann='Set a random color.',
                  command=partial(self.randomizeColors, colorSlider))
        controls = mc.layout(colorSlider, query=True, childArray=True)

        mc.setParent('..')

        return colorSlider


    def getHSV(self, swatch):
        hsv = mc.colorSliderGrp(swatch, query=True, hsv=True)
        return hsv[0]/360.0,hsv[1],hsv[2]

    def randomizeColors(self, widget, *args):

        hsv = (random.uniform(0,360),
               random.uniform(0.7,1)**2,
               random.uniform(0.4,1))
        mc.colorSliderGrp(widget, edit=True, hsv=hsv)


    def setFromSelected(self, widget, *args):
        sel = mc.ls(sl=True)
        if not sel:
            mc.warning('Please make a selection')
            return
        if mc.getAttr('{}.overrideRGBColors'.format(sel[0])):
            color = mc.getAttr('{}.overrideColorRGB'.format(sel[0]))
            mc.colorSliderGrp(widget, edit=True, rgb=color[0])
        else:
            mc.warning('Selected node is not in RGB color mode.')


    def colorSelected(self, *args):
        sel = mc.ls(sl=True)
        if not sel:
            mc.warning('Please make a selection')
            return
        hsv = self.getHSV(self.swatch_selected)
        for each in sel:
            colorShape(each, hsv=hsv)


    def colorSelectedRange(self, *args):
        sel = mc.ls(sl=True)
        if not sel:
            mc.warning('Please make a selection')
            return
        hsv1 = self.getHSV(self.swatch_range1)
        hsv2 = self.getHSV(self.swatch_range2)
        colorShapes(sel,
                    hue1=hsv1[0],
                    hue2=hsv2[0],
                    saturation1=hsv1[1],
                    saturation2=hsv2[1],
                    value1=hsv1[2],
                    value2=hsv2[2])


def colorShapes(objs, hue1=0.5, hue2=0.5, saturation1=0.5, saturation2=0.5, value1=0.5, value2=0.5):

    def step(x, length, lower, upper):
        return lower + x * (upper-lower) / length

    length = len(objs)
    for x,obj in enumerate(objs):
        colorShape(obj,
                   hsv=[step(x,length,hue1,hue2),
                        step(x,length,saturation1,saturation2),
                        step(x,length,value1,value2)]
                   )


def colorShape(obj, rgb=None, hsv=None):

    if not rgb:
        if hsv and len(hsv) == 3:
            rgb = colorsys.hsv_to_rgb(*hsv)
        else:
            raise RuntimeError('colorShape requires an rgb or hsv input.')

    mc.setAttr('{}.overrideEnabled'.format(obj), 1)
    mc.setAttr('{}.overrideRGBColors'.format(obj), 1)
    mc.setAttr('{}.overrideColorRGB'.format(obj), *rgb)

    shapes = mc.listRelatives(obj, shapes=True, pa=True)
    for shape in shapes:
        #if mc.getAttr('{}.overrideEnabled'.format(shape)):
        mc.setAttr('{}.overrideEnabled'.format(shape), 1)
        mc.setAttr('{}.overrideRGBColors'.format(shape), 1)
        mc.setAttr('{}.overrideColorRGB'.format(shape), *rgb)

if __name__ == '__main__':
    ui()

#      ______________________
# - -/__ Revision History __/- - - - - - - - - - - - - - - - - - - - - - - -
#
# Revision 1: 2016-09-02 : First publish.
#
# Revision 2: 2018-02-17 : Updating license to MIT.