Skip to content

Instantly share code, notes, and snippets.

@pyrustic
Last active March 21, 2022 20:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pyrustic/79c9ee0efde8c06b7d4685f3c58b7761 to your computer and use it in GitHub Desktop.
Save pyrustic/79c9ee0efde8c06b7d4685f3c58b7761 to your computer and use it in GitHub Desktop.
Gaspium Demo

Gaspium Demo

This is a demo for Gaspium.

Gaspium is a framework to build Python apps with the GASP metaphor.

To play with this demo, copy-paste the Python code below and then run it after installing Gaspium.

To install Gaspium:

$ pip install gaspium

Description

In short, the app contains four pages: home, login, config, and about. The home page cannot open until you submit a random username and password on the login page. In fact, when the home page is about to be opened, the on_open callback is called. Inside this callback, a conditional redirection is performed: the login page is opened instead of the home depending on whether you are authenticated or not.

Screenshots

These are two screenshots of the demo running on Ubuntu

Demo

The login form


Demo

The home page

The source code

Run the source code below to get an app with four pages, a decent login form, a nice colorful pattern, and the ability to launch each page directly from the command line.


Back to top

import tkinter as tk
import subrun
from tkinter.scrolledtext import ScrolledText
from gaspium import App
from megawidget import Toast
from cyberpunk_theme.widget.button import get_button_red_style
# ====== PAGES =======
def home_page(context):
"""
Define the home page
"""
body = tk.Frame(context.root)
# rowconfigure and columnconfigure
for i in range(3):
body.rowconfigure(i, weight=1)
body.columnconfigure(i, weight=1)
# rows
rows = [("#CCCC00", "#CCCC00", "#BD0000"),
("#B200B2", "#121C20", "#BD0000"),
("#B200B2", "#0000B3", "#0000B3")]
# Here we loop over rows of colors to create a beautiful grid
for row, colors in enumerate(rows):
for col, color in enumerate(colors):
tk.Frame(body, bg=color).grid(column=col, row=row,
sticky="nswe")
return body
def login_page(context):
"""
Define the login page
"""
body = tk.Frame(context.root)
# stringvars
username_strvar = tk.StringVar()
password_strvar = tk.StringVar()
# Login Frame
title_frame = get_title_frame(body)
title_frame.pack(fill=tk.X, padx=5, pady=5)
# Form Frame
form_frame = get_form_frame(body, username_strvar, password_strvar)
form_frame.pack(fill=tk.X, padx=5, pady=5)
# Buttons frame
buttons_frame = get_buttons_frame(context.app, body, username_strvar, password_strvar)
buttons_frame.pack(fill=tk.X, padx=5, pady=5)
return body
def config_page(context):
"""
Define the config page
"""
body = tk.Frame(context.root)
# Label
font = ("Liberation Mono", 15, "bold")
label = tk.Label(body, text="Config", fg="#C6C6AD", font=font)
label.pack(side=tk.LEFT, anchor="n", padx=5, pady=5)
return body
def about_page(context):
"""
Define the about page
"""
body = tk.Frame(context.root)
# Capture the output of the Zen of Python with Subrun
info = subrun.capture("python -m this")
text = info.output.decode("utf-8")
# Install the textwidget
textwidget = ScrolledText(body, wrap="word")
textwidget.pack(expand=1, fill=tk.BOTH)
# Populate the textwidget witht the Zen of Python
textwidget.insert("1.0", text)
# Readonly mode
textwidget.config(state=tk.DISABLED)
return body
# ====== CALLBACKS =======
def on_open_home(context):
"""
This callback is called when the home_page is opened
"""
app = context.app
# redirection: open the login_page if the user is not yet authenticated
username = app.data.get("username")
if not username:
app.open("login")
def clear_form(username_strvar, password_strvar):
"""
This callback is called when the user clicks the 'Clear' button on the login_page
"""
username_strvar.set("")
password_strvar.set("")
def login(app, username, password):
"""
This callback is called when the user clicks the 'Submit' button on the login_page.
"""
accepted = False
if not username or not password:
msg = "Please fill the form !"
else:
accepted = True
msg = "Welcome {} !".format(username)
# Pop-up a message to the user with the method 'toast'.
toast = Toast(app.root, message=msg)
toast.wait_window() # block the flow of execution
if accepted:
# store the username in the 'data' dictionary provided by 'app'.
app.data["username"] = username
# Open the home_page by providing its pid (page id) to the method 'open'.
app.open("home")
# ====== LAYOUTS FOR LOGIN PAGE ======
def get_title_frame(parent):
body = tk.Frame(parent)
# Label
font = ("Liberation Mono", 15, "bold")
label = tk.Label(body, text="Login", fg="#C6C6AD", font=font)
label.pack(side=tk.LEFT)
return body
def get_form_frame(parent, username_strvar, password_strvar):
body = tk.Frame(parent)
# rowconfigure and columnconfigure
for i in range(3):
body.rowconfigure(i, pad=5)
body.columnconfigure(i, pad=5)
# == Username Label and Entry
# username_label
username_label = tk.Label(body, text="Username")
username_label.grid(row=0, column=0, sticky="w")
# username_entry
username_entry = tk.Entry(body, textvariable=username_strvar)
username_entry.grid(row=1, column=0, sticky="w")
# == Password Label and Entry
# password_label
password_label = tk.Label(body, text="Password")
password_label.grid(row=0, column=1, sticky="w")
# password_entry
password_entry = tk.Entry(body, show="*", textvariable=password_strvar)
password_entry.grid(row=1, column=1, sticky="w")
return body
def get_buttons_frame(app, parent, username_strvar, password_strvar):
body = tk.Frame(parent)
# clear button
command = (lambda username_strvar=username_strvar,
password_strvar=password_strvar:
clear_form(username_strvar, password_strvar))
clear_button = tk.Button(body, text="Clear", command=command)
clear_button.pack(side=tk.LEFT)
# apply red style to Clear Button
button_red_style = get_button_red_style()
button_red_style.apply(clear_button)
# submit button
command = (lambda app=app, username_strvar=username_strvar,
password_strvar=password_strvar:
login(app, username_strvar.get(), password_strvar.get()))
submit_button = tk.Button(body, text="Submit", command=command)
submit_button.pack(side=tk.LEFT, padx=5)
return body
# ====== APPLICATION =======
def main():
# the app
app = App(title="Demo", geometry="500x400", caching=True)
# add home_page (the first added page is de facto the home page)
app.add(home_page, title="Home", on_open=on_open_home)
# add login_page (this page won't be referenced in the menu bar)
app.add(login_page, pid="login", title="Login", indexable=False)
# add config_page (referenced in the menu bar under the 'Help' dropdown menu)
app.add(config_page, pid="config", title="Config", category="Help")
# add about_page (referenced in the menu bar under the 'Help' dropdown menu)
app.add(about_page, pid="about", title="About", category="Help")
# start the app
app.start()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment