mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 21:37:57 +08:00
HEX support
This commit is contained in:
parent
c2d88cab28
commit
d8a9a881f4
@ -36,6 +36,7 @@
|
||||
EraOSBeta!)
|
||||
- Added a UI for customizing Series Length in Teams and Points-to-Win in FFA
|
||||
(Thanks EraOSBeta!)
|
||||
- Implemented HEX code support to the advanced color picker (Thanks 3alTemp!)
|
||||
|
||||
### 1.7.32 (build 21741, api 8, 2023-12-20)
|
||||
- Fixed a screen message that no one will ever see (Thanks vishal332008?...)
|
||||
|
||||
@ -43,9 +43,7 @@ class ColorPicker(PopupWindow):
|
||||
scale = (
|
||||
2.3
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.65
|
||||
if uiscale is bui.UIScale.MEDIUM
|
||||
else 1.23
|
||||
else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23
|
||||
)
|
||||
self._parent = parent
|
||||
self._position = position
|
||||
@ -206,9 +204,7 @@ class ColorPickerExact(PopupWindow):
|
||||
scale = (
|
||||
2.3
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.65
|
||||
if uiscale is bui.UIScale.MEDIUM
|
||||
else 1.23
|
||||
else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23
|
||||
)
|
||||
self._delegate = delegate
|
||||
self._transitioning_out = False
|
||||
@ -217,6 +213,8 @@ class ColorPickerExact(PopupWindow):
|
||||
self._last_press_time = bui.apptime()
|
||||
self._last_press_color_name: str | None = None
|
||||
self._last_press_increasing: bool | None = None
|
||||
self._hex_timer: bui.AppTimer | None = None
|
||||
self._hex_prev_text: str = '#FFFFFF'
|
||||
self._change_speed = 1.0
|
||||
width = 180.0
|
||||
height = 240.0
|
||||
@ -233,11 +231,25 @@ class ColorPickerExact(PopupWindow):
|
||||
)
|
||||
self._swatch = bui.imagewidget(
|
||||
parent=self.root_widget,
|
||||
position=(width * 0.5 - 50, height - 70),
|
||||
size=(100, 70),
|
||||
texture=bui.gettexture('buttonSquare'),
|
||||
position=(width * 0.5 - 65 + 5, height - 95),
|
||||
size=(130, 115),
|
||||
texture=bui.gettexture('clayStroke'),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
self._hex_textbox = bui.textwidget(
|
||||
parent=self.root_widget,
|
||||
position=(width * 0.5 - 37.5 + 3, height - 51),
|
||||
max_chars=9,
|
||||
text='#FFFFFF',
|
||||
# on_return_press_call=self._done,
|
||||
autoselect=True,
|
||||
size=(75, 30),
|
||||
v_align='center',
|
||||
editable=True,
|
||||
maxwidth=70,
|
||||
force_internal_editing=True,
|
||||
)
|
||||
|
||||
x = 50
|
||||
y = height - 90
|
||||
self._label_r: bui.Widget
|
||||
@ -292,6 +304,33 @@ class ColorPickerExact(PopupWindow):
|
||||
# color to the delegate, so start doing that.
|
||||
self._update_for_color()
|
||||
|
||||
# Update our HEX stuff!
|
||||
self._update_for_hex()
|
||||
self._hex_timer = bui.AppTimer(0.025, self._update_for_hex, repeat=True)
|
||||
|
||||
def _update_for_hex(self) -> None:
|
||||
"""Update for any HEX or color change."""
|
||||
from typing import cast
|
||||
|
||||
hextext = cast(str, bui.textwidget(query=self._hex_textbox))
|
||||
hexcolor: tuple[float, float, float, float]
|
||||
# Check if our current hex text doesn't match with our old one.
|
||||
# Convert our current hex text into a color if possible.
|
||||
if hextext != self._hex_prev_text:
|
||||
try:
|
||||
hexcolor = hex_to_color(hextext)
|
||||
r, g, b, _ = hexcolor
|
||||
# Replace the color!
|
||||
for i, ch in enumerate((r, g, b)):
|
||||
self._color[i] = max(0.0, min(1.0, ch))
|
||||
self._update_for_color()
|
||||
# Usually, a ValueError will occur if the provided hex
|
||||
# is incomplete, which occurs when in the midst of typing it.
|
||||
except ValueError:
|
||||
pass
|
||||
# Store the current text for our next comparison.
|
||||
self._hex_prev_text = hextext
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def _update_for_color(self) -> None:
|
||||
if not self.root_widget:
|
||||
@ -307,6 +346,16 @@ class ColorPickerExact(PopupWindow):
|
||||
if self._delegate is not None:
|
||||
self._delegate.color_picker_selected_color(self, self._color)
|
||||
|
||||
# Show the HEX code of this color.
|
||||
r, g, b = self._color
|
||||
hexcode = color_to_hex(r, g, b, None)
|
||||
self._hex_prev_text = hexcode
|
||||
bui.textwidget(
|
||||
edit=self._hex_textbox,
|
||||
text=hexcode,
|
||||
color=color_overlay_func(r, g, b),
|
||||
)
|
||||
|
||||
def _color_change_press(self, color_name: str, increasing: bool) -> None:
|
||||
# If we get rapid-fire presses, eventually start moving faster.
|
||||
current_time = bui.apptime()
|
||||
@ -335,6 +384,8 @@ class ColorPickerExact(PopupWindow):
|
||||
return self._tag
|
||||
|
||||
def _transition_out(self) -> None:
|
||||
# Kill our timer
|
||||
self._hex_timer = None
|
||||
if not self._transitioning_out:
|
||||
self._transitioning_out = True
|
||||
if self._delegate is not None:
|
||||
@ -346,3 +397,100 @@ class ColorPickerExact(PopupWindow):
|
||||
if not self._transitioning_out:
|
||||
bui.getsound('swish').play()
|
||||
self._transition_out()
|
||||
|
||||
|
||||
def hex_to_color(hex_color: str) -> tuple:
|
||||
"""Transforms an RGB / RGBA hex code into an rgb1/rgba1 tuple.
|
||||
|
||||
Args:
|
||||
hex_color (str): The HEX color.
|
||||
Raises:
|
||||
ValueError: If the provided HEX color isn't 6 or 8 characters long.
|
||||
Returns:
|
||||
tuple: The color tuple divided by 255.
|
||||
"""
|
||||
# Remove the '#' from the string if provided.
|
||||
if hex_color.startswith('#'):
|
||||
hex_color = hex_color.lstrip('#')
|
||||
# Check if this has a valid length.
|
||||
hexlength = len(hex_color)
|
||||
if not hexlength in [6, 8]:
|
||||
raise ValueError(f'Invalid HEX color provided: "{hex_color}"')
|
||||
|
||||
# Convert the hex bytes to their true byte form.
|
||||
ar, ag, ab, aa = (
|
||||
(int.from_bytes(bytes.fromhex(hex_color[0:2]))),
|
||||
(int.from_bytes(bytes.fromhex(hex_color[2:4]))),
|
||||
(int.from_bytes(bytes.fromhex(hex_color[4:6]))),
|
||||
(
|
||||
int.from_bytes(bytes.fromhex(hex_color[6:8]))
|
||||
if hexlength == 8
|
||||
else 255
|
||||
),
|
||||
)
|
||||
# Divide all numbers by 255 and return.
|
||||
nr, ng, nb, na = (x / 255 if x is not None else None for x in (ar, ag, ab, aa))
|
||||
return (nr, ng, nb, na) if aa is not None else (nr, ng, nb)
|
||||
|
||||
|
||||
def color_to_hex(r: float, g: float, b: float, a: float | None = 1.0) -> str:
|
||||
"""Converts an rgb1 tuple to a HEX color code.
|
||||
|
||||
Args:
|
||||
r (float): Red.
|
||||
g (float): Green.
|
||||
b (float): Blue.
|
||||
a (float, optional): Alpha. Defaults to 1.0.
|
||||
|
||||
Returns:
|
||||
str: The hexified rgba values.
|
||||
"""
|
||||
# Turn our rgb1 to rgb255
|
||||
nr, ng, nb, na = [
|
||||
int(min(255, x * 255)) if x is not None else x for x in [r, g, b, a]
|
||||
]
|
||||
# Merge all values into their HEX representation.
|
||||
hex_code = (
|
||||
f'#{nr:02x}{ng:02x}{nb:02x}{na:02x}'
|
||||
if na is not None
|
||||
else f'#{nr:02x}{ng:02x}{nb:02x}'
|
||||
)
|
||||
return hex_code
|
||||
|
||||
|
||||
def color_overlay_func(
|
||||
r: float, g: float, b: float, a: float | None = None
|
||||
) -> tuple:
|
||||
"""I could NOT come up with a better function name.
|
||||
|
||||
Args:
|
||||
r (float): Red.
|
||||
g (float): Green.
|
||||
b (float): Blue.
|
||||
a (float | None, optional): Alpha. Defaults to None.
|
||||
|
||||
Returns:
|
||||
tuple: A brighter color if the provided one is dark,
|
||||
and a darker one if it's darker.
|
||||
"""
|
||||
|
||||
# Calculate the relative luminance using the formula for sRGB
|
||||
# https://www.w3.org/TR/WCAG20/#relativeluminancedef
|
||||
def relative_luminance(color: float) -> Any:
|
||||
if color <= 0.03928:
|
||||
return color / 12.92
|
||||
return ((color + 0.055) / 1.055) ** 2.4
|
||||
|
||||
luminance = (
|
||||
0.2126 * relative_luminance(r)
|
||||
+ 0.7152 * relative_luminance(g)
|
||||
+ 0.0722 * relative_luminance(b)
|
||||
)
|
||||
# Set our color multiplier depending on the provided color's luminance.
|
||||
luminant = 1.65 if luminance < 0.33 else 0.2
|
||||
# Multiply our given numbers, making sure
|
||||
# they don't blend in the original bg.
|
||||
avg = (0.7 - (r + g + b / 3)) + 0.15
|
||||
r, g, b = [max(avg, x * luminant) for x in (r, g, b)]
|
||||
# Include our alpha and ship it!
|
||||
return (r, g, b, a) if a is not None else (r, g, b)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user