Git Product home page Git Product logo

adafruit_circuitpython_display_button's Introduction

Introduction

Documentation Status Discord Build Status Code Style: Black

UI Buttons for displayio

Dependencies

This driver depends on:

Please ensure all dependencies are available on the CircuitPython filesystem. This is easily achieved by downloading the Adafruit library and driver bundle.

Installing from PyPI

On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally from PyPI. To install for current user:

pip3 install adafruit-circuitpython-display-button

To install system-wide (this may be required in some cases):

sudo pip3 install adafruit-circuitpython-display-button

To install in a virtual environment in your current project:

mkdir project-name && cd project-name
python3 -m venv .venv
source .venv/bin/activate
pip3 install adafruit-circuitpython-display-button

Usage Example

See examples in examples/ folder.

Documentation

API documentation for this library can be found on Read the Docs.

For information on building library documentation, please check out this guide.

Contributing

Contributions are welcome! Please read our Code of Conduct before contributing to help this project stay welcoming.

Building locally

Zip release files

To build this library locally you'll need to install the circuitpython-build-tools package.

python3 -m venv .venv
source .venv/bin/activate
pip install circuitpython-build-tools

Once installed, make sure you are in the virtual environment:

source .venv/bin/activate

Then run the build:

circuitpython-build-bundles --filename_prefix adafruit-circuitpython-display_button --library_location .

Sphinx documentation

Sphinx is used to build the documentation based on rST files and comments in the code. First, install dependencies (feel free to reuse the virtual environment from above):

python3 -m venv .venv
source .venv/bin/activate
pip install Sphinx sphinx-rtd-theme

Now, once you have the virtual environment activated:

cd docs
sphinx-build -E -W -b html . _build/html

This will output the documentation to docs/_build/html. Open the index.html in your browser to view them. It will also (due to -W) error out on any warning like Travis will. This is a good way to locally verify it will pass.

adafruit_circuitpython_display_button's People

Contributors

caternuson avatar dhalbert avatar djdevon3 avatar evaherrada avatar foamyguy avatar jpecor avatar jposada202020 avatar kattni avatar kmatch98 avatar ladyada avatar lcmcninch avatar lesamouraipourpre avatar makermelissa avatar prcutler avatar siddacious avatar sommersoft avatar tannewt avatar tekktrik avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

adafruit_circuitpython_display_button's Issues

Minimum button width depends on maximum glyph width

This may be intentional fault-tolerant behavior (or for simplicity or performance), but since the check for button width uses the widest possible glyph width (bounding_box), the minimum button width using a non-monospace font is often much wider than needed for the actual button text. For some applications, dynamic button dimensions and / or minimum button dimensions are desirable.

            button_label = "Some skiiiiiiiiiiny striiiiiiiiiiiiing"
            button_label_bytes = button_label.encode()
            button_width = 0
            for _ in button_label_bytes:
                button_width += font.get_glyph(_).width

Results in RuntimeError: Button not large enough for label

Using 'len(button_label) * font.get_bounding_box()[0]' instead with a non-monospace font works, but can yield a button width easily twice as wide or more than the text.

Oddly, using a monospace font like terminalio.FONT with the expected method of calculating button width len(button_label) * font.get_bounding_box()[0] also results in Button not large enough for label. There may be an implicit margin assumption.

Button has a Group, but is not a subclass of Group

JMK expected a Button to act like a Label, in that it would be a Group that you would add to a Group. But Button is not a subclass of Group: It has a Group (.group), but it is not itself one.

There is a mirrored page in Learn Guides with an example that assumes a Button is a Group:
https://learn.adafruit.com/pyportal-calculator-using-the-displayio-ui-elements/ui-quickstart#button-3-15
https://learn.adafruit.com/circuitpython-display-support-using-displayio/ui-quickstart

Is it possible for it to be Group? If not, the examples should be fixed, and the documentation here should explain how to use .group.

Tagging @makermelissa @tannewt @ladyada

Button Registering Twice

On button press it will always register 2 presses. Attempted to change the time.sleep(1). It will just wait 1 second and print a 2nd button press anyway. If you hold down on the button it will print button presses forever. Using SpriteButton simpletest but it happens with all examples using this library. Request adding debouncer like feature with rise/fall.

Adafruit ESP32-S3 Feather with 3.5" TFT Featherwing (with touch). I've done a few customizations to get it working with the TFT Featherwing without using the featherwing library.

from adafruit_hx8357 import HX8357
import adafruit_stmpe610
from adafruit_button.sprite_button import SpriteButton

# 3.5" TFT Featherwing is 480x320
displayio.release_displays()
DISPLAY_WIDTH = 480
DISPLAY_HEIGHT = 320

# Initialize TFT Display
spi = board.SPI()
tft_cs = board.D9
tft_dc = board.D10
display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs)
display = HX8357(display_bus, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT)
display.rotation = 0
_touch_flip = (False, True)

# Initialize 3.5" TFT Featherwing Touchscreen
ts_cs_pin = digitalio.DigitalInOut(board.D6)
touchscreen = adafruit_stmpe610.Adafruit_STMPE610_SPI(
    board.SPI(),
    ts_cs_pin,
    calibration=((231, 3703), (287, 3787)),
    size=(display.width, display.height),
    disp_rotation=display.rotation,
    touch_flip=_touch_flip,
)

TEXT_WHITE = 0xFFFFFF
small_font = bitmap_font.load_font("/fonts/GoodTimesRg-Regular-16.bdf")

# --| Button Config |--
BUTTON_WIDTH = 7 * 16
BUTTON_HEIGHT = 2 * 16
BUTTON_MARGIN = 5

# Defiine the button
button = SpriteButton(
    x=BUTTON_MARGIN,
    y=BUTTON_MARGIN,
    width=BUTTON_WIDTH,
    height=BUTTON_HEIGHT,
    label="MENU",
    label_font=small_font,
    label_color=TEXT_WHITE,
    bmp_path="icons/gradient_button_0.bmp",
    selected_bmp_path="icons/gradient_button_1.bmp",
    transparent_index=0,
)

while True:
            p = touchscreen.touch_point
            if p:
                if button.contains(p):
                    button.selected = True
                    print("Button Pressed")
                    time.sleep(0.25)  # Wait a bit so we can see the button color change
                else:
                    button.selected = False  # When touch moves outside of button
            else:
                button.selected = False  # When button is released

press the button on the screen once and registers twice no matter how fast I try to tap

Button Pressed
Button Pressed

This is a problem when used with GUI navigation as it skips pages. Next Page becomes page 3 instead of 2 for example. I've attempted to use debouncer and ticks to no avail. It's like button.selected = True is keeping the button selection in a memory buffer. No matter what I do it will press twice in most circumstances.

`name` argument in constructor seems unused

The Button constructor takes an argument called name and sets it into a variable on self, but it appears to be unused beyond getting put into that variable.

I think it could be removed. We can do a scan on learn guide and examples to ensure nothing has attempted to use it before doing so though.

Add a label orientation flag to Button

Button allows you to position an instance horizontally or vertically based on the x,y co-ordinates it's created with. Labels default to a horizontal layout though. I'm wondering if labels should support a similar x,y system in the bounding box of the Button instance it belongs to, or something like an orientation/rotation flag?

Happy to help contribute to adding this functionality, but wanted to get some feedback first.

Please remove the custom font usage or add note

It was very confusing to have to deal with the custom font usage for the display_button_simpletest.py example.

Please add a note to line 22 letting people know that they need to add the font file to a directory named fonts on CIRCUITPY. I would also suggest that you just remove the custom font and use the terminalio.FONT to bring the focus back to simple button use. Maybe put the custom font option in comments.

Thanks :)

Missing Type Annotations

There are missing type annotations for some functions in this library.

The typing module does not exist on CircuitPython devices so the import needs to be wrapped in try/except to catch the error for missing import. There is an example of how that is done here:

try:
    from typing import List, Tuple
except ImportError:
    pass

Once imported the typing annotations for the argument type(s), and return type(s) can be added to the function signature. Here is an example of a function that has had this done already:

def wrap_text_to_pixels(
    string: str, max_width: int, font=None, indent0: str = "", indent1: str = ""
) -> List[str]:

If you are new to Git or Github we have a guide about contributing to our projects here: https://learn.adafruit.com/contribute-to-circuitpython-with-git-and-github

There is also a guide that covers our CI utilities and how to run them locally to ensure they will pass in Github Actions here: https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/check-your-code In particular the pages: Sharing docs on ReadTheDocs and Check your code with pre-commit contain the tools to install and commands to run locally to run the checks.

If you are attempting to resolve this issue and need help, you can post a comment on this issue and tag both @FoamyGuy and @kattni or reach out to us on Discord: https://adafru.it/discord in the #circuitpython-dev channel.

The following locations are reported by mypy to be missing type annotations:

  • adafruit_button.py:34
  • adafruit_button.py:126
  • adafruit_button.py:182
  • adafruit_button.py:216
  • adafruit_button.py:245
  • adafruit_button.py:260
  • adafruit_button.py:271
  • adafruit_button.py:282
  • adafruit_button.py:293
  • adafruit_button.py:304
  • adafruit_button.py:313
  • adafruit_button.py:323
  • adafruit_button.py:337
  • adafruit_button.py:345

allow changing fill and outline colors after initialization

Currently the constructor is the only way to change fill_color and outline_color of a Button.

The underlying display_shapes objects do have fill and outline properties that allow them to be be changed any time after initialization.

It would be great to have properties and setters to the Button that allow user code to set those without having know about or mess with the underlying shapes objects.

I think it's a pretty natural assumption for users make to think the button would allow this, the issue was first noted on a forum post here: https://forums.adafruit.com/viewtopic.php?f=60&t=174113

FR: Image button

It would be nice to have a way to make an image button, instead of having to use a label.

Set label scale

It looks like there isn't a way to set the font size of the button label. The Label object itself is stored as a "protected" member of the button object so you can hack it by setting _label.scale but that isn't ideal.

Assuming I'm not overlooking something obvious, I was thinking I could contribute a small enhancement that would provide either a set_label_scale method or a scale property. Possibly the same for the "selected label".

Any thoughts? Am I missing something obvious? If not, does that sound like it would be a good addition?

Button extends Group and holds a Group

The Button class is extending group:

class Button(displayio.Group):

Inside of Button.__init__() we are calling up to Group.__init__() with default params:

But we are also creating another new group and storing it at self.group:

self.group = displayio.Group()

Which we later append the body, outline, and text label to:

self.group.append(self.body)

If I am understanding correctly then the button instance that we are extending is never being used after being instantiated. Instead everything gets put into the self.group instance.

In user code the result of this is when we want to use a Button we have to create it and then specifically access the group property on it when we add it to the screen:

button = Button( ... )
# Add button to the display context
splash.append(button.group)

Adding to the confusion Button itself is also a Group so this code does not throw any errors:

button = Button( ... )
splash.append(button)

But won't result in the button being added to the screen.

I think we can get rid of one of the two Group instances. I think it would make sense to keep the instance that Button is extending and use that one, getting rid of self.group. This would make Button behave more like the adafruit_display_text.Label in that the object resulting from __init__() is ready to be added to the screen, or other Groups, directly. i.e.

text_area = label.Label(terminalio.FONT, text="Hello")
board.DISPLAY.show(text_area)

The adafruit_display_shapes objects, and adafruit_progressbar.ProgressBar are a few other examples that work this way.

Index out of range error for label, sometimes...

I am getting an index out of range error from the button_3 code in the example:

button_3 = Button(x=BUTTON_MARGIN*3+2*BUTTON_WIDTH, y=BUTTON_MARGIN*2+BUTTON_HEIGHT, width=BUTTON_WIDTH, height=BUTTON_HEIGHT, label="button3", label_font=font, label_color=0x0000FF, fill_color=None, outline_color=None) buttons.append(button_3)

Here's the error:

Traceback (most recent call last): File "code.py", line 71, in <module> File "adafruit_button.py", line 127, in __init__ File "adafruit_button.py", line 140, in label IndexError: Group index out of range

After tinkering a bit with the code, I found that if I pass in a value for EITHER the fill_color OR outline_color, it works. So, for example, this works:

button_3 = Button(x=BUTTON_MARGIN*3+2*BUTTON_WIDTH, y=BUTTON_MARGIN*2+BUTTON_HEIGHT, width=BUTTON_WIDTH, height=BUTTON_HEIGHT, label="button3", label_font=font, label_color=0x0000FF, fill_color=0x00FF00, outline_color=None) buttons.append(button_3)

IMG_8025

I have not dug into this any deeper, yet, but wanted to post the issue in case it's more obvious to someone else.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.