Architecture

The EPL GUI system provides cross-platform native components for Windows, Linux, and macOS with:

  • TUIMatrix - Main layout manager with JSON-based responsive schemes
  • BaseWidget hierarchy - Consistent widget base with events
  • TWinSignal - Thread-safe event queue for GUI updates
  • TProtocol - Encrypted client-server communication for thin clients

Widget Hierarchy

BaseControl (V_* native)
    │
BaseWidget
    ├── Position (x, y, width, height)
    ├── Event handlers (OnChange, OnClick)
    ├── Theme support
    │
    ├── TForm (window container)
    ├── TWButton (button)
    ├── TWEditBox (text input)
    ├── TWLabel (text display)
    ├── TWCheckBox (checkbox)
    ├── TWComboBox (dropdown)
    ├── TWListView (list/table)
    ├── TWTreeView (tree)
    ├── TWTab (tabbed container)
    ├── TWImage (image display)
    ├── TWScrollBar (scrollbar)
    └── ... more widgets

TUIMatrix Layout Manager

TUIMatrix manages widget layout with JSON-based responsive schemes for different screen sizes.

Layout Methods

// Load layout scheme from JSON
Matrix->LoadScheme("layout.json");

// Apply scheme for current screen size
Matrix->ApplyScheme();

// Dynamic positioning expressions
Widget->SetPosition("after:OtherWidget", "below:Header");
Widget->SetSize("form_width:20", "100");

Position Expressions

ExpressionMeaning
after:WidgetPosition after another widget
below:WidgetPosition below another widget
form_right:2020px from form right edge
form_bottom:2020px from form bottom
centerCenter in parent

Application Structure

// Font definitions
string MainFontName = "Roboto.etf";
string BkpFontName = "DejaVu.etf";
include_file "$Studio/ElastLib/main_inc.epl";

// Main application class
class TMatrix : public TUIMatrix {
    TWTitle     TitleBar;
    TForm       MainForm;
    TWButton    MyButton;
    TWEditBox   NameField;
}

TMatrix @Matrix;

// Called when GUI is ready
virtual void TMatrix::OnGUIReady() {
    // Setup event handlers
    MyButton->ProcObj = this_obj;
    MyButton->OnChange = "OnButtonClick";

    // Initialize widgets
    NameField->Text = "Default";
}

// Event handler
void TMatrix::OnButtonClick() {
    string name = NameField->Text;
    print "Button clicked! Name: " . name . "\n";
}

Widget Catalog

Containers

WidgetDescription
TFormWindow/form container
TWTabTabbed container
TWPanelGeneric panel
TWScrollViewScrollable area

Input Controls

WidgetDescription
TWButtonPush button
TWEditBoxSingle-line text input
TWTextAreaMulti-line text input
TWCheckBoxCheckbox
TWRadioButtonRadio button
TWComboBoxDropdown select
TWSliderSlider control

Display Widgets

WidgetDescription
TWLabelText label
TWImageImage display
TWProgressBarProgress indicator
TWChartChart/graph

Data Views

WidgetDescription
TWListViewList/table view
TWTreeViewTree view
TWGridData grid

Event Handling

// Setup event handler
MyButton->ProcObj = this_obj;      // Object to call method on
MyButton->OnChange = "OnClick";     // Method name to call

// Event handler method
void TMatrix::OnClick() {
    // Handle button click
}

// Alternative: Convention-based naming
void TMatrix::MyButton_OnClick() {
    // Auto-wired if naming convention matches
}

Common Events

EventTriggered When
OnChangeValue changes (buttons, checkboxes)
OnClickWidget clicked
OnDoubleClickWidget double-clicked
OnFocusWidget gains focus
OnBlurWidget loses focus
OnKeyPressKey pressed
OnSelectItem selected (lists, trees)

JSON GUI Definitions

GUI layouts can be defined declaratively in JSON with responsive schemes:

{
  "schemes": {
    "phone": { "minWidth": 0, "maxWidth": 480 },
    "tablet": { "minWidth": 481, "maxWidth": 1024 },
    "desktop": { "minWidth": 1025 }
  },
  "widgets": {
    "MainForm": {
      "type": "TForm",
      "title": "My Application",
      "width": 800,
      "height": 600
    },
    "NameLabel": {
      "type": "TWLabel",
      "text": "Name:",
      "parent": "MainForm",
      "x": 20,
      "y": 20
    },
    "NameField": {
      "type": "TWEditBox",
      "parent": "MainForm",
      "x": "after:NameLabel:10",
      "y": 20,
      "width": 200
    },
    "SubmitBtn": {
      "type": "TWButton",
      "text": "Submit",
      "parent": "MainForm",
      "x": "form_right:20",
      "y": "form_bottom:20"
    }
  }
}

Client-Server GUI Architecture

EPL supports thin client applications where GUI runs locally but logic executes on a server.

Architecture

┌─────────────────┐         ┌─────────────────┐
│   GUI Client    │◄───────►│    App Server   │
│                 │ TProtocol│                 │
│  - Renders GUI  │ (RSA+AES)│  - Business     │
│  - User input   │         │    logic        │
│  - TWinSignal   │         │  - Database     │
│    event queue  │         │  - Processing   │
└─────────────────┘         └─────────────────┘

Client Implementation

class TMyClient : public TUIMatrix {
    TProtocol   Protocol;
    int         hApp;
}

virtual void TMyClient::OnGUIReady() {
    // Initialize protocol
    Protocol = new TProtocol;
    Protocol->AddPubKey("/path/to/server_public.key");

    // Register application callback
    Protocol->RegisterApp("MyApp-GUID", hApp, this_obj, "OnServerResponse");

    // Connect to server
    Protocol->Connect("192.168.1.100:3360");
    Protocol->RunClient(hApp);
}

// Handle server responses
void TMyClient::OnServerResponse(int ptr CtrlCode, variant ptr Data) {
    if(CtrlCode == 1){
        // Update GUI with server data
        UpdateList(Data);
    }
}

TProtocol Reference

Binary protocol framework with RSA + AES256 encryption.

Initialization

TProtocol Protocol;
Protocol = new TProtocol;

// Load encryption keys
Protocol->AddPubKey("/path/to/public.key");
Protocol->AddPrvKey("/path/to/private.key");

// Register app with callback
int hApp;
Protocol->RegisterApp("MyApp-GUID", hApp, this_obj, "OnData");

// Connect
Protocol->Connect("192.168.1.100:9000");

Sending Requests

// Create request
TProtocol::TReq Req;
Req = new TProtocol::TReq;

// Start request with control code
Protocol->StartAppRequest(hApp, ctrlCode, Req);

// Add data
Protocol->AddVariant(Req, myData);
Protocol->AddString(Req, "text");
Protocol->AddInt(Req, 123);

// Send
Protocol->Send(Req);

Receiving Data

// Callback signature
void TMyClass::OnData(int ptr CtrlCode, variant ptr Data) {
    // CtrlCode identifies message type
    // Data contains server response

    if(CtrlCode == 1){
        // Process response
        string result = Data["result"];
    }
}

Stream Types (AppItem)

TypeValueDescription
Video1Video stream
Audio2Audio stream
App3Application data
Initial5Initial connection

Thread-Safe GUI Updates

GUI updates from background threads must use TWinSignal to queue events:

// From background thread, queue GUI update
TWinSignal Signal;
Signal = new TWinSignal;
Signal->TargetObj = Widget;           // Target widget
Signal->SignalType = SIG_UPDATE;      // Signal type
Signal->Data = newData;               // Data to pass
PostSignal(Signal);                   // Queue for main thread

// Main thread processes signals automatically

Signal Types

SignalDescription
SIG_UPDATEUpdate widget content
SIG_REFRESHRefresh/redraw widget
SIG_CALLBACKCall method on main thread
SIG_CLOSEClose widget/form

Safe Pattern

// Network callback (runs on network thread)
void TMyClient::OnServerResponse(int ptr CtrlCode, variant ptr Data) {
    // DON'T update GUI directly here!

    // Queue update for main thread
    TWinSignal Signal;
    Signal = new TWinSignal;
    Signal->TargetObj = this_obj;
    Signal->SignalType = SIG_CALLBACK;
    Signal->CallbackMethod = "UpdateGUI";
    Signal->Data = Data;
    PostSignal(Signal);
}

// Runs on main thread (safe to update GUI)
void TMyClient::UpdateGUI(variant ptr Data) {
    MyListView->Clear();
    foreach(Data["items"]; int i; variant item){
        MyListView->AddItem(item["name"]);
    }
}