feat: redesign installer on MTK toolkit with component selection
Rewrite the Installer app on the Montauk Toolkit (Canvas + gui/mtk widgets, theme, hover states, scrollbar) replacing the hand-rolled px_* renderer and bespoke TrueType usage. Add a new "Software" step: an expandable checkbox tree for optional components (Montauk SDK with gcc/g++, binutils, tcc, lua sub-items; Games; Office; Internet apps; Printing; experimental httpd and SDR). Unchecked components' paths are excluded from the install copy, with a longest-path ownership rule so e.g. sdk/tcc installs even when the rest of the SDK is deselected. The update flow refreshes only the components the target already has. Add tri-state checkbox and disclosure-arrow widgets to the MTK toolkit (anti-aliased, supersampled). Merge tcc and lua into 0:/sdk (0:/sdk/tcc, 0:/sdk/lua) and drop 0:/lib: update tcc config.h, lua luaconf.h, both Makefiles, the devkit clean scope, man pages and montaukos.org notices. Make printing optional: init skips printd when 0:/os/printd.elf is absent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,8 @@
|
||||
#include <montauk/string.h>
|
||||
#include <montauk/heap.h>
|
||||
#include <gui/gui.hpp>
|
||||
#include <gui/truetype.hpp>
|
||||
#include <gui/font.hpp>
|
||||
#include <gui/mtk.hpp>
|
||||
|
||||
extern "C" {
|
||||
#include <string.h>
|
||||
@@ -23,34 +24,20 @@ using namespace gui;
|
||||
// Constants
|
||||
// ============================================================================
|
||||
|
||||
static constexpr int INIT_W = 520;
|
||||
static constexpr int INIT_H = 440;
|
||||
static constexpr int TOOLBAR_H = 36;
|
||||
static constexpr int STEP_BAR_H = 32;
|
||||
static constexpr int CONTENT_TOP = TOOLBAR_H + STEP_BAR_H;
|
||||
static constexpr int INIT_W = 560;
|
||||
static constexpr int INIT_H = 500;
|
||||
static constexpr int HEADER_H = 44;
|
||||
static constexpr int STEP_BAR_H = 30;
|
||||
static constexpr int CONTENT_TOP = HEADER_H + STEP_BAR_H;
|
||||
static constexpr int BOTTOM_H = 48;
|
||||
static constexpr int PAD = 16;
|
||||
static constexpr int BTN_H = 30;
|
||||
static constexpr int MAX_DISKS = 32;
|
||||
static constexpr int MAX_PARTS = 32;
|
||||
static constexpr int STATUS_H = 26;
|
||||
|
||||
// Font sizes — adjusted at runtime by apply_scale()
|
||||
extern int FONT_SIZE;
|
||||
extern int FONT_SM;
|
||||
|
||||
static constexpr int TB_BTN_Y = 5;
|
||||
static constexpr int TB_BTN_H = 26;
|
||||
static constexpr int TB_BTN_RAD = 8;
|
||||
|
||||
static constexpr Color BG_COLOR = Color::from_rgb(0xFF, 0xFF, 0xFF);
|
||||
static constexpr Color TOOLBAR_BG = Color::from_rgb(0xF5, 0xF5, 0xF5);
|
||||
static constexpr Color BORDER_COLOR = Color::from_rgb(0xCC, 0xCC, 0xCC);
|
||||
static constexpr Color TEXT_COLOR = Color::from_rgb(0x22, 0x22, 0x22);
|
||||
static constexpr Color DIM_TEXT = Color::from_rgb(0x66, 0x66, 0x66);
|
||||
static constexpr Color FAINT_TEXT = Color::from_rgb(0x88, 0x88, 0x88);
|
||||
static constexpr Color WHITE = Color::from_rgb(0xFF, 0xFF, 0xFF);
|
||||
static constexpr Color ACCENT = Color::from_rgb(0x33, 0x66, 0xCC);
|
||||
static constexpr Color DANGER = Color::from_rgb(0xCC, 0x33, 0x33);
|
||||
static constexpr Color SUCCESS_COLOR = Color::from_rgb(0x33, 0x99, 0x33);
|
||||
static constexpr Color DISABLED_BG = Color::from_rgb(0xBB, 0xBB, 0xBB);
|
||||
static constexpr int COMP_ROW_H = 28;
|
||||
static constexpr int COMP_INDENT = 26;
|
||||
static constexpr int COMP_TOGGLE_W = 18;
|
||||
|
||||
// ============================================================================
|
||||
// Install steps
|
||||
@@ -65,6 +52,7 @@ enum InstallStep {
|
||||
STEP_MODE_SELECT,
|
||||
STEP_SELECT_DISK,
|
||||
STEP_PARTITION_SCHEME,
|
||||
STEP_COMPONENTS,
|
||||
STEP_CONFIRM,
|
||||
STEP_INSTALLING,
|
||||
STEP_DONE,
|
||||
@@ -95,6 +83,55 @@ static const char* scheme_descs[] = {
|
||||
"One partition for boot, OS, and data. Simple and compatible.",
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Optional components
|
||||
// ============================================================================
|
||||
|
||||
static constexpr int MAX_COMPONENT_PATHS = 16;
|
||||
|
||||
struct Component {
|
||||
const char* id;
|
||||
const char* label;
|
||||
const char* desc; // shown in the status bar on hover
|
||||
int parent; // index of parent component, or -1 for top level
|
||||
// Path that identifies this component in an image / on a target drive.
|
||||
const char* probe;
|
||||
// Files or directories (relative to the drive root, no "0:/" prefix)
|
||||
// owned by this component; nullptr-terminated. Empty for pure groups.
|
||||
const char* paths[MAX_COMPONENT_PATHS];
|
||||
// A child that needs its parent's base payload (e.g. gcc needs the
|
||||
// SDK sysroot). Checking it re-checks the parent.
|
||||
bool requires_parent;
|
||||
// Another component this one cannot work without (e.g. gcc drives the
|
||||
// binutils assembler/linker), or -1.
|
||||
int depends_on;
|
||||
|
||||
// Runtime state
|
||||
bool checked;
|
||||
bool expanded; // parents only
|
||||
bool present; // this component (or a child) exists in the image
|
||||
bool base_present; // own probe exists (parents with own payload)
|
||||
uint64_t bytes; // exclusive payload size in the source image
|
||||
};
|
||||
|
||||
extern Component g_components[];
|
||||
extern const int g_component_count;
|
||||
|
||||
// components.cpp
|
||||
void components_init();
|
||||
void components_compute_sizes();
|
||||
bool component_has_children(int idx);
|
||||
mtk::CheckState component_state(int idx);
|
||||
void component_toggle(int idx);
|
||||
int component_visible_rows(int* out, int max);
|
||||
bool component_allows(const char* rel);
|
||||
bool component_subtree_needed(const char* rel);
|
||||
void components_set_from_target(int drive);
|
||||
uint64_t components_selected_bytes();
|
||||
uint64_t components_unselected_bytes();
|
||||
void components_excluded_summary(char* buf, int bufsize);
|
||||
bool components_sizes_ready();
|
||||
|
||||
// ============================================================================
|
||||
// State
|
||||
// ============================================================================
|
||||
@@ -120,8 +157,12 @@ struct InstallerState {
|
||||
char log[LOG_LINES][LOG_LINE_LEN];
|
||||
int log_count;
|
||||
|
||||
char status[80];
|
||||
char status[96];
|
||||
uint64_t status_time;
|
||||
|
||||
int mouse_x;
|
||||
int mouse_y;
|
||||
int comp_scroll;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
@@ -130,10 +171,68 @@ struct InstallerState {
|
||||
|
||||
extern int g_win_w, g_win_h;
|
||||
extern InstallerState g_state;
|
||||
extern TrueTypeFont* g_font;
|
||||
extern uint32_t* g_pixels;
|
||||
extern uint32_t* g_backbuf;
|
||||
extern int g_win_id;
|
||||
extern Color g_accent;
|
||||
|
||||
// ============================================================================
|
||||
// Shared layout helpers
|
||||
// ============================================================================
|
||||
|
||||
inline int content_x() { return PAD; }
|
||||
inline int content_w() { return g_win_w - PAD * 2; }
|
||||
inline int content_bottom() { return g_win_h - BOTTOM_H; }
|
||||
|
||||
// Heading block: title line + smaller subtitle line
|
||||
inline int heading_bottom() {
|
||||
return CONTENT_TOP + 14 + system_font_height() * 2 + 16;
|
||||
}
|
||||
|
||||
inline Rect bottom_bar_rect() {
|
||||
return {0, g_win_h - BOTTOM_H, g_win_w, BOTTOM_H};
|
||||
}
|
||||
|
||||
inline Rect primary_btn_rect() {
|
||||
int y = g_win_h - BOTTOM_H + (BOTTOM_H - BTN_H) / 2;
|
||||
return {g_win_w - PAD - 108, y, 108, BTN_H};
|
||||
}
|
||||
|
||||
inline Rect secondary_btn_rect() {
|
||||
Rect p = primary_btn_rect();
|
||||
return {p.x - 8 - 96, p.y, 96, BTN_H};
|
||||
}
|
||||
|
||||
inline Rect tertiary_btn_rect() {
|
||||
Rect s = secondary_btn_rect();
|
||||
return {s.x - 8 - 84, s.y, 84, BTN_H};
|
||||
}
|
||||
|
||||
// Mode select cards
|
||||
inline Rect mode_card_rect(int index) {
|
||||
int card_h = 56;
|
||||
int y = heading_bottom() + index * (card_h + 10);
|
||||
return {content_x(), y, content_w(), card_h};
|
||||
}
|
||||
|
||||
// Disk / partition / scheme list rows
|
||||
inline Rect list_row_rect(int index, int row_h) {
|
||||
int y = heading_bottom() + index * (row_h + 6);
|
||||
return {content_x(), y, content_w(), row_h};
|
||||
}
|
||||
|
||||
static constexpr int DISK_ROW_H = 48;
|
||||
static constexpr int SCHEME_ROW_H = 50;
|
||||
static constexpr int PART_ROW_H = 48;
|
||||
|
||||
// Component tree viewport
|
||||
inline Rect components_list_rect() {
|
||||
int top = heading_bottom();
|
||||
return {content_x(), top, content_w(), content_bottom() - top - 8};
|
||||
}
|
||||
|
||||
inline Rect component_row_rect(int visible_index) {
|
||||
Rect list = components_list_rect();
|
||||
return {list.x, list.y + visible_index * COMP_ROW_H - g_state.comp_scroll,
|
||||
list.w, COMP_ROW_H};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Function declarations — helpers (main.cpp)
|
||||
@@ -143,7 +242,7 @@ void set_status(const char* msg);
|
||||
void add_log(const char* msg);
|
||||
void flush_ui();
|
||||
void format_disk_size(char* buf, int bufsize, uint64_t sectors, uint16_t sectorSize);
|
||||
void apply_scale(int scale);
|
||||
void format_bytes(char* buf, int bufsize, uint64_t bytes);
|
||||
|
||||
// ============================================================================
|
||||
// Function declarations — render.cpp
|
||||
@@ -159,3 +258,21 @@ void installer_refresh_disks();
|
||||
void installer_refresh_parts();
|
||||
void do_install();
|
||||
void do_update();
|
||||
bool installer_path_exists(const char* abs_path);
|
||||
|
||||
// Heap-backed directory listing. Entries are full paths relative to the
|
||||
// drive root (e.g. "apps/doom"), with is_dir derived from the trailing '/'
|
||||
// the VFS appends to directory names. Survives nested listings, unlike the
|
||||
// kernel's rotating readdir scratch pages.
|
||||
struct DirEntry {
|
||||
char* rel; // path relative to drive root, no trailing '/'
|
||||
bool is_dir;
|
||||
};
|
||||
|
||||
struct DirList {
|
||||
DirEntry* entries;
|
||||
int count;
|
||||
};
|
||||
|
||||
bool installer_list_dir(const char* abs_dir, DirList* out);
|
||||
void installer_free_dir_list(DirList* list);
|
||||
|
||||
Reference in New Issue
Block a user