WTS/game/scripts/interface/color_picker.rpy

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)