nice_gui.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #!/usr/bin/env python3
  2. import justpy as jp
  3. from starlette.applications import Starlette
  4. import uvicorn
  5. import inspect
  6. import time
  7. import asyncio
  8. from utils import handle_exceptions, provide_arguments
  9. wp = jp.WebPage(delete_flag=False, title='Nice GUI', favicon='favicon.png')
  10. main = jp.Div(a=wp, classes='m-4 flex flex-col items-start gap-4')
  11. jp.justpy(lambda: wp, start_server=False)
  12. view_stack = [main]
  13. class Element:
  14. def __init__(self, view: jp.HTMLBaseComponent):
  15. view_stack[-1].add(view)
  16. self.view = view
  17. @property
  18. def text(self):
  19. return self.view.text
  20. @text.setter
  21. def text(self, text):
  22. self.view.text = text
  23. def set_text(self, text):
  24. self.view.text = text
  25. def __enter__(self):
  26. view_stack.append(self.view)
  27. def __exit__(self, *_):
  28. view_stack.pop()
  29. class Ui(Starlette):
  30. def label(self, text=''):
  31. view = jp.Div(text=text)
  32. return Element(view)
  33. def button(self, text, on_click=None):
  34. view = jp.Button(text=text, classes='bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded')
  35. if on_click is not None:
  36. view.on('click', handle_exceptions(provide_arguments(on_click)))
  37. return Element(view)
  38. def row(self):
  39. view = jp.Div(classes='flex flex-row gap-4 items-start')
  40. return Element(view)
  41. def column(self):
  42. view = jp.Div(classes='flex flex-col gap-4 items-start')
  43. return Element(view)
  44. def card(self):
  45. view = jp.Div(classes='flex flex-col gap-4 items-start p-4 rounded shadow-lg')
  46. return Element(view)
  47. def timer(self, inverval, callback):
  48. async def loop():
  49. while True:
  50. start = time.time()
  51. handle_exceptions(callback)()
  52. jp.run_task(wp.update())
  53. dt = time.time() - start
  54. await asyncio.sleep(inverval - dt)
  55. jp.run_task(loop())
  56. def run(self):
  57. # NOTE: prevent reloader to restart uvicorn
  58. if inspect.stack()[-2].filename.endswith('spawn.py'):
  59. return
  60. uvicorn.run('nice_gui:ui', host='0.0.0.0', port=80, lifespan='on', reload=True)
  61. # NOTE: instantiate our own ui object with all capabilities of jp.app
  62. ui = Ui()
  63. ui.__dict__.update(jp.app.__dict__)