import { VerticalBox, HorizontalBox, ProgressIndicator, ScrollView } from "std-widgets.slint";
import { HomeTab } from "tabs/HomeTab.slint";
import { ProjectTab } from "tabs/ProjectTab.slint";
import { EntitiesTab } from "tabs/EntitiesTab.slint";
import { FeaturesTab } from "tabs/FeaturesTab.slint";
import { UserInterfaceTab } from "tabs/UserInterfaceTab.slint";
import { GenerateTab } from "tabs/GenerateTab.slint";
import { ConfirmationDialog } from "components/confirmation_dialog.slint";
import { NewManifestWizard } from "components/new_manifest_wizard.slint";
import { DemoWizard } from "components/demo_wizard.slint";
import { StyledButton } from "components/misc.slint";
import { CheckWidget } from "components/check_widget.slint";
// Import and export globals for Rust access
import { ManifestCommands, UndoRedoCommands, GenerateCommands, ProjectTabState, EntitiesTabState, FeaturesTabState, UserInterfaceTabState, AppState, CheckState, CommonTools, NewManifestWizardState, DemoWizardState } from "globals.slint";
export { ManifestCommands, UndoRedoCommands, GenerateCommands, ProjectTabState, EntitiesTabState, FeaturesTabState, UserInterfaceTabState, AppState, CheckState, CommonTools, NewManifestWizardState, DemoWizardState }
// Custom NavItem component for sidebar navigation
component NavItem inherits Rectangle {
in property <bool> active: false;
in property <string> label;
in property <image> icon;
in property <bool> enable: true;
callback clicked();
height: 48px;
background: active ? #228be6 : transparent;
border-radius: 8px;
HorizontalLayout {
padding: 12px;
spacing: 12px;
Image {
source: icon;
width: 24px;
height: 24px;
colorize: active ? #ffffff : enable? #495057 : #adb5bd;
}
Text {
text: label;
color: active ? #ffffff : enable? #495057 : #adb5bd;
font-size: 14px;
vertical-alignment: center;
}
}
TouchArea {
clicked => { root.clicked(); }
enabled: enable;
}
}
export component App inherits Window {
title: AppState.manifest_is_open ? (AppState.manifest_path == "" ? "Qleany - new manifest without path" : "Qleany - " + AppState.manifest_path) : "Qleany";
min-width: 1400px;
min-height: 800px;
// All state and callbacks are now in globals (AppState, ManifestCommands, etc.)
// See globals.slint for the complete list
Rectangle {
background: #f8f9fa;
VerticalLayout {
// Header Bar
Rectangle {
height: 60px;
background: #ffffff;
drop-shadow-blur: 4px;
drop-shadow-color: #00000020;
drop-shadow-offset-y: 2px;
HorizontalLayout {
padding: 16px;
spacing: 12px;
Text {
text: "Qleany";
font-size: 24px;
font-weight: 700;
vertical-alignment: center;
color: #212529;
}
// Undo button
StyledButton {
text: "↩";
enabled: AppState.manifest_is_open;
clicked => { UndoRedoCommands.undo(); }
visible: false;
}
// Redo button
StyledButton {
text: "↪";
enabled: AppState.manifest_is_open;
clicked => { UndoRedoCommands.redo(); }
visible: false;
}
// Save button
StyledButton {
text: "Save Manifest";
enabled: AppState.manifest_is_open && !AppState.manifest_is_saved && !AppState.is_loading;
clicked => {
if (AppState.manifest_path == "") {
ManifestCommands.save_manifest_as();
} else {
ManifestCommands.save_manifest();
}
}
primary: true;
}
// Spacer
Rectangle { horizontal-stretch: 1; }
}
}
// Main content area with sidebar
HorizontalLayout {
// Left Sidebar Navigation
Rectangle {
width: 140px;
background: #f8f9fa;
VerticalLayout {
padding: 4px;
spacing: 4px;
alignment: start;
NavItem {
label: "Home";
icon: @image-url("icons/home.svg");
active: AppState.current_tab == 0;
clicked => {
if (AppState.current_tab == 5) { GenerateCommands.cancel_fill_code(); }
AppState.current_tab = 0;
}
}
NavItem {
label: "Project";
icon: @image-url("icons/tag.svg");
active: AppState.current_tab == 1 && AppState.manifest_is_open;
enable: AppState.manifest_is_open;
clicked => {
if (AppState.current_tab == 5) { GenerateCommands.cancel_fill_code(); }
AppState.current_tab = 1;
}
}
NavItem {
label: "Entities";
icon: @image-url("icons/entities.svg");
active: AppState.current_tab == 2 && AppState.manifest_is_open;
enable: AppState.manifest_is_open;
clicked => {
if (AppState.current_tab == 5) { GenerateCommands.cancel_fill_code(); }
AppState.current_tab = 2;
}
}
NavItem {
label: "Features";
icon: @image-url("icons/features.svg");
active: AppState.current_tab == 3 && AppState.manifest_is_open;
enable: AppState.manifest_is_open;
clicked => {
if (AppState.current_tab == 5) { GenerateCommands.cancel_fill_code(); }
AppState.current_tab = 3;
}
}
NavItem {
label: "User Interface";
icon: @image-url("icons/user_interface.svg");
active: AppState.current_tab == 4 && AppState.manifest_is_open;
enable: AppState.manifest_is_open;
clicked => {
if (AppState.current_tab == 5) { GenerateCommands.cancel_fill_code(); }
AppState.current_tab = 4;
}
}
NavItem {
label: "Generate";
icon: @image-url("icons/factory.svg");
active: AppState.current_tab == 5 && AppState.manifest_is_open;
enable: AppState.manifest_is_open && CheckState.check-status != "critical";
clicked => {
AppState.current_tab = 5;
AppState.refresh_generate_tab();
}
}
// Spacer
Rectangle { vertical-stretch: 1; }
}
}
// Main Content Area
Rectangle {
background: #ffffff;
border-radius: 8px;
// Tab components now use globals directly for state and callbacks
if AppState.current_tab == 0 : HomeTab { }
if AppState.current_tab == 1 && AppState.manifest_is_open : ProjectTab { }
if AppState.current_tab == 2 && AppState.manifest_is_open : EntitiesTab { }
if AppState.current_tab == 3 && AppState.manifest_is_open : FeaturesTab { }
if AppState.current_tab == 4 && AppState.manifest_is_open : UserInterfaceTab { }
if AppState.current_tab == 5 && AppState.manifest_is_open && CheckState.check-status != "critical" : GenerateTab { }
}
}
// Status bar at the bottom
Rectangle {
height: AppState.error_message != "" || AppState.success_message_visible ? 32px : 0px;
background: AppState.error_message != "" ? #ffc9c9 : (AppState.success_message_visible ? #d3f9d8 : #ffffff);
animate height { duration: 200ms; }
HorizontalLayout {
padding-left: 16px;
padding-right: 16px;
alignment: start;
if AppState.error_message != "" : Text {
text: AppState.error_message;
color: #c92a2a;
font-size: 14px;
vertical-alignment: center;
}
if AppState.error_message == "" && AppState.success_message_visible : Text {
text: AppState.success_message;
color: #2b8a3e;
font-size: 14px;
vertical-alignment: center;
}
}
}
}
// Check widget overlay (FAB + side panel)
CheckWidget {
x: 0px;
y: 0px;
width: parent.width;
height: parent.height;
}
// Global loading overlay
if AppState.is_loading : Rectangle {
background: #00000040;
x: 0px;
y: 0px;
width: parent.width;
height: parent.height;
ProgressIndicator {
width: 48px;
height: 48px;
x: (parent.width - self.width) / 2;
y: (parent.height - self.height) / 2;
indeterminate: true;
}
}
// New manifest wizard dialog
if NewManifestWizardState.visible : NewManifestWizard {
width: parent.width;
height: parent.height;
cancelled => {
NewManifestWizardState.visible = false;
NewManifestWizardState.step = 0;
}
confirmed => {
NewManifestWizardState.visible = false;
NewManifestWizardState.step = 0;
ManifestCommands.create_wizard_confirmed();
}
}
// Demo wizard dialog
if DemoWizardState.visible : DemoWizard {
width: parent.width;
height: parent.height;
cancelled => {
DemoWizardState.visible = false;
DemoWizardState.step = 0;
DemoWizardState.completed = false;
DemoWizardState.error_message = "";
}
}
// Confirmation dialog for unsaved changes
if AppState.confirm_dialog_visible : ConfirmationDialog {
width: parent.width;
height: parent.height;
message: AppState.confirm_dialog_message;
accepted => {
// Execute the pending action based on confirm_dialog_pending_action value
if (AppState.confirm_dialog_pending_action == "new") {
ManifestCommands.new_manifest();
} else if (AppState.confirm_dialog_pending_action == "open") {
ManifestCommands.open_manifest();
} else if (AppState.confirm_dialog_pending_action == "close") {
ManifestCommands.close_manifest();
} else if (AppState.confirm_dialog_pending_action == "exit") {
AppState.force_exit = true;
ManifestCommands.exit_app();
} else if (AppState.confirm_dialog_pending_action == "open_qleany") {
ManifestCommands.open_qleany_manifest();
}
// Reset and close the dialog
AppState.confirm_dialog_pending_action = "none";
AppState.confirm_dialog_message = "";
AppState.confirm_dialog_visible = false;
}
rejected => {
// Just close the dialog without executing the action
AppState.confirm_dialog_pending_action = "none";
AppState.confirm_dialog_message = "";
AppState.confirm_dialog_visible = false;
}
}
}
}