From 083575cf564b2fbebb4e392321c56fbcc8f6c796 Mon Sep 17 00:00:00 2001 From: Brian Whitman Date: Wed, 22 May 2024 20:46:18 -0400 Subject: [PATCH] finishing up #220, still have to doc this --- tulip/fs/app/buttons/buttons.py | 41 ++++++++++++ tulip/fs/ex/buttons.py | 33 ---------- tulip/shared/py/editor.py | 48 ++++++++++++++ tulip/shared/py/ui.py | 112 +++++++++++++------------------- 4 files changed, 134 insertions(+), 100 deletions(-) create mode 100644 tulip/fs/app/buttons/buttons.py delete mode 100644 tulip/fs/ex/buttons.py create mode 100644 tulip/shared/py/editor.py diff --git a/tulip/fs/app/buttons/buttons.py b/tulip/fs/app/buttons/buttons.py new file mode 100644 index 000000000..7bc8ce97d --- /dev/null +++ b/tulip/fs/app/buttons/buttons.py @@ -0,0 +1,41 @@ +# make some UI elements on the REPL + +import tulip + +def button_cb(e): + obj = e.get_target_obj() + print("label of button pressed is %s" % (obj.get_child(0).get_text())) + +def slider_cb(e): + obj = e.get_target_obj() + print("slider value is %d" % (obj.get_value())) + +def check_cb(e): + obj = e.get_target_obj() + print("checkbox value is %s" % (obj.get_state())) + +def text_cb(e): + obj = e.get_target_obj() + print("text value is %s" % (obj.get_text())) + + +def run(screen): + screen.bg_color = 9 + + screen.add(tulip.UILabel("hello it is a test"), x=200,y=200) + screen.add(tulip.UIButton(text="Click me", fg_color=255, bg_color=200, callback=button_cb), x=600, y=200) + screen.add(tulip.UIButton(text="here again", fg_color=255, bg_color=3, w=250, callback=button_cb), x=700, y=400) + + screen.add(tulip.UISlider(val=50, w=15, h=150, bar_color=151, handle_color=188, callback=slider_cb), x=300, y=400) + screen.add(tulip.UISlider(val=50, w=400, h=15, bar_color=255, handle_color=0, callback=slider_cb), x=250, y=300) + + screen.add(tulip.UIText(text="12",fg_color=255,w=100,bg_color=0, font=tulip.lv.font_unscii_8, callback=text_cb), x=200, y=200) + screen.add(tulip.UIText(placeholder="Type here", w=220, fg_color=255,bg_color=0, font=tulip.lv.font_unscii_8, callback=text_cb), x=400, y=100) + + screen.add(tulip.UICheckbox(text="Extra text", fg_color=255, bg_color = 0, callback=check_cb), x=400, y=400) + screen.add(tulip.UICheckbox(fg_color=255, bg_color = 0, callback=check_cb), x=400, y=460) + + screen.handle_keyboard = True + screen.keep_tfb = True + screen.present() + diff --git a/tulip/fs/ex/buttons.py b/tulip/fs/ex/buttons.py deleted file mode 100644 index d6ce8180f..000000000 --- a/tulip/fs/ex/buttons.py +++ /dev/null @@ -1,33 +0,0 @@ -# make some UI elements on the REPL - -import tulip - -def button_cb(e): - obj = e.get_target_obj() - print("label of button pressed is %s" % (obj.get_child(0).get_text())) - -def slider_cb(e): - obj = e.get_target_obj() - print("slider value is %d" % (obj.get_value())) - -# Choose your screen to draw on. -# If you're making a UIScreen 'app", use the screen object passed into run(screen): -# Here we'll use the REPL. -screen = tulip.repl_screen - -screen.add(tulip.UILabel("hello it is a test"), x=200,y=200) -screen.add(tulip.UIButton(text="Click me", fg_color=255, bg_color=200, w=250, callback=button_cb), x=600, y=200) -screen.add(tulip.UIButton(text="here again", fg_color=255, bg_color=3, w=250, callback=button_cb), x=700, y=400) - -screen.add(tulip.UISlider(val=50, w=15, h=150, bar_color=151, handle_color=188, callback=slider_cb), x=300, y=400) -screen.add(tulip.UISlider(val=50, w=400, h=15, bar_color=255, handle_color=0, callback=slider_cb), x=250, y=300) - - -#tulip.ui_text(ui_id=4, text="12", x=200, y=200, w=100, fg_color=255, bg_color=0, font=tulip.lv.font_unscii_8) -#tulip.ui_text(ui_id=5, placeholder="Type here", x=400, y=200, w=200, fg_color=255, bg_color=0) - -#tulip.ui_checkbox(ui_id=6, text="Extra text", x=400, y=400, fg_color=255, bg_color=0) -#tulip.ui_checkbox(ui_id=7, x=400, y=430, fg_color=255, bg_color=0) - - - diff --git a/tulip/shared/py/editor.py b/tulip/shared/py/editor.py new file mode 100644 index 000000000..34749ea36 --- /dev/null +++ b/tulip/shared/py/editor.py @@ -0,0 +1,48 @@ +# editor.py +# Tulip C editor wrapped in UIScreen. +# One day (not today), we should re-write the editor in pure python here too (still using the TFB) +# That will let us do LVGL stuff for saving/searching/etc + +import tulip + +class Editor(tulip.UIScreen): + def __init__(self, filename): + self.filename = filename + # Make sure to turn off the offsets for the task bar + super().__init__('edit', bg_color=36, keep_tfb=True, offset_x=0, offset_y=0) + self.quit_callback = self.quit_editor_cb + self.deactivate_callback = self.deactivate_editor_cb + self.activate_callback = self.activate_editor_cb + self.first_run = True + self.present() + + def deactivate_editor_cb(self, screen): + tulip.keyboard_callback() + tulip.tfb_restore() + # Fudge the repl line as it got eaten during the TFB restore. This will never be a problem, lol + print(">>> ",end='') + + def quit_editor_cb(self, screen): + tulip.keyboard_callback() + tulip.deinit_editor() + tulip.tfb_restore() + + def activate_editor_cb(self,screen): + # Only load in the file on first run + tulip.tfb_save() + if(self.first_run): + self.first_run = False + if(self.filename is None): + tulip.run_editor() + else: + tulip.run_editor(self.filename) + + tulip.keyboard_callback(tulip.key_editor) + # The TFB switches over, but the REPL will print >>> after this runs, + # overwriting the first line. So wait a bit and activate then + # (This also means the >>> will print on the alternate TFB, so we have to fudge on reactivate) + tulip.defer(tulip.activate_editor, 50) + +# Launch the tulip editor as a UIScreen +def edit(filename=None): + editor = Editor(filename) diff --git a/tulip/shared/py/ui.py b/tulip/shared/py/ui.py index f10bbb89c..45d54869c 100644 --- a/tulip/shared/py/ui.py +++ b/tulip/shared/py/ui.py @@ -73,7 +73,6 @@ def __init__(self, name, keep_tfb = False, bg_color=default_bg_color, offset_x=d self.offset_x = offset_x self.offset_y = offset_y self.last_obj_added = None - self.group.set_style_bg_color(pal_to_lv(self.bg_color), lv.PART.MAIN) self.name = name self.alttab_button = None self.quit_button = None @@ -192,7 +191,7 @@ def present(self): current_app_string = self.name self.active = True self.draw_task_bar() - + self.group.set_style_bg_color(pal_to_lv(self.bg_color), lv.PART.MAIN) lv.screen_load(self.screen) if(self.handle_keyboard): @@ -232,6 +231,7 @@ def __init__(self): self.group = lv.obj(UIElement.temp_screen) # Hot tip - set this to 1 if you're debugging why elements are not aligning like you think they should self.group.set_style_border_width(0, lv.PART.MAIN) + self.group.remove_flag(lv.obj.FLAG.SCROLLABLE) def update_callbacks(self, cb): pass @@ -381,7 +381,6 @@ def __init__(self, label_text="", filled_text="", ok_callback=None, cancel_callb self.cancel.align_to(self.ok, lv.ALIGN.OUT_RIGHT_MID,10,0) self.cancel.add_event_cb(self.cancel_callback, lv.EVENT.CLICKED, None) self.box.remove_flag(lv.obj.FLAG.SCROLLABLE) - self.group.remove_flag(lv.obj.FLAG.SCROLLABLE) self.external_ok_callback = ok_callback self.external_cancel_callback = cancel_callback @@ -435,7 +434,6 @@ def __init__(self, val=0, w=None, h=None, bar_color=None, unset_bar_color=None, self.slider.align(lv.ALIGN.CENTER,0,0) self.slider.set_value(int(val),lv.ANIM.OFF) - self.group.remove_flag(lv.obj.FLAG.SCROLLABLE) if(callback is not None): self.slider.add_event_cb(callback, lv.EVENT.VALUE_CHANGED, None) @@ -467,10 +465,9 @@ def __init__(self, text=None, w=None, h=None, bg_color=None, fg_color=None, font self.label.set_style_text_color(pal_to_lv(fg_color), 0) if(callback is not None): self.button.add_event_cb(callback, lv.EVENT.CLICKED, None) - self.group.remove_flag(lv.obj.FLAG.SCROLLABLE) class UILabel(UIElement): - def __init__(self, text, x=0, y=0, fg_color=None, font=None): + def __init__(self, text, fg_color=None, font=None): super().__init__() self.label = lv.label(self.group) self.label.set_text(text) @@ -479,68 +476,49 @@ def __init__(self, text, x=0, y=0, fg_color=None, font=None): self.label.set_style_text_font(font, 0) if(fg_color is not None): self.label.set_style_text_color(pal_to_lv(fg_color),0) - self.group.remove_flag(lv.obj.FLAG.SCROLLABLE) - self.label.align_to(self.group, lv.ALIGN.CENTER,0, 0) - -# TODO: Make UIMsgBox -# Draw a msgbox on screen. -def ui_msgbox(buttons=['OK', 'Cancel'], title='Title', message='Message box', ui_id=None): - mbox = lv.msgbox(current_lv_group()) - mbox.add_text(message) - mbox.add_title(title) - mbox.add_close_button() - for b in buttons: - mbox.add_footer_button(b) - if(ui_id is not None): - mbox.add_event_cb(lambda e: lv_callback(e, ui_id), lv.EVENT.CLICKED, None) - return mbox - -# TODO : make UIText - -# Copy of our ui_text with lvgl textarea -#tulip.ui_text(ui_element_id, default_value, x, y, w, h, text_color, box_color, font_number) -def ui_text(ui_id=None, text=None, placeholder=None, x=0, y=0, w=None, h=None, bg_color=None, fg_color=None, font=None, one_line=True): - ta = lv.textarea(current_lv_group()) - ta.set_pos(x,y) - if(w is not None): - ta.set_width(w) - if(h is not None): - ta.set_height(h) - if(font is not None): - ta.set_style_text_font(font, 0) - if(bg_color is not None): - ta.set_style_bg_color(pal_to_lv(bg_color), lv.PART.MAIN) - if(fg_color is not None): - ta.set_style_text_color(pal_to_lv(fg_color),0) - if placeholder is not None: - ta.set_placeholder_text(placeholder) - if text is not None: - ta.set_text(text) - if(one_line): ta.set_one_line(True) - if(ui_id is not None): - ta.add_event_cb(lambda e: lv_callback(e, ui_id), lv.EVENT.VALUE_CHANGED, None) - return ta - -# TODO: Make UICheckbox - -# Copy of our ui_checkbox with lvgl -def ui_checkbox(ui_id=None, text=None, val=False, x=0, y=0, bg_color=None, fg_color=None): - cb = lv.checkbox(current_lv_group()) - if(text is not None): - cb.set_text(text) - cb.set_pos(x,y) - if(bg_color is not None): - cb.set_style_bg_color(pal_to_lv(bg_color), lv.PART.INDICATOR) - cb.set_style_bg_color(pal_to_lv(bg_color), lv.PART.INDICATOR | lv.STATE.CHECKED) - if(fg_color is not None): - cb.set_style_border_color(pal_to_lv(fg_color), lv.PART.INDICATOR) - cb.set_state(lv.STATE.CHECKED, val) - if(ui_id is not None): - cb.add_event_cb(lambda e: lv_callback(e, ui_id), lv.EVENT.VALUE_CHANGED, None) - return cb - -#TODO : Make UILabel + lv_depad(self.label) + lv_depad(self.group) + + +# TODO -- get the kb_group back involved +class UIText(UIElement): + def __init__(self, text=None, placeholder=None, w=None, h=None, bg_color=None, fg_color=None, font=None, one_line=True, callback=None): + super().__init__() + self.ta = lv.textarea(self.group) + if(w is not None): + self.ta.set_width(w) + if(h is not None): + self.ta.set_height(h) + if(font is not None): + self.ta.set_style_text_font(font, 0) + if(bg_color is not None): + self.ta.set_style_bg_color(pal_to_lv(bg_color), lv.PART.MAIN) + if(fg_color is not None): + self.ta.set_style_text_color(pal_to_lv(fg_color),0) + if placeholder is not None: + self.ta.set_placeholder_text(placeholder) + if text is not None: + self.ta.set_text(text) + if(one_line): self.ta.set_one_line(True) + if(callback is not None): + self.ta.add_event_cb(callback, lv.EVENT.VALUE_CHANGED, None) + if(w is not None): + self.group.set_width(w+20) +class UICheckbox(UIElement): + def __init__(self, text=None, val=False, bg_color=None, fg_color=None, callback=None): + super().__init__() + self.cb = lv.checkbox(self.group) + if(text is not None): + self.cb.set_text(text) + if(bg_color is not None): + self.cb.set_style_bg_color(pal_to_lv(bg_color), lv.PART.INDICATOR) + self.cb.set_style_bg_color(pal_to_lv(bg_color), lv.PART.INDICATOR | lv.STATE.CHECKED) + if(fg_color is not None): + self.cb.set_style_border_color(pal_to_lv(fg_color), lv.PART.INDICATOR) + self.cb.set_state(lv.STATE.CHECKED, val) + if(callback is not None): + self.cb.add_event_cb(callback, lv.EVENT.VALUE_CHANGED, None) repl_screen = UIScreen("repl", bg_color=9, handle_keyboard=True)