|
@@ -1,116 +0,0 @@
|
|
|
-import justpy as jp
|
|
|
-from typing import List
|
|
|
-from contextlib import contextmanager
|
|
|
-import asyncio
|
|
|
-import time
|
|
|
-import uuid
|
|
|
-from utils import handle_exceptions, provide_arguments
|
|
|
-
|
|
|
-class Group:
|
|
|
-
|
|
|
- def label(self, text) -> jp.Div:
|
|
|
-
|
|
|
- return jp.Div(text=text, a=self.view, classes='')
|
|
|
-
|
|
|
- def button(self, text, on_click=None) -> jp.Button:
|
|
|
-
|
|
|
- b = jp.Button(text=text, a=self.view, classes='bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded')
|
|
|
- if on_click is not None:
|
|
|
- b.on('click', handle_exceptions(provide_arguments(on_click)))
|
|
|
- return b
|
|
|
-
|
|
|
- def checkbox(self, text=None, on_change=None) -> jp.Input:
|
|
|
-
|
|
|
- d = jp.Div(a=self.view, classes='flex gap-4')
|
|
|
- c = jp.Input(a=d, type='checkbox', classes='form-checkbox mt-1 ml-4')
|
|
|
- if text is not None:
|
|
|
- jp.Div(text=text, a=d)
|
|
|
- if on_change is not None:
|
|
|
- c.on('change', handle_exceptions(provide_arguments(on_change, 'checked')))
|
|
|
- return d
|
|
|
-
|
|
|
- def select(self, options: List[str], value=None, on_change=None) -> jp.Input:
|
|
|
-
|
|
|
- s = jp.Select(classes='p-2 border rounded', a=self.view, value=value)
|
|
|
- if on_change is not None:
|
|
|
- s.on('change', handle_exceptions(provide_arguments(on_change, 'value')))
|
|
|
- [ jp.Option(value=option, text=option, a=s) for option in options]
|
|
|
- return s
|
|
|
-
|
|
|
- def radio(self, options: List[str], value=None, vertical=False, on_change=None) -> jp.Input:
|
|
|
-
|
|
|
- flex_direction = 'flex-col' if vertical else 'flex-row'
|
|
|
- name = str(uuid.uuid4())
|
|
|
- outer = jp.Div(a=self.view, classes=f'flex gap-2 {flex_direction}')
|
|
|
- for option in options:
|
|
|
- inner = jp.Label(classes='inline-block', a=outer)
|
|
|
- r = jp.Input(type='radio', name=name, value=option, checked=option==value, a=inner, classes='mx-2')
|
|
|
- r.on('change', handle_exceptions(provide_arguments(on_change, 'value')))
|
|
|
- jp.Span(a=inner, text=option)
|
|
|
-
|
|
|
- return outer
|
|
|
-
|
|
|
- @contextmanager
|
|
|
- def plot(self):
|
|
|
-
|
|
|
- yield
|
|
|
- jp.Matplotlib(a=self.view)
|
|
|
-
|
|
|
- @contextmanager
|
|
|
- def card(self):
|
|
|
-
|
|
|
- yield Card(self)
|
|
|
-
|
|
|
- @contextmanager
|
|
|
- def column(self):
|
|
|
-
|
|
|
- yield Column(self)
|
|
|
-
|
|
|
- @contextmanager
|
|
|
- def row(self):
|
|
|
-
|
|
|
- yield Row(self)
|
|
|
-
|
|
|
- def timer(self, inverval, callback):
|
|
|
-
|
|
|
- async def loop():
|
|
|
-
|
|
|
- while True:
|
|
|
- start = time.time()
|
|
|
- handle_exceptions(callback)()
|
|
|
- jp.run_task(self.view.update())
|
|
|
- dt = time.time() - start
|
|
|
- await asyncio.sleep(inverval - dt)
|
|
|
-
|
|
|
- jp.run_task(loop())
|
|
|
-
|
|
|
-
|
|
|
-class Page(Group):
|
|
|
-
|
|
|
- def __init__(self):
|
|
|
-
|
|
|
- self.view = jp.WebPage(delete_flag=False, body_classes='m-4', title='Nice GUI', favicon='favicon.png')
|
|
|
-
|
|
|
-
|
|
|
-class Card(Group):
|
|
|
-
|
|
|
- def __init__(self, parent) -> None:
|
|
|
-
|
|
|
- self.parent = parent
|
|
|
- self.view = jp.Div(a=parent.view, classes='p-4 flex flex-col gap-4 items-start rounded shadow-lg')
|
|
|
-
|
|
|
-
|
|
|
-class Column(Group):
|
|
|
-
|
|
|
- def __init__(self, parent) -> None:
|
|
|
-
|
|
|
- self.parent = parent
|
|
|
- self.view = jp.Div(a=parent.view, classes='flex flex-col gap-4 items-start')
|
|
|
-
|
|
|
-
|
|
|
-class Row(Group):
|
|
|
-
|
|
|
- def __init__(self, parent) -> None:
|
|
|
-
|
|
|
- self.parent = parent
|
|
|
- self.view = jp.Div(a=parent.view, classes='flex flex-row flex-wrap gap-4 items-start')
|