Compare commits

..

No commits in common. "10562d64107dddc6bf954c0542efe66c0641fc72" and "ed664eb794b055b2951a53a914e7de2919aa6aed" have entirely different histories.

2 changed files with 37 additions and 36 deletions

View File

@ -8,10 +8,10 @@ This project is the completely rewritten successor of my old (and now archived)
## Roadmap ## Roadmap
- [x] forward, backward and select button - [x] forward, backward and select button
- [x] support for horizontal and vertical scrolling - [ ] support for horizontal and vertical scrolling
- [x] support for both 2x16 and 4x20 LCDs - [x] support for both 2x16 and 4x20 LCDs
- [x] a reliable order of the menu items - [x] a reliable order of the menu items
- [x] good documentation for all of this (maybe through examples) - [ ] good documentation for all of this (maybe through examples)
- [x] show an exit screen when a specific exit code is returned by a callback function - [x] show an exit screen when a specific exit code is returned by a callback function
- [ ] make the menu itself exitable (to enable stuff like submenus, etc.) - [ ] make the menu itself exitable (to enable stuff like submenus, etc.)
- [x] make the project a valid python package - [x] make the project a valid python package
@ -19,4 +19,4 @@ This project is the completely rewritten successor of my old (and now archived)
## License ## License
This project is licensed under the GPL-v3-or-later. A copy can be found [here](LICENSE). This project is licensed under the GPL-v3-or-later. A copy can be found [here](LICENSE).

View File

@ -63,10 +63,10 @@ class lcdMenu:
# fill the custom character fields in the displays memory # fill the custom character fields in the displays memory
self.lcd.custom_char(0, bytearray([0x04,0x0A,0x11,0x00,0x00,0x00,0x00,0x00])) # arrow up self.lcd.custom_char(0, bytearray([0x04,0x0A,0x11,0x00,0x00,0x00,0x00,0x00])) # arrow up
self.lcd.custom_char(1, bytearray([0x00,0x00,0x00,0x00,0x00,0x11,0x0A,0x04])) # arrow down self.lcd.custom_char(1, bytearray([0x00,0x00,0x00,0x00,0x00,0x11,0x0A,0x04])) # arrow down
self.lcd.custom_char(2, bytearray([0x04,0x0A,0x11,0x00,0x00,0x11,0x0A,0x04])) # arrow up and down self.lcd.custom_char(2, bytearray([0x04,0x0A,0x11,0x00,0x00,0x11,0x0A,0x04])) # arrow up and down (variant 5 from above)
self.lcd.custom_char(3, bytearray([0x11,0x0A,0x04,0x00,0x00,0x04,0x0A,0x11])) # no options self.lcd.custom_char(3, bytearray([0x11,0x0A,0x04,0x00,0x00,0x04,0x0A,0x11])) # no options (variant 3 from above)
self.lcd.custom_char(4, bytearray([0x08,0x08,0x08,0x0F,0x08,0x08,0x08,0x08])) # line with a fork (to show the current selection - v scrolling) self.lcd.custom_char(4, bytearray([0x08,0x08,0x08,0x0F,0x08,0x08,0x08,0x08])) # line with a fork (to show the current selection - h scrolling)
self.lcd.custom_char(5, bytearray([0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08])) # line without a fork (to show unselected items - v scrolling) self.lcd.custom_char(5, bytearray([0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08])) # line without a fork (to show unselected items - h scrolling)
self.lcd.custom_char(6, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00])) # three dots in a row self.lcd.custom_char(6, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00])) # three dots in a row
# now show it off! # now show it off!
@ -97,28 +97,31 @@ class lcdMenu:
# maybe the following could be done with a crazy math formula - but I want to keep it simpler! # maybe the following could be done with a crazy math formula - but I want to keep it simpler!
# as there aren't enough menu items after the current selection to fill the display, we have to... # as there aren't enough menu items after the current selection to fill the display, we have to...
# ... calculate where to place the current selection, how many items there are before it and how many after it # ... calculate where to place the current selection, how many items there are before it and how many after it
menu_items_cut = self.menu_items[:lines_for_display:-1][::-1] # cut the menu_items list to the relevant last n ones maintaining order (n = number of lines for display) """
current_pos_in_cut = -len(self.menu_items) + self.current_selection + lines_for_display # calculate the current index of the selection in the new cut if lines_for_display > len(self.menu_items): # if it is because of an overall small number of menu items (less than we can display)
# draw all the lines for i in range(len(self.menu_items)):
for i in range(lines_for_display): if i < self.current_selection:
if i == current_pos_in_cut: # if drawing the currently selected item self.lcd.putstr(chr(5)+" "+self.menu_items[i][0][0:lw-4])
self.lcd.putstr(f"{chr(4)} {menu_items_cut[i][0][0:lw-4]}") self.lcd.putstr(" "*(lw-4-len(self.menu_items[i][0][0:lw-4])))
self.lcd.putstr(" " * ((lw-4)-len(menu_items_cut[i][0][0:lw-4]))) # fit the line if len(self.menu_items) <= 1:
else: self.lcd.putstr(" " + chr(3)) # no options icon (as there's only one menu item!)
self.lcd.putstr(f"{chr(5)} {menu_items_cut[i][0][0:lw-4]}") elif self.current_selection == 0 and not self.cycle:
self.lcd.putstr(" " * ((lw-4)-len(menu_items_cut[i][0][0:lw-4]))) # fit the line self.lcd.putstr(" "+chr(1))
# now the arrow elif self.current_selection == (len(self.menu_items)-1) and not self.cycle:
if i == 0: # if the first element is drawn, think about printing or not printing the up arrow self.lcd.putstr(" "+chr(0))
if self.current_selection == 0 and not self.cycle: # first item selected and no cycling else:
self.lcd.putstr(" ") # leave the line with spaces self.lcd.putstr(" "+chr(2))
else: elif i == self.current_selection:
self.lcd.putstr(" " + chr(0)) self.lcd.putstr(chr(5)+" "+self.menu_items[i][0][0:lw-4])
elif i == lines_for_display-1: # if the last element is drawn, print a down arrow? self.lcd.putstr(" "*(lw-4-len(self.menu_items[i][0][0:lw-4])))
if self.current_selection == (len(self.menu_items)-1) and not self.cycle: # first item selected and no cycling elif i > self.current_selection:
self.lcd.putstr(" ") # leave the line with spaces
else:
self.lcd.putstr(" " + chr(1)) # arrow down
print("Im here!")
else: # if it is because we reached the end of a (possibly) long menu list -> we have enough items to fill all the available lines
print("Else here!")
"""
print("ToDo!")
else: # there are enough items to fill the display after the current selection else: # there are enough items to fill the display after the current selection
# the first line # the first line
self.lcd.putstr(f"{chr(4)} {selection_name[0:lw-4]}") self.lcd.putstr(f"{chr(4)} {selection_name[0:lw-4]}")
@ -126,18 +129,18 @@ class lcdMenu:
if len(self.menu_items) <= 1: if len(self.menu_items) <= 1:
self.lcd.putstr(" " + chr(3)) # no options icon (as there's only one menu item!) self.lcd.putstr(" " + chr(3)) # no options icon (as there's only one menu item!)
elif lines_for_display == 1: # if there is exactly one line to display the menu entries... elif lines_for_display == 1: # if there is exactly one line to display the menu entries
if self.current_selection == 0 and not self.cycle: # ...and the first element is selected and cycling is disabled so you can't go back if self.current_selection == 0 and not self.cycle:
self.lcd.putstr(" "+chr(1)) self.lcd.putstr(" "+chr(1))
elif self.current_selection == (len(self.menu_items)-1) and not self.cycle: # ...as before but with the last element -> you can't go further elif self.current_selection == (len(self.menu_items)-1) and not self.cycle:
self.lcd.putstr(" "+chr(0)) self.lcd.putstr(" "+chr(0))
else: # ...or anything else (cycling or in the middle -> you can go in both directions else:
self.lcd.putstr(" "+chr(2)) self.lcd.putstr(" "+chr(2))
elif self.current_selection == 0 and not self.cycle: # first item selected and no cycling elif self.current_selection == 0 and not self.cycle: # first item selected and no cycling
self.lcd.putstr(" ") # leave the line with spaces self.lcd.putstr(" ") # leave the line with spaces
else: else:
self.lcd.putstr(" " + chr(0)) self.lcd.putstr(" " + chr(0))
# the other lines... (if existing!) # the other lines... (if existing!)
for i in range(lines_for_display-1): for i in range(lines_for_display-1):
self.lcd.putstr(f"{chr(5)} {self.menu_items[self.current_selection+i+1][0][0:lw-4]}") self.lcd.putstr(f"{chr(5)} {self.menu_items[self.current_selection+i+1][0][0:lw-4]}")
@ -187,7 +190,7 @@ class lcdMenu:
return_value = selection[1]() return_value = selection[1]()
# show a exit when there's no specific return value # show a exit when there's no specific return value
if not return_value: # if the return value is None / nothing was returned -> show a closing message if not return_value: # if the return value is None / nothing was returned
while self.ok_btn.value() == 1: time.sleep(self.debounce_time) # wait till ok_btn release (e.g. if the "program" is a simple send action) while self.ok_btn.value() == 1: time.sleep(self.debounce_time) # wait till ok_btn release (e.g. if the "program" is a simple send action)
self.lcd.move_to(0,0) self.lcd.move_to(0,0)
if self.lcd.num_lines == 4: if self.lcd.num_lines == 4:
@ -196,8 +199,6 @@ class lcdMenu:
self.lcd.putstr(f"[{selection[0][0:lw].center(lw-2)}]{self.end_execution_msg[0:lw].center(lw)}") self.lcd.putstr(f"[{selection[0][0:lw].center(lw-2)}]{self.end_execution_msg[0:lw].center(lw)}")
sleep(self.end_execution_wait) sleep(self.end_execution_wait)
self.show_selection() self.show_selection()
else: # -> show no message and quit directly back into the lcdMenu
self.show_selection()
# listen for button presses (this method should be called in an endless loop, see method run) # listen for button presses (this method should be called in an endless loop, see method run)