Instantly share code, notes, and snippets.
Last active
September 25, 2020 16:39
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save kmatch98/bffd7f9097dc1b797b2f140b480bd63d to your computer and use it in GitHub Desktop.
Button layout simplification using a grid layout.\
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import board | |
import displayio | |
from adafruit_bitmap_font import bitmap_font | |
from adafruit_button import Button | |
import adafruit_touchscreen | |
# These pins are used as both analog and digital! XL, XR and YU must be analog | |
# and digital capable. YD just need to be digital | |
ts = adafruit_touchscreen.Touchscreen( | |
board.TOUCH_XL, | |
board.TOUCH_XR, | |
board.TOUCH_YD, | |
board.TOUCH_YU, | |
calibration=((5200, 59000), (5800, 57000)), | |
size=(320, 240), | |
) | |
# the current working directory (where this file is) | |
cwd = ("/" + __file__).rsplit("/", 1)[0] | |
fonts = [ | |
file | |
for file in os.listdir(cwd + "/fonts/") | |
if (file.endswith(".bdf") and not file.startswith("._")) | |
] | |
for i, filename in enumerate(fonts): | |
fonts[i] = cwd + "/fonts/" + filename | |
print(fonts) | |
THE_FONT = "/fonts/Arial-16.bdf" | |
DISPLAY_STRING = "Button Text" | |
# Make the display context | |
splash = displayio.Group(max_size=20) | |
board.DISPLAY.auto_refresh=False | |
board.DISPLAY.show(splash) | |
BUTTON_WIDTH = 80 | |
BUTTON_HEIGHT = 40 | |
BUTTON_MARGIN = 20 | |
########################################################################## | |
# Make a background color fill | |
color_bitmap = displayio.Bitmap(320, 240, 1) | |
color_palette = displayio.Palette(1) | |
color_palette[0] = 0x404040 | |
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) | |
print(bg_sprite.x, bg_sprite.y) | |
splash.append(bg_sprite) | |
########################################################################## | |
# Load the font | |
font = bitmap_font.load_font(THE_FONT) | |
buttons = [] | |
# Default button styling: | |
button_0 = Button( | |
x=BUTTON_MARGIN, | |
y=BUTTON_MARGIN, | |
width=BUTTON_WIDTH, | |
height=BUTTON_HEIGHT, | |
label="butn0", | |
label_font=font, | |
) | |
buttons.append(button_0) | |
# a button with no indicators at all | |
button_1 = Button( | |
x=BUTTON_MARGIN * 2 + BUTTON_WIDTH, | |
y=BUTTON_MARGIN, | |
width=BUTTON_WIDTH, | |
height=BUTTON_HEIGHT, | |
label_font=font, | |
label="butn1", | |
label_color=0x00FF00, | |
fill_color=0x0, | |
outline_color=None, | |
) | |
buttons.append(button_1) | |
# various colorings | |
button_2 = Button( | |
x=BUTTON_MARGIN * 3 + 2 * BUTTON_WIDTH, | |
y=BUTTON_MARGIN, | |
width=BUTTON_WIDTH, | |
height=BUTTON_HEIGHT, | |
label="butn2", | |
label_font=font, | |
label_color=0x0000FF, | |
fill_color=0x00FF00, | |
outline_color=0xFF0000, | |
) | |
buttons.append(button_2) | |
# Transparent button with text | |
button_3 = Button( | |
x=BUTTON_MARGIN, | |
y=BUTTON_MARGIN * 2 + BUTTON_HEIGHT, | |
width=BUTTON_WIDTH, | |
height=BUTTON_HEIGHT, | |
label="butn3", | |
label_font=font, | |
label_color=0x0, | |
fill_color=None, | |
outline_color=None, | |
) | |
buttons.append(button_3) | |
# a roundrect | |
button_4 = Button( | |
x=BUTTON_MARGIN * 2 + BUTTON_WIDTH, | |
y=BUTTON_MARGIN * 2 + BUTTON_HEIGHT, | |
width=BUTTON_WIDTH, | |
height=BUTTON_HEIGHT, | |
label="butn4", | |
label_font=font, | |
style=Button.ROUNDRECT, | |
) | |
buttons.append(button_4) | |
# a shadowrect | |
button_5 = Button( | |
x=BUTTON_MARGIN * 3 + BUTTON_WIDTH * 2, | |
y=BUTTON_MARGIN * 2 + BUTTON_HEIGHT, | |
width=BUTTON_WIDTH, | |
height=BUTTON_HEIGHT, | |
label="butn5", | |
label_font=font, | |
style=Button.SHADOWRECT, | |
) | |
buttons.append(button_5) | |
# a shadowroundrect | |
button_6 = Button( | |
x=BUTTON_MARGIN, | |
y=BUTTON_MARGIN * 3 + BUTTON_HEIGHT * 2, | |
width=BUTTON_WIDTH, | |
height=BUTTON_HEIGHT, | |
label="butn6", | |
label_font=font, | |
style=Button.SHADOWROUNDRECT, | |
selected_label=0x0, | |
selected_fill=0x707070, | |
selected_outline=0xa0a0a0, | |
) | |
buttons.append(button_6) | |
for b in buttons: | |
splash.append(b) | |
print("width: {}".format(board.DISPLAY.width)) | |
def button_grid_layout(button, grid_size, display=None, window_size=None, window_offset=(0,0), position=(0,0), button_size=(1,1), padding=10): | |
if display is not None: | |
window_size=(display.width, display.height) | |
elif window_size is None: | |
print('Must provide either a display or window_size=(width,height) entry') | |
grid_size_x=grid_size[0] | |
grid_size_y=grid_size[1] | |
grid_position_x=position[0] | |
grid_position_y=position[1] | |
button_size_x=button_size[0] | |
button_size_y=button_size[1] | |
button.width=int(button_size_x*window_size[0]/grid_size_x)-2*padding | |
button.height=int(button_size_y*window_size[1]/grid_size_y)-2*padding | |
button.x=window_offset[0] + int(grid_position_x*window_size[0]/grid_size_x)+padding | |
button.y=window_offset[1] + int(grid_position_y*window_size[1]/grid_size_y)+padding | |
my_grid_size=3,4 | |
my_padding=8 | |
my_window_size=(240,200) | |
my_window_offset=(320-240, 240-200) | |
button_grid_layout(button_0, window_size=my_window_size, window_offset=my_window_offset, grid_size=my_grid_size, position=(0,0), button_size=(1,1), padding=my_padding) | |
button_grid_layout(button_1, window_size=my_window_size, window_offset=my_window_offset, grid_size=my_grid_size, position=(1,0), button_size=(1,1), padding=my_padding) | |
button_grid_layout(button_2, window_size=my_window_size, window_offset=my_window_offset, grid_size=my_grid_size, position=(2,0), button_size=(1,1), padding=my_padding) | |
button_grid_layout(button_3, window_size=my_window_size, window_offset=my_window_offset, grid_size=my_grid_size, position=(0,1), button_size=(1,1), padding=my_padding) | |
button_grid_layout(button_4, window_size=my_window_size, window_offset=my_window_offset, grid_size=my_grid_size, position=(1,1), button_size=(2,1), padding=my_padding) | |
button_grid_layout(button_5, window_size=my_window_size, window_offset=my_window_offset, grid_size=my_grid_size, position=(0,2), button_size=(1,2), padding=my_padding) | |
button_grid_layout(button_6, window_size=my_window_size, window_offset=my_window_offset, grid_size=my_grid_size, position=(1,2), button_size=(2,2), padding=my_padding) | |
board.DISPLAY.refresh() | |
board.DISPLAY.auto_refresh=True | |
while True: | |
p = ts.touch_point | |
if p: | |
print(p) | |
for i, b in enumerate(buttons): | |
if b.contains(p): | |
print("Button %d pressed" % i) | |
b.selected = True | |
else: | |
b.selected = False | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The MIT License (MIT) | |
# | |
# Copyright (c) 2019 Limor Fried for Adafruit Industries | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining a copy | |
# of this software and associated documentation files (the "Software"), to deal | |
# in the Software without restriction, including without limitation the rights | |
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
# copies of the Software, and to permit persons to whom the Software is | |
# furnished to do so, subject to the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be included in | |
# all copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
# THE SOFTWARE. | |
""" | |
`adafruit_button` | |
================================================================================ | |
UI Buttons for displayio | |
* Author(s): Limor Fried | |
Implementation Notes | |
-------------------- | |
**Software and Dependencies:** | |
* Adafruit CircuitPython firmware for the supported boards: | |
https://github.com/adafruit/circuitpython/releases | |
""" | |
from micropython import const | |
import displayio | |
from adafruit_display_text.label import Label | |
from adafruit_display_shapes.rect import Rect | |
from adafruit_display_shapes.roundrect import RoundRect | |
__version__ = "0.0.0-auto.0" | |
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Button.git" | |
def _check_color(color): | |
# if a tuple is supplied, convert it to a RGB number | |
if isinstance(color, tuple): | |
r, g, b = color | |
return int((r << 16) + (g << 8) + (b & 0xFF)) | |
return color | |
class Button(displayio.Group): | |
# pylint: disable=too-many-instance-attributes, too-many-locals | |
"""Helper class for creating UI buttons for ``displayio``. | |
:param x: The x position of the button. | |
:param y: The y position of the button. | |
:param width: The width of the button in pixels. | |
:param height: The height of the button in pixels. | |
:param name: The name of the button. | |
:param style: The style of the button. Can be RECT, ROUNDRECT, SHADOWRECT, SHADOWROUNDRECT. | |
Defaults to RECT. | |
:param fill_color: The color to fill the button. Defaults to 0xFFFFFF. | |
:param outline_color: The color of the outline of the button. | |
:param label: The text that appears inside the button. Defaults to not displaying the label. | |
:param label_font: The button label font. | |
:param label_color: The color of the button label text. Defaults to 0x0. | |
:param selected_fill: Inverts the fill color. | |
:param selected_outline: Inverts the outline color. | |
:param selected_label: Inverts the label color. | |
""" | |
RECT = const(0) | |
ROUNDRECT = const(1) | |
SHADOWRECT = const(2) | |
SHADOWROUNDRECT = const(3) | |
def __init__( | |
self, | |
*, | |
x, | |
y, | |
width, | |
height, | |
name=None, | |
style=RECT, | |
fill_color=0xFFFFFF, | |
outline_color=0x0, | |
label=None, | |
label_font=None, | |
label_color=0x0, | |
selected_fill=None, | |
selected_outline=None, | |
selected_label=None | |
): | |
super().__init__(x=x, y=y) | |
self.x = x | |
self.y = y | |
self._width = width | |
self._height = height | |
self._font = label_font | |
self._selected = False | |
self.name = name | |
#self._label = label | |
self._label_object = None | |
self.body = self.fill = self.shadow = None | |
self.fill_color = _check_color(fill_color) | |
self.outline_color = _check_color(outline_color) | |
self._label_color = label_color | |
self._label_font = label_font | |
# Selecting inverts the button colors! | |
self.selected_fill = _check_color(selected_fill) | |
self.selected_outline = _check_color(selected_outline) | |
self.selected_label = _check_color(selected_label) | |
self.style=style | |
self._update_button(label) # Create the button elements. | |
def _update_button(self, label): | |
# store any existing text if there is not a new label | |
if self._label_object and self and (self[-1] == self._label_object) and (label is None): | |
label=self._label_object.text | |
for _ in range(len(self)): # clear any existing items in the current button Group | |
self.pop() | |
print("len self: {}".format(len(self))) | |
if self.selected_fill is None and self.fill_color is not None: | |
self.selected_fill = (~self.fill_color) & 0xFFFFFF | |
if self.selected_outline is None and self.outline_color is not None: | |
self.selected_outline = (~self.outline_color) & 0xFFFFFF | |
if (self.outline_color is not None) or (self.fill_color is not None): | |
if self.style == Button.RECT: | |
self.body = Rect( | |
0, | |
0, | |
self._width, | |
self._height, | |
fill=self.fill_color, | |
outline=self.outline_color, | |
) | |
elif self.style == Button.ROUNDRECT: | |
self.body = RoundRect( | |
0, | |
0, | |
self._width, | |
self._height, | |
r=10, | |
fill=self.fill_color, | |
outline=self.outline_color, | |
) | |
elif self.style == Button.SHADOWRECT: | |
self.shadow = Rect(2, 2, self._width - 2, self._height - 2, fill=self.outline_color) | |
self.body = Rect( | |
0, | |
0, | |
self._width - 2, | |
self._height - 2, | |
fill=self.fill_color, | |
outline=self.outline_color, | |
) | |
elif self.style == Button.SHADOWROUNDRECT: | |
self.shadow = RoundRect( | |
2, 2, self._width - 2, self._height - 2, r=10, fill=self.outline_color | |
) | |
self.body = RoundRect( | |
0, | |
0, | |
self._width - 2, | |
self._height - 2, | |
r=10, | |
fill=self.fill_color, | |
outline=self.outline_color, | |
) | |
if self.shadow: | |
self.append(self.shadow) | |
self.append(self.body) | |
self.label=label | |
@property | |
def width(self): | |
return self._width | |
@width.setter | |
def width(self, width): | |
self._width=width | |
self._update_button(None) | |
@property | |
def height(self): | |
return self._height | |
@height.setter | |
def height(self, height): | |
self._height=height | |
self._update_button(None) | |
@property | |
def label(self): | |
"""The text label of the button""" | |
return self._label_object.text | |
@label.setter | |
def label(self, newtext): | |
print("newtext: {}".format(newtext)) | |
if self._label_object and self and (self[-1] == self._label_object): | |
self.pop() | |
self._label_object = None | |
if not newtext or (self._label_color is None): # no new text | |
return # nothing to do! | |
if not self._label_font: | |
raise RuntimeError("Please provide label font") | |
# This is odd usage, since the input value of label was a text string, and now it is defined as a Label object. | |
self._label_object = Label(self._label_font, text=newtext) | |
dims = self._label_object.bounding_box | |
print("self.width: {}, self.height: {} dims2: {}, dims3: {}".format(self.width, self.height, dims[2], dims[3])) | |
if dims[2] >= self.width or dims[3] >= self.height: | |
raise RuntimeError("Button not large enough for label") | |
self._label_object.x = (self.width - dims[2]) // 2 | |
self._label_object.y = self.height // 2 | |
self._label_object.color = self._label_color | |
self.append(self._label_object) | |
if (self.selected_label is None) and (self._label_color is not None): | |
self.selected_label = (~self._label_color) & 0xFFFFFF | |
@property | |
def selected(self): | |
"""Selected inverts the colors.""" | |
return self._selected | |
@selected.setter | |
def selected(self, value): | |
if value == self._selected: | |
return # bail now, nothing more to do | |
self._selected = value | |
if self._selected: | |
new_fill = self.selected_fill | |
new_out = self.selected_outline | |
new_label = self.selected_label | |
if self.style == Button.SHADOWROUNDRECT: | |
self.shadow.x=0 | |
self.shadow.y=0 | |
self.shadow.fill=self.selected_outline | |
self.body.x=2 | |
self.body.y=2 | |
else: | |
new_fill = self.fill_color | |
new_out = self.outline_color | |
new_label = self._label_color | |
if self.style == Button.SHADOWROUNDRECT: | |
self.shadow.x=2 | |
self.shadow.y=2 | |
self.shadow.fill=self.outline_color | |
self.shadow.outline=self.outline_color | |
self.body.x=0 | |
self.body.y=0 | |
# update all relevant colors! | |
if self.body is not None: | |
self.body.fill = new_fill | |
self.body.outline = new_out | |
if self._label_object is not None: | |
self._label_object.color = new_label | |
@property | |
def group(self): | |
"""Return self for compatibility with old API.""" | |
print( | |
"Warning: The group property is being deprecated. " | |
"User code should be updated to add the Button directly to the " | |
"Display or other Groups." | |
) | |
return self | |
def contains(self, point): | |
"""Used to determine if a point is contained within a button. For example, | |
``button.contains(touch)`` where ``touch`` is the touch point on the screen will allow for | |
determining that a button has been touched. | |
""" | |
return (self.x <= point[0] <= self.x + self.width) and ( | |
self.y <= point[1] <= self.y + self.height | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment