feat: MontaukOS installer app, toml config, app directory with manifests, and more
This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* main.cpp
|
||||
* MontaukOS Installer — entry point, event loop, state
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include "installer.h"
|
||||
|
||||
// ============================================================================
|
||||
// Global state definitions
|
||||
// ============================================================================
|
||||
|
||||
int g_win_w = INIT_W;
|
||||
int g_win_h = INIT_H;
|
||||
|
||||
int FONT_SIZE = 18;
|
||||
int FONT_SM = 14;
|
||||
|
||||
InstallerState g_state;
|
||||
TrueTypeFont* g_font = nullptr;
|
||||
uint32_t* g_pixels = nullptr;
|
||||
int g_win_id = -1;
|
||||
|
||||
void apply_scale(int scale) {
|
||||
switch (scale) {
|
||||
case 0: FONT_SIZE = 14; FONT_SM = 11; break;
|
||||
case 2: FONT_SIZE = 22; FONT_SM = 17; break;
|
||||
default: FONT_SIZE = 18; FONT_SM = 14; break;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Helpers
|
||||
// ============================================================================
|
||||
|
||||
void set_status(const char* msg) {
|
||||
int i = 0;
|
||||
for (; i < 79 && msg[i]; i++) g_state.status[i] = msg[i];
|
||||
g_state.status[i] = '\0';
|
||||
g_state.status_time = montauk::get_milliseconds();
|
||||
}
|
||||
|
||||
void add_log(const char* msg) {
|
||||
if (g_state.log_count >= LOG_LINES) {
|
||||
// Scroll: shift all lines up by one
|
||||
for (int j = 0; j < LOG_LINES - 1; j++)
|
||||
montauk::memcpy(g_state.log[j], g_state.log[j + 1], LOG_LINE_LEN);
|
||||
g_state.log_count = LOG_LINES - 1;
|
||||
}
|
||||
int i = 0;
|
||||
for (; i < LOG_LINE_LEN - 1 && msg[i]; i++)
|
||||
g_state.log[g_state.log_count][i] = msg[i];
|
||||
g_state.log[g_state.log_count][i] = '\0';
|
||||
g_state.log_count++;
|
||||
}
|
||||
|
||||
void flush_ui() {
|
||||
if (g_pixels && g_win_id >= 0) {
|
||||
render(g_pixels);
|
||||
montauk::win_present(g_win_id);
|
||||
}
|
||||
}
|
||||
|
||||
void format_disk_size(char* buf, int bufsize, uint64_t sectors, uint16_t sectorSize) {
|
||||
uint64_t bytes = sectors * sectorSize;
|
||||
uint64_t gb = bytes / (1024ULL * 1024 * 1024);
|
||||
if (gb >= 1024) {
|
||||
uint64_t tb = gb / 1024;
|
||||
uint64_t frac = ((gb % 1024) * 10) / 1024;
|
||||
snprintf(buf, bufsize, "%lu.%lu TB", (unsigned)tb, (unsigned)frac);
|
||||
} else if (gb > 0) {
|
||||
uint64_t frac = ((bytes % (1024ULL * 1024 * 1024)) * 10) / (1024ULL * 1024 * 1024);
|
||||
snprintf(buf, bufsize, "%lu.%lu GB", (unsigned)gb, (unsigned)frac);
|
||||
} else {
|
||||
uint64_t mb = bytes / (1024ULL * 1024);
|
||||
snprintf(buf, bufsize, "%lu MB", (unsigned)mb);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Mouse handling
|
||||
// ============================================================================
|
||||
|
||||
static bool handle_click(int mx, int my) {
|
||||
auto& st = g_state;
|
||||
int fh = g_font ? g_font->get_cache(FONT_SIZE)->ascent - g_font->get_cache(FONT_SIZE)->descent : 16;
|
||||
|
||||
// Common bottom button area
|
||||
int btn_w = 120, btn_h = 34;
|
||||
int btn_y = g_win_h - STATUS_H - btn_h - 12;
|
||||
|
||||
if (st.step == STEP_SELECT_DISK) {
|
||||
// Disk list items
|
||||
int y = CONTENT_TOP + 40 + fh + 12;
|
||||
for (int i = 0; i < st.disk_count; i++) {
|
||||
int item_h = 48;
|
||||
if (mx >= 16 && mx < g_win_w - 16 && my >= y && my < y + item_h) {
|
||||
st.selected_disk = i;
|
||||
return true;
|
||||
}
|
||||
y += item_h + 4;
|
||||
}
|
||||
|
||||
// "Next" button
|
||||
int next_x = g_win_w - btn_w - 16;
|
||||
if (st.selected_disk >= 0 &&
|
||||
mx >= next_x && mx < next_x + btn_w &&
|
||||
my >= btn_y && my < btn_y + btn_h) {
|
||||
st.step = STEP_PARTITION_SCHEME;
|
||||
return true;
|
||||
}
|
||||
|
||||
// "Refresh" button
|
||||
int ref_w = 80;
|
||||
int ref_x = next_x - ref_w - 8;
|
||||
if (mx >= ref_x && mx < ref_x + ref_w &&
|
||||
my >= btn_y && my < btn_y + btn_h) {
|
||||
installer_refresh_disks();
|
||||
return true;
|
||||
}
|
||||
} else if (st.step == STEP_PARTITION_SCHEME) {
|
||||
// Scheme radio buttons
|
||||
int y = CONTENT_TOP + 40 + fh + 12;
|
||||
for (int i = 0; i < SCHEME_COUNT; i++) {
|
||||
int item_h = 52;
|
||||
if (mx >= 16 && mx < g_win_w - 16 && my >= y && my < y + item_h) {
|
||||
st.partition_scheme = i;
|
||||
return true;
|
||||
}
|
||||
y += item_h + 4;
|
||||
}
|
||||
|
||||
// "Next" button
|
||||
int next_x = g_win_w - btn_w - 16;
|
||||
if (mx >= next_x && mx < next_x + btn_w &&
|
||||
my >= btn_y && my < btn_y + btn_h) {
|
||||
st.step = STEP_CONFIRM;
|
||||
return true;
|
||||
}
|
||||
|
||||
// "Back" button
|
||||
int back_x = next_x - btn_w - 8;
|
||||
if (mx >= back_x && mx < back_x + btn_w &&
|
||||
my >= btn_y && my < btn_y + btn_h) {
|
||||
st.step = STEP_SELECT_DISK;
|
||||
return true;
|
||||
}
|
||||
} else if (st.step == STEP_CONFIRM) {
|
||||
int center_x = g_win_w / 2;
|
||||
int gap = 16;
|
||||
|
||||
// "Install" button
|
||||
int conf_x = center_x - btn_w - gap / 2;
|
||||
if (mx >= conf_x && mx < conf_x + btn_w &&
|
||||
my >= btn_y && my < btn_y + btn_h) {
|
||||
st.step = STEP_INSTALLING;
|
||||
st.log_count = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// "Back" button
|
||||
int canc_x = center_x + gap / 2;
|
||||
if (mx >= canc_x && mx < canc_x + btn_w &&
|
||||
my >= btn_y && my < btn_y + btn_h) {
|
||||
st.step = STEP_PARTITION_SCHEME;
|
||||
return true;
|
||||
}
|
||||
} else if (st.step == STEP_DONE || st.step == STEP_ERROR) {
|
||||
int close_x = (g_win_w - 100) / 2;
|
||||
if (mx >= close_x && mx < close_x + 100 &&
|
||||
my >= btn_y && my < btn_y + btn_h) {
|
||||
return false; // signal quit
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Entry point
|
||||
// ============================================================================
|
||||
|
||||
extern "C" void _start() {
|
||||
montauk::memset(&g_state, 0, sizeof(g_state));
|
||||
g_state.selected_disk = -1;
|
||||
g_state.partition_scheme = SCHEME_SINGLE_FAT32;
|
||||
g_state.step = STEP_SELECT_DISK;
|
||||
|
||||
// Load font
|
||||
{
|
||||
TrueTypeFont* f = (TrueTypeFont*)montauk::malloc(sizeof(TrueTypeFont));
|
||||
if (f) {
|
||||
montauk::memset(f, 0, sizeof(TrueTypeFont));
|
||||
if (!f->init("0:/fonts/Roboto-Medium.ttf")) { montauk::mfree(f); f = nullptr; }
|
||||
}
|
||||
g_font = f;
|
||||
}
|
||||
|
||||
apply_scale(montauk::win_getscale());
|
||||
|
||||
installer_refresh_disks();
|
||||
|
||||
// Create window
|
||||
Montauk::WinCreateResult wres;
|
||||
if (montauk::win_create("Install MontaukOS", INIT_W, INIT_H, &wres) < 0 || wres.id < 0)
|
||||
montauk::exit(1);
|
||||
|
||||
int win_id = wres.id;
|
||||
uint32_t* pixels = (uint32_t*)(uintptr_t)wres.pixelVa;
|
||||
g_pixels = pixels;
|
||||
g_win_id = win_id;
|
||||
|
||||
render(pixels);
|
||||
montauk::win_present(win_id);
|
||||
|
||||
bool install_triggered = false;
|
||||
|
||||
while (true) {
|
||||
Montauk::WinEvent ev;
|
||||
bool redraw = false;
|
||||
|
||||
int r = montauk::win_poll(win_id, &ev);
|
||||
if (r < 0) break;
|
||||
|
||||
if (r == 0) {
|
||||
if (g_state.step == STEP_INSTALLING && !install_triggered) {
|
||||
install_triggered = true;
|
||||
render(pixels);
|
||||
montauk::win_present(win_id);
|
||||
do_install();
|
||||
render(pixels);
|
||||
montauk::win_present(win_id);
|
||||
}
|
||||
montauk::sleep_ms(16);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev.type == 3) break;
|
||||
|
||||
if (ev.type == 4) {
|
||||
apply_scale(ev.scale.scale);
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (ev.type == 2) {
|
||||
g_win_w = ev.resize.w;
|
||||
g_win_h = ev.resize.h;
|
||||
pixels = (uint32_t*)(uintptr_t)montauk::win_resize(win_id, g_win_w, g_win_h);
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (ev.type == 0 && ev.key.pressed) {
|
||||
if (ev.key.scancode == 0x01) break;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (ev.type == 1) {
|
||||
bool clicked = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1);
|
||||
if (clicked) {
|
||||
if (!handle_click(ev.mouse.x, ev.mouse.y))
|
||||
break;
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (redraw) { render(pixels); montauk::win_present(win_id); }
|
||||
}
|
||||
|
||||
montauk::win_destroy(win_id);
|
||||
montauk::exit(0);
|
||||
}
|
||||
Reference in New Issue
Block a user