diff --git a/wiki/Home.md b/wiki/Home.md index 3af2400..eb623ff 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -20,11 +20,11 @@ MicroHydra includes a built-in library, intended to help you easily make apps. C ├── $lib$ │       ├── [audio](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/Playing-Sound) │       ├── [display](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/Display) -│       │       ├── palette -│       │       └── named_palette +│       │       ├── [palette](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/Palette) +│       │       └── [namedpalette](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/Palette#libdisplaynamedpalettenamedpalette) │       │ │       ├── $hydra$ -│       │       ├── beeper +│       │       ├── [beeper](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/Playing-Sound#beeper) │       │       ├── color │       │       ├── [config](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/Accessing-config-files) │       │       ├── [menu](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/HydraMenu) diff --git a/wiki/HydraMenu.md b/wiki/HydraMenu.md index f5a38e8..de10d94 100644 --- a/wiki/HydraMenu.md +++ b/wiki/HydraMenu.md @@ -1,25 +1,24 @@ -[HydraMenu.py](https://github.com/Gabriel-F-Sousa/HydraMenu/blob/main/HydraMenu.py) is a module contributed by [Gabriel-F-Sousa](https://github.com/echo-lalia/Cardputer-MicroHydra/commits?author=Gabriel-F-Sousa), which is designed to make it easy to create menu screens for MicroHydra apps. +[HydraMenu.py](https://github.com/echo-lalia/Cardputer-MicroHydra/blob/wikiimprovements/src/lib/hydra/menu.py) is a module contributed by [Gabriel-F-Sousa](https://github.com/echo-lalia/Cardputer-MicroHydra/commits?author=Gabriel-F-Sousa), which is designed to make it easy to create menu screens for MicroHydra apps. -HydraMenu is being utilized heavily by the (newly refurbished) inbuilt [settings app](https://github.com/echo-lalia/Cardputer-MicroHydra/blob/main/MicroHydra/launcher/settings.py). Please take a look at that file for some practical examples of what can be done with the module. +HydraMenu is being utilized heavily by the (newly refurbished) inbuilt [settings app](https://github.com/echo-lalia/Cardputer-MicroHydra/blob/wikiimprovements/src/launcher/settings.py). Please take a look at that file for some practical examples of what can be done with the module. -And for a simplified example app utilizing HydraMenu, check out the [example app](https://github.com/Gabriel-F-Sousa/HydraMenu/blob/main/examplebuf.py). - -Here's a trimmed excerpt from that example, for your reference: +Here's a simplified example, for your reference: ``` Python -from lib import st7789fbuf, keyboard, mhconfig, HydraMenu +from lib.display import Display +from lib.userinput import UserInput +from lib.hydra.config import Config +from lib.hydra import menu as HydraMenu + +# ... +userinput = UserInput() +display = Display() +config = Config() +# ... -... """ Create our HydraMenu.Menu: """ -menu = HydraMenu.Menu( - # display_fbuf is passed to signal that we are using the st7789fbuf driver. - # we would use display_py if we were using st7789py. - display_fbuf=display, - # pass our config object, which was created above. - # if omitted, HydraMenu will create it's own config object. - config=config, - ) +menu = HydraMenu.Menu() """Add menu items to the menu: @@ -36,10 +35,10 @@ menu.append(HydraMenu.IntItem( min_int=0, max_int=10, # callbacks are what makes this all functional. # Pass the function you want to be called every time a value is confirmed. - callback=print_menu_callback, + callback=lambda item, val: print(f"Confirmed val: {val}"), # You can also use an 'instant_callback' if you want to track the value as it changes. # this is what the main settings app uses to update the volume, and ui colors as they're changed. - instant_callback=print_instant_callback + instant_callback=lambda item, val: print(val) )) ... @@ -51,7 +50,7 @@ redraw = True while True: # get our newly pressed keys - keys = kb.get_new_keys() + keys = userinput.get_new_keys() # pass each key to the handle_input method of our menu. for key in keys: @@ -69,4 +68,5 @@ while True: # and False when the animation is done (therefore, does not need to be redrawn until another key is pressed) redraw = menu.draw() display.show() -``` \ No newline at end of file + +``` diff --git a/wiki/Palette.md b/wiki/Palette.md new file mode 100644 index 0000000..3726b42 --- /dev/null +++ b/wiki/Palette.md @@ -0,0 +1,85 @@ +## lib.display.palette.Palette + +This Palette class is designed to be used for storing a list of RGB565 colors, +and for returning the apropriate colors by index to be used with MicroHydra's display module. + +When `Config` from `lib.hydra.config` is initialized, it reads the user set color data from `config.json` and creates a 16-color palette from it. + +
+ +Key notes on Palette: + - Has a static length of 16 colors + + - Is used by both `lib.hydra.config.Config` and `lib.display.Display` (it is the same Palette in both) + + - uses a bytearray to store color information, + this is intended for fast/easy use with Viper's ptr16. + + - Returns an RGB565 color when using normal framebuffer, or an index when Display is initialized with `use_tiny_buf`. + (This makes it so that you can pass a `Palette[i]` to the Display class in either mode.) + + - Palette is a singleton, which is important so that different MH classes can modify and share it's data + (without initializing the Display). + + +Retrieving a color from the Palette is fairly fast, but if you want to maximize your speed, it's probably smart to read and store the colors you need as local variables (after initializing the `Display` and `Config`). + +
+ +For your reference, here is a complete list of the colors, by index, contained in the palette: +
    +
  1. Black
  2. +
  3. Darker bg_color
  4. +
  5. bg_color
  6. +
+ +
    +
  1. 84% bg_color 16% ui_color
  2. +
  3. 67% bg_color 33% ui_color
  4. +
  5. 50% bg_color 50% ui_color (mid_color)
  6. +
  7. 33% bg_color 67% ui_color
  8. +
  9. 16% bg_color 84% ui_color
  10. +
+ +
    +
  1. ui_color
  2. +
  3. Lighter ui_color
  4. +
  5. white
  6. +
+ +
    +
  1. reddish bg_color
  2. +
  3. greenish mid_color
  4. +
  5. bluish ui_color
  6. +
+ +
    +
  1. compliment bg_color (opposite hue)
  2. +
  3. compliment ui_color
  4. +
+ +



+ + +## lib.display.namedpalette.NamedPalette + +As an alternative, for improved readability and simplicity, you can import the optional `NamedPalette` class, which works similarly to the normal `Palette`, but also accepts strings containing color names. + +``` Py +names = { + 'black':0, + 'bg_dark':1, + 'bg_color':2, + 'mid_color':5, + 'ui_color':8, + 'ui_light':9, + 'white':10, + 'red':11, + 'green':12, + 'blue':13, + 'bg_complement':14, + 'ui_complement':15, +} +``` + +
diff --git a/wiki/Playing-Sound.md b/wiki/Playing-Sound.md index b252977..c7eaca0 100644 --- a/wiki/Playing-Sound.md +++ b/wiki/Playing-Sound.md @@ -3,11 +3,15 @@ There are two main modules built-in to MicroHydra currently, which can be used f
-### M5Sound.py -[M5Sound](https://github.com/echo-lalia/Cardputer-MicroHydra/blob/main/MicroHydra/lib/M5Sound.py) is a module contributed by [Lana-chan](https://github.com/echo-lalia/Cardputer-MicroHydra/commits?author=Lana-chan) for playing high-quality sound on the Cardputer. +### lib.audio.Audio +MicroHydra's [audio](https://github.com/echo-lalia/Cardputer-MicroHydra/tree/wikiimprovements/src/lib/audio) module subclasses the apropriate audio module for the current device (Currently this is only `i2ssound`, but may be expanded in the future), and initializes it with the apropriate values for the device. -It can play samples stored in a variable, or read large samples from storage using little memory. -It also can change the pitch of those samples, and even play several at the same time, overlapping. Unlike the beeper module, this one is non-blocking (your code can continue to execute while sound is playing). +Note: +> *`i2ssound` was previously named `M5Sound`, and was contributed by [Lana-chan](https://github.com/echo-lalia/Cardputer-MicroHydra/commits?author=Lana-chan), for playing high-quality sound on the Cardputer. +> It has been renamed for consistency with MicroHydras other modules.* + +It can play samples stored in a variable, or read large samples from storage using little memory. +It also can change the pitch of those samples, and even play several at the same time, overlapping.
@@ -16,9 +20,9 @@ It also can change the pitch of those samples, and even play several at the same ``` Python import time -from lib import M5Sound +from lib.audio import Audio -sound = M5Sound.M5Sound() +audio = Audio() _SQUARE = const(\ b'\x00\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x80'\ @@ -32,17 +36,17 @@ _SQUARE = const(\ SQUARE = memoryview(_SQUARE) for note in range(24,60): # note values, C-3 to B-5 - sound.play(SQUARE, note, 0, 14, 0, True) + audio.play(SQUARE, note, 0, 14, 0, True) for i in range(13,1,-1): # fade out volume - sound.setvolume(i) + audio.setvolume(i) time.sleep(0.05) - sound.stop(0) + audio.stop(0) ``` Samples can also be loaded from a 'raw' file on the flash or SDCard. ``` Python -M5Sound.Sample(source, buffer_size=1024) +i2ssound.Sample(source, buffer_size=1024) """Initialize a sample for playback - source: If string, filename. Otherwise, use MemoryView. @@ -55,16 +59,17 @@ M5Sound.Sample(source, buffer_size=1024)


### beeper -[beeper.py](https://github.com/echo-lalia/Cardputer-MicroHydra/blob/main/MicroHydra/lib/beeper.py) is a module for playing simple UI beeps. +[beeper.py](https://github.com/echo-lalia/Cardputer-MicroHydra/blob/wikiimprovements/src/lib/hydra/beeper.py) is a module for playing simple UI beeps. -This module is very imperfect. It is somewhat limited in its use, and it uses more memory than what is probably needed. However, it *is* simple to use, and it thankfully does work decent for short UI tones. +This module is very imperfect. It is somewhat limited in its use, however, it *is* simple to use. +> In previous versions, this module used its own, blocking, implementation for sending audio to the speaker. However, the current version is just a wrapper for the `Audio` class above. The audio is now much higher quality and more consistent, however there is a noticable delay in it. I would like to fix this in the future, but I'm not sure how to do that. To use it: ``` Python -from lib import beeper +from lib.hydra import beeper ``` ``` Python @@ -72,9 +77,13 @@ from lib import beeper beep = beeper.Beeper() beep.play( - notes=('C4',('D4','D4')), # a tuple of strings containing notes to play. a nested tuple can be used to play multiple notes together. - time_ms=120, # how long to play each note - volume=4) # an integer from 0-10 representing the volume of the playback. Default is 2, 0 is almost inaudible, 10 is loud. + # a tuple of strings containing notes to play. a nested tuple can be used to play multiple notes together. + notes=('C4',('D4','D4')), + # how long to play each note + time_ms=120, + # an integer from 0-10 representing the volume of the playback. Default is 2, 0 is almost inaudible, 10 is loud. + volume=10, +) ```


diff --git a/wiki/popup.md b/wiki/popup.md index 2b91964..eaac5c3 100644 --- a/wiki/popup.md +++ b/wiki/popup.md @@ -1,103 +1,46 @@ -MicroHydra includes a module called mhoverlay, which provides some simple, common tools for displaying various UI popups and overlays. +## lib.hydra.popup -To use the module, you must first import mhoverlay, and then create keyboard, config, and display objects, which you must pass to the mhoverlay.UI_Overlay object on creation. +MicroHydra includes a module called `popup`, which provides some simple, common tools for displaying various UI popups and overlays. -``` Python -import st7789py, keyboard, mhconfig, mhoverlay -from machine import Pin, - -tft = st7789py.ST7789( - SPI(1, baudrate=40000000, sck=Pin(36), mosi=Pin(35), miso=None), - 135, - 240, - reset=Pin(33, Pin.OUT), - cs=Pin(37, Pin.OUT), - dc=Pin(34, Pin.OUT), - backlight=Pin(38, Pin.OUT), - rotation=1, - color_order=st7789py.BGR - ) - -kb = keyboard.KeyBoard() -config = Config() - -# pass the config, keyboard, and display objects to the overlay -overlay = UI_Overlay(config=config, keyboard=kb, display_py=tft) -``` -UI_Overlay supports both st7789py, and st7789fbuf, but it requires you to specify which one you're using. - -If you're using st7789py, you can use ```display_py=tft``` on initialization. However, for st7789fbuf, you can use ```display_fbuf=tft```. -*Important note: If you are using st7789py, UI_Overlay will import font.vga1_8x16 to write to the screen.* - ----- - -
-
-
- -#### Here's a quick overview on the methods provided by UI_Overlay: - -
-
- -``` Python -UI_Overlay.text_entry(start_value='', title="Enter text:", blackout_bg=False) -``` -Creates a popup text box for the user to enter text. Blocks until user submits text with "enter" key. Returns entered text (str) or None if user backs out. -*Params:* -- start_value(str): the value in the text field to start with -- title(str): the text to show above the text box -- blackout_bg(bool): whether or not to draw a large box behind textbox. - ----- -
+To use the module, you must first import it, create a display object, and create the `popup.UIOverlay` object to access its methods. ``` Python -UI_Overlay.popup_options(options, title=None, shadow=True, extended_border=False) +from lib.display import Display +from lib.hydra import popup + +# create the display object first +# (Display must be initialized before UIOverlay can work) +display = Display() +# Create our overlay object +overlay = popup.UIOverlay() + +# this demo creates a list of options, and allows the user to select one. +demo = overlay.popup_options( + options = ('text entry', '2d options', 'popup message', 'error message'), + title = "Pick a demo:" +) + +# popup_options returns a string, so we can use this to select another demo to display: +if demo == 'text entry': + # this allows the user to enter some text, and returns it as a string. + print(overlay.text_entry(start_value='', title="Enter text:")) + +elif demo == '2d options': + # popup options also allows you to make several columns using nested lists (or tuples) + print(overlay.popup_options( + options = ( + ('you', 'also', 'more'), + ('can', 'make', 'columns.'), + ('and', 'they', 'can', 'have', 'different', 'lengths') + ), + )) + +elif demo == 'popup message': + # this simply displays a message on the screen, and blocks until the user clicks any button + print(overlay.popup("This is a test")) + +elif demo == 'error message': + # this is exactly the same as overlay.popup, but with custom styling for an error message + print(overlay.error("This is an error message")) ``` -Creates a popup list of menu options, which the user can select with arrow keys + enter. Returns selection (str) or None if user hits escape. -*Params:* -- options (list[str]): a list of menu options to choose from -- title (str): the text to show above the options -- shadow (bool): whether or not to draw a shadow behind the popup box -- extended_border (bool): whether or not to blackout a larger section behind the popup box (for, possibly, better readability) - ----- -
- -``` Python -UI_Overlay.popup(text) -``` -Creates a popup message with the given text written in it. Blocks until user presses any key. -*Params:* -- text (str): The text to write. This text will automatically be broken into lines to fit on the display. - ----- -
- -``` Python -UI_Overlay.error(text) -``` -Similar to "popup"; creates a popup error message with the given text written in it. Blocks until user presses any key. -*Params:* -- text (str): The text to write. This text will automatically be broken into lines to fit on the display. - ----- -
- -``` Python -UI_Overlay.draw_textbox(text, x, y, padding=8, shadow=True, extended_border=False): -``` -Draw a textbox centered at the given position without blocking. -*Params:* -- text (str): The text to write. -- x (int): The x coordinate to center the textbox on -- y (int): The y coordinate to center the textbox on -- padding (int): The extra size added to the textbox, around the text -- shadow (bool): Whether or not to draw a shadow behind the text box -- extended_border (bool): Whether or not to blackout a larger region behind the popup box (to potentially improve readability) - - ----- -
diff --git a/wiki/userinput.md b/wiki/userinput.md index a642095..4fdc541 100644 --- a/wiki/userinput.md +++ b/wiki/userinput.md @@ -1,32 +1,88 @@ -### keyboard -[keyboard.py](https://github.com/echo-lalia/Cardputer-MicroHydra/blob/main/MicroHydra/lib/keyboard.py) makes it easy to get button inputs from the keyboard matrix on the Cardputer. To use it, you import it with: -```from lib import keyboard``` +### lib.userinput.UserInput -Then, you can access the pressed keys like this: -``` Python -kb = keyboard.KeyBoard() # init the object controlling our keyboard +[userinput](https://github.com/echo-lalia/Cardputer-MicroHydra/blob/wikiimprovements/src/lib/userinput/userinput.py) provides a all of a devices physical inputs in one place. -# return a list of keys that are newly pressed (not keys that were already pressed) -keys = kb.get_new_keys() +At its core, the module is based on the device-specific `_keys` module, which provides logic for reading the keypresses and converting them into readable strings. The `UserInput` class subclasses the `_keys.Keys` class, and inherits those device-specific features. +`UserInput` can also provide other kinds of input, such as providing touch data from a device with a touchscreen. These extra features, of course, are based on the specific device being used. -# if you would also like to check for a specific key being held (for example, checking for key combinations), -# you can do something like this: -if "CTL" in kb.key_state: - print("Control!") -``` +The `UserInput` class also handles key-repeating behaviour, and locking modifier keys. -If you'd like to process key presses manually, you can also just use something like this: -``` Python -# get a list of keys that are currently pressed down -pressed_keys = kb.get_pressed_keys() -``` +> *This module was previously the `lib.smartkeyboard` module. It has been renamed and expanded for MicroHydra 2.x to support different devices and input methods.* -And that's it! It even automatically applies the 'shift' and 'fn' keys for you, so it's very quick and easy to work with. -Take a look at the keymaps at the top of lib/keyboard.py if you want to see all the possible key values. + +

+ +# UserInput: + +## Constructor: + +`userinput.UserInput(hold_ms=600, repeat_ms=80, use_sys_commands=True, allow_locking_keys=False, **kwargs)` +> Creat the object for accessing user inputs. +> +> Args: +> * `hold_ms`: +> The amount of time, in milliseconds, a key must be held before it starts to repeat. +> +> * `repeat_ms`: +> While a key is being held and repeating, how long between repetitions. +> +> * `use_sys_commands`: +> Whether or not to enable keyboard shortcuts for built-in system commands +> +> * `allow_locking_keys`: +> Whether or not to allow modifier keys to 'lock' (stay activated when tapped). This draws an overlay on the screen using the display module. +> +> * `**kwargs`: +> Any other keyword args given are passed along to the `_keys.Keys` class, allowing for device-specific options to be used. +>

+## Read keys: + +`UserInput.get_pressed_keys()` +> Return a list of strings, representing the names of keys that are currently being pressed. +>
+
+ +`UserInput.get_new_keys()` +> Return a list of strings, representing the names of keys that are newly pressed (are now pressed but were not pressed last time we checked). +> +> This method also runs additional logic based on the settings provided in the constructor: +> - key repeating logic: +> Keys will return when they are new, *and* periodically after they have been held down for the time specified by `UserInput.hold_ms` +> +> - locking keys logic: +> When `allow_locking_keys` is `True`, if a modifier key is pressed without pressing another key, that key will be 'locked', and held until it is pressed again. +> This also draws an overlay (displaying the locked keys) to the screen using a callback every time `Display.show()` is called. +> +>

-*One more note on the keyboard library; I named the key on the top of the device "GO" instead of "G0" because I thought it was cute. Now that people are actually using my library I'm feeling a little silly for this choice, as I worry it might confuse some developers. That said, I also don't want to change it because it would be a breaking change, and it doesn't really harm anyone otherwise. So, figure I'll just make a note here to help prevent confusion instead.* +`UserInput.get_mod_keys()` +> Return a list of modifier keys that are being held, including keys that are locked if `allow_locking_keys` is `True`. +>
+
+ +

+ + +## Read touch: +*These methods only exist when the device has a touchscreen* + +`UserInput.get_current_points()` +> Return the current touch data in the form of a list of `TouchPoints` +> Touchpoints are `namedtuple`s with the following format: +> `namedtuple("TouchPoint", ["id", "x", "y", "size"])` +>
+
+ +`UserInput.get_touch_events()` +> Similar to `get_new_keys`, this method does some pre-processing on touch data to make it easier to parse. +> +> Touch events are only returned once, when they are completed, and take the form of either a `Tap` or a `Swipe`: +> `namedtuple("Tap", ['x', 'y', 'size', 'duration'])` +> `namedtuple("Swipe", ['x0', 'y0', 'x1', 'y1', 'size', 'duration', 'distance', 'direction'])` +>
+