Skip to content

Commit

Permalink
Add docs for styling (#1931)
Browse files Browse the repository at this point in the history
UI: add style docs and hide inner method in UIFlatButton
  • Loading branch information
eruvanos committed Nov 24, 2023
1 parent 245a003 commit 31ebfef
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 6 deletions.
8 changes: 4 additions & 4 deletions arcade/gui/widgets/buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,14 +188,14 @@ def do_render(self, surface: Surface):
style = self.get_current_style()

# update label
self.apply_style(style)
self._apply_style(style)

current_state = self.get_current_state()
current_texture = self._textures.get(current_state)
if current_texture:
surface.draw_texture(0, 0, self.content_width, self.content_height, current_texture)

def apply_style(self, style: UITextureButtonStyle):
def _apply_style(self, style: UITextureButtonStyle):
"""
Callback which is called right before rendering to apply changes for rendering.
"""
Expand Down Expand Up @@ -324,7 +324,7 @@ def do_render(self, surface: Surface):
style: UIFlatButton.UIStyle = self.get_current_style()

# update label
self.apply_style(style)
self._apply_style(style)

# Render button
border_width = style.get("border_width", UIFlatButton.UIStyle.border_width)
Expand All @@ -344,7 +344,7 @@ def do_render(self, surface: Surface):
border_width=border_width,
)

def apply_style(self, style: UIStyle):
def _apply_style(self, style: UIStyle):
"""
Callback which is called right before rendering to apply changes for rendering.
"""
Expand Down
193 changes: 191 additions & 2 deletions doc/programming_guide/gui/style.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,195 @@
GUI Style
---------

WIP

Whole new styling system in 2.7
With arcade 3.0 a whole new styling mechanism for GUI widgets was introduced.
The new styling allows more type safe and clear styling while staying flexible.

Following widgets support styling:

- :py:class:`~arcade.gui.UITextureButton`
- :py:class:`~arcade.gui.UIFlatButton`
- :py:class:`~arcade.gui.UISlider`

For an advanced description about the style system read the 'Advanced' section.

Basic Usage
===========

This section covers how to use the existing stylable widgets.

In the following examples we will use the :py:class:`~arcade.gui.UIFlatButton` as the stylable widget,
you can do the same with any stylable widget listed above.


Quickstart
```````````

The following example shows how to adjust the style.


.. code-block::
# create an own style
new_style = {
# provide a style for each widget state
"normal": UIFlatButton.UIStyle(), # use default values for `normal` state
"hover": UIFlatButton.UIStyle(
font_color=arcade.color.BLACK,
bg=arcade.color.WHITE,
),
"press": UIFlatButton.UIStyle(
font_color=arcade.color.BLACK,
bg=arcade.color.WHITE,
border=arcade.color.WHITE,
),
"disabled": UIFlatButton.UIStyle(
bg=arcade.color.GRAY,
)
}
UIFlatButton(style=new_style)
Default style
``````````````

Stylable widgets have a property which holds the default style for
the type of widget. For the :py:class:`~arcade.gui.UIFlatButton` this is `UIFlatButton.DEFAULT_STYLE`.

This default style will be used if no other style is provided within the constructor.
The default style looks like this:

.. code-block::
class UIFlatButton(UIInteractiveWidget, UIStyledWidget, UITextWidget):
DEFAULT_STYLE = {
"normal": UIStyle(),
"hover": UIStyle(
font_size=12,
font_name=("calibri", "arial"),
font_color=arcade.color.WHITE,
bg=(21, 19, 21, 255),
border=(77, 81, 87, 255),
border_width=2,
),
"press": UIStyle(
font_size=12,
font_name=("calibri", "arial"),
font_color=arcade.color.BLACK,
bg=arcade.color.WHITE,
border=arcade.color.WHITE,
border_width=2,
),
"disabled": UIStyle(
font_size=12,
font_name=("calibri", "arial"),
font_color=arcade.color.WHITE,
bg=arcade.color.GRAY,
border=None,
border_width=2,
)
}
Style attributes
`````````````````

A UIStyle is a typed description of available style options.
For the UIFlatButton the supported attributes are:


================ ================= ===================== ==================================
Name Type Default value Description
================ ================= ===================== ==================================
font_size int 12 Size of the text on the button
font_name FontNameOrNames ("calibri", "arial") Font of the text
font_color RGBA255 arcade.color.WHITE Color of text
bg RGBA255 (21, 19, 21, 255) Background color
border Optional None Border color
border_width int 0 Border width
================ ================= ===================== ==================================

The style attribute is a dictionary, which maps a state like 'normal, 'hover' etc.
to an instance of UIFlatButton.UIStyle.

Wellknown states
`````````````````

======== ======================================================
Name Description
======== ======================================================
normal The default state of a widget.
hover Mouse hovered over an interactive widget.
press Mouse is pressed while hovering over the widget.
disabled The widget is disabled.
======== ======================================================


Advanced
========

This section describes the styling system itself,
and how it can be used to create own stylable widgets or extend existing ones.

Stylable widgets inherit from `UIStyledWidget`, which provides two basic features:

1. owns a style property, which provides a mapping between a widgets state and style to be applied
2. provides an abstractmethod which have to provide a state (which is a simple string)


Tha basic idea:

- a stylable widget has a state (e.g. 'normal', 'hover', 'press', or 'disabled')
- the state is used to define, which style will be applied

Your own stylable widget
````````````````````````

.. code-block::
class MyColorBox(UIStyledWidget, UIInteractiveWidget, UIWidget):
"""
A colored box, which changes on mouse interaction
"""
# create the style class, which will be used to define style for any widget state
@dataclass
class UIStyle(UIStyleBase):
color: RGBA255 = arcade.color.GREEN
DEFAULT_STYLE = {
"normal": UIStyle(),
"hover": UIStyle(color=arcade.color.YELLOW),
"press": UIStyle(color=arcade.color.RED),
"disabled": UIStyle(color=arcade.color.GRAY)
}
def get_current_state(self) -> str:
"""Returns the current state of the widget i.e disabled, press, hover or normal."""
if self.disabled:
return "disabled"
elif self.pressed:
return "press"
elif self.hovered:
return "hover"
else:
return "normal"
def do_render(self, surface: Surface):
self.prepare_render(surface)
# get current style
style: MyColorBox.UIStyle = self.get_current_style()
# Get color from current style, it is a good habit to be
# bullet proven for missing values in case a dict is provided instead of a UIStyle
color = style.get("color", MyColorBox.UIStyle.bg)
# render
if color: # support for not setting a color at all
surface.clear(bg_color)

0 comments on commit 31ebfef

Please sign in to comment.