451 lines
17 KiB
Plaintext
451 lines
17 KiB
Plaintext
default color_history = []
|
|
default color_favorites = [[167, 77, 42, 255], [237, 179, 14, 255], [89, 116, 194, 255], [216, 163, 10, 255], [58, 115, 75, 255], [205, 205, 206, 255], [251, 198, 10, 255], [51, 43, 54, 255]]
|
|
|
|
screen color_picker(color, alpha, title, pos_xy, color_default):
|
|
tag color_picker
|
|
zorder 25
|
|
modal True
|
|
|
|
# Screen variables
|
|
default rgba = color
|
|
default rgba_old = color
|
|
default hue = 0
|
|
default sat = 0
|
|
default val = 0
|
|
default alpha_ = 0 # Avoid name conflict with 'alpha' screen variable in other active screens
|
|
default edit_mode = False
|
|
default preview_old = Solid(rgba)
|
|
$ preview_new = Solid(rgba)
|
|
$ gradient_map = SVGradientButton(
|
|
color_picker_clicked,
|
|
Fixed(
|
|
Color(hsv=(1-hue, 1, 1)),
|
|
Frame("interface/color_picker/saturation_value_gradient.webp")
|
|
),
|
|
xysize=(255, 255),
|
|
#area=(25, 25, 255, 255),
|
|
focus_mask=None,
|
|
keyboard_focus=False,
|
|
key_events=False
|
|
)
|
|
|
|
default icon_frame = Frame(gui.format("interface/frames/{}/iconframe.webp"), 6, 6)
|
|
default icon_transparent = Frame("interface/color_picker/checker.webp", tile=True)
|
|
default slider_thumb = Image(gui.format("interface/color_picker/{}/cursor_h.webp"), xalign=0.5)
|
|
|
|
# Set HSVA variables based on RGBA when screen shows
|
|
on "show" action Function(color_picker_update_hsva)
|
|
|
|
frame:
|
|
style_prefix gui.theme()
|
|
if pos_xy and False:
|
|
pos pos_xy
|
|
else:
|
|
align (0.5, 0.5)
|
|
padding (18, 18)
|
|
|
|
vbox:
|
|
spacing 12
|
|
|
|
# Colour swatches
|
|
hbox:
|
|
ysize 80
|
|
spacing 12
|
|
vbox:
|
|
spacing 12
|
|
#pos (0,0)
|
|
|
|
hbox:
|
|
spacing 12
|
|
text "Colour swatches"
|
|
textbutton "Edit":
|
|
yoffset -4
|
|
text_size 12
|
|
action [SelectedIf(edit_mode),ToggleScreenVariable("edit_mode", True, False)]
|
|
hbox:
|
|
spacing 2
|
|
for i in range(8):
|
|
$ is_valid = (i < len(color_favorites))
|
|
$ background = Fixed(icon_transparent, Color(tuple(color_favorites[i])), icon_frame) if is_valid else icon_frame
|
|
|
|
if edit_mode:
|
|
if is_valid:
|
|
$ action = Return(["rem_swatch", i])
|
|
$ icon = Text("X", color="#b20000", align=(0.5, 0.5), outlines=[(1, "#000", 0, 0)])
|
|
$ tooltip = "Remove"
|
|
else:
|
|
$ action = Return(["add_swatch", list(rgba)])
|
|
$ icon = Image("interface/icons/small/star_yellow.webp", align=(0.5, 0.5))
|
|
$ tooltip = "Add"
|
|
elif is_valid:
|
|
$ action = Return(["use_swatch", color_favorites[i]])
|
|
$ icon = None
|
|
$ tooltip = "Select"
|
|
|
|
button:
|
|
xysize (32, 32)
|
|
background background
|
|
hover_foreground "#ffffff80"
|
|
tooltip tooltip
|
|
action action
|
|
add icon
|
|
|
|
vbox:
|
|
text "History"
|
|
frame:
|
|
xsize 140
|
|
background icon_frame
|
|
viewport id "history":
|
|
scrollbars "vertical"
|
|
mousewheel True
|
|
draggable False
|
|
pagekeys True
|
|
side_yfill True
|
|
vbox:
|
|
for c in color_history[::-1]:
|
|
textbutton rgba_to_hex(c):
|
|
style "empty"
|
|
xfill True
|
|
ysize 16
|
|
text_size 11
|
|
text_color "#000"
|
|
text_hover_color "#fff"
|
|
text_outlines [(1, "#fff", 0, 0)]
|
|
text_hover_outlines [(1, "#000", 0, 0)]
|
|
text_align (0.5, 0.5)
|
|
background Color(tuple(c))
|
|
action Return(["history", c])
|
|
|
|
# Colour picker
|
|
text title xalign 0.5 text_align 0.5
|
|
|
|
hbox:
|
|
spacing 12
|
|
|
|
fixed:
|
|
xysize (255, 255)
|
|
fit_first True
|
|
add gradient_map
|
|
|
|
add icon_frame
|
|
|
|
draggroup:
|
|
# Allow cursor to extend 8 pixels outside map
|
|
area (-8, -8, 255 + 16, 255 + 16)
|
|
drag:
|
|
pos (int(sat * 253), int((1 - val) * 253))
|
|
anchor (0, 0)
|
|
child gui.format("interface/color_picker/{}/cursor_sq.webp")
|
|
focus_mask None
|
|
dragged color_picker_dragged
|
|
|
|
# Hue slider
|
|
# frame:
|
|
# margin (-6, -6)
|
|
fixed:
|
|
fit_first True
|
|
add hue_gradient_image
|
|
vbar:
|
|
xysize (30, 255)
|
|
value ScreenVariableValue("hue", range=1.0, action=Function(color_picker_update_rgba))
|
|
base_bar icon_frame
|
|
thumb slider_thumb
|
|
thumb_offset 0
|
|
top_gutter 0
|
|
bottom_gutter 0
|
|
|
|
vbox:
|
|
xysize (110, 255)
|
|
fixed:
|
|
yfill False
|
|
fit_first True
|
|
|
|
# TODO: Merge RGB(A) input into a single action, add HEX(A) and add copy/paste functionality
|
|
vbox:
|
|
textbutton "Red: " + str(int(rgba[0])):
|
|
xfill True
|
|
size_group "rgba"
|
|
text_size 12
|
|
clicked Return(["input", 0])
|
|
textbutton "Green: " + str(int(rgba[1])):
|
|
size_group "rgba"
|
|
text_size 12
|
|
clicked Return(["input", 1])
|
|
textbutton "Blue: " + str(int(rgba[2])):
|
|
size_group "rgba"
|
|
text_size 12
|
|
clicked Return(["input", 2])
|
|
if alpha:
|
|
textbutton "Alpha: " + str(int(rgba[3])):
|
|
size_group "rgba"
|
|
text_size 12
|
|
clicked Return(["input", 3])
|
|
if color_default:
|
|
textbutton "Reset":
|
|
size_group "rgba"
|
|
text_size 12
|
|
text_xalign 0.5
|
|
clicked Return("reset")
|
|
add icon_frame
|
|
|
|
# Selected color
|
|
fixed:
|
|
fit_first True
|
|
xysize (110, 110)
|
|
yalign 1.0
|
|
add Frame("interface/color_picker/checker.webp", tile=True, )
|
|
frame:
|
|
area (0, 0, 55, 110)
|
|
background preview_new
|
|
text "New" xalign 0.5 color "#fff" outlines [(1, "#00000080", 1, 0)]
|
|
frame:
|
|
area (55, 0, 55, 110)
|
|
background preview_old
|
|
text "Old" xalign 0.5 color "#fff" outlines [(1, "#00000080", 1, 0)]
|
|
add icon_frame
|
|
|
|
if alpha:
|
|
# Opacity slider
|
|
fixed:
|
|
xysize (255, 30)
|
|
fit_first True
|
|
add Fixed(Frame("interface/color_picker/checker.webp", tile=True),
|
|
Transform(alpha_gradient_image, matrixcolor=ColorizeMatrix(rgba, rgba)))
|
|
bar:
|
|
xysize (255, 30)
|
|
value ScreenVariableValue("alpha_", range=1.0, action=Function(color_picker_update_rgba))
|
|
base_bar icon_frame
|
|
thumb Image(gui.format("interface/color_picker/{}/cursor_v.webp"), xalign=0.5)
|
|
thumb_offset 0
|
|
top_gutter 0
|
|
bottom_gutter 0
|
|
|
|
# Window buttons
|
|
hbox:
|
|
align (1.0, 1.0)
|
|
spacing 6
|
|
textbutton "Cancel" action Return("cancel")
|
|
textbutton "Apply" action Return(["apply", rgba])
|
|
|
|
default picking_color = None
|
|
|
|
define alpha_gradient_image = AlphaSlider()
|
|
define hue_gradient_image = HueSlider()
|
|
|
|
init -1 python:
|
|
|
|
def color_picker(color=(0,0,0,0), alpha=True, title="Pick a colour", pos_xy=(240, 130), color_default=None):
|
|
global picking_color
|
|
picking_color = list(color) # Color object (list) to be updated live
|
|
start_color = list(color) # Keep a copy
|
|
|
|
renpy.show_screen("color_picker", tuple(color), alpha, title, pos_xy, color_default)
|
|
|
|
while True:
|
|
_return = ui.interact()
|
|
|
|
if _return[0] == "input":
|
|
color_picker_input(_return[1])
|
|
|
|
elif _return == "reset":
|
|
scope = renpy.get_screen("color_picker").scope
|
|
scope["rgba"] = tuple(color_default)
|
|
color_picker_update_hsva()
|
|
update_picking_color(color_default)
|
|
|
|
elif _return[0] == "use_swatch":
|
|
scope = renpy.get_screen("color_picker").scope
|
|
scope["rgba"] = tuple(_return[1])
|
|
color_picker_update_hsva()
|
|
update_picking_color(_return[1])
|
|
|
|
elif _return[0] == "add_swatch":
|
|
color_picker_add(_return[1])
|
|
|
|
elif _return[0] == "rem_swatch":
|
|
color_picker_rem(_return[1])
|
|
|
|
elif _return[0] == "history":
|
|
scope = renpy.get_screen("color_picker").scope
|
|
scope["rgba"] = tuple(_return[1])
|
|
color_picker_update_hsva()
|
|
update_picking_color(_return[1])
|
|
|
|
elif _return == "cancel":
|
|
hide_color_picker()
|
|
update_picking_color(start_color) # Reset live color object
|
|
picking_color = None
|
|
return start_color
|
|
|
|
elif _return[0] == "apply":
|
|
hide_color_picker()
|
|
picking_color = None
|
|
return color # Return live color object instead of _return tuple
|
|
|
|
def hide_color_picker():
|
|
renpy.hide_screen("color_picker")
|
|
|
|
def update_picking_color(rgba):
|
|
global picking_color
|
|
for (i, x) in enumerate(rgba):
|
|
picking_color[i] = x
|
|
|
|
def color_picker_input(comp):
|
|
scope = renpy.get_screen("color_picker").scope
|
|
x = renpy.input(["Red", "Green", "Blue", "Alpha"][comp], str(scope["rgba"][comp]), "0123456789", length=3)
|
|
x = max(0, min(255, int(x)))
|
|
tuplist = list(scope["rgba"])
|
|
tuplist[comp] = x
|
|
scope["rgba"] = tuple(tuplist)
|
|
color_picker_update_hsva()
|
|
update_picking_color(scope["rgba"])
|
|
|
|
def color_picker_update_hsva():
|
|
scope = renpy.get_screen("color_picker").scope
|
|
(r, g, b, a) = scope["rgba"]
|
|
(h, s, v) = Color((r, g, b)).hsv
|
|
scope["hue"] = 1 - h
|
|
scope["sat"] = s
|
|
scope["val"] = v
|
|
scope["alpha_"] = a / 255.0
|
|
|
|
def color_picker_update_rgba():
|
|
scope = renpy.get_screen("color_picker").scope
|
|
(r, g, b) = Color(hsv=(1 - scope["hue"], scope["sat"], scope["val"])).rgb
|
|
r = int(r * 255)
|
|
g = int(g * 255)
|
|
b = int(b * 255)
|
|
a = int(scope["alpha_"] * 255)
|
|
scope["rgba"] = (r, g, b, a)
|
|
update_picking_color(scope["rgba"])
|
|
renpy.restart_interaction()
|
|
|
|
#def color_picker_clicked(offset, size):
|
|
def color_picker_clicked(x, y, size):
|
|
# Mouse screen position to local position
|
|
# (x, y) = renpy.get_mouse_pos()
|
|
# x = max(0, min(x - offset[0], size[0]))
|
|
# y = max(0, min(y - offset[1], size[1]))
|
|
# Update screen variables
|
|
scope = renpy.get_screen("color_picker").scope
|
|
scope["sat"] = float(x) / size[0]
|
|
scope["val"] = 1 - float(y) / size[1]
|
|
color_picker_update_rgba()
|
|
color_picker_history()
|
|
|
|
def color_picker_dragged(drags, drop=None):
|
|
# Compensate for draggable area
|
|
width = drags[0].parent_width - drags[0].w
|
|
height = drags[0].parent_height - drags[0].h
|
|
x = drags[0].x
|
|
y = drags[0].y
|
|
# Update screen variables
|
|
scope = renpy.get_screen("color_picker").scope
|
|
scope["sat"] = float(x) / width
|
|
scope["val"] = 1 - float(y) / height
|
|
color_picker_update_rgba()
|
|
color_picker_history()
|
|
|
|
def color_picker_history():
|
|
global color_history
|
|
scope = renpy.get_screen("color_picker").scope
|
|
color_history.append(scope["rgba"])
|
|
if len(color_history) > 30:
|
|
del color_history[0]
|
|
|
|
def color_picker_add(item):
|
|
global color_favorites
|
|
color_favorites.append(item)
|
|
|
|
def color_picker_rem(item):
|
|
global color_favorites
|
|
del color_favorites[item]
|
|
|
|
def rgba_to_hex(c):
|
|
return '#%02x%02x%02x%02x' % (c[0], c[1], c[2], c[3])
|
|
|
|
class HueSlider(renpy.Displayable, NoRollback):
|
|
def __init__(self, size=(30,255), **properties):
|
|
super(HueSlider, self).__init__(**properties)
|
|
self.size = size
|
|
|
|
def render(self, width, height, st, at):
|
|
w, h = self.size
|
|
rv = renpy.Render(w, h)
|
|
canvas = rv.canvas()
|
|
surf = canvas.get_surface()
|
|
|
|
for x in range(w):
|
|
for y in range(h):
|
|
hue = float(y) / h
|
|
r, g, b = Color(hsv=(hue, 1.0, 1.0)).rgb
|
|
color = (r * 255, g * 255, b * 255)
|
|
surf.set_at((x, y), color)
|
|
|
|
#surf = renpy.display.scale.smoothscale(surf, (w, h))
|
|
|
|
rv.blit(surf, (0, 0))
|
|
|
|
return rv
|
|
|
|
def event(self, ev, x, y, st):
|
|
return
|
|
|
|
class AlphaSlider(renpy.Displayable, NoRollback):
|
|
def __init__(self, size=(255,30), **properties):
|
|
super(AlphaSlider, self).__init__(**properties)
|
|
self.size = size
|
|
|
|
def render(self, width, height, st, at):
|
|
w, h = self.size
|
|
rv = renpy.Render(w, h)
|
|
canvas = rv.canvas()
|
|
surf = canvas.get_surface()
|
|
|
|
for x in range(w):
|
|
for y in range(h):
|
|
hue = float(y) / h
|
|
color = (255.0, 255.0, 255.0, x)
|
|
surf.set_at((x, y), color)
|
|
|
|
#surf = pygame.transform.scale(surf, (w, h))
|
|
|
|
rv.blit(surf, (0, 0))
|
|
|
|
return rv
|
|
|
|
def event(self, ev, x, y, st):
|
|
return
|
|
|
|
class GradientImageBase(im.ImageBase):
|
|
def __init__(self, **properties):
|
|
super(GradientImageBase, self).__init__(**properties)
|
|
self.size = properties.get('size')
|
|
self.cached_surf = None
|
|
|
|
class SVGradientButton(ImageButton):
|
|
|
|
def __init__(self, on_click, idle_image, *args, **kwargs):
|
|
super(SVGradientButton, self).__init__(idle_image, *args, sensitive=True, action=NullAction(), **kwargs)
|
|
self.width = 0
|
|
self.height = 0
|
|
self.on_click = on_click
|
|
|
|
def render(self, width, height, st, at):
|
|
rv = super(SVGradientButton, self).render(width, height, st, at)
|
|
self.width, self.height = rv.get_size()
|
|
return rv
|
|
|
|
def event(self, ev, x, y, st):
|
|
if ev.type == pygame.MOUSEBUTTONUP and 0 <= x <= self.width and 0 <= y <= self.height:
|
|
self.on_click(x, y, (self.width, self.height))
|
|
|
|
return super(SVGradientButton, self).event(ev, x, y, st)
|
|
|
|
# image testsurface = HueSlider()
|
|
|
|
# screen testzone():
|
|
# tag testzone
|
|
# zorder 1000
|
|
# add "testsurface" #align (0.5, 0.5)
|