Krita/krita/pykrita/pigment_o/pigment_o_modulo.py

4968 lines
204 KiB
Python
Raw Normal View History

2025-03-07 08:03:18 +01:00
# Pigment.O is a Krita plugin and it is a Color Picker and Color Mixer.
# Copyright ( C ) 2020 Ricardo Jeremias.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# ( at your option ) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#region Imports ####################################################################
# Python Modules
import os
import math
import time
import subprocess
import zipfile
# Krita Module
from krita import *
# PyQt5 Modules
from PyQt5 import QtWidgets, QtCore, QtGui, uic
# Pigment.O Modules
from .pigment_o_constants import *
from .pigment_o_calculations import (
Geometry,
Convert,
)
#endregion
#region Shared #####################################################################
# ZIP
def Read_Zip( self, location, tan_range, space, shape ):
try:
qpixmap_list = []
if zipfile.is_zipfile( location ):
archive = zipfile.ZipFile( location, "r" )
for i in range( 0, tan_range+1 ):
# Mode Sensitive
name = f"{ space }_{ shape }_{ str( i ).zfill( 3 ) }.png"
# Read File
archive_open = archive.open( name )
archive_read = archive_open.read()
# Image
image = QImage()
image.loadFromData( archive_read )
qpixmap = QPixmap().fromImage( image )
qpixmap_list.append( qpixmap )
return qpixmap_list
except Exception as e:
try:QtCore.qDebug( f"Pigment.O ERROR | { e }" )
except:pass
# Colors
def krita_theme( self ):
theme = QApplication.palette().color( QPalette.Window ).value()
if theme > 128:
self.color_1 = QColor( "#191919" ) # Dark
self.color_2 = QColor( "#e5e5e5" ) # Light
else:
self.color_1 = QColor( "#e5e5e5" ) # Light
self.color_2 = QColor( "#191919" ) # Dark
self.color_black = QColor( "#000000" )
self.color_white = QColor( "#ffffff" )
self.color_alpha = QColor( 0, 0, 0, 50 )
# Region
def Circles( self, painter ):
# Circle 0 ( Everything )
v0a = 0
v0b = 1 - ( 2*v0a )
circle_0 = QPainterPath()
circle_0.addEllipse( self.px + self.side * v0a, self.py + self.side * v0a, self.side * v0b, self.side * v0b )
# Circle 1 ( Outter Most Region )
v1a = 0.025
v1b = 1 - ( 2*v1a )
circle_1 = QPainterPath()
circle_1.addEllipse( self.px + self.side * v1a, self.py + self.side * v1a, self.side * v1b, self.side * v1b )
# Circle 2 ( Inner Most Region )
v2a = 0.068
v2b = 1 - ( 2*v2a )
circle_2 = QPainterPath()
circle_2.addEllipse( self.px + self.side * v2a, self.py + self.side * v2a, self.side * v2b, self.side * v2b )
# Circle 3 ( Central Dot )
v3a = 0.13
v3b = 1 - ( 2*v3a )
circle_3 = QPainterPath()
circle_3.addEllipse( self.px + self.side * v3a, self.py + self.side * v3a, self.side * v3b, self.side * v3b )
# Return
return circle_0, circle_1, circle_2, circle_3
# Cursor
def Cursor_Normal( self, painter, size ):
# Variables
w = 2
# Mask
mask = QPainterPath()
mask.addEllipse(
int( self.event_x - size ),
int( self.event_y - size ),
int( size * 2 ),
int( size * 2 ),
)
mask.addEllipse(
int( self.event_x - size + w * 2 ),
int( self.event_y - size + w * 2 ),
int( size * 2 - w * 4 ),
int( size * 2 - w * 4 ),
)
painter.setClipPath( mask )
# Black Circle
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_black ) )
painter.drawEllipse(
int( self.event_x - size ),
int( self.event_y - size ),
int( size * 2 ),
int( size * 2 ),
)
# White Circle
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_white ) )
painter.drawEllipse(
int( self.event_x - size + w ),
int( self.event_y - size + w ),
int( size * 2 - w * 2 ),
int( size * 2 - w * 2 ),
)
def Cursor_Zoom( self, painter, zoom_size, margin_size ):
# Border
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_black ) )
painter.drawEllipse(
int( self.event_x - zoom_size ),
int( self.event_y - zoom_size ),
int( zoom_size * 2 ),
int( zoom_size * 2 ),
)
# Hex Color
painter.setBrush( QBrush( self.hex_color ) )
painter.drawEllipse(
int( self.event_x - zoom_size + margin_size ),
int( self.event_y - zoom_size + margin_size ),
int( zoom_size * 2 - margin_size * 2 ),
int( zoom_size * 2 - margin_size * 2 ),
)
#endregion
#region Header #####################################################################
class Color_Header( QWidget ):
SIGNAL_SWAP = QtCore.pyqtSignal( int )
SIGNAL_SHIFT = QtCore.pyqtSignal( bool )
SIGNAL_RANDOM = QtCore.pyqtSignal( int )
SIGNAL_COMP = QtCore.pyqtSignal( int )
SIGNAL_ANALYSE = QtCore.pyqtSignal( int )
# Init
def __init__( self, parent ):
super( Color_Header, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, 100 )
def Init_Variables( self ):
# Widget
self.widget_width = 100
self.widget_height = 40
# Variables
self.mode_ab = True
self.progress_bar = 0
# Other
self.other_show = False
self.ui_k = 80
self.other_a = self.ui_k
self.other_b = self.widget_width - self.ui_k
# Colors HEX
self.kac_1 = QColor( '#000000' )
self.kac_2 = QColor( '#323232' )
self.kbc_1 = QColor( '#ffffff' )
self.kbc_2 = QColor( '#cbcbcb' )
# Modules
self.geometry = Geometry()
# Relay
def Set_Mode_AB( self, mode_ab ):
self.mode_ab = mode_ab
self.update()
def Set_Size( self, widget_width, widget_height ):
# widget
self.widget_width = widget_width
self.widget_height = widget_height
# Limits
if widget_width <= 200:
self.other_a = widget_width * 0.4
self.other_b = widget_width * 0.7
else:
self.other_a = self.ui_k
self.other_b = widget_width - self.ui_k
# Update
self.update()
def Set_Color_A1( self, kac_1 ):
self.kac_1 = QColor( kac_1 )
self.update()
def Set_Color_A2( self, kac_2 ):
self.kac_2 = QColor( kac_2 )
self.update()
def Set_Color_B1( self, kbc_1 ):
self.kbc_1 = QColor( kbc_1 )
self.update()
def Set_Color_B2( self, kbc_2 ):
self.kbc_2 = QColor( kbc_2 )
self.update()
def Set_Progress( self, progress_bar ):
self.progress_bar = progress_bar
self.update()
# Mouse Interaction
def mousePressEvent( self, event ):
self.update()
def mouseMoveEvent( self, event ):
self.update()
def mouseReleaseEvent( self, event ):
self.update()
# Context Menu Event
def contextMenuEvent( self, event ):
# Variables
if self.mode_ab == True:
side = "BG"
else:
side = "FG"
# Menu
if event.modifiers() == QtCore.Qt.NoModifier:
cmenu = QMenu( self )
# Actions
cmenu_swap = cmenu.addAction( "FG-BG Swap" )
cmenu_active = cmenu.addAction( side + " Active" )
cmenu_random = cmenu.addAction( "Random" )
cmenu_complementary = cmenu.addAction( "Complementary" )
cmenu_analyse = cmenu.addAction( "Analyse" )
# Map
action = cmenu.exec_( self.mapToGlobal( event.pos() ) )
# Triggers
if action == cmenu_swap:
self.SIGNAL_SWAP.emit( 0 )
if action == cmenu_active:
self.mode_ab = not self.mode_ab
self.SIGNAL_SHIFT.emit( self.mode_ab )
if action == cmenu_random:
self.SIGNAL_RANDOM.emit( 0 )
if action == cmenu_complementary:
self.SIGNAL_COMP.emit( 0 )
if action == cmenu_analyse:
self.SIGNAL_ANALYSE.emit( 0 )
# Interaction
def enterEvent( self, event ):
self.other_show = True
self.update()
def leaveEvent( self, event ):
self.other_show = False
self.update()
# Paint Style
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Start Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
painter.setPen( QtCore.Qt.NoPen )
# Variable
w1 = self.widget_width + 1
w2 = int( w1 * 0.5 )
# Progress Bar Mask
mask = QPainterPath()
mask.addRect( 0, 0, self.widget_width * self.progress_bar, self.widget_height )
painter.setClipPath( mask )
# Mode FG
if self.mode_ab == True:
# FG Active
painter.setBrush( QBrush( self.kac_1 ) )
painter.drawRect( 0, 0, w2, self.widget_height )
# FG Previous
painter.setBrush( QBrush( self.kac_2 ) )
painter.drawRect( w2, 0, w2, self.widget_height )
# BG over FG
painter.setBrush( QBrush( self.kbc_1 ) )
if self.other_show == True:
point = w1 - self.other_a
painter.drawRect( point, 0, self.other_a, self.widget_height )
# Mode BG
if self.mode_ab == False:
# BG Active
painter.setBrush( QBrush( self.kbc_1 ) )
painter.drawRect( 0, 0, w2, self.widget_height )
# BG Previous
painter.setBrush( QBrush( self.kbc_2 ) )
painter.drawRect( w2, 0, w2, self.widget_height )
# FG over BG
painter.setBrush( QBrush( self.kac_1 ) )
if self.other_show == True:
painter.drawRect( 0, 0, self.other_a, self.widget_height )
class Harmony_Swatch( QWidget ):
SIGNAL_RULE = QtCore.pyqtSignal( str )
SIGNAL_EDIT = QtCore.pyqtSignal( bool )
SIGNAL_INDEX = QtCore.pyqtSignal( int )
# Init
def __init__( self, parent ):
super( Harmony_Swatch, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, 100 )
def Init_Variables( self ):
# Widget
self.widget_width = 0
self.widget_height = 0
# Index
self.harmony_rule = "Analogous" # "Monochromatic" "Complementary" "Analogous" "Triadic" "Tetradic"
self.harmony_edit = False
self.harmony_index = 0
self.harmony_parts = 5
self.harmony_color = [ "#000000", "#000000", "#000000", "#000000", "#000000" ]
# Modules
self.geometry = Geometry()
# Relay
def Set_Size( self, widget_width, widget_height ):
self.widget_width = widget_width
self.widget_height = widget_height
self.update()
def Set_Harmony_Rule( self, harmony_rule ):
self.harmony_rule = harmony_rule
self.update()
def Set_Harmony_Parts( self, har_parts, har_color ):
self.harmony_parts = har_parts
self.harmony_color = har_color
self.update()
def Set_WheelSpace( self, wheel_space ):
self.wheel_space = wheel_space
self.update()
# Update
def Update_Harmony( self, harmony_rule, harmony_edit, harmony_index ):
self.harmony_rule = harmony_rule
self.harmony_edit = harmony_edit
self.harmony_index = harmony_index
self.update()
def Update_Index( self, harmony_index ):
self.harmony_index = harmony_index
self.update()
# Mouse Interaction
def mousePressEvent( self, event ):
self.Index_Signal( event )
self.update()
def mouseMoveEvent( self, event ):
self.Index_Signal( event )
self.update()
def mouseDoubleClickEvent( self, event ):
self.Index_Signal( event )
self.update()
def mouseReleaseEvent( self, event ):
self.Index_Signal( event )
self.update()
# Signals
def Index_Signal( self, event ):
self.event_x = self.geometry.Limit_Range( event.x(), 0, self.widget_width )
percentage = self.event_x / self.widget_width
self.harmony_index = self.geometry.Limit_Range( int( percentage * self.harmony_parts ), 0, self.harmony_parts - 1 ) + 1
self.SIGNAL_INDEX.emit( self.harmony_index )
self.update()
# Context
def contextMenuEvent( self, event ):
# Menu
cmenu = QMenu( self )
# Actions Harmony Rule
cmenu_rule = cmenu.addMenu( "Harmony Rule" )
cmenu_rule_m = cmenu_rule.addAction( "Monochromatic" )
cmenu_rule_c = cmenu_rule.addAction( "Complementary" )
cmenu_rule_a = cmenu_rule.addAction( "Analogous" )
cmenu_rule_tri = cmenu_rule.addAction( "Triadic" )
cmenu_rule_tet = cmenu_rule.addAction( "Tetradic" )
cmenu_rule_m.setCheckable( True )
cmenu_rule_c.setCheckable( True )
cmenu_rule_a.setCheckable( True )
cmenu_rule_tri.setCheckable( True )
cmenu_rule_tet.setCheckable( True )
cmenu_rule_m.setChecked( self.harmony_rule == "Monochromatic" )
cmenu_rule_c.setChecked( self.harmony_rule == "Complementary" )
cmenu_rule_a.setChecked( self.harmony_rule == "Analogous" )
cmenu_rule_tri.setChecked( self.harmony_rule == "Triadic" )
cmenu_rule_tet.setChecked( self.harmony_rule == "Tetradic" )
# Actions Edit
cmenu_edit = cmenu.addAction( "Edit" )
cmenu_edit.setCheckable( True )
cmenu_edit.setChecked( self.harmony_edit )
action = cmenu.exec_( self.mapToGlobal( event.pos() ) )
# Triggers
if action == cmenu_rule_m:
self.harmony_rule = "Monochromatic"
self.SIGNAL_RULE.emit( self.harmony_rule )
if action == cmenu_rule_c:
self.harmony_rule = "Complementary"
self.SIGNAL_RULE.emit( self.harmony_rule )
if action == cmenu_rule_a:
self.harmony_rule = "Analogous"
self.SIGNAL_RULE.emit( self.harmony_rule )
if action == cmenu_rule_tri:
self.harmony_rule = "Triadic"
self.SIGNAL_RULE.emit( self.harmony_rule )
if action == cmenu_rule_tet:
self.harmony_rule = "Tetradic"
self.SIGNAL_RULE.emit( self.harmony_rule )
if action == cmenu_edit:
self.harmony_edit = not self.harmony_edit
self.SIGNAL_EDIT.emit( self.harmony_edit )
# Paint
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Start Qpainter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Correct Variable Range
if self.harmony_index > self.harmony_parts:
self.harmony_index = 0
# Swatch
painter.setPen( QtCore.Qt.NoPen )
points = []
factor = 0.7
width = int( self.widget_width / self.harmony_parts + 1 )
height = int( self.widget_height*( 1-factor ) )
for i in range( 0, self.harmony_parts ):
# Variables
px = int( ( self.widget_width / self.harmony_parts ) * i )
py = int( self.widget_height * factor )
# Color
painter.setBrush( QBrush( QColor( self.harmony_color[i] ) ) )
painter.drawRect( px, 0, width, self.widget_height )
# Stops
points.append( px )
points.append( self.widget_width )
if self.harmony_index > len( points ):
self.harmony_index = 1
# Index Cursor
if self.harmony_index != 0:
px = points[self.harmony_index-1]
pw = points[self.harmony_index]
width = pw - px
painter.setBrush( QBrush( self.color_2 ) )
painter.drawRect( px, py, width, height+1 )
painter.setBrush( QBrush( self.color_1 ) )
painter.drawRect( px+1, py+1, width-2, height-1 )
class Harmony_Spread( QWidget ):
SIGNAL_SPAN = QtCore.pyqtSignal( float )
SIGNAL_RELEASE = QtCore.pyqtSignal( int )
# Init
def __init__( self, parent ):
super( Harmony_Spread, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, 100 )
def Init_Variables( self ):
# Widget
self.widget_width = 0
self.widget_height = 0
self.w2 = 0
# Range
self.harmony_span = 0.2
self.harmony_rule = "Analogous" # "Monochromatic" "Complementary" "Analogous" "Triadic" "Tetradic"
self.no_span = ["Monochromatic", "Complementary"] # Have no span
# Modules
self.geometry = Geometry()
# Relay
def Set_Size( self, widget_width, widget_height ):
self.widget_width = widget_width
self.widget_height = widget_height
self.w2 = int( widget_width * 0.5 )
self.update()
def Set_Rule( self, rule ):
self.harmony_rule = rule
self.update()
# Update
def Update_Span( self, harmony_span ):
# range 0-1
self.harmony_span = harmony_span
self.update()
# Mouse Interaction
def mousePressEvent( self, event ):
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.Range_Width( event )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ControlModifier ):
self.Range_Pin( event )
def mouseMoveEvent( self, event ):
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.Range_Width( event )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ControlModifier ):
self.Range_Pin( event )
def mouseDoubleClickEvent( self, event ):
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.Range_Width( event )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ControlModifier ):
self.Range_Pin( event )
def mouseReleaseEvent( self, event ):
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.Range_Width( event )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ControlModifier ):
self.Range_Pin( event )
self.SIGNAL_RELEASE.emit( 0 )
# Signals
def Range_Width( self, event ):
# Read
event_x = event.x()
# Consider Widget Size
value = self.geometry.Limit_Range( event_x, 0, self.widget_width )
# Sides
if value >= self.w2:
span_right = value
span_left = self.widget_width - value
else:
span_left = value
span_right = self.widget_width - value
# Normalize Values
delta = span_right - span_left
if self.widget_width == 0:
self.harmony_span = 0
else:
self.harmony_span = delta / self.widget_width
self.SIGNAL_SPAN.emit( self.harmony_span )
self.update()
def Range_Pin( self, event ):
# Read
event_x = event.x()
# Consider Widget Size
value = self.geometry.Limit_Range( event_x, 0, self.widget_width )
# Pin
stops = 72
unit = self.widget_width / stops
distances = []
for i in range( 0, stops+1 ):
dist = self.geometry.Trig_2D_Points_Distance( value, 0, ( unit * i ), 0 )
distances.append( dist )
value_min = min( distances )
index = distances.index( value_min )
value = unit * index
percent = value / self.widget_width
# Sides
if value >= self.w2:
span_right = value
span_left = self.widget_width - value
else:
span_left = value
span_right = self.widget_width - value
# Normalize Values
delta = span_right - span_left
if self.widget_width == 0:
self.harmony_span = 0
else:
self.harmony_span = delta / self.widget_width
self.SIGNAL_SPAN.emit( self.harmony_span )
self.update()
# Paint
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Start Qpainter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Harmony Angle
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_1 ) )
if self.harmony_rule in self.no_span:
px = int( self.w2 )
width = 1
else:
px = int( self.w2 - ( self.harmony_span * self.widget_width * 0.5 ) )
width = int( self.widget_width * self.harmony_span )
if width <= 1:
width = 1
painter.drawRect( px, 2, width, self.widget_height-4 )
#endregion
#region Panels #####################################################################
class Panel_Fill( QWidget ):
# Init
def __init__( self, parent ):
super( Panel_Fill, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, render_height )
def Init_Variables( self ):
# Widget
self.widget_width = 0
self.widget_height = 0
# Display
self.hex_color = QColor( "#000000" )
# Set
def Set_Size( self, widget_width, widget_height ):
self.widget_width = widget_width
self.widget_height = widget_height
self.update()
# Updates
def Update_Panel( self, color ):
self.hex_color = QColor( color["hex6_d"] )
self.update()
# Paint
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Draw Pixmaps
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.hex_color ) )
painter.drawRect( 0, 0, self.widget_width, self.widget_height )
class Panel_Square( QWidget ):
SIGNAL_VALUE = QtCore.pyqtSignal( dict )
SIGNAL_TAN = QtCore.pyqtSignal( float )
SIGNAL_RELEASE = QtCore.pyqtSignal( int )
SIGNAL_PIN_INDEX = QtCore.pyqtSignal( int )
SIGNAL_PIN_EDIT = QtCore.pyqtSignal( dict )
# Init
def __init__( self, parent ):
super( Panel_Square, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, render_height )
def Init_Variables( self ):
# Widget
self.widget_width = 0
self.widget_height = 0
self.origin_x = 0
self.origin_y = 0
self.origin_tan_axis = 0
self.event_x = 0
self.event_y = 0
self.press = False
self.pressure = 0
self.input_pressure = 0.5
# Display
self.zoom = False
self.tan_axis = 0 # 0-360 because of background index
self.tan_range = None # 360 255
self.qpixmap_list = []
# Format
self.directory = None # Path
self.d_cm = None # "A" "RGB" "CMYK" "YUV" "XYZ" "LAB"
self.shape = None # "3" "4" "R"
self.chan = None # "hsv" "hsl" "hsy" "ard" / "yuv"
# Wheel
self.wheel_space = None # "HSV" "HSL" "HSY" "ARD"
# Colors
self.hex_color = QColor( "#000000" )
self.color = None
# Harmony Colors
self.harmony_rule = None
self.harmony_index = None
self.harmony_list = None
# Pinned Colors
self.pin_index = None
self.pin_list = None
# Analyse Colors
self.analyse = None
# YUV primaries
self.CR = [ 1, 0, 0 ]
self.CY = [ 1, 1, 0 ]
self.CG = [ 0, 1, 0 ]
self.CC = [ 0, 1, 1 ]
self.CB = [ 0, 0, 1 ]
self.CM = [ 1, 0, 1 ]
# Modules
self.geometry = Geometry()
self.convert = None
def Init_Convert( self, convert ):
self.convert = convert
self.update()
# Set
def Set_ColorModel( self, d_cm ):
self.d_cm = d_cm
self.Set_ColorSpace_inDocument( self.directory, self.d_cm, self.wheel_space, self.shape )
self.update()
def Set_WheelSpace( self, wheel_space ):
self.wheel_space = wheel_space
self.Set_ColorSpace_inDocument( self.directory, self.d_cm, self.wheel_space, self.shape )
self.update()
def Set_Tangent_Range( self, tan_range ):
self.tan_range = tan_range
self.update()
def Set_ColorSpace_inDocument( self, directory, d_cm, wheel_space, shape ):
# Variables
self.directory = directory
self.d_cm = d_cm
self.wheel_space = wheel_space
self.shape = shape
self.chan = self.wheel_space.lower()
# Cursor
if self.color != None:
if self.shape == "3":
cx = self.color["hsl_2"]
cy = 1 - self.color["hsl_3"]
inter = self.Triangle_Inter( cy, 1, 1 )
self.event_x = self.geometry.Limit_Range( cx * inter * self.widget_width, 0, self.widget_width )
self.event_y = self.geometry.Limit_Range( cy * self.widget_height, 0, self.widget_height )
if self.shape == "4":
self.event_x = self.geometry.Limit_Range( self.color[f"{self.chan}_2"] * self.widget_width, 0, self.widget_width )
self.event_y = self.geometry.Limit_Range( self.color[f"{self.chan}_3"] * self.widget_height, 0, self.widget_height )
if self.shape == "R":
cx = self.color["hsl_2"]
cy = 1 - self.color["hsl_3"]
mini, maxi, delta = self.Diamond_Inter( cy, 1, 1 )
value = mini + cx * delta
self.event_x = self.geometry.Limit_Range( value * self.widget_width, mini * self.widget_width, maxi * self.widget_width )
self.event_y = self.geometry.Limit_Range( cy * self.widget_height, 0, self.widget_height )
# Primaries
if self.wheel_space == "YUV":
self.CR = self.convert.rgb_to_yuv( 1, 0, 0 )
self.CY = self.convert.rgb_to_yuv( 1, 1, 0 )
self.CG = self.convert.rgb_to_yuv( 0, 1, 0 )
self.CC = self.convert.rgb_to_yuv( 0, 1, 1 )
self.CB = self.convert.rgb_to_yuv( 0, 0, 1 )
self.CM = self.convert.rgb_to_yuv( 1, 0, 1 )
# Read Zip File
location = os.path.join( self.directory, panel )
location = os.path.join( location, f"{ self.d_cm }_{ self.wheel_space }_{ self.shape }.zip" )
self.qpixmap_list = Read_Zip( self, location, self.tan_range, self.wheel_space, self.shape )
# Update
self.update()
def Set_Size( self, widget_width, widget_height ):
# Variables
self.widget_width = widget_width
self.widget_height = widget_height
# Mask ( slightly bigger than color display )
if self.shape == "3":
polygon = QPolygon( [
QPoint( int( -1 ), int( -1 ) ),
QPoint( int( self.widget_width + 1 ), int( self.widget_height * 0.5 ) ),
QPoint( int( -1 ), int( self.widget_height + 1 ) ),
] )
triangle = QRegion( polygon, Qt.OddEvenFill )
self.setMask( triangle )
if self.shape == "4":
polygon = QPolygon( [
QPoint( int( -1 ), int( -1 ) ),
QPoint( int( self.widget_width + 1 ), int( -1 ) ),
QPoint( int( self.widget_width + 1 ), int( self.widget_height + 1 ) ),
QPoint( int( -1 ), int( self.widget_height + 1 ) ),
] )
square = QRegion( polygon, Qt.OddEvenFill )
self.setMask( square )
if self.shape == "R":
polygon = QPolygon( [
QPoint( int( self.widget_width * 0.5 ), int( -1 ) ),
QPoint( int( self.widget_width + 1 ), int( self.widget_height * 0.5 ) ),
QPoint( int( self.widget_width * 0.5 ), int( self.widget_height + 1 ) ),
QPoint( int( -1 ), int( self.widget_height * 0.5 ) ),
] )
diamond = QRegion( polygon, Qt.OddEvenFill )
self.setMask( diamond )
# Update
self.update()
def Set_Zoom( self, boolean ):
self.press = boolean
self.zoom = boolean
self.update()
# Updates
def Update_Panel( self, color ):
# Variables
self.color = color
# Display
self.hex_color = QColor( color["hex6"] )
if self.shape == "3":
# Variables
cx = color["hsl_2"]
cy = 1 - color["hsl_3"]
inter = self.Triangle_Inter( cy, 1, 1 )
# Values
self.tan_axis = color["hsl_1"]
self.event_x = self.geometry.Limit_Range( cx * inter * self.widget_width, 0, self.widget_width )
self.event_y = self.geometry.Limit_Range( cy * self.widget_height, 0, self.widget_height )
if self.shape == "4":
# Values
self.tan_axis = color[f"{self.chan}_1"]
self.event_x = color[f"{self.chan}_2"] * self.widget_width
self.event_y = ( 1 - color[f"{self.chan}_3"] ) * self.widget_height
if self.shape == "R":
# Variables
cx = color["hsl_2"]
cy = 1 - color["hsl_3"]
mini, maxi, delta = self.Diamond_Inter( cy, 1, 1 )
value = mini + cx * delta
# Values
self.tan_axis = color["hsl_1"]
self.event_x = self.geometry.Limit_Range( value * self.widget_width, mini * self.widget_width, maxi * self.widget_width )
self.event_y = self.geometry.Limit_Range( cy * self.widget_height, 0, self.widget_height )
# Update
self.update()
def Update_Harmony( self, harmony_rule, harmony_index, harmony_list ):
self.harmony_rule = harmony_rule
self.harmony_index = harmony_index
self.harmony_list = harmony_list
self.update()
def Update_Pin( self, pin_list ):
self.pin_list = pin_list
self.update()
def Update_Analyse( self, analyse ):
self.analyse = analyse
self.update()
# Panel Modifiers
def Triangle_Inter ( self, y, px, py ):
if y <= 0*py:
inter = 0
elif ( y >= 0*py and y <= 0.5*py ):
inter = self.geometry.Trig_2D_Points_Lines_Intersection( 0*px, y, 1*px, y, 0*px, 0*py, 1*px, 0.5*py )[0]
elif y == 0.5*py:
inter = 1
elif ( y >= 0.5*py and y <= 1*py ):
inter = self.geometry.Trig_2D_Points_Lines_Intersection( 0*px, y, 1*px, y, 0*px, 1*py, 1*px, 0.5*py )[0]
elif y >= 1*py:
inter = 0
return inter
def Diamond_Inter( self, y, px, py ):
if y <= 0*py:
mini = 0.5 * px
maxi = 0.5 * py
delta = 0
elif ( y >= 0*py and y <= 0.5*py ):
mini = self.geometry.Trig_2D_Points_Lines_Intersection( 0*px, y, 1*px, y, 0.5*px, 0*py, 0*px, 0.5*py )[0]
maxi = self.geometry.Trig_2D_Points_Lines_Intersection( 0*px, y, 1*px, y, 0.5*px, 0*py, 1*px, 0.5*py )[0]
delta = abs( maxi - mini )
elif y == 0.5*py:
mini = 0
maxi = py
delta = py
elif ( y >= 0.5*py and y <= 1*py ):
mini = self.geometry.Trig_2D_Points_Lines_Intersection( 0*px, y, 1*px, y, 0.5*px, 1*py, 0*px, 0.5*py )[0]
maxi = self.geometry.Trig_2D_Points_Lines_Intersection( 0*px, y, 1*px, y, 0.5*px, 1*py, 1*px, 0.5*py )[0]
delta = abs( maxi - mini )
elif y >= 1*py:
mini = 0.5 * px
maxi = 0.5 * py
delta = 0
return mini, maxi, delta
# Mouse Interaction
def mousePressEvent( self, event ):
# Event
ex = event.x()
ey = event.y()
# Variables
self.press = True
self.origin_x = ex
self.origin_y = ey
self.origin_tan_axis = self.tan_axis
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( ex, ey )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( ex, ey )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Snap( ex, ey )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
self.Cursor_Snap( ex, ey )
self.update()
def mouseMoveEvent( self, event ):
# Events
ex = event.x()
ey = event.y()
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( ex, ey )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( ex, ey )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Tangent( ex )
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Snap( ex, ey )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
self.Cursor_Position( ex, ey )
self.update()
def mouseDoubleClickEvent( self, event ):
# Events
ex = event.x()
ey = event.y()
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( ex, ey )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( ex, ey )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Tangent( ex )
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Snap( ex, ey )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
self.Cursor_Position( ex, ey )
self.update()
def mouseReleaseEvent( self, event ):
# Variables
self.press = False
self.zoom = False
self.pressure = 0
self.origin_tan_axis = 0
self.pin_index = None
# Updates
self.SIGNAL_RELEASE.emit( 0 )
self.update()
# Mouse Event
def Cursor_Position( self, ex, ey ):
# Variables
ww = self.widget_width
wh = self.widget_height
# Input
if self.shape == "3":
# Cursor
inter = self.Triangle_Inter( ey, ww, wh )
self.event_x = self.geometry.Limit_Range( ex, 0, inter )
self.event_y = self.geometry.Limit_Range( ey, 0, self.widget_height )
# Color
if inter == 0:px = 0
else:px = self.event_x / inter
py = ( wh - self.event_y ) / wh
if self.shape == "4":
# Cursor
self.event_x = self.geometry.Limit_Range( ex, 0, ww )
self.event_y = self.geometry.Limit_Range( ey, 0, wh )
# Color
px = self.event_x / ww
py = ( wh - self.event_y ) / wh
if self.shape == "R":
# Cursor
mini, maxi, delta = self.Diamond_Inter( ey, ww, wh )
self.event_x = self.geometry.Limit_Range( ex, mini, maxi )
self.event_y = self.geometry.Limit_Range( ey, 0, self.widget_height )
# Color
if delta == 0:px = 0
else:px = ( self.event_x - mini ) / delta
py = ( wh - self.event_y ) / wh
# Variables
if self.shape == "3":
mode = "HSL"
inter = self.Triangle_Inter( ey, self.widget_width, self.widget_height )
if inter == 0:c2 = 0
else:c2 = ex / inter
if self.shape == "4":
mode = self.wheel_space
c2 = ex / self.widget_width
if self.shape == "R":
mode = "HSL"
mini, maxi, delta = self.Diamond_Inter( ey, self.widget_width, self.widget_height )
if delta == 0:c2 = 0
else:c2 = ( ex - mini ) / delta
c3 = ( self.widget_height - ey ) / self.widget_height
# Limit
c2 = self.geometry.Limit_Float( c2 )
c3 = self.geometry.Limit_Float( c3 )
# Signals
dictionary = { "mode" : self.wheel_space, "c2" : c2, "c3" : c3, "pin_index" : self.pin_index }
self.SIGNAL_VALUE.emit( dictionary )
if self.pin_index != None:
self.SIGNAL_PIN_EDIT.emit( dictionary )
def Cursor_Tangent( self, ex ):
# Hue
delta_hue = ( ( ex - self.origin_x ) / self.widget_width )
angle = self.origin_tan_axis + delta_hue
if self.wheel_space == "YUV":
self.tan_axis = self.geometry.Limit_Float( angle )
else:
self.tan_axis = self.geometry.Limit_Looper( angle, 1 )
# Update
self.SIGNAL_TAN.emit( self.tan_axis )
def Cursor_Snap( self, ex, ey ):
if self.pin_list != None:
distance = []
for i in range( 0, len( self.pin_list ) ):
if self.pin_list[i]["active"] == True:
px = self.pin_list[i][f"{self.chan}_2"] * self.widget_width
py = ( 1 - self.pin_list[i][f"{self.chan}_3"] ) * self.widget_height
dist = self.geometry.Trig_2D_Points_Distance( ex, ey, px, py )
distance.append( ( dist, i ) )
if len( distance ) > 0:
distance.sort()
pin_index = distance[0][1]
if pin_index < 20:
self.pin_index = pin_index
self.SIGNAL_PIN_INDEX.emit( self.pin_index )
# Tablet Interaction
def tabletEvent( self, event ):
self.pressure = event.pressure()
self.update()
# Paint
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Draw Gradient
if len( self.qpixmap_list ) > 0:
try:
# Draw Masks
if self.shape == "3":
triangle = QPainterPath()
triangle.moveTo( int( 0 ), int( 1 ) )
triangle.lineTo( int( self.widget_width ), int( self.widget_height * 0.5 ) )
triangle.lineTo( int( 0 ), int( self.widget_height ) )
painter.setClipPath( triangle )
if self.shape == "R":
diamond = QPainterPath()
diamond.moveTo( int( self.widget_width * 0.5 ), int( 0 ) )
diamond.lineTo( int( self.widget_width ), int( self.widget_height * 0.5 ) )
diamond.lineTo( int( self.widget_width * 0.5 ), int( self.widget_height ) )
diamond.lineTo( int( 0 ), int( self.widget_height * 0.5 ) )
painter.setClipPath( diamond )
# Draw Pixmaps
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QtCore.Qt.NoBrush )
index = int( self.tan_axis * self.tan_range )
qpixmap = self.qpixmap_list[index]
if qpixmap.isNull() == False:
render = qpixmap.scaled( self.widget_width, self.widget_height, Qt.IgnoreAspectRatio, Qt.FastTransformation )
else:
render = qpixmap
painter.drawPixmap( 0, 0, render )
except Exception as e:
try:QtCore.qDebug( f"Pigment.O ERROR | { e }" )
except:pass
# YUV Line
if self.wheel_space == "YUV":
# Variables
line_size = 2
w1 = int( self.widget_width )
h1 = int( self.widget_height )
w2 = int( w1 * 0.5 )
h2 = int( h1 * 0.5 )
# Painter
painter.setPen( QPen( self.color_1, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QtCore.Qt.NoBrush )
# Draw Cross
painter.drawLine( w2, 0, w2, h1 )
painter.drawLine( 0, h2, w1, h2 )
# Draw Primaries
painter.drawLine( int( self.CR[1] * w1 ), int( ( 1-self.CR[2] ) * h1 ), int( self.CM[1] * w1 ), int( ( 1-self.CM[2] ) * h1 ) )
painter.drawLine( int( self.CM[1] * w1 ), int( ( 1-self.CM[2] ) * h1 ), int( self.CB[1] * w1 ), int( ( 1-self.CB[2] ) * h1 ) )
painter.drawLine( int( self.CB[1] * w1 ), int( ( 1-self.CB[2] ) * h1 ), int( self.CC[1] * w1 ), int( ( 1-self.CC[2] ) * h1 ) )
painter.drawLine( int( self.CC[1] * w1 ), int( ( 1-self.CC[2] ) * h1 ), int( self.CG[1] * w1 ), int( ( 1-self.CG[2] ) * h1 ) )
painter.drawLine( int( self.CG[1] * w1 ), int( ( 1-self.CG[2] ) * h1 ), int( self.CY[1] * w1 ), int( ( 1-self.CY[2] ) * h1 ) )
painter.drawLine( int( self.CY[1] * w1 ), int( ( 1-self.CY[2] ) * h1 ), int( self.CR[1] * w1 ), int( ( 1-self.CR[2] ) * h1 ) )
# Analyse Colors
if self.analyse != None:
# Variables
dot = 5
line_size = 2
length = len( self.analyse )
# Draw
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
for i in range( 0, length ):
color = self.analyse[i]
if int( self.tan_axis * 360 ) == int( color[f"{self.chan}_1"] * 360 ):
px = color[f"{self.chan}_2"] * self.widget_width
py = ( 1 - color[f"{self.chan}_3"] ) * self.widget_height
painter.drawEllipse( int( px - dot ), int( py - dot ), int( dot * 2 ), int( dot * 2 ) )
# Pinned Colors
if ( self.color != None and self.pin_list != None ):
# Variables
pin_size = 5
line_size = 2
length = len( self.pin_list )
# Draw
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
for i in range( 0, length ):
if self.pin_list[i]["active"] == True:
if self.shape == "3":
cx = self.pin_list[i]["hsl_2"]
cy = ( 1 - self.pin_list[i]["hsl_3"] )
inter = self.Triangle_Inter( cy, 1, 1 )
painter.drawEllipse(
int( ( cx * inter * self.widget_width ) - pin_size ),
int( ( cy * self.widget_height ) - pin_size ),
int( pin_size * 2 ),
int( pin_size * 2 )
)
if self.shape == "4":
painter.drawEllipse(
int( ( self.pin_list[i][f"{self.chan}_2"] * self.widget_width ) - pin_size ),
int( ( ( 1-self.pin_list[i][f"{self.chan}_3"] ) * self.widget_height ) - pin_size ),
int( pin_size * 2 ),
int( pin_size * 2 )
)
if self.shape == "R":
cx = self.pin_list[i]["hsl_2"]
cy = ( 1 - self.pin_list[i]["hsl_3"] )
mini, maxi, delta = self.Diamond_Inter( cy, 1, 1 )
value = mini + cx * delta
painter.drawEllipse(
int( ( value * self.widget_width ) - pin_size ),
int( ( cy * self.widget_height ) - pin_size ),
int( pin_size * 2 ),
int( pin_size * 2 )
)
# Harmony Colors
if ( self.color != None and self.harmony_list != None ):
# Variables
line_size = 2
radius = 5
# Parsing
points = []
for i in range( 0, len( self.harmony_list ) ):
if self.shape == "3":
cx = self.harmony_list[i]["hsl_2"]
cy = ( 1 - self.harmony_list[i]["hsl_3"] )
inter = self.Triangle_Inter( cy, 1, 1 )
har_x = cx * inter * self.widget_width
har_y = cy * self.widget_height
if self.shape == "4":
chan = self.wheel_space.lower()
har_x = self.harmony_list[i][f"{chan}_2"] * self.widget_width
har_y = ( 1 - self.harmony_list[i][f"{chan}_3"] ) * self.widget_height
if self.shape == "R":
cx = self.harmony_list[i]["hsl_2"]
cy = ( 1 - self.harmony_list[i]["hsl_3"] )
mini, maxi, delta = self.Diamond_Inter( cy, 1, 1 )
value = mini + cx * delta
har_x = value * self.widget_width
har_y = cy * self.widget_height
points.append( ( har_x, har_y ) )
length = len( points )
# Draw Line
painter.setPen( QPen( self.color_1, line_size, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin ) )
painter.setBrush( QtCore.Qt.NoBrush )
for i in range( 1, length ):
painter.drawLine( int( points[i-1][0] ), int( points[i-1][1] ), int( points[i][0] ), int( points[i][1] ) )
if self.harmony_rule in [ "Triadic", "Tetradic" ]:
painter.drawLine( int( points[0][0] ), int( points[0][1] ), int( points[length-1][0] ), int( points[length-1][1] ) )
# Draw Points
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
for i in range( 0, length ):
painter.drawEllipse( int( points[i][0] - radius ), int( points[i][1] - radius ), int( radius * 2 ), int( radius * 2 ) )
# Cursor
size = 10
zoom_size = 100
margin_size = 10
if ( self.press == True and self.zoom == True ):
size = zoom_size
Cursor_Zoom( self, painter, size, margin_size )
elif( self.pressure > self.input_pressure ):
size = zoom_size * self.pressure
Cursor_Zoom( self, painter, size, margin_size )
else:
Cursor_Normal( self, painter, size )
class Panel_HueCircle( QWidget ):
SIGNAL_VALUE = QtCore.pyqtSignal( float )
SIGNAL_RELEASE = QtCore.pyqtSignal( int )
SIGNAL_SUBPANEL = QtCore.pyqtSignal( str )
# Init
def __init__( self, parent ):
super( Panel_HueCircle, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, render_height )
def Init_Variables( self ):
# Widget
self.press = False
self.widget_width = 0
self.widget_height = 0
self.w2 = 0
self.h2 = 0
self.px = 0
self.py = 0
self.side = 0
# Variables
self.wheel_mode = "DIGITAL" # "DIGITAL" "ANALOG"
self.wheel_space = "HSV" # "HSV" "HSL" "HSY" "ARD"
self.huecircle_shape = "None" # "None" "Triangle" "Square" "Diamond"
# Color
self.color = None
self.hex_color = QColor( "#000000" )
self.theme_value = QColor( "#31363b" )
self.colors = [
[1, 0, 0], # Index = 0 > red
[1, 0.5, 0], # Index = 1 > orange
[1, 1, 0], # Index = 2 > yellow
[0, 1, 0], # Index = 3 > green
[0, 1, 1], # Index = 4 > cyan
[0, 0, 1], # Index = 5 > blue
[1, 0, 1], # Index = 6 > magenta
]
# Hue
self.digital = [ 0, 60, 120, 180, 240, 300, 360 ]
self.analog = [ 0, 122, 165, 218, 275, 330, 360 ]
# Harmony Colors
self.harmony_rule = None # "Monochromatic" "Complementary" "Analogous" "Triadic" "Tetradic"
self.harmony_index = None
self.harmony_list = None
self.harmony_span = 0
# Modules
self.geometry = Geometry()
self.convert = None
def Init_Convert( self, convert ):
self.convert = convert
self.update()
# Set
def Set_WheelMode( self, wheel_mode ):
self.wheel_mode = wheel_mode
self.update()
def Set_WheelSpace( self, wheel_space ):
self.wheel_space = wheel_space
self.update()
def Set_Shape( self, huecircle_shape ):
self.huecircle_shape = huecircle_shape
self.update()
def Set_Size( self, widget_width, widget_height, subpanel_shape ):
# Widget
self.widget_width = widget_width
self.widget_height = widget_height
self.w2 = widget_width * 0.5
self.h2 = widget_height * 0.5
# Frame
if self.widget_width >= self.widget_height:
self.side = self.widget_height
self.px = self.w2 - ( self.side * 0.5 )
self.py = 0
else:
self.side = self.widget_width
self.px = 0
self.py = self.h2 - ( self.side * 0.5 )
# Variables
m1 = 2
m2 = 2 * m1
m3 = 0.13
m4 = 1 - ( 2 * m3 )
# Regions
circle_outter = QRegion(
int( self.px - m1 ),
int( self.py - m1 ),
int( self.side + m2 ),
int( self.side + m2 ),
QRegion.Ellipse
)
circle_inner = QRegion(
int( self.px + self.side * m3 ),
int( self.py + self.side * m3 ),
int( self.side * m4 ),
int( self.side * m4 ),
QRegion.Ellipse
)
if subpanel_shape == "None":
region = circle_inner
if subpanel_shape == "Triangle":
x = 0.28
y = 0.13
k = 0.07
t = 1 - k - x
polygon = QPolygon( [
QPoint( int( self.px + x * self.side ), int( self.py + y * self.side ) ),
QPoint( int( self.px + self.side - k * self.side ), int( self.h2 ) ),
QPoint( int( self.px + x * self.side ), int( self.py + self.side - y * self.side ) ),
] )
triangle = QRegion( polygon, Qt.OddEvenFill )
region = triangle.united( circle_inner )
if subpanel_shape == "Square":
k = 0.2
square = QRegion(
int( self.px + self.side * k ),
int( self.py + self.side * k ),
int( self.side - ( 2 * k * self.side ) ),
int( self.side - ( 2 * k * self.side ) ),
QRegion.Rectangle
)
region = square.united( circle_inner )
if subpanel_shape == "Diamond":
k = 0.07
kk = ( 1 - k * 2 ) / 2
polygon = QPolygon( [
QPoint( int( self.w2 ), int( self.h2 - self.side * kk ) ),
QPoint( int( self.w2 + self.side * kk ), int( self.h2 ) ),
QPoint( int( self.w2 ), int( self.h2 + self.side * kk ) ),
QPoint( int( self.w2 - self.side * kk ), int( self.h2 ) ),
] )
diamond = QRegion( polygon, Qt.OddEvenFill )
region = diamond.united( circle_inner )
# Mask
mask_region = circle_outter.subtracted( region )
self.setMask( mask_region )
# Update
self.update()
def Set_Theme( self, theme_value ):
self.theme_value = QColor( theme_value )
self.update()
# Update
def Update_Panel( self, color ):
self.color = color
self.update()
def Update_Colors( self, colors ):
self.colors = colors
self.update()
def Update_Harmony( self, harmony_rule, harmony_index, harmony_list ):
self.harmony_rule = harmony_rule
self.harmony_index = harmony_index
self.harmony_list = harmony_list
self.update()
def Update_Span( self, harmony_span ):
self.harmony_span = harmony_span
self.update()
# Mouse Interaction
def mousePressEvent( self, event ):
# Variables
self.press = True
# LMB Neutral
if event.buttons() == QtCore.Qt.LeftButton:
self.Cursor_Angle( event )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
self.press = False
self.Context_Menu( event )
# Update
self.update()
def mouseMoveEvent( self, event ):
# LMB Neutral
if event.buttons() == QtCore.Qt.LeftButton:
self.Cursor_Angle( event )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# Update
self.update()
def mouseDoubleClickEvent( self, event ):
# LMB Neutral
if event.buttons() == QtCore.Qt.LeftButton:
self.Cursor_Angle( event )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# Update
self.update()
def mouseReleaseEvent( self, event ):
# Variables
self.press = False
# Update
self.SIGNAL_RELEASE.emit( 0 )
self.update()
def Cursor_Angle( self, event ):
# Variables
ex = event.x()
ey = self.widget_height - event.y()
# Angle Measure
if self.wheel_mode == "DIGITAL":
angle = self.geometry.Trig_2D_Points_Lines_Angle( ex, ey, self.w2, self.h2, 0, self.h2 )
if event.modifiers() == QtCore.Qt.ShiftModifier:
angle = int( angle )
if event.modifiers() == QtCore.Qt.ControlModifier:
angle = self.geometry.Limit_Angle( angle, 2.5 )
value = angle / 360
if self.wheel_mode == "ANALOG":
px = self.w2 - ( self.side * 0.5 )
py = self.h2 - ( self.side * 0.314 ) # Inverted for the formula
angle = self.geometry.Trig_2D_Points_Lines_Angle( ex, ey, self.w2, self.h2, px, py )
if event.modifiers() == QtCore.Qt.ShiftModifier:
angle = int( angle )
if event.modifiers() == QtCore.Qt.ControlModifier:
angle = self.geometry.Limit_Angle( angle, 2.5 )
value = self.convert.huea_to_hued( self.geometry.Limit_Looper( angle, 360 ) / 360 )
# Emit Values
self.SIGNAL_VALUE.emit( value )
# Context
def Context_Menu( self, event ):
if self.press == False:
# Menu
cmenu = QMenu( self )
# Action
cmenu_sn = cmenu.addAction( "None" )
cmenu_st = cmenu.addAction( "Triangle" )
cmenu_ss = cmenu.addAction( "Square" )
cmenu_sd = cmenu.addAction( "Diamond" )
cmenu_sn.setCheckable( True )
cmenu_st.setCheckable( True )
cmenu_ss.setCheckable( True )
cmenu_sd.setCheckable( True )
cmenu_sn.setChecked( self.huecircle_shape == "None" )
cmenu_st.setChecked( self.huecircle_shape == "Triangle" )
cmenu_ss.setChecked( self.huecircle_shape == "Square" )
cmenu_sd.setChecked( self.huecircle_shape == "Diamond" )
action = cmenu.exec_( self.mapToGlobal( event.pos() ) )
# Triggers
if action == cmenu_sn:
self.huecircle_shape = "None"
self.SIGNAL_SUBPANEL.emit( self.huecircle_shape )
if action == cmenu_st:
self.huecircle_shape = "Triangle"
self.SIGNAL_SUBPANEL.emit( self.huecircle_shape )
if action == cmenu_ss:
self.huecircle_shape = "Square"
self.SIGNAL_SUBPANEL.emit( self.huecircle_shape )
if action == cmenu_sd:
self.huecircle_shape = "Diamond"
self.SIGNAL_SUBPANEL.emit( self.huecircle_shape )
# Paint
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Variables
line_width = 4
circle_0, circle_1, circle_2, circle_3 = Circles( self, painter )
# Hue
if self.wheel_mode == "DIGITAL":
index = "hue_d"
if self.wheel_mode == "ANALOG":
index = "hue_a"
# Circle Points
radius = 0.5
circle_points = []
if self.harmony_rule != None:
for i in range( 0, len( self.harmony_list ) ):
if self.wheel_mode == "DIGITAL":
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius, self.harmony_list[i][index] * 360 )
if self.wheel_mode == "ANALOG":
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius, ( self.harmony_list[i][index] * 360 ) - hue_a )
circle_points.append( [ px, py ] )
else:
if self.wheel_mode == "DIGITAL":
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius, self.color[index] * 360 )
if self.wheel_mode == "ANALOG":
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius, ( self.color[index] * 360 ) - hue_a )
circle_points.append( [ px, py ] )
length = len( circle_points )
# Divisions
div = []
margin = 0.01
if self.wheel_mode == "DIGITAL":
for i in range( 0, len( self.digital ) ):
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius - margin, self.digital[i] )
div.append( [ px, py ] )
if self.wheel_mode == "ANALOG":
for i in range( 0, len( self.analog ) ):
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius - margin, self.analog[i] - hue_a )
div.append( [ px, py ] )
# Dark Border
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.theme_value ) )
circle_02 = circle_0.subtracted( circle_2 )
painter.drawPath( circle_02 )
# Dark Border
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.theme_value ) )
circle_02 = circle_0.subtracted( circle_2 )
painter.drawPath( circle_02 )
# Dark Lines
painter.setPen( QPen( self.theme_value, line_width, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QtCore.Qt.NoBrush )
s1 = self.side
s2 = self.side * 0.5
if self.wheel_mode == "DIGITAL":
for i in range( 0, len( self.digital ) ):
painter.drawLine( int( div[i][0] ), int( div[i][1] ), int( self.w2 ), int( self.h2 ) )
if self.wheel_mode == "ANALOG":
for i in range( 0, len( self.analog ) ):
painter.drawLine( int( div[i][0] ), int( div[i][1] ), int( self.w2 ), int( self.h2 ) )
# Line Gray
painter.setPen( QPen( self.color_1, line_width, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QtCore.Qt.NoBrush )
circle_13 = circle_1.subtracted( circle_3 )
if length > 0:
line_gray = QPainterPath()
for i in range( 0, length ):
# Variables
px = circle_points[i][0]
py = circle_points[i][1]
# Draw
line_gray.moveTo( int( self.w2 ), int( self.h2 ) )
line_gray.lineTo( int( px ), int( py ) )
painter.setClipPath( circle_13 )
painter.drawPath( line_gray )
# Hue Gradient
painter.setPen( QtCore.Qt.NoPen )
d = 255
if self.wheel_mode == "DIGITAL":
hue = QConicalGradient( QPoint( int( self.w2 ), int( self.h2 ) ), 180 )
hue.setColorAt( 0.000, QColor( int( self.colors[0][0] * d ), int( self.colors[0][1] * d ), int( self.colors[0][2] * d ) ) ) # RED
hue.setColorAt( 0.166, QColor( int( self.colors[6][0] * d ), int( self.colors[6][1] * d ), int( self.colors[6][2] * d ) ) ) # MAGENTA
hue.setColorAt( 0.333, QColor( int( self.colors[5][0] * d ), int( self.colors[5][1] * d ), int( self.colors[5][2] * d ) ) ) # BLUE
hue.setColorAt( 0.500, QColor( int( self.colors[4][0] * d ), int( self.colors[4][1] * d ), int( self.colors[4][2] * d ) ) ) # CYAN
hue.setColorAt( 0.666, QColor( int( self.colors[3][0] * d ), int( self.colors[3][1] * d ), int( self.colors[3][2] * d ) ) ) # GREEN
hue.setColorAt( 0.833, QColor( int( self.colors[2][0] * d ), int( self.colors[2][1] * d ), int( self.colors[2][2] * d ) ) ) # YELLOW
hue.setColorAt( 1.000, QColor( int( self.colors[0][0] * d ), int( self.colors[0][1] * d ), int( self.colors[0][2] * d ) ) ) # RED
if self.wheel_mode == "ANALOG":
hue = QConicalGradient( QPoint( int( self.w2 ), int( self.h2 ) ), 210 )
hue.setColorAt( 0.000, QColor( int( self.colors[0][0] * d ), int( self.colors[0][1] * d ), int( self.colors[0][2] * d ) ) ) # RED
hue.setColorAt( 0.083, QColor( int( self.colors[6][0] * d ), int( self.colors[6][1] * d ), int( self.colors[6][2] * d ) ) ) # MAGENTA
hue.setColorAt( 0.236, QColor( int( self.colors[5][0] * d ), int( self.colors[5][1] * d ), int( self.colors[5][2] * d ) ) ) # BLUE
hue.setColorAt( 0.394, QColor( int( self.colors[4][0] * d ), int( self.colors[4][1] * d ), int( self.colors[4][2] * d ) ) ) # CYAN
hue.setColorAt( 0.541, QColor( int( self.colors[3][0] * d ), int( self.colors[3][1] * d ), int( self.colors[3][2] * d ) ) ) # GREEN
hue.setColorAt( 0.661, QColor( int( self.colors[2][0] * d ), int( self.colors[2][1] * d ), int( self.colors[2][2] * d ) ) ) # YELLOW
hue.setColorAt( 0.833, QColor( int( self.colors[1][0] * d ), int( self.colors[1][1] * d ), int( self.colors[1][2] * d ) ) ) # ORANGE
hue.setColorAt( 1.000, QColor( int( self.colors[0][0] * d ), int( self.colors[0][1] * d ), int( self.colors[0][2] * d ) ) ) # RED
painter.setBrush( QBrush( hue ) )
circle_01 = circle_0.subtracted( circle_1 )
painter.setClipPath( circle_01 )
painter.drawRect( int( self.px ), int( self.py ), int( self.side ), int( self.side ) )
# Line Dark over Hue
painter.setPen( QPen( self.theme_value, line_width, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QtCore.Qt.NoBrush )
circle_01 = circle_0.subtracted( circle_1 )
painter.setClipPath( circle_01 )
for i in range( 0, length ):
painter.drawLine( int( circle_points[i][0] ), int( circle_points[i][1] ), int( self.w2 ), int( self.h2 ) )
class Panel_Gamut( QWidget ):
SIGNAL_VALUE = QtCore.pyqtSignal( dict )
SIGNAL_TAN = QtCore.pyqtSignal( float )
SIGNAL_RELEASE = QtCore.pyqtSignal( int )
SIGNAL_MASK = QtCore.pyqtSignal( str )
SIGNAL_PROFILE = QtCore.pyqtSignal( list )
SIGNAL_PIN_INDEX = QtCore.pyqtSignal( int )
SIGNAL_PIN_EDIT = QtCore.pyqtSignal( dict )
# Init
def __init__( self, parent ):
super( Panel_Gamut, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, render_height )
def Init_Variables( self ):
# Widget
self.press = False
self.widget_width = 0
self.widget_height = 0
self.w2 = 0
self.h2 = 0
self.event_x = 0
self.event_y = 0
self.origin_x = 0
self.origin_y = 0
self.origin_tan_axis = 0
self.origin_angle = 0
self.origin_dist = 0
self.previous_dist = 0
self.px = 0
self.py = 0
self.side = 0
self.pressure = 0
self.input_pressure = 0.5
self.region = None # "RING" "DISK"
# Disk
self.disk_var = 0.068
self.disk_radius = 0.5 * ( 1 - ( 2 * self.disk_var ) ) # 0.432
self.disk_x = 0
self.disk_y = 0
self.disk_side = 0
# Display
self.zoom = False
self.tan_axis = 0 # 0-255 because of background index
self.tan_range = 255
# Format
self.directory = None # Path
self.shape = None # "CD" "CA"
self.d_cm = None # "A" "RGB" "CMYK" "YUV" "XYZ" "LAB"
self.chan = None # "hsv" "hsl" "hsy" "ard"
# Wheel
self.wheel_mode = "DIGITAL" # "DIGITAL" "ANALOG"
self.wheel_space = "HSV" # "HSV" "HSL" "HSY" "ARD"
# Color
self.color = None
self.hex_color = QColor( "#000000" )
self.theme_value = QColor( "#31363b" )
# Harmony Colors
self.harmony_index = None
self.harmony_list = None
# Pinned Colors
self.pin_index = None
self.pin_list = None
# Analyse Colors
self.analyse = None
# Hue
self.digital = [ 0, 60, 120, 180, 240, 300, 360 ]
self.analog = [ 0, 122, 165, 218, 275, 330, 360 ]
# Harmony Colors
self.harmony_rule = None # "Monochromatic" "Complementary" "Analogous" "Triadic" "Tetradic"
self.harmony_index = None
self.harmony_list = None
self.harmony_span = 0
# Gamut
self.gamut_mask = "None" # "None" "Triangle" "Square" "Circle" "2 Circle" "3 Pie" "Reset"
self.gamut_index = None
self.gamut_rotation = None
# Gamut Neutral
self.neutral_1tri = [ ( 0.5, 0.5 ), ( 0.5, 0.1 ), ( 0.84641, 0.7 ), ( 0.15359, 0.7 ) ] # Centroid + Polygon
self.neutral_1squ = [ ( 0.5, 0.5 ), ( 0.5, 0.1 ), ( 0.9, 0.5 ), ( 0.5, 0.9 ), ( 0.1, 0.5 ) ] # Centroid + Polygon
self.neutral_1cir = [ ( 0.5, 0.5 ), ( 0.5, 0.1 ), ( 0.9, 0.5 ), ( 0.5, 0.9 ), ( 0.1, 0.5 ) ] # Centroid + Polygon
self.neutral_2cir = [ ( 0.5, 0.275 ), ( 0.5, 0.1 ), ( 0.675, 0.275 ), ( 0.5, 0.45 ), ( 0.325, 0.275 ), # Circle 1 ( Centroid + Polygon )
( 0.5, 0.725 ), ( 0.5, 0.55 ), ( 0.675, 0.725 ), ( 0.5, 0.9 ), ( 0.325, 0.725 ) ] # Circle 2 ( Centroid + Polygon )
self.neutral_3pie = [ ( 0.5, 0.5 ), ( 0.5, 0.15359 ), ( 0.8, 0.32679 ), ( 0.8, 0.67321 ), ( 0.5, 0.84641 ), ( 0.2, 0.67321 ), ( 0.2, 0.32679 ) ] # Centroid + Polygon
# Gamut Lists
self.gamut_1tri = self.neutral_1tri.copy()
self.gamut_1squ = self.neutral_1squ.copy()
self.gamut_1cir = self.neutral_1cir.copy()
self.gamut_2cir = self.neutral_2cir.copy()
self.gamut_3pie = self.neutral_3pie.copy()
# Modules
self.geometry = Geometry()
self.convert = None
def Init_Convert( self, convert ):
self.convert = convert
self.update()
# Set
def Set_ColorModel( self, d_cm ):
self.d_cm = d_cm
self.Set_ColorSpace_inDocument( self.directory, self.d_cm, self.wheel_space, self.shape )
self.update()
def Set_WheelMode( self, wheel_mode ):
self.wheel_mode = wheel_mode
if self.wheel_mode == "DIGITAL":
self.shape = "D"
if self.wheel_mode == "ANALOG":
self.shape = "A"
self.Set_ColorSpace_inDocument( self.directory, self.d_cm, self.wheel_space, self.shape )
self.update()
def Set_WheelSpace( self, wheel_space ):
self.wheel_space = wheel_space
self.Set_ColorSpace_inDocument( self.directory, self.d_cm, self.wheel_space, self.shape )
self.update()
def Set_ColorSpace_inDocument( self, directory, d_cm, wheel_space, shape ):
# Variables
self.directory = directory
self.d_cm = d_cm
self.wheel_space = wheel_space
self.shape = shape
self.chan = self.wheel_space.lower()
# Cursor
if self.color != None:
self.event_x, self.event_y = self.Update_Cursor( self.color )
# Read Zip File
location = os.path.join( self.directory, panel )
location = os.path.join( location, f"{ self.d_cm }_{ self.wheel_space }_{ self.shape }.zip" )
self.qpixmap_list = Read_Zip( self, location, self.tan_range, self.wheel_space, self.shape )
# Update
self.update()
def Set_Size( self, widget_width, widget_height ):
# Widget
self.widget_width = widget_width
self.widget_height = widget_height
self.w2 = widget_width * 0.5
self.h2 = widget_height * 0.5
# Frame
if self.widget_width >= self.widget_height:
self.side = self.widget_height
self.px = self.w2 - ( self.side * 0.5 )
self.py = 0
else:
self.side = self.widget_width
self.px = 0
self.py = self.h2 - ( self.side * 0.5 )
# Disk Coordinates
self.disk_x = self.px + self.disk_var * self.side
self.disk_y = self.py + self.disk_var * self.side
self.disk_side = ( 1 - 2 * self.disk_var ) * self.side
# Update
self.update()
def Set_Theme( self, theme_value ):
self.theme_value = QColor( theme_value )
self.update()
# Update
def Update_Panel( self, color ):
# Variables
self.color = color
self.hex_color = QColor( color["hex6"] )
# Location of Cursor
self.event_x, self.event_y = self.Update_Cursor( self.color )
self.previous_dist = self.geometry.Trig_2D_Points_Distance( self.event_x, self.event_y, self.w2, self.h2 )
# Update
self.update()
def Update_Cursor( self, color ):
# Angle
if self.wheel_mode == "DIGITAL":
angle = color["hue_d"] * 360
if self.wheel_mode == "ANALOG":
angle = color["hue_a"] * 360 - hue_a
# Radius
radius = color[f"{ self.chan }_2"]
self.tan_axis = color[f"{ self.chan }_3"]
# Location
ex, ey = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.disk_side * 0.5, radius, angle )
return ex, ey
def Update_Harmony( self, harmony_rule, harmony_index, harmony_list ):
self.harmony_rule = harmony_rule
self.harmony_index = harmony_index
self.harmony_list = harmony_list
self.update()
def Update_Pin( self, pin_list ):
self.pin_list = pin_list
self.update()
def Update_Analyse( self, analyse ):
self.analyse = analyse
self.update()
def Update_Mask( self, gamut_mask ):
self.gamut_mask = gamut_mask
self.update()
def Update_Profile( self, gamut_profile ):
self.gamut_1tri = gamut_profile[0]
self.gamut_1squ = gamut_profile[1]
self.gamut_1cir = gamut_profile[2]
self.gamut_2cir = gamut_profile[3]
self.gamut_3pie = gamut_profile[4]
self.update()
# Emit
def Signal_Profile( self ):
profile = [ self.gamut_1tri, self.gamut_1squ, self.gamut_1cir, self.gamut_2cir, self.gamut_3pie ]
self.SIGNAL_PROFILE.emit( profile )
# Mouse Interaction
def mousePressEvent( self, event ):
# Event
ex = event.x()
ey = event.y()
# Variables
self.press = True
self.origin_x = ex
self.origin_y = ey
self.origin_tan_axis = self.tan_axis
self.origin_angle = self.geometry.Trig_2D_Points_Lines_Angle( 0, self.h2, self.w2, self.h2, ex, ey )
self.origin_dist = self.geometry.Trig_2D_Points_Distance( ex, ey, self.w2, self.h2 )
self.region = self.geometry.Trig_2D_Points_Distance( ex, ey, self.w2, self.h2 ) <= ( self.side * self.disk_radius )
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( ex, ey, False )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( ex, ey, False )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Tangent( ex, ey )
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Snap( ex, ey )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
self.press = False
self.Context_Menu( event )
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
self.Cursor_Snap( ex, ey )
# Rotate
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == ( QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier | QtCore.Qt.AltModifier ) ):
self.gamut_rotation = self.Gamut_Rotation()
# Update
self.update()
def mouseMoveEvent( self, event ):
# Event
ex = event.x()
ey = event.y()
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( ex, ey, False )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( ex, ey, False )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Tangent( ex, ey )
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Snap( ex, ey )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
# self.Cursor_Move( ex, ey )
self.Cursor_Position( ex, ey, False )
# Rotate
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == ( QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier | QtCore.Qt.AltModifier ) ):
self.Cursor_Rotation( ex, ey )
# Update
self.update()
def mouseDoubleClickEvent( self, event ):
# Event
ex = event.x()
ey = event.y()
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( ex, ey, False )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( ex, ey, False )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Tangent( ex, ey )
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Snap( ex, ey )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
# self.Cursor_Move( ex, ey )
self.Cursor_Position( ex, ey, False )
# Rotate
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == ( QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier | QtCore.Qt.AltModifier ) ):
self.Cursor_Rotation( ex, ey )
# Update
self.update()
def mouseReleaseEvent( self, event ):
# Previous
self.previous_dist = self.geometry.Trig_2D_Points_Distance( self.event_x, self.event_y, self.w2, self.h2 )
# Variables
self.press = False
self.zoom = False
self.pressure = 0
self.region = None
self.origin_x = 0
self.origin_y = 0
self.origin_angle = 0
self.origin_dist = 0
# Gamut
self.gamut_index = None
self.gamut_rotation = None
# Pin
self.pin_index = None
# Updates
self.SIGNAL_RELEASE.emit( 0 )
self.update()
def Cursor_Position( self, ex, ey, clip ):
# Hue
angle = self.geometry.Trig_2D_Points_Lines_Angle( 0, self.h2, self.w2, self.h2, ex, ey )
if clip == True:
angle = self.geometry.Limit_Angle( angle, 2.5 )
if self.wheel_mode == "DIGITAL":
hue = angle / 360
if self.wheel_mode == "ANALOG":
angle = self.geometry.Limit_Looper( angle + hue_a, 360 )
hue = self.convert.huea_to_hued( angle / 360 )
# Saturation
distance = 0
radius = self.side * self.disk_radius
if self.region == False: # Ring
distance = self.previous_dist
self.event_x, self.event_y = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.disk_side, distance, angle )
if self.region == True: # Disk
distance = self.geometry.Trig_2D_Points_Distance( ex, ey, self.w2, self.h2 )
if distance >= radius:
distance = radius
self.event_x, self.event_y = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.disk_side, 0.5, angle )
else:
self.event_x = ex
self.event_y = ey
# Variables
c1 = hue
c2 = distance / radius
# Edit Dot
if self.gamut_index != None:
# Move
mx = ( self.event_x - self.disk_x ) / self.disk_side
my = ( self.event_y - self.disk_y ) / self.disk_side
# Apply
lista = self.Gamut_List( self.gamut_mask )
if ( self.gamut_mask != "2 Circle" and self.gamut_index != 0 ):
lista[self.gamut_index] = ( mx, my )
if ( self.gamut_mask == "2 Circle" and self.gamut_index != 0 and self.gamut_index != 5 ):
lista[self.gamut_index] = ( mx, my )
elif self.pin_index != None:
pin = { "pin_index" : self.pin_index, "c1" : c1, "c2" : c2 }
self.SIGNAL_PIN_EDIT.emit( pin )
# Emition
value = { "c1" : c1, "c2" : c2 }
self.SIGNAL_VALUE.emit( value )
# Update Centroids
self.Gamut_Centroid( self.gamut_mask )
def Cursor_Tangent( self, ex, ey ):
if self.region == False: # Ring
self.Cursor_Position( ex, ey, True )
if self.region == True: # Disk
# Hue
delta_hue = ( ( ex - self.origin_x ) / self.widget_width )
self.tan_axis = self.geometry.Limit_Float( self.origin_tan_axis + delta_hue )
# Update
self.SIGNAL_TAN.emit( self.tan_axis )
def Cursor_Snap( self, ex, ey ):
# Gamut Profile
lista = self.Gamut_List( self.gamut_mask )
points = self.Gamut_Points( ex, ey, lista )
# Pins
points = self.Pin_Points( ex, ey, points )
# Position
if len( points ) > 0:
points.sort( key = lambda row: row[0] )
check_gamut = points[0][3] # gamut_index
check_pin = points[0][4] # pin_index
if check_gamut != None:
self.gamut_index = check_gamut
self.Cursor_Position( points[0][1], points[0][2], False )
elif check_pin != None:
self.pin_index = check_pin
self.SIGNAL_PIN_INDEX.emit( check_pin )
def Cursor_Rotation( self, ex, ey ):
lista = self.Gamut_List( self.gamut_mask )
ang_new = self.geometry.Trig_2D_Points_Lines_Angle( 0, self.h2, self.w2, self.h2, ex, ey )
delta = self.geometry.Limit_Looper( ang_new - self.origin_angle, 360 )
for i in range( 0, len( lista ) ):
# Read
dis = self.gamut_rotation[i][0]
angle = self.gamut_rotation[i][1]
if dis != 0:
radius = dis / self.disk_side
angle = self.geometry.Limit_Looper( angle + delta, 360 )
dx, dy = self.geometry.Trig_2D_Angle_Circle( 0.5, 0.5, 1, radius, angle )
lista[i] = ( dx, dy )
# Update Centroids
self.Gamut_Centroid( self.gamut_mask )
# Gamut
def Gamut_List( self, mode ):
if mode == "None":
lista = []
if mode == "Triangle":
lista = self.gamut_1tri
if mode == "Square":
lista = self.gamut_1squ
if mode == "Circle":
lista = self.gamut_1cir
if mode == "2 Circle":
lista = self.gamut_2cir
if mode == "3 Pie":
lista = self.gamut_3pie
return lista
def Gamut_Rotation( self ):
lista = self.Gamut_List( self.gamut_mask )
rotation = []
for i in range( 0, len( lista ) ):
px = self.disk_x + lista[i][0] * self.disk_side
py = self.disk_y + lista[i][1] * self.disk_side
dist = self.geometry.Trig_2D_Points_Distance( px, py, self.w2, self.h2 )
angle = self.geometry.Trig_2D_Points_Lines_Angle( 0, self.h2, self.w2, self.h2, px, py )
rotation.append( ( dist, angle ) )
return rotation
def Gamut_Centroid( self, mode ):
# Update Centroid
if mode == "Triangle":
p = self.gamut_1tri
c = self.geometry.Trig_2D_Centroid_Triangle( p[1][0], p[1][1], p[2][0], p[2][1], p[3][0], p[3][1] )
self.gamut_1tri[0] = ( c[0], c[1] )
if mode == "Square":
p = self.gamut_1squ
c = self.geometry.Trig_2D_Centroid_Square( p[1][0], p[1][1], p[2][0], p[2][1], p[3][0], p[3][1], p[4][0], p[4][1] )
self.gamut_1squ[0] = ( c[0], c[1] )
if mode == "Circle":
p = self.gamut_1cir
c = self.geometry.Trig_2D_Centroid_Square( p[1][0], p[1][1], p[2][0], p[2][1], p[3][0], p[3][1], p[4][0], p[4][1] )
self.gamut_1cir[0] = ( c[0], c[1] )
if mode == "2 Circle":
# Circle 1
p = self.gamut_2cir[0:5]
c = self.geometry.Trig_2D_Centroid_Square( p[1][0], p[1][1], p[2][0], p[2][1], p[3][0], p[3][1], p[4][0], p[4][1] )
self.gamut_2cir[0] = ( c[0], c[1] )
# Circle 2
p = self.gamut_2cir[5:10]
c = self.geometry.Trig_2D_Centroid_Square( p[1][0], p[1][1], p[2][0], p[2][1], p[3][0], p[3][1], p[4][0], p[4][1] )
self.gamut_2cir[5] = ( c[0], c[1] )
# Save Profile
self.Signal_Profile()
# Points
def Gamut_Points( self, ex, ey, lista ):
points = []
for i in range( 0, len( lista ) ):
px = self.disk_x + lista[i][0] * self.disk_side
py = self.disk_y + lista[i][1] * self.disk_side
distance = self.geometry.Trig_2D_Points_Distance( ex, ey, px, py )
points.append( ( distance, px, py, i, None ) ) # dist px py gamut_index, pin_index
return points
def Pin_Points( self, ex, ey, points ):
if self.pin_list != None:
for i in range( 0, len( self.pin_list ) - 1 ):
if self.pin_list[i]["active"] == True:
if self.wheel_mode == "DIGITAL":
angle = self.pin_list[i]["hue_d"] * 360
if self.wheel_mode == "ANALOG":
angle = self.pin_list[i]["hue_a"] * 360 - hue_a
radius = self.pin_list[i][f"{self.chan}_2"]
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.disk_side * 0.5, radius, angle )
distance = self.geometry.Trig_2D_Points_Distance( ex, ey, px, py )
points.append( ( distance, px, py, None, i ) ) # dist px py gamut_index, pin_index
return points
# Context
def Context_Menu( self, event ):
if self.press == False:
# Menu
cmenu = QMenu( self )
# Action
cmenu_gn = cmenu.addAction( "None" )
cmenu_gt = cmenu.addAction( "Triangle" )
cmenu_gs = cmenu.addAction( "Square" )
cmenu_g1c = cmenu.addAction( "Circle" )
cmenu_g2c = cmenu.addAction( "2 Circle" )
cmenu_g3p = cmenu.addAction( "3 Pie" )
cmenu_gr = cmenu.addAction( "Reset" )
cmenu_gn.setCheckable( True )
cmenu_gt.setCheckable( True )
cmenu_gs.setCheckable( True )
cmenu_g1c.setCheckable( True )
cmenu_g2c.setCheckable( True )
cmenu_g3p.setCheckable( True )
cmenu_gn.setChecked( self.gamut_mask == "None" )
cmenu_gt.setChecked( self.gamut_mask == "Triangle" )
cmenu_gs.setChecked( self.gamut_mask == "Square" )
cmenu_g1c.setChecked( self.gamut_mask == "Circle" )
cmenu_g2c.setChecked( self.gamut_mask == "2 Circle" )
cmenu_g3p.setChecked( self.gamut_mask == "3 Pie" )
# Mapping
action = cmenu.exec_( self.mapToGlobal( event.pos() ) )
# Triggers
if action == cmenu_gn:
self.gamut_mask = "None"
self.SIGNAL_MASK.emit( self.gamut_mask )
if action == cmenu_gt:
self.gamut_mask = "Triangle"
self.SIGNAL_MASK.emit( self.gamut_mask )
if action == cmenu_gs:
self.gamut_mask = "Square"
self.SIGNAL_MASK.emit( self.gamut_mask )
if action == cmenu_g1c:
self.gamut_mask = "Circle"
self.SIGNAL_MASK.emit( self.gamut_mask )
if action == cmenu_g2c:
self.gamut_mask = "2 Circle"
self.SIGNAL_MASK.emit( self.gamut_mask )
if action == cmenu_g3p:
self.gamut_mask = "3 Pie"
self.SIGNAL_MASK.emit( self.gamut_mask )
if action == cmenu_gr:
if self.gamut_mask == "Triangle":
self.gamut_1tri = self.neutral_1tri.copy()
if self.gamut_mask == "Square":
self.gamut_1squ = self.neutral_1squ.copy()
if self.gamut_mask == "Circle":
self.gamut_1cir = self.neutral_1cir.copy()
if self.gamut_mask == "2 Circle":
self.gamut_2cir = self.neutral_2cir.copy()
if self.gamut_mask == "3 Pie":
self.gamut_3pie = self.neutral_3pie.copy()
self.update()
self.Signal_Profile()
# Tablet Interaction
def tabletEvent( self, event ):
self.pressure = event.pressure()
self.update()
# Paint
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Variables
line_width = 5
circle_0, circle_1, circle_2, circle_3 = Circles( self, painter )
# Hue
if self.wheel_mode == "DIGITAL":
hue_index = "hue_d"
if self.wheel_mode == "ANALOG":
hue_index = "hue_a"
# Circle Points
radius = 0.5
circle_points = []
if self.harmony_rule != None:
for i in range( 0, len( self.harmony_list ) ):
if self.wheel_mode == "DIGITAL":
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius, self.harmony_list[i][hue_index] * 360 )
if self.wheel_mode == "ANALOG":
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius, ( self.harmony_list[i][hue_index] * 360 ) - hue_a )
circle_points.append( [ px, py ] )
else:
if self.wheel_mode == "DIGITAL":
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius, self.color[hue_index] * 360 )
if self.wheel_mode == "ANALOG":
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius, ( self.color[hue_index] * 360 ) - hue_a )
circle_points.append( [ px, py ] )
length = len( circle_points )
# Divisions
div = []
if self.wheel_mode == "DIGITAL":
for i in range( 0, len( self.digital ) ):
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius, self.digital[i] )
div.append( [ px, py ] )
if self.wheel_mode == "ANALOG":
for i in range( 0, len( self.analog ) ):
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius, self.analog[i] - hue_a )
div.append( [ px, py ] )
# Outter Mask
outline = QPainterPath()
outline.addEllipse( 0, 0, self.widget_width, self.widget_height )
painter.setClipPath( circle_0 )
# Dark Border
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.theme_value ) )
circle_02 = circle_0.subtracted( circle_2 )
painter.drawPath( circle_02 )
# Dark Lines
painter.setPen( QPen( self.theme_value, line_width, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QtCore.Qt.NoBrush )
if self.wheel_mode == "DIGITAL":
for i in range( 0, len( self.digital ) ):
painter.drawLine( int( div[i][0] ), int( div[i][1] ), int( self.w2 ), int( self.h2 ) )
if self.wheel_mode == "ANALOG":
for i in range( 0, len( self.analog ) ):
painter.drawLine( int( div[i][0] ), int( div[i][1] ), int( self.w2 ), int( self.h2 ) )
# Line Gray
painter.setPen( QPen( self.color_1, line_width, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QtCore.Qt.NoBrush )
circle_02 = circle_0.subtracted( circle_2 )
if length > 0:
line_gray = QPainterPath()
for i in range( 0, length ):
# Variables
px = circle_points[i][0]
py = circle_points[i][1]
# Draw
line_gray.moveTo( self.w2, self.h2 )
line_gray.lineTo( px, py )
painter.setClipPath( circle_02 )
painter.drawPath( line_gray )
# Reset Mask
square = QPainterPath()
square.moveTo( int( 0 ), int( 0 ) )
square.lineTo( int( self.widget_width ), int( 0 ) )
square.lineTo( int( self.widget_width ), int( self.widget_height ) )
square.lineTo( int( 0 ), int( self.widget_height ) )
painter.setClipPath( square )
# Draw Gradient
if len( self.qpixmap_list ) > 0:
try:
# Pixmaps
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QtCore.Qt.NoBrush )
tan_index = int( self.tan_axis * self.tan_range )
qpixmap = self.qpixmap_list[tan_index]
# Brush
qbrush = QBrush( qpixmap )
if qpixmap.isNull() == False:
qtransform = QTransform()
qtransform.translate( int( self.disk_x ), int( self.disk_y ) )
qtransform.scale( int( self.disk_side ) / qpixmap.width(), int( self.disk_side ) / qpixmap.height() )
qbrush.setTransform( qtransform )
# Painter
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( qbrush )
except Exception as e:
try:QtCore.qDebug( f"Pigment.O ERROR | { e }" )
except:pass
# Polygon
dot = 5
line_size = 2
key = self.gamut_mask
gdx = self.disk_x
gdy = self.disk_y
gds = self.disk_side
if self.gamut_mask == "None":
painter.setPen( QtCore.Qt.NoPen )
painter.drawEllipse( int( gdx ), int( gdy ), int( gds ), int( gds ) )
if self.gamut_mask == "Triangle":
# Polygon
painter.setPen( QtCore.Qt.NoPen )
poly = QPolygon( [
QPoint( int( gdx + gds * self.gamut_1tri[1][0] ), int( gdy + gds * self.gamut_1tri[1][1] ) ),
QPoint( int( gdx + gds * self.gamut_1tri[2][0] ), int( gdy + gds * self.gamut_1tri[2][1] ) ),
QPoint( int( gdx + gds * self.gamut_1tri[3][0] ), int( gdy + gds * self.gamut_1tri[3][1] ) ),
] )
painter.drawPolygon( poly )
# Display Subjective Primaries
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_1tri[0][0] - dot ), int( gdy + gds * self.gamut_1tri[0][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_1tri[1][0] - dot ), int( gdy + gds * self.gamut_1tri[1][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_1tri[2][0] - dot ), int( gdy + gds * self.gamut_1tri[2][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_1tri[3][0] - dot ), int( gdy + gds * self.gamut_1tri[3][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
if self.gamut_mask == "Square":
# Polygon
painter.setPen( QtCore.Qt.NoPen )
poly = QPolygon( [
QPoint( int( gdx + gds * self.gamut_1squ[1][0] ), int( gdy + gds * self.gamut_1squ[1][1] ) ),
QPoint( int( gdx + gds * self.gamut_1squ[2][0] ), int( gdy + gds * self.gamut_1squ[2][1] ) ),
QPoint( int( gdx + gds * self.gamut_1squ[3][0] ), int( gdy + gds * self.gamut_1squ[3][1] ) ),
QPoint( int( gdx + gds * self.gamut_1squ[4][0] ), int( gdy + gds * self.gamut_1squ[4][1] ) ),
] )
painter.drawPolygon( poly )
# Display Subjective Primaries
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_1squ[0][0] - dot ), int( gdy + gds * self.gamut_1squ[0][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_1squ[1][0] - dot ), int( gdy + gds * self.gamut_1squ[1][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_1squ[2][0] - dot ), int( gdy + gds * self.gamut_1squ[2][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_1squ[3][0] - dot ), int( gdy + gds * self.gamut_1squ[3][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_1squ[4][0] - dot ), int( gdy + gds * self.gamut_1squ[4][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
if self.gamut_mask == "Circle":
# Profile Points
path, P0, P1, P2, P3, P4 = self.Render_Circle( gdx, gdy, gds, self.gamut_1cir )
# Polygon
painter.setPen( QtCore.Qt.NoPen )
painter.drawPath( path )
# Display Subjective Primaries
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
painter.drawEllipse( int( P0[0] - dot ), int( P0[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P1[0] - dot ), int( P1[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P2[0] - dot ), int( P2[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P3[0] - dot ), int( P3[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P4[0] - dot ), int( P4[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
if self.gamut_mask == "2 Circle":
# Profile Points
path_0, P0_0, P1_0, P2_0, P3_0, P4_0 = self.Render_Circle( gdx, gdy, gds, self.gamut_2cir[0:5] )
path_1, P0_1, P1_1, P2_1, P3_1, P4_1 = self.Render_Circle( gdx, gdy, gds, self.gamut_2cir[5:10] )
# Polygon
painter.setPen( QtCore.Qt.NoPen )
painter.drawPath( path_0 )
painter.drawPath( path_1 )
# Display Subjective Primaries
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
# Circle 0
painter.drawEllipse( int( P0_0[0] - dot ), int( P0_0[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P1_0[0] - dot ), int( P1_0[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P2_0[0] - dot ), int( P2_0[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P3_0[0] - dot ), int( P3_0[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P4_0[0] - dot ), int( P4_0[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
# Circle 1
painter.drawEllipse( int( P0_1[0] - dot ), int( P0_1[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P1_1[0] - dot ), int( P1_1[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P2_1[0] - dot ), int( P2_1[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P3_1[0] - dot ), int( P3_1[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( P4_1[0] - dot ), int( P4_1[1] - dot ), int( dot * 2 ), int( dot * 2 ) )
if self.gamut_mask == "3 Pie":
rect = QRect( int( gdx ), int( gdy ), int( gds ), int( gds ) )
ang_a1 = 16 * self.geometry.Trig_2D_Points_Lines_Angle(
gdx + self.gamut_3pie[1][0] * gds, gdy + self.gamut_3pie[1][1] * gds,
self.w2, self.h2,
self.widget_width, self.h2,
)
ang_a2 = -16 * self.geometry.Trig_2D_Points_Lines_Angle(
gdx + self.gamut_3pie[1][0] * gds, gdy + self.gamut_3pie[1][1] * gds,
self.w2, self.h2,
gdx + self.gamut_3pie[2][0] * gds, gdy + self.gamut_3pie[2][1] * gds,
)
ang_b1 = 16 * self.geometry.Trig_2D_Points_Lines_Angle(
gdx + self.gamut_3pie[3][0] * gds, gdy + self.gamut_3pie[3][1] * gds,
self.w2, self.h2,
self.widget_width, self.h2,
)
ang_b2 = -16 * self.geometry.Trig_2D_Points_Lines_Angle(
gdx + self.gamut_3pie[3][0] * gds, gdy + self.gamut_3pie[3][1] * gds,
self.w2, self.h2,
gdx + self.gamut_3pie[4][0] * gds, gdy + self.gamut_3pie[4][1] * gds,
)
ang_c1 = 16 * self.geometry.Trig_2D_Points_Lines_Angle(
gdx + self.gamut_3pie[5][0] * gds, gdy + self.gamut_3pie[5][1] * gds,
self.w2, self.h2,
self.widget_width, self.h2,
)
ang_c2 = -16 * self.geometry.Trig_2D_Points_Lines_Angle(
gdx + self.gamut_3pie[5][0] * gds, gdy + self.gamut_3pie[5][1] * gds,
self.w2, self.h2,
gdx + self.gamut_3pie[6][0] * gds, gdy + self.gamut_3pie[6][1] * gds,
)
# Polygon
painter.setPen( QtCore.Qt.NoPen )
painter.drawPie( rect, int( ang_a1 ), int( ang_a2 ) )
painter.drawPie( rect, int( ang_b1 ), int( ang_b2 ) )
painter.drawPie( rect, int( ang_c1 ), int( ang_c2 ) )
# Display Subjective Primaries
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_3pie[0][0] - dot ), int( gdy + gds * self.gamut_3pie[0][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_3pie[1][0] - dot ), int( gdy + gds * self.gamut_3pie[1][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_3pie[2][0] - dot ), int( gdy + gds * self.gamut_3pie[2][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_3pie[3][0] - dot ), int( gdy + gds * self.gamut_3pie[3][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_3pie[4][0] - dot ), int( gdy + gds * self.gamut_3pie[4][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_3pie[5][0] - dot ), int( gdy + gds * self.gamut_3pie[5][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
painter.drawEllipse( int( gdx + gds * self.gamut_3pie[6][0] - dot ), int( gdy + gds * self.gamut_3pie[6][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
# Analyse Colors
if self.analyse != None:
# Variables
dot = 5
line_size = 2
length = len( self.analyse )
# Draw
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
for i in range( 0, length ):
color = self.analyse[i]
if int( self.tan_axis * 255 ) == int( color[f"{self.chan}_3"] * 255 ):
if self.wheel_mode == "DIGITAL":
angle = color[hue_index] * 360
if self.wheel_mode == "ANALOG":
angle = color[hue_index] * 360 - hue_a
radius = color[f"{self.chan}_2"]
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.disk_side * 0.5, radius, angle )
painter.drawEllipse( int( px - dot ), int( py - dot ), int( dot * 2 ), int( dot * 2 ) )
# Pinned Colors
if ( self.color != None and self.pin_list != None ):
# Variables
dot = 5
line_size = 2
length = len( self.pin_list )
# Draw
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
for i in range( 0, length ):
if self.pin_list[i]["active"] == True:
if self.wheel_mode == "DIGITAL":
angle = self.pin_list[i][hue_index] * 360
if self.wheel_mode == "ANALOG":
angle = self.pin_list[i][hue_index] * 360 - hue_a
radius = self.pin_list[i][f"{self.chan}_2"]
px, py = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.disk_side * 0.5, radius, angle )
painter.drawEllipse( int( px - dot ), int( py - dot ), int( dot * 2 ), int( dot * 2 ) )
# Harmony Colors
if ( self.color != None and self.harmony_list != None ):
# Variables
line_size = 2
dot = 5
# Parsing
points = []
for i in range( 0, len( self.harmony_list ) ):
if self.wheel_mode == "DIGITAL":
angle = self.harmony_list[i][hue_index] * 360
if self.wheel_mode == "ANALOG":
angle = self.harmony_list[i][hue_index] * 360 - hue_a
radius = self.harmony_list[i][f"{self.chan}_2"]
har_x, har_y = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.disk_side * 0.5, radius, angle )
points.append( ( har_x, har_y ) )
length = len( points )
# Draw Line
painter.setPen( QPen( self.color_1, line_size, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin ) )
painter.setBrush( QtCore.Qt.NoBrush )
for i in range( 1, length ):
painter.drawLine( int( points[i-1][0] ), int( points[i-1][1] ), int( points[i][0] ), int( points[i][1] ) )
if self.harmony_rule in [ "Triadic", "Tetradic" ]:
painter.drawLine( int( points[0][0] ), int( points[0][1] ), int( points[length-1][0] ), int( points[length-1][1] ) )
# Draw Points
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
for i in range( 0, length ):
painter.drawEllipse( int( points[i][0] - dot ), int( points[i][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
# Cursor
size = 10
zoom_size = 100
margin_size = 10
if ( self.press == True and self.zoom == True ):
size = zoom_size
Cursor_Zoom( self, painter, size, margin_size )
elif( self.pressure > self.input_pressure ):
size = zoom_size * self.pressure
Cursor_Zoom( self, painter, size, margin_size )
else:
Cursor_Normal( self, painter, size )
def Render_Circle( self, px, py, side, points ):
# Points from User
P0 = [ px + points[0][0] * side, py + points[0][1] * side ]
P1 = [ px + points[1][0] * side, py + points[1][1] * side ]
P2 = [ px + points[2][0] * side, py + points[2][1] * side ]
P3 = [ px + points[3][0] * side, py + points[3][1] * side ]
P4 = [ px + points[4][0] * side, py + points[4][1] * side ]
# Angles from the Points
O1 = self.geometry.Trig_2D_Points_Lines_Angle( px, P0[1], P0[0],P0[1], P1[0],P1[1] )
O2 = self.geometry.Trig_2D_Points_Lines_Angle( px, P0[1], P0[0],P0[1], P2[0],P2[1] )
O3 = self.geometry.Trig_2D_Points_Lines_Angle( px, P0[1], P0[0],P0[1], P3[0],P3[1] )
O4 = self.geometry.Trig_2D_Points_Lines_Angle( px, P0[1], P0[0],P0[1], P4[0],P4[1] )
# Order Angles in Sequence
order = [ ( O1, P1 ), ( O2, P2 ), ( O3, P3 ), ( O4, P4 ) ]
order.sort()
A1 = order[0][1]
A2 = order[1][1]
A3 = order[2][1]
A4 = order[3][1]
# Bridge Points
B12 = [ self.geometry.Lerp_1D( 0.5, A1[0], A2[0] ), self.geometry.Lerp_1D( 0.5, A1[1], A2[1] ) ]
B23 = [ self.geometry.Lerp_1D( 0.5, A2[0], A3[0] ), self.geometry.Lerp_1D( 0.5, A2[1], A3[1] ) ]
B34 = [ self.geometry.Lerp_1D( 0.5, A3[0], A4[0] ), self.geometry.Lerp_1D( 0.5, A3[1], A4[1] ) ]
B41 = [ self.geometry.Lerp_1D( 0.5, A4[0], A1[0] ), self.geometry.Lerp_1D( 0.5, A4[1], A1[1] ) ]
# Bridge Components
dist_B12 = self.geometry.Trig_2D_Ortogonal_Components( P0[0], P0[1], B12[0], B12[1] )
dist_B23 = self.geometry.Trig_2D_Ortogonal_Components( P0[0], P0[1], B23[0], B23[1] )
dist_B34 = self.geometry.Trig_2D_Ortogonal_Components( P0[0], P0[1], B34[0], B34[1] )
dist_B41 = self.geometry.Trig_2D_Ortogonal_Components( P0[0], P0[1], B41[0], B41[1] )
# Intermediate Points
scalar = 2
P12 = [ P0[0] + scalar * dist_B12[0], P0[1] + scalar * dist_B12[1] ]
P23 = [ P0[0] + scalar * dist_B23[0], P0[1] + scalar * dist_B23[1] ]
P34 = [ P0[0] + scalar * dist_B34[0], P0[1] + scalar * dist_B34[1] ]
P41 = [ P0[0] + scalar * dist_B41[0], P0[1] + scalar * dist_B41[1] ]
# Painter Path Object
path = QPainterPath()
a = 0.551915024494
b = 1 - 0.551915024494
path.moveTo( A1[0], A1[1] )
path.cubicTo(
QPoint( self.geometry.Lerp_1D( a, A1[0], P12[0] ), self.geometry.Lerp_1D( a, A1[1], P12[1] ) ),
QPoint( self.geometry.Lerp_1D( b, P12[0], A2[0] ), self.geometry.Lerp_1D( b, P12[1], A2[1] ) ),
QPoint( A2[0], A2[1] ) )
path.cubicTo(
QPoint( self.geometry.Lerp_1D( a, A2[0], P23[0] ), self.geometry.Lerp_1D( a, A2[1], P23[1] ) ),
QPoint( self.geometry.Lerp_1D( b, P23[0], A3[0] ), self.geometry.Lerp_1D( b, P23[1], A3[1] ) ),
QPoint( A3[0], A3[1] ) )
path.cubicTo(
QPoint( self.geometry.Lerp_1D( a, A3[0], P34[0] ), self.geometry.Lerp_1D( a, A3[1], P34[1] ) ),
QPoint( self.geometry.Lerp_1D( b, P34[0], A4[0] ), self.geometry.Lerp_1D( b, P34[1], A4[1] ) ),
QPoint( A4[0], A4[1] ) )
path.cubicTo(
QPoint( self.geometry.Lerp_1D( a, A4[0], P41[0] ), self.geometry.Lerp_1D( a, A4[1], P41[1] ) ),
QPoint( self.geometry.Lerp_1D( b, P41[0], A1[0] ), self.geometry.Lerp_1D( b, P41[1], A1[1] ) ),
QPoint( A1[0], A1[1] ) )
# Return
return path, P0, P1, P2, P3, P4
class Panel_Hexagon( QWidget ):
SIGNAL_VALUE = QtCore.pyqtSignal( dict )
SIGNAL_TAN = QtCore.pyqtSignal( float )
SIGNAL_RELEASE = QtCore.pyqtSignal( int )
SIGNAL_PIN_INDEX = QtCore.pyqtSignal( int )
SIGNAL_PIN_EDIT = QtCore.pyqtSignal( dict )
# Init
def __init__( self, parent ):
super( Panel_Hexagon, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, render_height )
def Init_Variables( self ):
# Widget
self.widget_width = 0
self.widget_height = 0
self.w2 = 0
self.h2 = 0
self.origin_x = 0
self.origin_y = 0
self.origin_tan_axis = 0
self.event_x = 0
self.event_y = 0
self.press = False
self.pressure = 0
self.input_pressure = 0.5
self.px = 0
self.py = 0
self.side = 0
# Display
self.zoom = False
self.tan_axis = 0 # 0-360 because of background index
self.tan_range = 255
self.qpixmap_list = []
# Format
self.directory = None # Path
self.d_cm = None # "A" "RGB" "CMYK" "YUV" "XYZ" "LAB"
# Wheel
self.wheel_mode = "DIGITAL" # "DIGITAL" "ANALOG"
self.wheel_space = "HSV" # "HSV" "HSL" "HSY" "ARD"
# Geometry
self.O1 = None
self.O2 = None
self.O3 = None
self.O4 = None
self.O5 = None
self.O6 = None
self.C61 = None
# Colors
self.hex_color = QColor( "#000000" )
self.color = None
# Harmony Colors
self.harmony_rule = None
self.harmony_index = None
self.harmony_list = None
# Pinned Colors
self.pin_index = None
self.pin_list = None
# Analyse Colors
self.analyse = None
# Modules
self.geometry = Geometry()
self.convert = None
def Init_Convert( self, convert ):
self.convert = convert
self.update()
# Set
def Set_ColorModel( self, d_cm ):
self.d_cm = d_cm
self.Set_ColorSpace_inDocument( self.directory, self.d_cm )
self.update()
def Set_Wheel( self, wheel_mode, wheel_space ):
self.wheel_mode = wheel_mode
self.wheel_space = wheel_space
self.update()
def Set_ColorSpace_inDocument( self, directory, d_cm ):
# Variables
self.directory = directory
self.d_cm = d_cm
# Cursor
if self.color != None:
self.event_x = self.geometry.Limit_Range( self.color[f"uvd_1"] * self.widget_width, 0, self.widget_width )
self.event_y = self.geometry.Limit_Range( self.color[f"uvd_2"] * self.widget_height, 0, self.widget_height )
# Read Zip File
location = os.path.join( self.directory, panel )
location = os.path.join( location, f"{ self.d_cm }_UVD_4.zip" )
self.qpixmap_list = Read_Zip( self, location, self.tan_range, "UVD", "4" )
# Update
self.update()
def Set_Size( self, widget_width, widget_height ):
# Variables
self.widget_width = widget_width
self.widget_height = widget_height
self.w2 = widget_width * 0.5
self.h2 = widget_height * 0.5
# Frame
if self.widget_width >= self.widget_height:
self.side = self.widget_height
self.px = self.w2 - ( self.side * 0.5 )
self.py = 0
else:
self.side = self.widget_width
self.px = 0
self.py = self.h2 - ( self.side * 0.5 )
# Origin Points
self.O1, self.O2, self.O3, self.O4, self.O5, self.O6, C12, C23, C34, C45, C56, self.C61 = self.convert.uvd_hexagon( self.tan_axis, 0.5, 0.5, -1 )
# Update
self.update()
def Set_Zoom( self, boolean ):
self.press = boolean
self.zoom = boolean
self.update()
# Updates
def Update_Panel( self, color ):
# Variables
self.color = color
# Display
self.hex_color = QColor( color["hex6"] )
# Values
self.event_x = self.px + ( 0.5 + color["uvd_1"] * 0.5 ) * self.side
self.event_y = self.py + ( 0.5 - color["uvd_2"] * 0.5 ) * self.side
self.tan_axis = color["uvd_3"]
# Origin Points
self.O1, self.O2, self.O3, self.O4, self.O5, self.O6, C12, C23, C34, C45, C56, self.C61 = self.convert.uvd_hexagon( self.tan_axis, 0.5, 0.5, -1 )
# Update
self.update()
def Update_Harmony( self, harmony_rule, harmony_index, harmony_list ):
self.harmony_rule = harmony_rule
self.harmony_index = harmony_index
self.harmony_list = harmony_list
self.update()
def Update_Pin( self, pin_list ):
self.pin_list = pin_list
self.update()
def Update_Analyse( self, analyse ):
self.analyse = analyse
self.update()
# Mouse Interaction
def mousePressEvent( self, event ):
# Event
ex = event.x()
ey = event.y()
# Variables
self.origin_x = ex
self.origin_y = ey
self.origin_tan_axis = self.tan_axis
self.press = True
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( ex, ey, None )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( ex, ey, None )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Tangent( ex )
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Snap( ex, ey )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
self.Cursor_Snap( ex, ey )
self.update()
def mouseMoveEvent( self, event ):
# Events
ex = event.x()
ey = event.y()
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( ex, ey, None )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( ex, ey, None )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Tangent( ex )
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Snap( ex, ey )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
self.Cursor_Position( ex, ey, self.pin_index )
self.update()
def mouseDoubleClickEvent( self, event ):
# Events
ex = event.x()
ey = event.y()
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( ex, ey, None )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( ex, ey, None )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Tangent( ex )
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Snap( ex, ey )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
self.Cursor_Position( ex, ey, self.pin_index )
self.update()
def mouseReleaseEvent( self, event ):
# Variables
self.press = False
self.zoom = False
self.pressure = 0
self.pin_index = None
# Updates
self.SIGNAL_RELEASE.emit( 0 )
self.update()
# Mouse Event
def Cursor_Position( self, ex, ey, pin_index ):
# Calculation
if ( self.tan_axis <= 0 or self.tan_axis >= 1 ):
self.event_x = self.w2
self.event_y = self.h2
else:
self.event_x, self.event_y = self.Hexagon_Inter( ex, ey, self.tan_axis)
u = 2 * ( ( self.event_x - self.px ) / self.side ) - 1
v = -2 * ( ( self.event_y - self.py ) / self.side ) + 1
# Signal
values = { "c1" : u, "c2" : v, "pin_index" : pin_index }
self.SIGNAL_VALUE.emit( values )
if pin_index != None:
self.SIGNAL_PIN_EDIT.emit( values )
def Cursor_Tangent( self, ex ):
# Hue
delta_hue = ( ( ex - self.origin_x ) / self.widget_width )
self.tan_axis = self.geometry.Limit_Float( self.origin_tan_axis + delta_hue )
# Update
self.SIGNAL_TAN.emit( self.tan_axis )
def Cursor_Snap( self, ex, ey ):
if self.pin_list != None:
distance = []
for i in range( 0, len( self.pin_list ) ):
if self.pin_list[i]["active"] == True:
px = self.px + ( 0.5 + self.pin_list[i]["uvd_1"] * 0.5 ) * self.side
py = self.py + ( 0.5 - self.pin_list[i]["uvd_2"] * 0.5 ) * self.side
dist = self.geometry.Trig_2D_Points_Distance( ex, ey, px, py )
distance.append( ( dist, i ) )
if len( distance ) > 0:
distance.sort()
pin_index = distance[0][1]
if pin_index < 20:
self.pin_index = pin_index
self.SIGNAL_PIN_INDEX.emit( self.pin_index )
# Panel Modifiers
def Hexagon_Inter( self, ex, ey, d ):
# Variables
red_x = self.px + self.C61[0] * self.side
red_y = self.py + self.C61[1] * self.side
o1_x = self.px + self.O1[0] * self.side
o1_y = self.py + self.O1[1] * self.side
o2_x = self.px + self.O2[0] * self.side
o2_y = self.py + self.O2[1] * self.side
o3_x = self.px + self.O3[0] * self.side
o3_y = self.py + self.O3[1] * self.side
o4_x = self.px + self.O4[0] * self.side
o4_y = self.py + self.O4[1] * self.side
o5_x = self.px + self.O5[0] * self.side
o5_y = self.py + self.O5[1] * self.side
o6_x = self.px + self.O6[0] * self.side
o6_y = self.py + self.O6[1] * self.side
# Single Points
di = round( d * 3, 14 )
if ( di <= 0 or di >= 3 ):
ex = self.w2
ey = self.h2
else:
# Angles
angle = self.geometry.Trig_2D_Points_Lines_Angle( red_x, red_y, self.w2, self.h2, ex, ey )
a1 = self.geometry.Trig_2D_Points_Lines_Angle( red_x, red_y, self.w2, self.h2, o1_x, o1_y )
a2 = self.geometry.Trig_2D_Points_Lines_Angle( red_x, red_y, self.w2, self.h2, o2_x, o2_y )
a3 = self.geometry.Trig_2D_Points_Lines_Angle( red_x, red_y, self.w2, self.h2, o3_x, o3_y )
a4 = self.geometry.Trig_2D_Points_Lines_Angle( red_x, red_y, self.w2, self.h2, o4_x, o4_y )
a5 = self.geometry.Trig_2D_Points_Lines_Angle( red_x, red_y, self.w2, self.h2, o5_x, o5_y )
a6 = self.geometry.Trig_2D_Points_Lines_Angle( red_x, red_y, self.w2, self.h2, o6_x, o6_y )
if a6 == 0:
a6 = 360
# Limit
if angle <= a1:
lx, ly = self.geometry.Trig_2D_Points_Lines_Intersection( red_x, red_y, o1_x, o1_y, ex, ey, self.w2, self.h2 )
elif ( angle >= a1 and angle <= a2 ):
lx, ly = self.geometry.Trig_2D_Points_Lines_Intersection( o1_x, o1_y, o2_x, o2_y, ex, ey, self.w2, self.h2 )
elif ( angle >= a2 and angle <= a3 ):
lx, ly = self.geometry.Trig_2D_Points_Lines_Intersection( o2_x, o2_y, o3_x, o3_y, ex, ey, self.w2, self.h2 )
elif ( angle >= a3 and angle <= a4 ):
lx, ly = self.geometry.Trig_2D_Points_Lines_Intersection( o3_x, o3_y, o4_x, o4_y, ex, ey, self.w2, self.h2 )
elif ( angle >= a4 and angle <= a5 ):
lx, ly = self.geometry.Trig_2D_Points_Lines_Intersection( o4_x, o4_y, o5_x, o5_y, ex, ey, self.w2, self.h2 )
elif ( angle >= a5 and angle <= a6 ):
lx, ly = self.geometry.Trig_2D_Points_Lines_Intersection( o5_x, o5_y, o6_x, o6_y, ex, ey, self.w2, self.h2 )
elif angle >= a6:
lx, ly = self.geometry.Trig_2D_Points_Lines_Intersection( o6_x, o6_y, red_x, red_y, ex, ey, self.w2, self.h2 )
else:
radius = self.geometry.Trig_2D_Points_Distance( o1_x, o1_y, self.w2, self.h2 )
lx, ly = self.geometry.Trig_2D_Angle_Circle( self.w2, self.h2, self.side, radius, angle )
# Distance
event_dist = self.geometry.Trig_2D_Points_Distance( ex, ey, self.w2, self.h2 )
limit_dist = self.geometry.Trig_2D_Points_Distance( lx, ly, self.w2, self.h2 )
if event_dist >= limit_dist:
ex = lx
ey = ly
# Return
return ex, ey
# Tablet Interaction
def tabletEvent( self, event ):
self.pressure = event.pressure()
self.update()
# Paint
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Draw Gradient
if len( self.qpixmap_list ) > 0:
try:
# Draw Masks
hexagon = QPainterPath()
hexagon.moveTo( int( self.px + self.O1[0] * self.side ), int( self.py + self.O1[1] * self.side ) )
hexagon.lineTo( int( self.px + self.O2[0] * self.side ), int( self.py + self.O2[1] * self.side ) )
hexagon.lineTo( int( self.px + self.O3[0] * self.side ), int( self.py + self.O3[1] * self.side ) )
hexagon.lineTo( int( self.px + self.O4[0] * self.side ), int( self.py + self.O4[1] * self.side ) )
hexagon.lineTo( int( self.px + self.O5[0] * self.side ), int( self.py + self.O5[1] * self.side ) )
hexagon.lineTo( int( self.px + self.O6[0] * self.side ), int( self.py + self.O6[1] * self.side ) )
painter.setClipPath( hexagon )
# Draw Pixmaps
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QtCore.Qt.NoBrush )
index = int( self.tan_axis * self.tan_range )
qpixmap = self.qpixmap_list[index]
if qpixmap.isNull() == False:
render = qpixmap.scaled( self.side, self.side, Qt.IgnoreAspectRatio, Qt.FastTransformation )
painter.drawPixmap( int( self.px ), int( self.py ), render )
# Reset Mask
square = QPainterPath()
square.moveTo( int( 0 ), int( 0 ) )
square.lineTo( int( self.widget_width ), int( 0 ) )
square.lineTo( int( self.widget_width ), int( self.widget_height ) )
square.lineTo( int( 0 ), int( self.widget_height ) )
painter.setClipPath( square )
except Exception as e:
try:QtCore.qDebug( f"Pigment.O ERROR | { e }" )
except:pass
# Analyse Colors
if self.analyse != None:
# Variables
dot = 5
line_size = 2
length = len( self.analyse )
# Draw
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
for i in range( 0, length ):
color = self.analyse[i]
if int( self.tan_axis * 255 ) == int( color[f"uvd_3"] * 255 ):
px = self.px + ( 0.5 + color["uvd_1"] * 0.5 ) * self.side
py = self.py + ( 0.5 - color["uvd_2"] * 0.5 ) * self.side
painter.drawEllipse( int( px - dot ), int( py - dot ), int( dot * 2 ), int( dot * 2 ) )
# Pinned Colors
if ( self.color != None and self.pin_list != None ):
# Variables
pin_size = 5
line_size = 2
length = len( self.pin_list )
# Draw
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
for i in range( 0, length ):
if self.pin_list[i]["active"] == True:
cx = self.px + ( 0.5 + self.pin_list[i]["uvd_1"] * 0.5 ) * self.side
cy = self.py + ( 0.5 - self.pin_list[i]["uvd_2"] * 0.5 ) * self.side
painter.drawEllipse( int( cx - pin_size ), int( cy - pin_size ), int( pin_size * 2 ), int( pin_size * 2 ) )
# Harmony Colors
if ( self.color != None and self.harmony_list != None ):
# Variables
line_size = 2
dot = 5
# Parsing
points = []
for i in range( 0, len( self.harmony_list ) ):
har_x = self.px + ( 0.5 + self.harmony_list[i]["uvd_1"] * 0.5 ) * self.side
har_y = self.py + ( 0.5 - self.harmony_list[i]["uvd_2"] * 0.5 ) * self.side
points.append( ( har_x, har_y ) )
length = len( points )
# Draw Line
painter.setPen( QPen( self.color_1, line_size, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin ) )
painter.setBrush( QtCore.Qt.NoBrush )
for i in range( 1, length ):
painter.drawLine( int( points[i-1][0] ), int( points[i-1][1] ), int( points[i][0] ), int( points[i][1] ) )
if self.harmony_rule in [ "Triadic", "Tetradic" ]:
painter.drawLine( int( points[0][0] ), int( points[0][1] ), int( points[length-1][0] ), int( points[length-1][1] ) )
# Draw Points
painter.setPen( QPen( self.color_2, line_size, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin ) )
painter.setBrush( QBrush( self.color_1 ) )
for i in range( 0, length ):
painter.drawEllipse( int( points[i][0] - dot ), int( points[i][1] - dot ), int( dot * 2 ), int( dot * 2 ) )
# Cursor
size = 10
zoom_size = 100
margin_size = 10
if ( self.press == True and self.zoom == True ):
size = zoom_size
Cursor_Zoom( self, painter, size, margin_size )
elif( self.pressure > self.input_pressure ):
size = zoom_size * self.pressure
Cursor_Zoom( self, painter, size, margin_size )
else:
Cursor_Normal( self, painter, size )
class Panel_Dot( QWidget ):
SIGNAL_VALUE = QtCore.pyqtSignal( str )
SIGNAL_RELEASE = QtCore.pyqtSignal( int )
SIGNAL_INTERPOLATION = QtCore.pyqtSignal( str )
SIGNAL_DIMENSION = QtCore.pyqtSignal( int )
SIGNAL_EDIT = QtCore.pyqtSignal( bool )
SIGNAL_ZORN = QtCore.pyqtSignal( int )
# Init
def __init__( self, parent ):
super( Panel_Dot, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, render_height )
def Init_Variables( self ):
# Widget
self.press = False
self.widget_width = 0
self.widget_height = 0
self.w2 = 0
self.h2 = 0
self.press = False
self.zoom = False
self.pressure = 0
self.input_pressure = 0.5
# Events
self.event_x = 0
self.event_y = 0
self.dot_x = 0
self.dot_y = 0
# Settings
self.dot_interpolation = "RGB"
self.dot_dimension = 11
self.dot_edit = True
self.dot_matrix = None
self.unit = 24
self.margin = 5
self.shape = "CIRCLE" # SQUARE CIRCLE
self.Update_Side()
self.Cursor_Move( self.dot_x, self.dot_y )
# Context Menu Checks
self.dot_interpolation = "RGB"
self.dot_dimension = 11
# Color
self.hex_color = QColor( "#000000" )
# Modules
self.geometry = Geometry()
self.convert = None
def Init_Convert( self, convert ):
self.convert = convert
self.update()
# Relay
def Set_Size( self, widget_width, widget_height ):
# Widget Size
self.widget_width = widget_width
self.widget_height = widget_height
self.w2 = int( widget_width * 0.5 )
self.h2 = int( widget_height * 0.5 )
# Cursor Move
self.Cursor_Move( self.dot_x, self.dot_y )
self.update()
def Set_Interpolation( self, string ):
self.dot_interpolation = string
self.update()
def Set_Dimension( self, number ):
self.dot_dimension = number
self.Update_Side()
self.update()
def Set_Edit( self, boolean ):
self.dot_edit = boolean
self.update()
# Update
def Update_Color( self, dot_matrix ):
self.dot_matrix = dot_matrix
self.update()
def Update_Side( self ):
self.side = ( self.unit * self.dot_dimension ) + ( self.margin * ( self.dot_dimension - 1 ) )
# Mouse Interaction
def mousePressEvent( self, event ):
# Input
self.origin_x = event.x()
self.origin_y = event.y()
self.press = True
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( event )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( event )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( event )
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( event )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
self.press = False
self.Context_Menu( event )
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
self.update()
def mouseMoveEvent( self, event ):
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( event )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( event )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( event )
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( event )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
self.update()
def mouseDoubleClickEvent( self, event ):
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( event )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Position( event )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( event )
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Position( event )
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
self.update()
def mouseReleaseEvent( self, event ):
# Variables
self.press = False
self.zoom = False
self.pressure = 0
# Updates
self.SIGNAL_RELEASE.emit( 0 )
self.update()
# Mouse Event
def Cursor_Move( self, dot_x, dot_y ):
if self.dot_matrix != None:
self.event_x = int( self.w2 - ( self.side * 0.5 ) + ( self.unit*dot_x + self.margin*( dot_x-1 ) ) + ( self.unit * 0.5 ) )
self.event_y = int( self.h2 - ( self.side * 0.5 ) + ( self.unit*dot_y + self.margin*( dot_y-1 ) ) + ( self.unit * 0.5 ) )
def Cursor_Position( self, event ):
# Read
ex = event.x()
ey = event.y()
if self.dot_matrix != None:
# Points
points = []
for y in range( 0, self.dot_dimension ):
for x in range( 0, self.dot_dimension ):
px = int( self.w2 - ( self.side * 0.5 ) + ( self.unit*x + self.margin*( x-1 ) ) + ( self.unit * 0.5 ) )
py = int( self.h2 - ( self.side * 0.5 ) + ( self.unit*y + self.margin*( y-1 ) ) + ( self.unit * 0.5 ) )
dist = self.geometry.Trig_2D_Points_Distance( px, py, ex, ey )
hex_code = self.dot_matrix[y][x]
points.append( [dist, px, py, hex_code, x, y] )
points.sort()
# Input
self.event_x = points[0][1]
self.event_y = points[0][2]
# Lock
self.dot_x = points[0][4]
self.dot_y = points[0][5]
# Signal
hex_code = points[0][3]
self.Hex_Color( hex_code )
def Hex_Color( self, hex_code ):
self.hex_color = QColor( hex_code )
self.SIGNAL_VALUE.emit( hex_code )
self.update()
# Context
def Context_Menu( self, event ):
if self.press == False:
# Menu
cmenu = QMenu( self )
# Interpolation
cmenu_interpolation = cmenu.addMenu( "Interpolation" )
cmenu_int_rgb = cmenu_interpolation.addAction( "RGB" )
cmenu_int_cmyk = cmenu_interpolation.addAction( "CMYK" )
cmenu_int_ryb = cmenu_interpolation.addAction( "RYB" )
cmenu_int_yuv = cmenu_interpolation.addAction( "YUV" )
cmenu_int_hsv = cmenu_interpolation.addAction( "HSV" )
cmenu_int_hsl = cmenu_interpolation.addAction( "HSL" )
cmenu_int_hsy = cmenu_interpolation.addAction( "HSY" )
cmenu_int_ard = cmenu_interpolation.addAction( "ARD" )
cmenu_int_rgb.setCheckable( True )
cmenu_int_cmyk.setCheckable( True )
cmenu_int_ryb.setCheckable( True )
cmenu_int_yuv.setCheckable( True )
cmenu_int_hsv.setCheckable( True )
cmenu_int_hsl.setCheckable( True )
cmenu_int_hsy.setCheckable( True )
cmenu_int_ard.setCheckable( True )
cmenu_int_rgb.setChecked( self.dot_interpolation == "RGB" )
cmenu_int_cmyk.setChecked( self.dot_interpolation == "CMYK" )
cmenu_int_ryb.setChecked( self.dot_interpolation == "RYB" )
cmenu_int_yuv.setChecked( self.dot_interpolation == "YUV" )
cmenu_int_hsv.setChecked( self.dot_interpolation == "HSV" )
cmenu_int_hsl.setChecked( self.dot_interpolation == "HSL" )
cmenu_int_hsy.setChecked( self.dot_interpolation == "HSY" )
cmenu_int_ard.setChecked( self.dot_interpolation == "ARD" )
# Dimension
cmenu_dimension = cmenu.addMenu( "Dimension" )
cmenu_dim_3 = cmenu_dimension.addAction( "3 x 3" )
cmenu_dim_5 = cmenu_dimension.addAction( "5 x 5" )
cmenu_dim_7 = cmenu_dimension.addAction( "7 x 7" )
cmenu_dim_9 = cmenu_dimension.addAction( "9 x 9" )
cmenu_dim_11 = cmenu_dimension.addAction( "11 x 11" )
cmenu_dim_13 = cmenu_dimension.addAction( "13 x 13" )
cmenu_dim_15 = cmenu_dimension.addAction( "15 x 15" )
cmenu_dim_17 = cmenu_dimension.addAction( "17 x 17" )
cmenu_dim_19 = cmenu_dimension.addAction( "19 x 19" )
cmenu_dim_21 = cmenu_dimension.addAction( "21 x 21" )
cmenu_dim_3.setCheckable( True )
cmenu_dim_5.setCheckable( True )
cmenu_dim_7.setCheckable( True )
cmenu_dim_9.setCheckable( True )
cmenu_dim_11.setCheckable( True )
cmenu_dim_13.setCheckable( True )
cmenu_dim_15.setCheckable( True )
cmenu_dim_17.setCheckable( True )
cmenu_dim_19.setCheckable( True )
cmenu_dim_21.setCheckable( True )
cmenu_dim_3.setChecked( self.dot_dimension == "3 x 3" )
cmenu_dim_5.setChecked( self.dot_dimension == "5 x 5" )
cmenu_dim_7.setChecked( self.dot_dimension == "7 x 7" )
cmenu_dim_9.setChecked( self.dot_dimension == "9 x 9" )
cmenu_dim_11.setChecked( self.dot_dimension == "11 x 11" )
cmenu_dim_13.setChecked( self.dot_dimension == "13 x 13" )
cmenu_dim_15.setChecked( self.dot_dimension == "15 x 15" )
cmenu_dim_17.setChecked( self.dot_dimension == "17 x 17" )
cmenu_dim_19.setChecked( self.dot_dimension == "19 x 19" )
cmenu_dim_21.setChecked( self.dot_dimension == "21 x 21" )
# Edit
cmenu_edit = cmenu.addAction( "Edit" )
cmenu_edit.setCheckable( True )
cmenu_edit.setChecked( self.dot_edit )
# Reset
cmenu_zorn = cmenu.addAction( "Zorn Palette" )
# Actions
action = cmenu.exec_( self.mapToGlobal( event.pos() ) )
# Triggers
if action == cmenu_int_rgb:
self.dot_interpolation = "RGB"
self.SIGNAL_INTERPOLATION.emit( self.dot_interpolation )
if action == cmenu_int_cmyk:
self.dot_interpolation = "CMYK"
self.SIGNAL_INTERPOLATION.emit( self.dot_interpolation )
if action == cmenu_int_ryb:
self.dot_interpolation = "RYB"
self.SIGNAL_INTERPOLATION.emit( self.dot_interpolation )
if action == cmenu_int_yuv:
self.dot_interpolation = "YUV"
self.SIGNAL_INTERPOLATION.emit( self.dot_interpolation )
if action == cmenu_int_hsv:
self.dot_interpolation = "HSV"
self.SIGNAL_INTERPOLATION.emit( self.dot_interpolation )
if action == cmenu_int_hsl:
self.dot_interpolation = "HSL"
self.SIGNAL_INTERPOLATION.emit( self.dot_interpolation )
if action == cmenu_int_hsy:
self.dot_interpolation = "HSY"
self.SIGNAL_INTERPOLATION.emit( self.dot_interpolation )
if action == cmenu_int_ard:
self.dot_interpolation = "ARD"
self.SIGNAL_INTERPOLATION.emit( self.dot_interpolation )
if action == cmenu_dim_3:
self.dot_dimension = 3
self.SIGNAL_DIMENSION.emit( self.dot_dimension )
if action == cmenu_dim_5:
self.dot_dimension = 5
self.SIGNAL_DIMENSION.emit( self.dot_dimension )
if action == cmenu_dim_7:
self.dot_dimension = 7
self.SIGNAL_DIMENSION.emit( self.dot_dimension )
if action == cmenu_dim_9:
self.dot_dimension = 9
self.SIGNAL_DIMENSION.emit( self.dot_dimension )
if action == cmenu_dim_11:
self.dot_dimension = 11
self.SIGNAL_DIMENSION.emit( self.dot_dimension )
if action == cmenu_dim_13:
self.dot_dimension = 13
self.SIGNAL_DIMENSION.emit( self.dot_dimension )
if action == cmenu_dim_15:
self.dot_dimension = 15
self.SIGNAL_DIMENSION.emit( self.dot_dimension )
if action == cmenu_dim_17:
self.dot_dimension = 17
self.SIGNAL_DIMENSION.emit( self.dot_dimension )
if action == cmenu_dim_19:
self.dot_dimension = 19
self.SIGNAL_DIMENSION.emit( self.dot_dimension )
if action == cmenu_dim_21:
self.dot_dimension = 21
self.SIGNAL_DIMENSION.emit( self.dot_dimension )
if action == cmenu_edit:
self.SIGNAL_EDIT.emit( not self.dot_edit )
if action == cmenu_zorn:
self.SIGNAL_ZORN.emit( 0 )
# Tablet Interaction
def tabletEvent( self, event ):
self.pressure = event.pressure()
self.update()
# Paint
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Dots
if self.dot_matrix != None:
painter.setPen( QtCore.Qt.NoPen )
for y in range( 0, self.dot_dimension ):
for x in range( 0, self.dot_dimension ):
try:
hex6 = self.dot_matrix[y][x]
except:
hex6 = "#000000"
painter.setBrush( QBrush( QColor( hex6 ) ) )
point_x = int( self.w2 - ( self.side * 0.5 ) + ( self.unit * x + self.margin * x ) )
point_y = int( self.h2 - ( self.side * 0.5 ) + ( self.unit * y + self.margin * y ) )
if self.shape == "CIRCLE":
painter.drawEllipse( point_x, point_y, self.unit, self.unit )
elif self.shape == "SQUARE":
painter.drawRect( point_x, point_y, self.unit, self.unit )
# Cursor
zoom_size = 100
margin_size = 10
size = 10
s2 = int( size * 0.5 )
if ( self.press == True and self.zoom == True ):
size = zoom_size
self.Cursor_Zoom( painter, size, margin_size, s2 )
elif( self.pressure > self.input_pressure ):
size = zoom_size * self.pressure
self.Cursor_Zoom( painter, size, margin_size, s2 )
else:
self.Cursor_Normal( painter, size, s2 )
# Cursor
def Cursor_Normal( self, painter, size, s2 ):
# Variables
w = 2
# Mask
mask = QPainterPath()
mask.addEllipse(
int( self.event_x - s2 ),
int( self.event_y - s2 ),
int( size * 2 ),
int( size * 2 ),
)
mask.addEllipse(
int( self.event_x - s2 + w * 2 ),
int( self.event_y - s2 + w * 2 ),
int( size * 2 - w * 4 ),
int( size * 2 - w * 4 ),
)
painter.setClipPath( mask )
# Black Circle
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_black ) )
painter.drawEllipse(
int( self.event_x - s2 ),
int( self.event_y - s2 ),
int( size * 2 ),
int( size * 2 ),
)
# White Circle
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_white ) )
painter.drawEllipse(
int( self.event_x - s2 + w ),
int( self.event_y - s2 + w ),
int( size * 2 - w * 2 ),
int( size * 2 - w * 2 ),
)
def Cursor_Zoom( self, painter, zoom_size, margin_size, s2 ):
# Border
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_black ) )
painter.drawEllipse(
int( self.event_x - zoom_size + s2 ),
int( self.event_y - zoom_size + s2 ),
int( zoom_size * 2 ),
int( zoom_size * 2 ),
)
# Hex Color
painter.setBrush( QBrush( self.hex_color ) )
painter.drawEllipse(
int( self.event_x - zoom_size + margin_size + s2 ),
int( self.event_y - zoom_size + margin_size + s2 ),
int( zoom_size * 2 - margin_size * 2 ),
int( zoom_size * 2 - margin_size * 2 ),
)
class Panel_Mask( QWidget ):
SIGNAL_VALUE = QtCore.pyqtSignal( str )
SIGNAL_RELEASE = QtCore.pyqtSignal( int )
SIGNAL_MASKSET = QtCore.pyqtSignal( str )
SIGNAL_EDIT = QtCore.pyqtSignal( bool )
SIGNAL_RESET = QtCore.pyqtSignal( bool )
# Init
def __init__( self, parent ):
super( Panel_Mask, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, render_height )
def Init_Variables( self ):
# Widget
self.press = False
self.widget_width = 0
self.widget_height = 0
self.w2 = 0
self.h2 = 0
self.press = False
self.zoom = False
self.pressure = 0
self.input_pressure = 0.5
# Events
self.origin_x = -10
self.origin_y = -10
self.event_x = -10
self.event_y = -10
# Mask
self.mask_edit = True
# Path
self.directory = None
self.file_format = ".png"
self.files = [
"b1",
"b2",
"b3",
"d1",
"d2",
"d3",
"d4",
"d5",
"d6",
"f1",
"f2",
"f3",
]
# Masks
self.mask_path = []
self.mask_color = {
"b1" : "#7f7f7f",
"b2" : "#000000",
"b3" : "#000000",
"d1" : "#231402",
"d2" : "#543713",
"d3" : "#fe9f0e",
"d4" : "#ffca32",
"d5" : "#000000",
"d6" : "#000000",
"f1" : "#000000",
"f2" : "#ffff96",
"f3" : "#ffffff",
}
self.mask_alpha = {
"b1" : 0.0,
"b2" : 1.0,
"b3" : 1.0,
"d1" : 1.0,
"d2" : 1.0,
"d3" : 1.0,
"d4" : 1.0,
"d5" : 0.0,
"d6" : 0.0,
"f1" : 1.0,
"f2" : 1.0,
"f3" : 1.0,
}
self.mask_qpixmaps = None
# Color
self.hex_color = QColor( "#000000" )
# Modules
self.geometry = Geometry()
# Image
self.qimage = QImage()
# Set
def Set_Size( self, widget_width, widget_height ):
self.widget_width = widget_width
self.widget_height = widget_height
self.w2 = widget_width * 0.5
self.h2 = widget_height * 0.5
self.event_x = -10
self.event_y = -10
self.update()
def Set_Directory( self, directory_plugin ):
# Variables
self.directory = os.path.normpath( directory_plugin )
# Update
self.Update_Path( os.path.join( self.directory, "SPHERE" ) )
self.update()
def Set_Edit( self, boolean ):
self.mask_edit = boolean
self.update()
# Update
def Update_Path( self, mask_set ):
self.mask_path = []
for i in range( 0, len( self.files ) ):
path = os.path.normpath( str( mask_set ) + "\\" + self.files[i] + self.file_format )
qpixmap = QPixmap( path )
if qpixmap.isNull() == False:
self.mask_path.append( path )
else:
self.mask_path.append( None )
if None not in self.mask_path:
self.mask_qpixmaps = self.Pixmap_Composite( self.mask_path, self.mask_color, self.mask_alpha )
else:
self.mask_qpixmaps = None
self.update()
def Update_Color( self, mask_color, mask_alpha ):
self.mask_color = mask_color
self.mask_alpha = mask_alpha
self.mask_qpixmaps = self.Pixmap_Composite( self.mask_path, self.mask_color, self.mask_alpha )
self.update()
# Calculations
def Pixmap_Composite( self, mask_path, mask_color, mask_alpha ):
# Pre Compose pixmaps to display
qpixmaps = []
for i in range( 0, len( mask_path ) ):
pixmap_1 = QPixmap.fromImage( QImage( mask_path[i] ) )
image = QImage( pixmap_1.width(), pixmap_1.height(), QImage.Format_ARGB32_Premultiplied )
color = QColor( self.mask_color[self.files[i]] )
color.setAlphaF( self.mask_alpha[self.files[i]] )
image.fill( color )
pixmap_2 = QPixmap.fromImage( image )
painter = QPainter()
painter.begin( pixmap_1 )
painter.setCompositionMode( QPainter.CompositionMode_SourceIn )
painter.drawImage( 0, 0, pixmap_2.toImage() )
painter.end()
qpixmaps.append( pixmap_1 )
# Return
return qpixmaps
# Mouse Interaction
def mousePressEvent( self, event ):
# Input
ex = event.x()
ey = event.y()
self.origin_x = ex
self.origin_y = ey
self.press = True
self.qimage = self.grab().toImage()
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Color( ex, ey, self.qimage )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Color( ex, ey, self.qimage )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
pass
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
self.press = False
self.Context_Menu( event )
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
self.update()
def mouseMoveEvent( self, event ):
# Input
ex = event.x()
ey = event.y()
self.event_x = ex
self.event_y = ey
self.press = True
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Color( ex, ey, self.qimage )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Color( ex, ey, self.qimage )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
pass
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
self.update()
def mouseDoubleClickEvent( self, event ):
# Input
ex = event.x()
ey = event.y()
self.event_x = ex
self.event_y = ey
self.press = True
# LMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.Cursor_Color( ex, ey, self.qimage )
# LMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.LeftButton ):
self.zoom = True
self.Cursor_Color( ex, ey, self.qimage )
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.LeftButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.LeftButton ):
pass
# RMB Neutral
if ( event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
# RMB Modifiers
if ( event.modifiers() == QtCore.Qt.ShiftModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.ControlModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
if ( event.modifiers() == QtCore.Qt.AltModifier and event.buttons() == QtCore.Qt.RightButton ):
pass
self.update()
def mouseReleaseEvent( self, event ):
# Input
self.event_x = event.x()
self.event_y = event.y()
# Variables
self.press = False
self.zoom = False
self.pressure = 0
# Updates
self.SIGNAL_RELEASE.emit( 0 )
self.update()
def Cursor_Color( self, ex, ey, qimage ):
# Pixel Color
pixel = qimage.pixelColor( ex, ey )
code = pixel.name()
self.hex_color = QColor( code )
# Emit
self.SIGNAL_VALUE.emit( code )
# Context
def Context_Menu( self, event ):
# Variables
sub_folder = [name for name in os.listdir( self.directory ) if os.path.isdir( os.path.join( self.directory, name ) )]
# Menu
if self.press == False:
# Menu
cmenu = QMenu( self )
# Mask Sets
cmenu_maps = cmenu.addMenu( "Maps" )
actions = {}
for i in range( 0, len( sub_folder ) ):
actions[i] = cmenu_maps.addAction( sub_folder[i] )
# Edit
cmenu_edit = cmenu.addAction( "Edit" )
cmenu_edit.setCheckable( True )
cmenu_edit.setChecked( self.mask_edit )
# Reset
cmenu_reset = cmenu.addAction( "Reset" )
# Actions
action = cmenu.exec_( self.mapToGlobal( event.pos() ) )
# Triggers
for i in range( 0, len( sub_folder ) ):
if action == actions[i]:
path = os.path.join( self.directory, sub_folder[i] )
self.Update_Path( path )
self.SIGNAL_MASKSET.emit( path )
break
if action == cmenu_edit:
self.SIGNAL_EDIT.emit( not self.mask_edit )
if action == cmenu_reset:
self.SIGNAL_RESET.emit( True )
# Tablet Interaction
def tabletEvent( self, event ):
self.pressure = event.pressure()
self.update()
# Paint
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Background
painter.setPen( QtCore.Qt.NoPen )
bw = QLinearGradient( 0, 0, 0, self.widget_height )
bw.setColorAt( 0.000, QColor( 0, 0, 0, 0 ) ) # White
bw.setColorAt( 1.000, QColor( 0, 0, 0, 100 ) ) # Black
painter.setBrush( QBrush( bw ) )
painter.drawRect( 0,0, self.widget_width,self.widget_height )
# Draw Pixmaps
if self.mask_qpixmaps != None:
for i in range( 0, len( self.mask_qpixmaps ) ):
qpixmap = self.mask_qpixmaps[i]
if qpixmap.isNull() == False:
render = qpixmap.scaled( self.widget_width, self.widget_height, Qt.KeepAspectRatio, Qt.FastTransformation )
else:
render = QPixmap( 1,1 ).scaled( self.widget_width, self.widget_height, Qt.KeepAspectRatio, Qt.FastTransformation )
w = render.width()
h = render.height()
px = int( self.w2 - ( w * 0.5 ) )
py = int( self.h2 - ( h * 0.5 ) )
painter.drawPixmap( px, py, render )
# Cursor
size = 10
zoom_size = 100
margin_size = 10
if ( self.press == True and self.zoom == True ):
size = zoom_size
Cursor_Zoom( self, painter, size, margin_size )
elif( self.pressure > self.input_pressure ):
size = zoom_size * self.pressure
Cursor_Zoom( self, painter, size, margin_size )
else:
Cursor_Normal( self, painter, size )
#endregion
#region Channels ###################################################################
class Channel_Slider( QWidget ):
SIGNAL_VALUE = QtCore.pyqtSignal( dict )
SIGNAL_RELEASE = QtCore.pyqtSignal( bool )
SIGNAL_STOPS = QtCore.pyqtSignal( int )
SIGNAL_TEXT = QtCore.pyqtSignal( str )
# Init
def __init__( self, parent ):
super( Channel_Slider, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, 100 )
def Init_Variables( self ):
# Modules
self.geometry = Geometry()
# Widget
self.widget_width = 1
self.widget_height = 1
# Display
self.origin_x = 0
self.origin_stops = 0
# Variables
self.mode = "LINEAR" # "LINEAR" "CIRCULAR" "MIXER"
self.minimum = 0
self.half = 0.5
self.maximum = 1
self.stops = 1
self.value = 0
self.colors = None
self.alpha = 1
self.index = None
# Relay
def Set_Mode( self, mode ):
self.mode = mode
self.update()
def Set_Size( self, widget_width, widget_height ):
self.widget_width = widget_width
self.widget_height = widget_height
self.update()
def Set_Limits( self, minimum, half, maximum ):
self.minimum = minimum
self.half = half
self.maximum = maximum
self.update()
def Set_Colors( self, colors, alpha ):
self.colors = colors
self.alpha = alpha
self.update()
def Set_Stops( self, stops ):
self.stops = stops
self.update()
def Set_Value( self, value ):
self.value = value * self.widget_width
self.update()
def Set_Index( self, index ):
self.index = index
# Interaction
def mousePressEvent( self, event ):
# Start Event
self.origin_x = event.x()
self.origin_stops = self.stops
# LMB Neutral
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.Emit_Value_Linear( event )
# LMB Modifier
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ShiftModifier ):
pass
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ControlModifier ):
self.Snap_Stop( event )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.AltModifier ):
self.Stops_Shift( event )
self.update()
def mouseMoveEvent( self, event ):
# LMB Neutral
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.Emit_Value_Linear( event )
# LMB Modifier
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ShiftModifier ):
pass
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ControlModifier ):
self.Snap_Stop( event )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.AltModifier ):
self.Stops_Shift( event )
self.update()
def mouseDoubleClickEvent( self, event ):
# LMB Neutral
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.Emit_Value_Linear( event )
# LMB Modifier
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ShiftModifier ):
pass
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ControlModifier ):
self.Snap_Half( event )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.AltModifier ):
self.Stops_Reset()
self.update()
def mouseReleaseEvent( self, event ):
# Update
self.SIGNAL_TEXT.emit( "" )
self.SIGNAL_RELEASE.emit( True )
self.update()
# Functions
def Mouse_Position( self, event ):
# Event read
pos_x = event.pos().x()
# Calculations
if ( self.mode == "LINEAR" or self.mode == "MIXER" ):
value = self.geometry.Limit_Range( pos_x, 0, self.widget_width )
if self.mode == "CIRCULAR":
value = self.Loop_Hue( pos_x, self.widget_width )
return value
def Loop_Hue( self, value, limit ):
if value < 0:
delta = value - limit
units = abs( int( delta / limit ) )
value = value + ( limit*units )
if value > limit:
units = abs( int( value / limit ) )
value = value - ( limit*units )
return value
# Value
def Emit_Value_Linear( self, event ):
# Mouse
self.value = self.Mouse_Position( event )
# Calculations
percent = self.value / self.widget_width
text = str( round( percent*100,2 ) ) + " %"
# Emission
self.SIGNAL_VALUE.emit( { "index":self.index, "value":percent } )
self.SIGNAL_TEXT.emit( text )
# Snap
def Snap_Half( self, event ):
self.value = self.half * self.widget_width
self.SIGNAL_VALUE.emit( { "index":self.index, "value":self.half } )
self.SIGNAL_TEXT.emit( "50 %" )
def Snap_Stop( self, event ):
# Mouse
value = self.Mouse_Position( event )
# Calculations
unit = self.widget_width / self.stops
distances = []
for i in range( 0, self.stops+1 ):
dist = self.geometry.Trig_2D_Points_Distance( value, 0, ( unit * i ), 0 )
distances.append( dist )
value_min = min( distances )
index = distances.index( value_min )
self.value = unit * index
percent = self.value / self.widget_width
text = str( round( percent*100,2 ) ) + " %"
# Emission
self.SIGNAL_VALUE.emit( { "index":self.index, "value":percent } )
self.SIGNAL_TEXT.emit( text )
# Stops
def Stops_Shift( self, event ):
# Variables
minimum = 2
divisions = 100
unit = 50
# Calculations
delta = event.x() - self.origin_x
value = int( delta / unit )
self.stops = self.geometry.Limit_Range( self.origin_stops + value, minimum, divisions )
# Emission
self.SIGNAL_STOPS.emit( self.stops )
self.SIGNAL_TEXT.emit( "snap " + str( self.stops ) )
def Stops_Reset( self ):
# Set Number
if self.mode == "LINEAR":
self.stops = 4
if self.mode == "CIRCULAR":
self.stops = 6
if self.mode == "MIXER":
self.stops = 2
# Emission
self.SIGNAL_STOPS.emit( self.stops )
# Wheel Events
def wheelEvent( self, event ):
delta_y = event.angleDelta().y()
if delta_y > 20:
num = 1
if delta_y < -20:
num = -1
# Calculate
if ( self.mode == "LINEAR" or self.mode == "MIXER" ):
self.value = self.geometry.Limit_Range( self.value + num, 0, self.widget_width )
if self.mode == "CIRCULAR":
self.value = self.Loop_Hue( self.value + num, self.widget_width )
percent = self.value / self.widget_width
text = str( round( percent*100,2 ) ) + " %"
# Emit
self.SIGNAL_VALUE.emit( { "index":self.index, "value":percent } )
self.SIGNAL_TEXT.emit( text )
self.update()
# Paint Style
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Variables
ww = self.widget_width
hh = self.widget_height
w1 = ww - 1
w2 = ww - 2
h1 = hh - 1
h4 = hh - 4
# Background Style
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_alpha ) )
painter.drawRect( 0, 0, self.widget_width, self.widget_height )
# Stops
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_1 ) )
if self.stops <= 0 :
painter.drawRect( 0, 0, self.widget_width, 1 )
else:
for i in range( 0, self.stops ):
percent = int( self.widget_width * ( i / self.stops ) )
painter.drawRect( percent, 0, 1, 1 )
painter.drawRect( self.widget_width * 1 - 1, 0, 1, 1 )
# Draw Colors Gradient
if self.colors != None:
painter.setPen( QtCore.Qt.NoPen )
grad = QLinearGradient( 0, 0, self.widget_width, 0 )
number = len( self.colors )
for i in range( 0, number ):
grad.setColorAt( round( i / number, 3 ), QColor( int( self.colors[i][0] * 255 ), int( self.colors[i][1] * 255 ), int( self.colors[i][2] * 255 ), int( self.alpha * 255 ) ) )
painter.setBrush( QBrush( grad ) )
square = QPolygon( [
QPoint( 1, 1 ),
QPoint( w1, 1 ),
QPoint( w1, h1 ),
QPoint( 1, h1 ),
] )
painter.drawPolygon( square )
# Cursor
value = int( self.value )
bl = value - 3
br = value + 3
wl = value - 1
wr = value + 1
top1 = 0
bot1 = self.widget_height
top2 = 1
bot2 = self.widget_height - 1
# Black Square
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_black ) )
black = QPolygon( [
QPoint( bl, top1 ),
QPoint( bl, bot1 ),
QPoint( br, bot1 ),
QPoint( br, top1 ),
] )
painter.drawPolygon( black )
# White Square
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_white ) )
white = QPolygon( [
QPoint( wl, top2 ),
QPoint( wl, bot2 ),
QPoint( wr, bot2 ),
QPoint( wr, top2 ),
] )
painter.drawPolygon( white )
class Channel_Selection( QWidget ):
SIGNAL_VALUE = QtCore.pyqtSignal( dict )
SIGNAL_RELEASE = QtCore.pyqtSignal( bool )
SIGNAL_RESET = QtCore.pyqtSignal( int )
# Init
def __init__( self, parent ):
super( Channel_Selection, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, 100 )
def Init_Variables( self ):
# Modules
self.geometry = Geometry()
# Widget
self.widget_width = 1
self.widget_height = 1
# Variables
self.mode = "LINEAR" # "LINEAR" "CIRCULAR"
self.value = 0
self.colors = None
self.alpha = 1
self.sele = None
self.sele_origin = None
self.marker = None
# Relay
def Set_Mode( self, mode ):
self.mode = mode
self.update()
def Set_Size( self, widget_width, widget_height ):
self.widget_width = widget_width
self.widget_height = widget_height
self.update()
# Update
def Update_Value( self, value ):
self.value = value
self.update()
def Update_Colors( self, colors, alpha ):
self.colors = colors
self.alpha = alpha
self.update()
def Update_Selection( self, sele ):
self.sele = sele
self.update()
# Interaction
def mousePressEvent( self, event ):
# Event
ex = event.x()
# Variables
self.sele_origin = self.sele
QtCore.qDebug( "self.sele_origin = " + str( self.sele_origin ) )
# LMB Neutral
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.marker = self.Marker_Index( ex, "ALL" )
QtCore.qDebug( "self.marker = " + str( self.marker ) )
self.Cursor_Position( ex )
# LMB Modifier
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ShiftModifier ):
self.marker = self.Marker_Index( ex, "1" )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ControlModifier ):
self.marker = self.Marker_Index( ex, "0" )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.AltModifier ):
pass
# Reset
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == ( QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier | QtCore.Qt.AltModifier ) ):
self.Cursor_Reset()
self.update()
def mouseMoveEvent( self, event ):
# Event
ex = event.x()
# LMB Neutral
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.Cursor_Position( ex )
# LMB Modifier
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ShiftModifier ):
self.Cursor_Position( ex )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ControlModifier ):
self.Cursor_Position( ex )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.AltModifier ):
pass
# Reset
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == ( QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier | QtCore.Qt.AltModifier ) ):
self.Cursor_Reset()
self.update()
def mouseDoubleClickEvent( self, event ):
# Event
ex = event.x()
# LMB Neutral
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.Cursor_Position( ex )
# LMB Modifier
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ShiftModifier ):
self.Cursor_Position( ex )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.ControlModifier ):
self.Cursor_Position( ex )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.AltModifier ):
pass
# Reset
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == ( QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier | QtCore.Qt.AltModifier ) ):
self.Cursor_Reset()
self.update()
def mouseReleaseEvent( self, event ):
# Variables
self.marker = None
# Update
self.SIGNAL_RELEASE.emit( True )
self.update()
# Cursor
def Cursor_Position( self, ex ):
if ( self.mode != None ):
# Interaction
limit = 20
if self.marker[0] <= limit:
# Variables
index = self.marker[1]
ww = self.widget_width
vv = self.value * ww
# Markers Normal
l0 = vv - self.sele_origin["l0"] * ww
l1 = vv - self.sele_origin["l1"] * ww
r1 = vv + self.sele_origin["r1"] * ww
r0 = vv + self.sele_origin["r0"] * ww
# Markers Negative
n_l0 = vv - self.sele_origin["l0"] * ww + ww
n_l1 = vv - self.sele_origin["l1"] * ww + ww
n_r1 = vv + self.sele_origin["r1"] * ww - ww
n_r0 = vv + self.sele_origin["r0"] * ww - ww
# Calculations
if index == "l0":
delta = ex - l0
value = l0 + delta
if self.mode == "CIRCULAR":
value = self.geometry.Limit_Range( value, n_r0, l1 )
else:
value = self.geometry.Limit_Range( value, 0, l1 )
percentage = ( vv - value ) / self.widget_width
self.sele["l0"] = percentage
if index == "l1":
delta = ex - l1
value = l1 + delta
if self.mode == "CIRCULAR":
value = self.geometry.Limit_Range( value, l0, vv )
else:
value = self.geometry.Limit_Range( value, l0, vv )
percentage = ( vv - value ) / self.widget_width
self.sele["l1"] = percentage
if index == "r1":
delta = ex - r1
value = r1 + delta
if self.mode == "CIRCULAR":
value = self.geometry.Limit_Range( value, vv, r0 )
else:
value = self.geometry.Limit_Range( value, vv, r0 )
percentage = ( value - vv ) / self.widget_width
self.sele["r1"] = percentage
if index == "r0":
delta = ex - r0
value = r0 + delta
if self.mode == "CIRCULAR":
value = self.geometry.Limit_Range( value, r1, n_l0 )
else:
value = self.geometry.Limit_Range( value, r1, ww )
percentage = ( value - vv ) / self.widget_width
self.sele["r0"] = percentage
if index == "n_l0":
delta = ex - l0
value = l0 + delta
if self.mode == "CIRCULAR":
value = self.geometry.Limit_Range( value, n_r0, l1 ) - ww
else:
value = self.geometry.Limit_Range( value, 0, l1 ) - ww
percentage = ( vv - value - ww ) / self.widget_width
self.sele["l0"] = percentage
if index == "n_l1":
delta = ex - l1
value = l1 + delta
if self.mode == "CIRCULAR":
value = self.geometry.Limit_Range( value, l0, vv ) - ww
else:
value = self.geometry.Limit_Range( value, l0, vv ) - ww
percentage = ( vv - value -ww ) / self.widget_width
self.sele["l1"] = percentage
if index == "n_r1":
delta = ex - r1
value = r1 + delta
if self.mode == "CIRCULAR":
value = self.geometry.Limit_Range( value, vv, r0 ) + ww
else:
value = self.geometry.Limit_Range( value, vv, r0 ) + ww
percentage = ( value - vv - ww ) / self.widget_width
self.sele["r1"] = percentage
if index == "n_r0":
delta = ex - r0
value = r0 + delta
if self.mode == "CIRCULAR":
value = self.geometry.Limit_Range( value, r1, n_l0 ) + ww
else:
value = self.geometry.Limit_Range( value, r1, ww ) + ww
percentage = ( value - vv - ww ) / self.widget_width
self.sele["r0"] = percentage
self.SIGNAL_VALUE.emit( self.sele )
self.update()
def Cursor_Reset( self ):
if self.mode != None:
self.SIGNAL_RESET.emit( 0 )
# Marker
def Marker_Index( self, ex, mode ):
# Markers Normal
ww = self.widget_width
vv = self.value * ww
l0 = vv - self.sele["l0"] * ww
l1 = vv - self.sele["l1"] * ww
r1 = vv + self.sele["r1"] * ww
r0 = vv + self.sele["r0"] * ww
# Markers Negative
n_l0 = vv - self.sele["l0"] * ww + ww
n_l1 = vv - self.sele["l1"] * ww + ww
n_r1 = vv + self.sele["r1"] * ww - ww
n_r0 = vv + self.sele["r0"] * ww - ww
# Distance
d_ml0 = abs( ex - l0 )
d_ml1 = abs( ex - l1 )
d_mr1 = abs( ex - r1 )
d_mr0 = abs( ex - r0 )
d_n_ml0 = abs( ex - n_l0 )
d_n_ml1 = abs( ex - n_l1 )
d_n_mr1 = abs( ex - n_r1 )
d_n_mr0 = abs( ex - n_r0 )
# Index
if mode == "ALL":
distance = [ ( d_n_ml0, "n_l0" ), ( d_n_ml1, "n_l1" ), ( d_ml0, "l0" ), ( d_ml1, "l1" ), ( d_mr1, "r1" ), ( d_mr0, "r0" ), ( d_n_mr1, "n_r1" ), ( d_n_mr0, "n_r0" ) ]
elif mode == "1":
distance = [ ( d_n_ml1, "n_l1" ), ( d_ml1, "l1" ), ( d_mr1, "r1" ), ( d_n_mr1, "n_r1" ) ]
elif mode == "0":
distance = [ ( d_n_ml0, "n_l0" ), ( d_ml0, "l0" ), ( d_mr0, "r0" ), ( d_n_mr0, "n_r0" ) ]
distance.sort()
marker = distance[0]
# Return
return marker
# Paint Style
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Variables
ww = self.widget_width
hh = self.widget_height
w1 = ww - 1
w2 = ww - 2
h1 = hh - 1
h4 = hh - 4
h5 = hh - 5
h6 = hh - 6
# Slider
if ( self.value != None and self.sele != None ):
# Variables 1
vv = int( self.value * self.widget_width )
l0 = int( vv - self.sele["l0"] * self.widget_width )
l1 = int( vv - self.sele["l1"] * self.widget_width )
r1 = int( vv + self.sele["r1"] * self.widget_width )
r0 = int( vv + self.sele["r0"] * self.widget_width )
# Variables 2
l0i = int( l0 + 1 )
l1i = int( l1 + 1 )
r1i = int( r1 - 1 )
r0i = int( r0 - 1 )
# Background Style
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_alpha ) )
painter.drawRect( 0, h5, self.widget_width, 5 )
# Markers Range
left_full = QPolygon( [
QPoint( vv, 1 ),
QPoint( vv, 2 ),
QPoint( l1i, 2 ),
QPoint( l1i, h6 ),
QPoint( vv, h6 ),
QPoint( vv, h5 ),
QPoint( l1, h5 ),
QPoint( l1, 1 ),
] )
right_full = QPolygon( [
QPoint( vv, 1 ),
QPoint( vv, 2 ),
QPoint( r1i, 2 ),
QPoint( r1i, h6 ),
QPoint( vv, h6 ),
QPoint( vv, h5 ),
QPoint( r1, h5 ),
QPoint( r1, 1 ),
] )
left_tri = QPolygon( [
QPoint( l1, 1 ),
QPoint( l1, h5 ),
QPoint( l0, h5 ),
QPoint( l0, 1 ),
] )
right_tri = QPolygon( [
QPoint( r1, 1 ),
QPoint( r1, h5 ),
QPoint( r0, h5 ),
QPoint( r0, 1 ),
] )
left_cap = QPolygon( [
QPoint( l0, 1 ),
QPoint( l0, h5 ),
QPoint( l0+1, h5 ),
QPoint( l0+1, 1 ),
] )
right_cap = QPolygon( [
QPoint( r0, 1 ),
QPoint( r0, h5 ),
QPoint( r0-1, h5 ),
QPoint( r0-1, 1 ),
] )
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( QColor( self.color_1 ) ) )
painter.drawPolygon( left_full )
painter.drawPolygon( right_full )
painter.setBrush( QBrush( QColor( self.color_1 ), Qt.BDiagPattern ) )
painter.drawPolygon( left_tri )
painter.setBrush( QBrush( QColor( self.color_1 ), Qt.FDiagPattern ) )
painter.drawPolygon( right_tri )
painter.setBrush( QBrush( QColor( self.color_1 ) ) )
painter.drawPolygon( left_cap )
painter.setBrush( QBrush( QColor( self.color_1 ) ) )
painter.drawPolygon( right_cap )
if self.mode == "CIRCULAR":
# Polygons
neg_left_full = QPolygon( [
QPoint( vv - ww, 1 ),
QPoint( vv - ww, 2 ),
QPoint( r1i - ww, 2 ),
QPoint( r1i - ww, h6 ),
QPoint( vv - ww, h6 ),
QPoint( vv - ww, h5 ),
QPoint( r1 - ww, h5 ),
QPoint( r1 - ww, 1 ),
] )
neg_right_full = QPolygon( [
QPoint( vv + ww, 1 ),
QPoint( vv + ww, 2 ),
QPoint( l1i + ww, 2 ),
QPoint( l1i + ww, h6 ),
QPoint( vv + ww, h6 ),
QPoint( vv + ww, h5 ),
QPoint( l1 + ww, h5 ),
QPoint( l1 + ww, 1 ),
] )
neg_left_tri = QPolygon( [
QPoint( r1 - ww, 1 ),
QPoint( r1 - ww, h5 ),
QPoint( r0 - ww, h5 ),
QPoint( r0 - ww, 1 ),
] )
neg_right_tri = QPolygon( [
QPoint( l1 + ww, 1 ),
QPoint( l1 + ww, h5 ),
QPoint( l0 + ww, h5 ),
QPoint( l0 + ww, 1 ),
] )
neg_left_cap = QPolygon( [
QPoint( r0 - ww, 1 ),
QPoint( r0 - ww, h5 ),
QPoint( r0-1 - ww, h5 ),
QPoint( r0-1 - ww, 1 ),
] )
neg_right_cap = QPolygon( [
QPoint( l0 + ww, 1 ),
QPoint( l0 + ww, h5 ),
QPoint( l0+1 + ww, h5 ),
QPoint( l0+1 + ww, 1 ),
] )
# Draw
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( QColor( self.color_1 ) ) )
painter.drawPolygon( neg_left_full )
painter.drawPolygon( neg_right_full )
painter.setBrush( QBrush( QColor( self.color_1 ), Qt.FDiagPattern ) )
painter.drawPolygon( neg_left_tri )
painter.setBrush( QBrush( QColor( self.color_1 ), Qt.BDiagPattern ) )
painter.drawPolygon( neg_right_tri )
painter.setBrush( QBrush( QColor( self.color_1 ) ) )
painter.drawPolygon( neg_left_cap )
painter.setBrush( QBrush( QColor( self.color_1 ) ) )
painter.drawPolygon( neg_right_cap )
# Draw Colors Gradient
if self.colors != None:
painter.setPen( QtCore.Qt.NoPen )
grad = QLinearGradient( 0, 0, self.widget_width, 0 )
number = len( self.colors )
for i in range( 0, number ):
grad.setColorAt( round( i / number, 3 ), QColor( int( self.colors[i][0] * 255 ), int( self.colors[i][1] * 255 ), int( self.colors[i][2] * 255 ), int( self.alpha * 255 ) ) )
painter.setBrush( QBrush( grad ) )
square = QPolygon( [
QPoint( 1, h4 ),
QPoint( w1, h4 ),
QPoint( w1, h1 ),
QPoint( 1, h1 ),
] )
painter.drawPolygon( square )
# Cursor
if self.value != None:
vv = int( self.value * self.widget_width )
bl = vv - 3
br = vv + 3
wl = vv - 1
wr = vv + 1
top1 = 0
bot1 = self.widget_height
top2 = 1
bot2 = self.widget_height - 1
# Black Square
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_black ) )
black = QPolygon( [
QPoint( bl, top1 ),
QPoint( bl, bot1 ),
QPoint( br, bot1 ),
QPoint( br, top1 ),
] )
painter.drawPolygon( black )
# White Square
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_white ) )
white = QPolygon( [
QPoint( wl, top2 ),
QPoint( wl, bot2 ),
QPoint( wr, bot2 ),
QPoint( wr, top2 ),
] )
painter.drawPolygon( white )
#endregion
#region Pin ########################################################################
class Pin_Color( QWidget ):
SIGNAL_APPLY = QtCore.pyqtSignal( int )
SIGNAL_SAVE = QtCore.pyqtSignal( int )
SIGNAL_CLEAN = QtCore.pyqtSignal( int )
SIGNAL_ALPHA = QtCore.pyqtSignal( float )
SIGNAL_TEXT = QtCore.pyqtSignal( str )
# Init
def __init__( self, parent ):
super( Pin_Color, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( 500, 500 )
def Init_Variables( self ):
# Widget
self.widget_width = 1
self.widget_height = 1
# Events
self.event_x = 0
self.event_y = 0
# States
self.press = False
self.active = False
self.index = None
# Color
self.color = None # None == no color
self.alpha = None # None == no alpha
# Modifier Keys
self.mod_1 = [ QtCore.Qt.ShiftModifier, QtCore.Qt.ControlModifier, QtCore.Qt.AltModifier ]
self.mod_3 = ( QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier | QtCore.Qt.AltModifier )
# Modules
self.geometry = Geometry()
# Relay
def Set_Size( self, widget_width, widget_height ):
self.widget_width = widget_width
self.widget_height = widget_height
self.update()
def Set_Index( self, index ):
self.index = index
def Set_Active( self, active ):
self.active = active
self.update()
def Set_Color( self, color ):
self.color = QColor( color )
self.update()
def Set_Clean( self ):
self.color = None
self.update()
def Set_Alpha( self, alpha ):
self.alpha = alpha
self.update()
# Interaction
def mousePressEvent( self, event ):
# Variables
self.press = True
# LMB Neutral
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.press = "operation"
self.Swipe_String( event )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() in self.mod_1 ):
self.press = "alpha"
self.Swipe_Alpha( event )
# RMB Neutral
if ( event.buttons() == QtCore.Qt.RightButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.press = False
self.Context_Menu( event )
# Clean
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == self.mod_3 ):
self.press = True
self.SIGNAL_CLEAN.emit( self.index )
self.update()
def mouseMoveEvent( self, event ):
# LMB Neutral
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.Swipe_String( event )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() in self.mod_1 ):
self.Swipe_Alpha( event )
# RMB Neutral
if ( event.buttons() == QtCore.Qt.RightButton and event.modifiers() == QtCore.Qt.NoModifier ):
pass
# Clean
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == self.mod_3 ):
pass
self.update()
def mouseDoubleClickEvent( self, event ):
# LMB Neutral
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier ):
self.Swipe_String( event )
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() in self.mod_1 ):
self.Swipe_Alpha( event )
# RMB Neutral
if ( event.buttons() == QtCore.Qt.RightButton and event.modifiers() == QtCore.Qt.NoModifier ):
pass
# Clean
if ( event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == self.mod_3 ):
pass
self.update()
def mouseReleaseEvent( self, event ):
# Input
self.Swipe_Operation( event )
self.press = False
# Update
self.update()
# Swipe Operations
def Swipe_String( self, event ):
if self.press == "operation":
# Input
ex = event.x()
ey = event.y()
# Signals
if ( ( ex >= 0 and ex <= self.widget_width ) and ey <= 0 ):
self.SIGNAL_TEXT.emit( "APPLY" )
elif ( ( ex >= 0 and ex <= self.widget_width ) and ey >= self.widget_height ):
self.SIGNAL_TEXT.emit( "SAVE" )
else:
self.SIGNAL_TEXT.emit( "" )
def Swipe_Operation( self, event ):
if self.press == "operation":
# Input
ex = event.x()
ey = event.y()
# Signals
if ( ( ex >= 0 and ex <= self.widget_width ) and ey <= 0 ):
self.SIGNAL_APPLY.emit( self.index )
elif ( ( ex >= 0 and ex <= self.widget_width ) and ey >= self.widget_height ):
self.SIGNAL_SAVE.emit( self.index )
self.SIGNAL_TEXT.emit( "" )
def Swipe_Alpha( self, event ):
if ( self.press == "alpha" and self.alpha != None ):
# Input
ex = event.x()
ex = self.geometry.Limit_Range( ex, 0, self.widget_width )
# Signals
if self.widget_width != 0:
self.alpha = ex / self.widget_width
self.SIGNAL_ALPHA.emit( self.alpha )
self.update()
# Context
def Context_Menu( self, event ):
if self.press == False:
# Menu
cmenu = QMenu( self )
# Actions
cmenu_apply = cmenu.addAction( "APPLY" )
cmenu_save = cmenu.addAction( "SAVE" )
cmenu_clean = cmenu.addAction( "CLEAN" )
action = cmenu.exec_( self.mapToGlobal( QPoint( 10,5 ) ) )
# Triggers
if action == cmenu_apply:
self.SIGNAL_APPLY.emit( self.index )
if action == cmenu_save:
self.SIGNAL_SAVE.emit( self.index )
if action == cmenu_clean:
self.SIGNAL_CLEAN.emit( self.index )
# Paint Style
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Background
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.color_alpha ) )
painter.drawRect( 0, 0, self.widget_width, self.widget_height )
# Active
if self.active == True:
# Dot
w1 = 1
w3 = self.widget_width-2
# Color
h2 = 2
h4 = self.widget_height-3
else:
# Dot
w1 = 0
w3 = 1
# Color
h2 = 1
h4 = self.widget_height-2
if self.alpha == None:
a1 = 0
else:
a1 = 2
# Dot
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( QColor( self.color_1 ) ) )
painter.drawRect( w1, 0, w3, 1 )
# Color
painter.setPen( QtCore.Qt.NoPen )
if self.color != None:
qcolor = self.color
if self.alpha != None:
qcolor.setAlphaF( self.alpha )
painter.setBrush( QBrush( qcolor ) )
painter.drawRect( QRectF( 1, h2, self.widget_width - 2, h4 - a1 ) )
# Alpha
if self.alpha != None:
painter.setPen( QtCore.Qt.NoPen )
# Background
painter.setBrush( QBrush( self.color_2 ) )
painter.drawRect( QRectF( 1, self.widget_height-a1, self.widget_width - 2, a1 ) )
# Slider
painter.setBrush( QBrush( self.color_1 ) )
painter.drawRect( QRectF( 1, self.widget_height-a1, ( self.widget_width*self.alpha ) - 2, a1 ) )
#endregion
#region Ink #######################################################################
class Sample_Map( QWidget ):
SIGNAL_INDEX = QtCore.pyqtSignal( int )
# Init
def __init__( self, parent ):
super( Sample_Map, self ).__init__( parent )
self.Init_Variables()
def sizeHint( self ):
return QtCore.QSize( render_width, render_height )
def Init_Variables( self ):
# Widget
self.widget_width = 1
self.widget_height = 1
# Render
self.index = None
self.qpixmap = None
self.qcolor = QColor( 0, 0, 0, 50 )
# Relay
def Set_Size( self, widget_width, widget_height ):
self.widget_width = widget_width
self.widget_height = widget_height
self.update()
def Set_Sample( self, index, qpixmap, qcolor ):
self.index = index
self.qpixmap = qpixmap
if qcolor == True:
self.qcolor = QColor( 255, 0, 0, 50 )
else:
self.qcolor = QColor( 0, 0, 0, 50 )
self.update()
# Context Menu
def contextMenuEvent( self, event ):
# Variables
check = self.index != None and self.qpixmap != None
# Menu
cmenu = QMenu( self )
# Actions
if check == True:
cmenu_insert = cmenu.addAction( "Insert Map" )
# Map
action = cmenu.exec_( self.mapToGlobal( event.pos() ) )
# Triggers
if check == True:
if action == cmenu_insert:
self.SIGNAL_INDEX.emit( self.index )
# Paint Style
def paintEvent( self, event ):
# Theme
krita_theme( self )
# Painter
painter = QPainter( self )
painter.setRenderHint( QtGui.QPainter.Antialiasing, True )
# Background
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QBrush( self.qcolor ) )
painter.drawRect( 0, 0, self.widget_width, self.widget_height )
# Render
try:
# Scale
render_pix = self.qpixmap.scaled( self.widget_width, self.widget_height, Qt.KeepAspectRatio, Qt.FastTransformation )
# Variables
rw = render_pix.width()
rh = render_pix.height()
px = int( ( self.widget_width * 0.5 ) - ( rw * 0.5 ) )
py = int( ( self.widget_height * 0.5 ) - ( rh * 0.5 ) )
# Painter settings
painter.setPen( QtCore.Qt.NoPen )
painter.setBrush( QtCore.Qt.NoBrush )
# Image
painter.drawPixmap( px, py, render_pix )
except:
self.Render_None( painter, event )
def Render_None( self, painter, event ):
painter.setPen( self.color_1 )
painter.setFont( QFont( 'Liberation Mono', 10 ) )
painter.drawText( event.rect(), Qt.AlignCenter, "None" )
#endregion