Skip to content

Commit 19b53a1

Browse files
authored
Gui/colorpicker (#2354)
* Add color picker example
1 parent 10143b9 commit 19b53a1

10 files changed

Lines changed: 254 additions & 15 deletions

File tree

‎arcade/examples/gui/0_basic_setup.py‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
UITextureButton,
1616
UIAnchorLayout,
1717
)
18-
from arcade.types import Color
1918

2019
# Preload textures, because they are mostly used multiple times, so they are not
2120
# loaded multiple times
@@ -60,7 +59,7 @@ def on_hide_view(self) -> None:
6059

6160
def on_draw(self):
6261
# Clear the screen
63-
self.clear(color=Color(46, 204, 113))
62+
self.clear(color=arcade.uicolor.GREEN_EMERALD)
6463

6564
# Add draw commands that should be below the UI
6665
# ...
@@ -76,7 +75,7 @@ class BlueView(arcade.gui.UIView):
7675

7776
def __init__(self):
7877
super().__init__()
79-
self.background_color = Color(52, 152, 219)
78+
self.background_color = arcade.uicolor.BLUE_PETER_RIVER
8079

8180
# Create a anchor layout, which can be used to position widgets on screen
8281
anchor = self.add_widget(UIAnchorLayout())

‎arcade/examples/gui/1_layouts.py‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
import arcade
1717
from arcade.gui import UIAnchorLayout
18-
from arcade.types import Color
1918

2019
arcade.resources.load_system_fonts()
2120

@@ -66,22 +65,22 @@ class LayoutView(arcade.gui.UIView):
6665

6766
def __init__(self):
6867
super().__init__()
69-
self.background_color = Color(52, 152, 219)
68+
self.background_color = arcade.uicolor.BLUE_PETER_RIVER
7069

7170
# Create a anchor layout, which can be used to position widgets on screen
7271
self.anchor = self.add_widget(UIAnchorLayout())
7372

7473
# Add describing text in center
7574
text_area = arcade.gui.UITextArea(
7675
text=DESCRIPTION,
77-
text_color=Color(236, 240, 241),
76+
text_color=arcade.uicolor.WHITE_CLOUDS,
7877
font_name=("Lato", "proxima-nova", "Helvetica Neue", "Arial", "sans-serif"),
7978
font_size=12,
8079
size_hint=(0.5, 0.8),
8180
)
8281
self.anchor.add(text_area, anchor_x="center_x", anchor_y="center_y")
83-
text_area.with_border(color=Color(149, 165, 166))
84-
text_area.with_background(color=Color(149, 165, 166, 125))
82+
text_area.with_border(color=arcade.uicolor.GRAY_CONCRETE)
83+
text_area.with_background(color=arcade.uicolor.GRAY_CONCRETE.replace(a=125))
8584
text_area.with_padding(left=5)
8685

8786
# add a grid layout with the window and grid size and grid position
@@ -90,8 +89,8 @@ def __init__(self):
9089
row_count=2,
9190
align_horizontal="left",
9291
)
93-
self.grid.with_background(color=Color(149, 165, 166))
94-
self.grid.with_border(color=Color(127, 140, 141))
92+
self.grid.with_background(color=arcade.uicolor.GRAY_CONCRETE)
93+
self.grid.with_border(color=arcade.uicolor.GRAY_ASBESTOS)
9594
self.grid.with_padding(all=10)
9695
self.anchor.add(self.grid, anchor_x="left", anchor_y="top", align_x=10, align_y=-10)
9796
self.grid.add(

‎arcade/examples/gui/4_gui_and_camera.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,6 @@ def on_key_release(self, symbol: int, modifiers: int) -> Optional[bool]:
262262

263263
if __name__ == "__main__":
264264
window = arcade.Window(1280, 720, "GUI Example: Coin Game (Camera)", resizable=False)
265-
window.background_color = arcade.color.DARK_BLUE_GRAY
265+
window.background_color = arcade.uicolor.DARK_BLUE_MIDNIGHT_BLUE
266266
window.show_view(MyCoinGame())
267267
window.run()
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
"""Show all arcade.uicolors in a grid.
2+
3+
Click on a color to select
4+
it and copy the arcade reference to the clipboard.
5+
6+
If arcade and Python are properly installed, you can run this example with:
7+
python -m arcade.examples.gui.5_uicolor_picker
8+
9+
"""
10+
11+
from dataclasses import dataclass
12+
13+
import arcade
14+
from arcade.gui import (
15+
UIAnchorLayout,
16+
UIEvent,
17+
UIInteractiveWidget,
18+
UITextWidget,
19+
)
20+
21+
22+
@dataclass
23+
class ChooseColorEvent(UIEvent):
24+
"""Custom event, which is dispatched when a color button is clicked."""
25+
26+
color_name: str
27+
color: arcade.color.Color
28+
29+
30+
class Toast(arcade.gui.UILabel):
31+
"""Label which disappears after a certain time."""
32+
33+
def __init__(self, text: str, duration: float = 2.0, **kwargs):
34+
super().__init__(**kwargs)
35+
self.text = text
36+
self.duration = duration
37+
self.time = 0
38+
39+
def on_update(self, dt):
40+
self.time += dt
41+
42+
if self.time > self.duration:
43+
self.parent.remove(self)
44+
45+
46+
class ColorButton(UITextWidget, UIInteractiveWidget):
47+
"""Button which shows a color and color name and
48+
emits a ChooseColorEvent event when clicked."""
49+
50+
def __init__(
51+
self,
52+
color_name: str,
53+
color: arcade.color.Color,
54+
**kwargs,
55+
):
56+
super().__init__(text=color_name, **kwargs)
57+
# set color and place text on the bottom
58+
self.with_background(color=color)
59+
self.place_text(anchor_y="bottom")
60+
61+
# set font color based on background color
62+
f = 2 if color_name.startswith("DARK") else 0.5
63+
self.ui_label.update_font(
64+
font_color=arcade.color.Color(int(color[0] * f), int(color[1] * f), int(color[2] * f))
65+
)
66+
67+
# store color name and color for later reference
68+
self._color_name = color_name
69+
self._color = color
70+
71+
# register custom event
72+
self.register_event_type("on_choose_color")
73+
74+
def on_update(self, dt):
75+
"""Update the button state.
76+
77+
UIInteractiveWidget provides properties like hovered and pressed,
78+
which can be used to highlight the button."""
79+
if self.pressed:
80+
self.with_border(color=arcade.uicolor.WHITE_CLOUDS, width=3)
81+
elif self.hovered:
82+
self.with_border(color=arcade.uicolor.WHITE_CLOUDS, width=2)
83+
else:
84+
self.with_border(color=arcade.color.BLACK, width=1)
85+
86+
def on_click(self, event) -> bool:
87+
"""Emit a ChooseColorEvent event when clicked."""
88+
self.dispatch_event(
89+
"on_choose_color", ChooseColorEvent(self, self._color_name, self._color)
90+
)
91+
return True
92+
93+
def on_choose_color(self, event: ChooseColorEvent):
94+
"""ChooseColorEvent event handler, which can be overridden."""
95+
pass
96+
97+
98+
class ColorView(arcade.gui.UIView):
99+
"""Uses the arcade.gui.UIView which takes care about the UIManager setup."""
100+
101+
def __init__(self):
102+
super().__init__()
103+
# Create an anchor layout, which can be used to position widgets on screen
104+
self.root = self.add_widget(UIAnchorLayout())
105+
106+
# Define colors in grid order
107+
self.colors = {
108+
# row 0
109+
"GREEN_TURQUOISE": arcade.uicolor.GREEN_TURQUOISE,
110+
"GREEN_EMERALD": arcade.uicolor.GREEN_EMERALD,
111+
"BLUE_PETER_RIVER": arcade.uicolor.BLUE_PETER_RIVER,
112+
"PURPLE_AMETHYST": arcade.uicolor.PURPLE_AMETHYST,
113+
"DARK_BLUE_WET_ASPHALT": arcade.uicolor.DARK_BLUE_WET_ASPHALT,
114+
# row 1
115+
"GREEN_GREEN_SEA": arcade.uicolor.GREEN_GREEN_SEA,
116+
"GREEN_NEPHRITIS": arcade.uicolor.GREEN_NEPHRITIS,
117+
"BLUE_BELIZE_HOLE": arcade.uicolor.BLUE_BELIZE_HOLE,
118+
"PURPLE_WISTERIA": arcade.uicolor.PURPLE_WISTERIA,
119+
"DARK_BLUE_MIDNIGHT_BLUE": arcade.uicolor.DARK_BLUE_MIDNIGHT_BLUE,
120+
# row 2
121+
"YELLOW_SUN_FLOWER": arcade.uicolor.YELLOW_SUN_FLOWER,
122+
"ORANGE_CARROT": arcade.uicolor.ORANGE_CARROT,
123+
"RED_ALIZARIN": arcade.uicolor.RED_ALIZARIN,
124+
"WHITE_CLOUDS": arcade.uicolor.WHITE_CLOUDS,
125+
"GRAY_CONCRETE": arcade.uicolor.GRAY_CONCRETE,
126+
# row 3
127+
"YELLOW_ORANGE": arcade.uicolor.YELLOW_ORANGE,
128+
"ORANGE_PUMPKIN": arcade.uicolor.ORANGE_PUMPKIN,
129+
"RED_POMEGRANATE": arcade.uicolor.RED_POMEGRANATE,
130+
"WHITE_SILVER": arcade.uicolor.WHITE_SILVER,
131+
"GRAY_ASBESTOS": arcade.uicolor.GRAY_ASBESTOS,
132+
}
133+
134+
# setup grid with colors
135+
self.grid = self.root.add(
136+
arcade.gui.UIGridLayout(
137+
column_count=5,
138+
row_count=4,
139+
size_hint=(1, 1),
140+
)
141+
)
142+
for i, (name, color) in enumerate(self.colors.items()):
143+
button = self.root.add(
144+
ColorButton(
145+
color_name=name,
146+
color=color,
147+
# giving width and height is a workaround for a bug in the grid layout
148+
# we would want to set size_hint=(1, 1) and let
149+
# the grid layout handle the size
150+
width=self.window.width // 5,
151+
height=self.window.height // 4,
152+
size_hint=None,
153+
)
154+
)
155+
self.grid.add(button, row=i // 5, column=i % 5)
156+
157+
# connect event handler
158+
button.on_choose_color = self.on_color_button_choose_color
159+
160+
# setup toasts (temporary messages)
161+
self.toasts = self.root.add(
162+
arcade.gui.UIBoxLayout(space_between=2), anchor_x="right", anchor_y="top"
163+
)
164+
self.toasts.with_padding(all=10)
165+
166+
def on_color_button_choose_color(self, event: ChooseColorEvent) -> bool:
167+
"""Color button click event handler, which copies the color name to the clipboard.
168+
169+
And shows a temporary message."""
170+
self.window.set_clipboard_text(f"arcade.uicolor.{event.color_name}")
171+
172+
# prepare and show toast
173+
toast = Toast(f"Copied {event.color_name}", width=250, size_hint=(None, 0))
174+
toast.update_font(
175+
font_color=arcade.uicolor.DARK_BLUE_MIDNIGHT_BLUE,
176+
font_size=9,
177+
bold=True,
178+
)
179+
toast.with_background(color=arcade.uicolor.GREEN_EMERALD)
180+
toast.with_padding(all=10)
181+
182+
self.toasts.add(toast)
183+
184+
return True
185+
186+
def on_draw_before_ui(self):
187+
# Add draw commands that should be below the UI
188+
pass
189+
190+
def on_draw_after_ui(self):
191+
# Add draw commands that should be on top of the UI (uncommon)
192+
pass
193+
194+
195+
if __name__ == "__main__":
196+
window = arcade.Window(title="GUI Example: Color Picker")
197+
window.show_view(ColorView())
198+
window.run()

‎arcade/gui/widgets/__init__.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,8 @@ def __init__(
540540
*,
541541
x: float = 0,
542542
y: float = 0,
543-
width: float,
544-
height: float,
543+
width: float = 100,
544+
height: float = 100,
545545
size_hint=None,
546546
size_hint_min=None,
547547
size_hint_max=None,

‎arcade/gui/widgets/text.py‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ def update_font(
222222
font_name: Optional[FontNameOrNames] = None,
223223
font_size: Optional[float] = None,
224224
font_color: Optional[Color] = None,
225+
bold: Optional[bool | str] = None,
226+
italic: Optional[bool] = None,
225227
):
226228
"""Update font of the label.
227229
@@ -231,20 +233,34 @@ def update_font(
231233
success.
232234
font_size: Font size of font.
233235
font_color: Color of the text.
236+
bold: If enabled, the label's text will be in a **bold** style.
237+
italic: If enabled, the label's text will be in an *italic*
234238
"""
235239
font_name = font_name or self._label.font_name
236240
font_size = font_size or self._label.font_size
237241
font_color = font_color or self._label.color
242+
font_bold = bold if bold is not None else self._label.bold
243+
font_italic = italic if italic is not None else self._label.italic
238244

239245
# Check if values actually changed, if then update and trigger render
240246
font_name_changed = self._label.font_name != font_name
241247
font_size_changed = self._label.font_size != font_size
242248
font_color_changed = self._label.color != font_color
243-
if font_name_changed or font_size_changed or font_color_changed:
249+
font_bold_changed = self._label.bold != font_bold
250+
font_italic_changed = self._label.italic != font_italic
251+
if (
252+
font_name_changed
253+
or font_size_changed
254+
or font_color_changed
255+
or font_bold_changed
256+
or font_italic_changed
257+
):
244258
with self._label:
245259
self._label.font_name = font_name
246260
self._label.font_size = font_size
247261
self._label.color = font_color
262+
self._label.bold = font_bold
263+
self._label.italic = font_italic
248264
self._update_size_hint_min()
249265

250266
# Optimised render behaviour

‎arcade/text.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ def italic(self) -> bool | str:
537537
return self._label.italic
538538

539539
@italic.setter
540-
def italic(self, italic: bool):
540+
def italic(self, italic: bool | str):
541541
self._label.italic = italic
542542

543543
@property
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
:orphan:
2+
3+
.. _gui_5_uicolor_picker:
4+
5+
GUI UIColor Picker
6+
==================
7+
8+
Arcade provides constants for colors, which work great for GUI widgets.
9+
They are based on FlatUI colors.
10+
11+
This example provides an interactive color picker, widgets can be used as a util
12+
to find the right color for your GUI widgets.
13+
14+
.. image:: images/gui_5_uicolor_picker.png
15+
:width: 600px
16+
:align: center
17+
:alt: Screen shot of advanced button usage
18+
19+
.. literalinclude:: ../../arcade/examples/gui/5_uicolor_picker.py
20+
:caption: 5_uicolor_picker.py
21+
:linenos:
156 KB
Loading

‎doc/example_code/index.rst‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,12 @@ Graphical User Interface
611611
:ref:`gui_3_buttons`
612612

613613

614+
.. figure:: images/thumbs/gui_5_uicolor_picker.png
615+
:figwidth: 170px
616+
:target: gui_5_uicolor_picker.html
617+
618+
:ref:`gui_5_uicolor_picker`
619+
614620
.. note::
615621

616622
Not all existing examples made it into this section. You can find more under `Arcade GUI Examples <https://github.com/pythonarcade/arcade/tree/development/arcade/examples/gui>`_

0 commit comments

Comments
 (0)