Dynamic Forms System
Overview
SaleFlex.PyPOS uses a database-driven dynamic form system instead of TOML files. This change makes forms more flexible and manageable. All form definitions are stored in the database, allowing for dynamic form creation and modification without code changes.
Key Changes
Database Model Updates
Form Model
New fields added to the Form model:
fore_color: Form foreground coloris_startup: Boolean flag to determine the initial form to opendisplay_mode: Which screen to display on ("MAIN", "CUSTOMER", "BOTH")
FormControl Model
New fields added to the FormControl model:
fk_target_form_id: UUID ForeignKey to the target form when button is clickedform_transition_mode: Transition mode ("MODAL" or "REPLACE")
New Classes
DynamicFormRenderer
File: user_interface/render/dynamic_renderer.py
Reads form and control definitions from the database and converts them to the appropriate format for BaseWindow.
# Usage
renderer = DynamicFormRenderer(form_id=form_id)
# or
renderer = DynamicFormRenderer(form_name='LOGIN')
# Get settings
settings = renderer.settings
toolbar_settings = renderer.toolbar_settings
design = renderer.design
Features:
- Loads form and control data from database
- Returns data in the same format as TOML interpreter
- Color parsing (hex string -> integer)
- Startup form selection
DynamicDialog
File: user_interface/window/dynamic_dialog.py
QDialog-based modal form window. Displays forms loaded from the database as modal dialogs.
# Usage (usually through Interface)
result = interface.show_modal(form_id=target_form_id)
# or
result = interface.show_modal(form_name='CUSTOMER_FORM')
Features:
- Modal (temporary) form display
- Works without closing the main window
- Supports all standard controls (button, textbox, combobox, etc.)
- Automatic cleanup
Updated Classes
Interface
Now uses database-based form rendering:
# Old usage (DEPRECATED)
interface.draw(FormName.LOGIN)
interface.redraw(FormName.SALE)
# New usage
interface.draw(form_id=form_uuid)
interface.draw(form_name='LOGIN')
interface.redraw(form_name='SALE')
interface.show_modal(form_name='CUSTOMER_FORM') # New!
CurrentStatus
Startup form support added:
# New features
current_form_id # Current form's UUID
startup_form_id # Startup form's UUID
load_startup_form() # Loads startup form from database
Application
Loads startup form from database at startup:
# During init
self.load_startup_form() # Loads from database
# During run
if self.current_form_id:
self.interface.draw(form_id=self.current_form_id)
else:
self.interface.draw(form_name='LOGIN') # Fallback
Form Transition System
Button-Based Form Transition
For a button in the FormControl table:
# Database example
button = FormControl(
name="BTN_CUSTOMER",
type="button",
caption1="Müşteri",
fk_target_form_id="<customer_form_uuid>",
form_transition_mode="MODAL", # or "REPLACE"
...
)
Transition Modes:
MODAL: Form opens as a modal dialog (temporary, on top)REPLACE: Current form closes, new form opens (saves RAM)
Programmatic Form Transition
# From event handler
self._navigate_to_form(
target_form_id="<uuid>",
transition_mode="MODAL" # or "REPLACE"
)
# Or through Interface
self.interface.show_modal(form_id="<uuid>")
self.interface.redraw(form_id="<uuid>")
Startup Form System
Setting in Database
# Mark a form as startup form
login_form = Form.get_by_name("LOGIN")
login_form.is_startup = True
login_form.save()
- Multiple forms can have
is_startup=True(accidentally) - System sorts by ID and uses the first one
- If no startup form exists, searches for form with
name='LOGIN' - If that doesn't exist, returns None as fallback
Startup Form Priority Order
- Forms with
is_startup=True(first by ID) - Form with
name='LOGIN' - None (error condition)
Examples
Example 1: Creating a Customer Form
from data_layer.model import Form, FormControl
# 1. Create form
customer_form = Form(
name="CUSTOMER_FORM",
form_no=10,
caption="Müşteri Tanımı",
width=800,
height=600,
back_color="0xFFFFFF",
fore_color="0x000000",
need_login=True,
is_startup=False,
display_mode="MAIN"
)
customer_form.save()
# 2. Add controls
# Name textbox
name_textbox = FormControl(
name="TXT_CUSTOMER_NAME",
fk_form_id=customer_form.id,
type="textbox",
caption1="Ad",
width=300,
height=40,
location_x=50,
location_y=100,
back_color="0xFFFFFF",
fore_color="0x000000"
)
name_textbox.save()
Example 2: Transition from Main Form to Customer Form
# Create a button in main form
customer_button = FormControl(
name="BTN_OPEN_CUSTOMER",
fk_form_id=main_form.id,
type="button",
caption1="Müşteri",
width=150,
height=50,
location_x=10,
location_y=10,
back_color="0x0066CC",
fore_color="0xFFFFFF",
fk_target_form_id=customer_form.id,
form_transition_mode="MODAL" # Open as modal
)
customer_button.save()
Known Issues and Solutions
Issue 1: Form Not Found
Symptom: "Form not found" error
Solution:
# Check if form exists
forms = Form.filter_by(name='LOGIN', is_deleted=False)
if not forms:
print("Form not found, creating...")
# Create form
Issue 2: Colors Not Displaying Correctly
Symptom: Colors appear black or white
Solution:
# Color format: "0xRRGGBB" must be a string
form.back_color = "0x3268A8" # Correct
# form.back_color = 0x3268A8 # Wrong (integer)
# form.back_color = "#3268A8" # Works but not recommended
Issue 3: Modal Form Not Opening
Symptom: Modal form not displaying
Solution:
# Ensure transition_mode is written correctly
control.form_transition_mode = "MODAL" # Correct (uppercase)
# control.form_transition_mode = "modal" # Works (code does upper())
Deprecated Files
Interpreter.py
The file is preserved but shows a deprecation warning.
settings.toml
The [design_files] section has been removed. Form definitions are now in the database.