Skip to content

Instantly share code, notes, and snippets.

@AFCMS
Last active May 19, 2022 15:12
Show Gist options
  • Save AFCMS/6541707c5ffde3f09ab107dec649a82c to your computer and use it in GitHub Desktop.
Save AFCMS/6541707c5ffde3f09ab107dec649a82c to your computer and use it in GitHub Desktop.
QT-EPSILON
#####################################################
# QT_EPSILON #
# GUI Framework for the Numworks calculator #
# By AFCMS, under GPLv3 #
#####################################################
"""
This Framework is inspired by QT design and aims to simplificate the process of creation of basic GUIs
WARNING: This script is very big, so make sure to leave enough space for it
Features:
- Widgets:
- Buttons (with virtual keypress callbacks)
- Labels
- Selectable Lists (with callbacks)
- Color Viewer
- Horizontal Sliders (with callbacks)
- more to come!
- Customisation:
- Per App/Widget Styling properties
- Easy Widget creation
"""
import math
import random
import kandinsky
import ion
import time
screensize = {"x": 320,"y": 222}
app_theme = {
"bgcolor": kandinsky.color(10, 50, 100), # Blue
"basecolor": kandinsky.color(100, 100, 100),
"hoveredcolor": kandinsky.color(78, 90, 0),
}
button_theme_normal = {
"background": kandinsky.color(0, 150, 100), # Green
}
button_theme_danger = {
"background": kandinsky.color(255, 30, 17), # Red
}
label_theme = {
"textcolor": kandinsky.color(0, 0, 0) # Black
"background": kandinsky.color(0, 150, 100),
}
class App:
def __init__(self):
self.isDrawed = False
self.elements = []
self.theme = app_theme
def add_element(self, element):
self.elements.append(element)
def draw_all(self):
for i in self.elements:
i.draw()
def main(self):
kandinsky.fill_rect(0, 0, screensize["x"], screensize["y"], self.theme["bgcolor"])
self.draw_all()
self.isDrawed = True
while True:
self.loop()
for i in self.elements:
if i.loop() == True:
self.exit()
return
def loop(self):
pass
def exit(self):
kandinsky.fill_rect(0, 0, screensize["x"], screensize["y"], self.theme["bgcolor"])
kandinsky.draw_string("Press OK to Quit...", 60, 100)
class GenericWidget:
def __init__(self, app: App):
self.x = None
self.y = None
self.callbacks = {}
app.add_element(self)
def move(self, x: int, y: int):
self.x = x
self.y = y
def set_style(self, style):
for n in style:
self.style[n] = style[n]
def draw(self):
pass
def loop(self):
pass
def connect(self, name: str, action: callable):
self.callbacks[name] = action
class ButtonWidget(GenericWidget):
def __init__(self, text: str, key: int, app):
assert type(text) == str
self.txt = text
self.key = key
self.style = button_theme_normal
super().__init__(app)
def draw(self):
assert self.x, self.y
kandinsky.fill_rect(self.x, self.y, 6 + len(self.txt) * 10, 18 + 6, self.style["background"])
kandinsky.draw_string(self.txt, self.x + 3, self.y + 3)
def loop(self):
if ion.keydown(self.key):
a = self.callbacks.get("clicked")
if a:
return a(self)
class LabelWidget(GenericWidget):
def __init__(self, app):
self.style = label_theme
super().__init__(app)
def set_text(self, txt: str):
self.txt = txt
def update_text(self):
kandinsky.draw_string(self.txt, self.x + 3, self.y + 3, self.style["textcolor"])
def draw(self):
kandinsky.fill_rect(self.x, self.y, 6 + len(self.txt) * 10, 18 + 6, self.style["background"])
self.update_text()
class ListSelectorWidget(GenericWidget):
def __init__(self, size_x, size_y, key_up, key_down, app):
self.size_x = size_x
self.size_y = size_y
self.list = []
self.selected = 0
self.key_up = key_up
self.key_down = key_down
self.style = {
"background": kandinsky.color(0, 150, 100),
"selected": kandinsky.color(78, 90, 0),
}
super().__init__(app)
def set_list(self,list):
assert len(list) > 0
self.list = list
def get_list(self):
return self.list
def get_selected(self):
return self.selected
def draw(self):
assert len(self.list) <= self.size_x
assert len(self.list) > 0
_i=0
kandinsky.fill_rect(self.x, self.y, 6 + self.size_y * 18, 6 + (len(self.list) * 18) + (len(self.list) - 1) * 2, self.style["background"])
kandinsky.fill_rect(self.x + 1, 2 + self.y + 20 * self.selected, (5 + self.size_y * 18) - 1, 20, self.style["selected"])
for e in self.list:
kandinsky.draw_string(e, self.x + 3, self.y + 3 + _i)
_i += 20
def _run_callbacks(self, old_id, new_id):
a = self.callbacks.get("changed")
if a:
return a(self, old_id, new_id)
def loop(self):
if ion.keydown(self.key_up):
if self.selected - 1 >= 0:
self.selected -= 1
self.draw()
self._run_callbacks(self.selected + 1, self.selected)
time.sleep(0.2)
elif ion.keydown(self.key_down):
if self.selected + 1 < len(self.list):
self.selected += 1
self.draw()
self._run_callbacks(self.selected - 1, self.selected)
time.sleep(0.2)
class ColorViewWidget(GenericWidget):
def __init__(self, width: int, height: int, app):
self.width = width
self.height = height
self.style = {
"background": kandinsky.color(0, 150, 100),
}
super().__init__(app)
def set_color(self,color):
self.color = color
def update_color(self):
kandinsky.fill_rect(self.x + 3, self.y + 3, self.width, self.height, self.color)
def draw(self):
assert self.color, "no init"
kandinsky.fill_rect(self.x, self.y, 6 + self.width, self.height + 6, self.style["background"])
self.update_color()
class SliderHorizontalWidget(GenericWidget):
def __init__(self, width: int, height: int, range: int, default: int, key_left, key_right, app):
self.width = width
self.height = height
self.range = range
self.value = default
self.key_left = key_left
self.key_right = key_right
self.speed = 0.001
self.style = {
"background": kandinsky.color(0, 150, 100),
"handlebg": kandinsky.color(250, 100, 10),
"handlecolor": kandinsky.color(120, 110, 50),
"handlesize": 20,
}
super().__init__(app)
def get_value(self):
return self.value
def pdraw(self):
kandinsky.fill_rect(self.x + 3, self.y + 3, self.width, self.height, self.style["handlebg"])
kandinsky.fill_rect(self.x + 3 + int((self.width - self.style["handlesize"]) * (self.value / self.range)), self.y + 3, self.style["handlesize"], self.height, self.style["handlecolor"])
def draw(self):
kandinsky.fill_rect(self.x, self.y, self.width + 6, self.height + 6, self.style["background"])
self.pdraw()
def run_callbacks(self, old, new):
a = self.callbacks.get("changed")
if a:
return a(self, old, new)
def loop(self):
if ion.keydown(self.key_left):
if self.value - 1 >= 0:
self.value -= 1
self.pdraw()
self.run_callbacks(self.value + 1, self.value)
time.sleep(self.speed)
elif ion.keydown(self.key_right):
if self.value + 1 <= self.range:
self.value += 1
self.pdraw()
self.run_callbacks(self.value - 1,self.value)
time.sleep(self.speed)
import qteps2 as qt
import ion
class f(qt.App):
def __init__(self):
super().__init__()
self.InitGUI()
def InitGUI(self):
self.lbl=qt.LabelWidget(self)
self.lbl.set_text("Test")
self.lbl.move(10,10)
self.btn=qt.ButtonWidget("OK",ion.KEY_OK,self)
self.btn.move(10,110)
self.btn.connect("clicked", self.btnCallback)
#self.btn.connect(None)
self.dummy_list = ["test","dummy","stuff"]
self.l=qt.ListSelectorWidget(5,10,ion.KEY_UP,ion.KEY_DOWN,self)
self.l.move(10,40)
self.l.set_list(self.dummy_list)
self.l.connect("changed", self.lCallback)
def btnCallback(self, sender):
print("out =",self.dummy_list[self.l.get_selected()])
return True
def lCallback(self, sender, old, new):
print(self.dummy_list[old],"=>",self.dummy_list[new])
a=f()
a.main()
@AFCMS
Copy link
Author

AFCMS commented May 19, 2022

TODO:

  • UI
    • Default style types
    • Selected Button style
    • Colored text on button
  • Accessibility
    • Run button callback on key release
    • Make button press async (remove time.sleep and while True)
  • API
    • Allow Multiple apps to be shown in a row (allow removing the "Press OK to quit..." screen)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment