299 lines
9.4 KiB
C++
299 lines
9.4 KiB
C++
/*
|
|
* spreadsheet.h
|
|
* Shared header for the MontaukOS spreadsheet app
|
|
* Copyright (c) 2026 Daniel Hammer
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <montauk/syscall.h>
|
|
#include <montauk/string.h>
|
|
#include <montauk/heap.h>
|
|
#include <gui/gui.hpp>
|
|
#include <gui/truetype.hpp>
|
|
#include <gui/stb_math.h>
|
|
#include <gui/svg.hpp>
|
|
|
|
extern "C" {
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
}
|
|
|
|
using namespace gui;
|
|
|
|
// ============================================================================
|
|
// Constants
|
|
// ============================================================================
|
|
|
|
static constexpr int INIT_W = 900;
|
|
static constexpr int INIT_H = 600;
|
|
static constexpr int TOOLBAR_H = 36;
|
|
static constexpr int FORMULA_BAR_H = 36;
|
|
static constexpr int COL_HEADER_H = 28;
|
|
static constexpr int ROW_HEADER_W = 48;
|
|
static constexpr int STATUS_BAR_H = 24;
|
|
static constexpr int SCROLL_STEP = 50;
|
|
static constexpr int TB_BTN_SIZE = 24;
|
|
static constexpr int TB_BTN_Y = 6;
|
|
static constexpr int TB_BTN_RAD = 3;
|
|
|
|
static constexpr int MAX_COLS = 26; // A-Z
|
|
static constexpr int MAX_ROWS = 100;
|
|
static constexpr int DEF_COL_W = 100;
|
|
static constexpr int MIN_COL_W = 30;
|
|
static constexpr int ROW_H = 26;
|
|
static constexpr int COL_RESIZE_GRAB = 5; // pixels from border edge for grab zone
|
|
static constexpr int FILL_HANDLE_SIZE = 6;
|
|
static constexpr int AC_MAX_MATCHES = 8;
|
|
static constexpr int DBLCLICK_MS = 400;
|
|
|
|
static constexpr int CELL_TEXT_MAX = 128;
|
|
static constexpr int FONT_SIZE = 18;
|
|
static constexpr int HEADER_FONT = 16;
|
|
|
|
static constexpr Color BG_COLOR = Color::from_rgb(0xFF, 0xFF, 0xFF);
|
|
static constexpr Color GRID_COLOR = Color::from_rgb(0xD0, 0xD0, 0xD0);
|
|
static constexpr Color HEADER_BG = Color::from_rgb(0xF0, 0xF0, 0xF0);
|
|
static constexpr Color HEADER_TEXT = Color::from_rgb(0x55, 0x55, 0x55);
|
|
static constexpr Color CELL_TEXT = Color::from_rgb(0x22, 0x22, 0x22);
|
|
static constexpr Color SELECT_BORDER = Color::from_rgb(0x36, 0x7B, 0xF0);
|
|
static constexpr Color SELECT_FILL = Color::from_rgb(0xD8, 0xE8, 0xFD);
|
|
static constexpr Color FORMULA_BG = Color::from_rgb(0xFF, 0xFF, 0xFF);
|
|
static constexpr Color FORMULA_BORDER = Color::from_rgb(0xCC, 0xCC, 0xCC);
|
|
static constexpr Color STATUS_BG = Color::from_rgb(0x2B, 0x3E, 0x50);
|
|
static constexpr Color STATUS_TEXT = Color::from_rgb(0xFF, 0xFF, 0xFF);
|
|
static constexpr Color NUM_COLOR = Color::from_rgb(0x10, 0x50, 0x90);
|
|
static constexpr Color ERR_COLOR = Color::from_rgb(0xCC, 0x22, 0x22);
|
|
static constexpr Color TOOLBAR_BG = Color::from_rgb(0xF5, 0xF5, 0xF5);
|
|
static constexpr Color TB_BTN_BG = Color::from_rgb(0xE8, 0xE8, 0xE8);
|
|
static constexpr Color TB_BTN_ACTIVE = Color::from_rgb(0xC0, 0xD0, 0xE8);
|
|
static constexpr Color TB_SEP_COLOR = Color::from_rgb(0xCC, 0xCC, 0xCC);
|
|
|
|
// ============================================================================
|
|
// Types
|
|
// ============================================================================
|
|
|
|
enum CellAlign : uint8_t { ALIGN_AUTO = 0, ALIGN_LEFT = 1, ALIGN_CENTER = 2, ALIGN_RIGHT = 3 };
|
|
enum NumFormat : uint8_t { FMT_AUTO = 0, FMT_DECIMAL = 1, FMT_CURRENCY = 2, FMT_PERCENT = 3 };
|
|
|
|
enum CellType : uint8_t {
|
|
CT_EMPTY = 0,
|
|
CT_TEXT = 1,
|
|
CT_NUMBER = 2,
|
|
CT_FORMULA = 3,
|
|
CT_ERROR = 4,
|
|
};
|
|
|
|
struct Cell {
|
|
char input[CELL_TEXT_MAX]; // raw user input
|
|
char display[CELL_TEXT_MAX]; // computed display string
|
|
double value; // numeric value (for formulas/numbers)
|
|
CellType type;
|
|
CellAlign align;
|
|
NumFormat fmt;
|
|
bool bold;
|
|
};
|
|
|
|
static constexpr int CLIP_MAX_CELLS = 256;
|
|
struct ClipCell {
|
|
char text[CELL_TEXT_MAX];
|
|
int rel_col;
|
|
int rel_row;
|
|
CellAlign align;
|
|
NumFormat fmt;
|
|
bool bold;
|
|
};
|
|
|
|
static constexpr int UNDO_MAX = 6;
|
|
struct UndoCellData {
|
|
char input[CELL_TEXT_MAX];
|
|
CellAlign align;
|
|
NumFormat fmt;
|
|
bool bold;
|
|
};
|
|
struct UndoEntry {
|
|
UndoCellData cells[MAX_ROWS][MAX_COLS];
|
|
};
|
|
|
|
static constexpr int PATHBAR_H = 32;
|
|
|
|
// ============================================================================
|
|
// Toolbar button IDs (must match handle_toolbar_click and render order)
|
|
// ============================================================================
|
|
|
|
enum ToolBtnId {
|
|
TB_OPEN,
|
|
TB_SAVE,
|
|
TB_CUT,
|
|
TB_COPY,
|
|
TB_PASTE,
|
|
TB_BOLD,
|
|
TB_AL,
|
|
TB_AC,
|
|
TB_AR,
|
|
TB_FMT,
|
|
TB_UNDO,
|
|
TB_REDO,
|
|
TB_COUNT
|
|
};
|
|
int tb_btn_x0(ToolBtnId id);
|
|
int tb_btn_x1(ToolBtnId id);
|
|
|
|
// ============================================================================
|
|
// Global state (extern — defined in main.cpp)
|
|
// ============================================================================
|
|
|
|
extern int g_win_w, g_win_h;
|
|
extern Cell g_cells[MAX_ROWS][MAX_COLS];
|
|
extern int g_sel_col, g_sel_row;
|
|
extern int g_scroll_x, g_scroll_y;
|
|
extern int g_col_widths[MAX_COLS];
|
|
|
|
extern bool g_editing;
|
|
extern char g_edit_buf[CELL_TEXT_MAX];
|
|
extern int g_edit_len;
|
|
extern int g_edit_cursor;
|
|
|
|
extern bool g_has_selection;
|
|
extern int g_anchor_col, g_anchor_row;
|
|
|
|
extern ClipCell g_clipboard[CLIP_MAX_CELLS];
|
|
extern int g_clip_count;
|
|
extern int g_clip_cols, g_clip_rows;
|
|
|
|
extern char g_filepath[256];
|
|
extern bool g_modified;
|
|
|
|
extern bool g_pathbar_open;
|
|
extern bool g_pathbar_save;
|
|
extern char g_pathbar_text[256];
|
|
extern int g_pathbar_len;
|
|
extern int g_pathbar_cursor;
|
|
|
|
extern TrueTypeFont* g_font;
|
|
extern TrueTypeFont* g_font_bold;
|
|
|
|
extern bool g_fmt_dropdown_open;
|
|
|
|
extern bool g_col_resizing;
|
|
extern int g_col_resize_idx;
|
|
extern int g_col_resize_start_x;
|
|
extern int g_col_resize_start_w;
|
|
|
|
extern UndoEntry* g_undo[UNDO_MAX + 1];
|
|
extern int g_undo_count;
|
|
extern int g_undo_pos;
|
|
|
|
// Formula autocomplete
|
|
extern bool g_ac_open;
|
|
extern int g_ac_sel;
|
|
extern int g_ac_count;
|
|
extern char g_ac_matches[AC_MAX_MATCHES][16];
|
|
extern char g_ac_hints[AC_MAX_MATCHES][32];
|
|
|
|
// Fill handle
|
|
extern bool g_fill_dragging;
|
|
extern int g_fill_target_row;
|
|
|
|
// Mouse drag selection
|
|
extern bool g_mouse_selecting;
|
|
|
|
// Double-click detection
|
|
extern uint64_t g_last_click_ms;
|
|
extern int g_last_click_col;
|
|
extern int g_last_click_row;
|
|
|
|
// ============================================================================
|
|
// Function declarations — helpers.cpp
|
|
// ============================================================================
|
|
|
|
void px_fill(uint32_t* px, int bw, int bh, int x, int y, int w, int h, Color c);
|
|
void px_hline(uint32_t* px, int bw, int bh, int x, int y, int w, Color c);
|
|
void px_vline(uint32_t* px, int bw, int bh, int x, int y, int h, Color c);
|
|
void px_rect(uint32_t* px, int bw, int bh, int x, int y, int w, int h, Color c);
|
|
void px_fill_rounded(uint32_t* px, int bw, int bh, int x, int y, int w, int h, int r, Color c);
|
|
|
|
int str_len(const char* s);
|
|
void str_cpy(char* dst, const char* src, int max);
|
|
bool is_digit(char c);
|
|
bool is_alpha(char c);
|
|
char to_upper(char c);
|
|
double str_to_double(const char* s, bool* ok);
|
|
void double_to_str(char* buf, int max, double v);
|
|
bool str_is_int(const char* s);
|
|
int str_to_int(const char* s);
|
|
void int_to_str(char* dst, int max, int v);
|
|
|
|
// ============================================================================
|
|
// Function declarations — formula.cpp
|
|
// ============================================================================
|
|
|
|
void eval_cell(int col, int row);
|
|
void eval_all_cells();
|
|
int col_x(int col);
|
|
int content_width();
|
|
int content_height();
|
|
void cell_name(char* buf, int col, int row);
|
|
void format_value(char* buf, int max, double val, NumFormat fmt);
|
|
void update_autocomplete();
|
|
void accept_autocomplete();
|
|
void adjust_formula_refs(const char* src, char* dst, int max, int dcol, int drow);
|
|
|
|
// ============================================================================
|
|
// Function declarations — fileio.cpp
|
|
// ============================================================================
|
|
|
|
void save_file();
|
|
void load_file(const char* path);
|
|
|
|
// ============================================================================
|
|
// Function declarations — edit.cpp
|
|
// ============================================================================
|
|
|
|
void undo_push();
|
|
void undo_do();
|
|
void redo_do();
|
|
void start_editing();
|
|
void commit_edit();
|
|
void cancel_edit();
|
|
void sel_range(int* c0, int* r0, int* c1, int* r1);
|
|
void clear_selection();
|
|
void copy_selection();
|
|
void cut_selection();
|
|
void paste_at_cursor();
|
|
void apply_bold_toggle();
|
|
void apply_align(CellAlign a);
|
|
void apply_format(NumFormat f);
|
|
void clamp_scroll();
|
|
void ensure_sel_visible();
|
|
void fill_down(int src_r0, int src_c0, int src_r1, int src_c1, int dst_r1);
|
|
void auto_fit_column(int col);
|
|
|
|
// ============================================================================
|
|
// Function declarations — render.cpp
|
|
// ============================================================================
|
|
|
|
void render(uint32_t* pixels);
|
|
|
|
// ============================================================================
|
|
// Icons
|
|
// ============================================================================
|
|
|
|
extern SvgIcon g_icon_folder;
|
|
extern SvgIcon g_icon_save;
|
|
extern SvgIcon g_icon_cut;
|
|
extern SvgIcon g_icon_copy;
|
|
extern SvgIcon g_icon_paste;
|
|
|
|
void ss_load_icons();
|
|
void ss_unload_icons();
|
|
|
|
// ============================================================================
|
|
// Function declarations — main.cpp
|
|
// ============================================================================
|
|
|
|
bool hit_cell(int mx, int my, int* out_col, int* out_row);
|
|
bool hit_fill_handle(int mx, int my);
|
|
bool handle_toolbar_click(int mx, int my);
|
|
bool handle_fmt_dropdown_click(int mx, int my);
|