feat: add drag-down spreadsheet functions for numbers, fix click mapping issue
This commit is contained in:
@@ -225,9 +225,28 @@ void fill_down(int src_r0, int src_c0, int src_r1, int src_c1, int dst_r1) {
|
||||
|
||||
int src_rows = src_r1 - src_r0 + 1;
|
||||
|
||||
// Detect integer-sequence fill: all source cells must be plain integers
|
||||
bool is_int_seq = true;
|
||||
int step[MAX_COLS];
|
||||
for (int c = src_c0; is_int_seq && c <= src_c1; c++) {
|
||||
if (src_rows == 1) {
|
||||
if (!str_is_int(g_cells[src_r0][c].input)) is_int_seq = false;
|
||||
step[c] = 1;
|
||||
} else {
|
||||
if (!str_is_int(g_cells[src_r0][c].input) ||
|
||||
!str_is_int(g_cells[src_r1][c].input)) {
|
||||
is_int_seq = false;
|
||||
} else {
|
||||
step[c] = str_to_int(g_cells[src_r1][c].input) -
|
||||
str_to_int(g_cells[src_r0][c].input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int r = src_r1 + 1; r <= dst_r1; r++) {
|
||||
int src_r = src_r0 + ((r - src_r0) % src_rows);
|
||||
int drow = r - src_r;
|
||||
int fill_num = r - src_r1; // 1, 2, 3, ... past last source row
|
||||
for (int c = src_c0; c <= src_c1; c++) {
|
||||
Cell* src = &g_cells[src_r][c];
|
||||
Cell* dst = &g_cells[r][c];
|
||||
@@ -238,6 +257,11 @@ void fill_down(int src_r0, int src_c0, int src_r1, int src_c1, int dst_r1) {
|
||||
if (src->input[0] == '=') {
|
||||
// Formula: adjust cell references
|
||||
adjust_formula_refs(src->input, dst->input, CELL_TEXT_MAX, 0, drow);
|
||||
} else if (is_int_seq) {
|
||||
// Integer sequence: continue the arithmetic series
|
||||
int last_val = str_to_int(g_cells[src_r1][c].input);
|
||||
int val = last_val + fill_num * step[c];
|
||||
int_to_str(dst->input, CELL_TEXT_MAX, val);
|
||||
} else {
|
||||
str_cpy(dst->input, src->input, CELL_TEXT_MAX);
|
||||
}
|
||||
|
||||
@@ -100,6 +100,46 @@ bool is_digit(char c) { return c >= '0' && c <= '9'; }
|
||||
bool is_alpha(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); }
|
||||
char to_upper(char c) { return (c >= 'a' && c <= 'z') ? c - 32 : c; }
|
||||
|
||||
bool str_is_int(const char* s) {
|
||||
if (!s || !s[0]) return false;
|
||||
int i = 0;
|
||||
if (s[i] == '-' || s[i] == '+') i++;
|
||||
if (!is_digit(s[i])) return false;
|
||||
while (is_digit(s[i])) i++;
|
||||
return s[i] == '\0';
|
||||
}
|
||||
|
||||
int str_to_int(const char* s) {
|
||||
if (!s || !s[0]) return 0;
|
||||
int i = 0;
|
||||
bool neg = false;
|
||||
if (s[i] == '-') { neg = true; i++; }
|
||||
else if (s[i] == '+') i++;
|
||||
int result = 0;
|
||||
while (is_digit(s[i])) {
|
||||
result = result * 10 + (s[i] - '0');
|
||||
i++;
|
||||
}
|
||||
return neg ? -result : result;
|
||||
}
|
||||
|
||||
void int_to_str(char* dst, int max, int v) {
|
||||
if (max <= 0) return;
|
||||
if (v == 0) { dst[0] = '0'; dst[1] = '\0'; return; }
|
||||
int i = 0;
|
||||
bool neg = false;
|
||||
if (v < 0) { neg = true; v = -v; }
|
||||
char buf[16];
|
||||
int j = 0;
|
||||
while (v > 0 && j < 16) {
|
||||
buf[j++] = '0' + (v % 10);
|
||||
v /= 10;
|
||||
}
|
||||
if (neg && j < 15) buf[j++] = '-';
|
||||
for (int k = j - 1; k >= 0 && i < max - 1; k--) dst[i++] = buf[k];
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
double str_to_double(const char* s, bool* ok) {
|
||||
*ok = false;
|
||||
if (!s || !s[0]) return 0;
|
||||
|
||||
@@ -196,38 +196,87 @@ static void save_file_dialog() {
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Toolbar button geometry (mirrors render.cpp layout exactly)
|
||||
// ============================================================================
|
||||
|
||||
// Button widths matching render.cpp: icons=24, Bold/Align=24, Fmt=64, Undo/Redo=36
|
||||
static constexpr int TB_ICON_W = 24;
|
||||
static constexpr int TB_FMT_W = 64;
|
||||
static constexpr int TB_UNDOREDO_W = 36;
|
||||
|
||||
int tb_btn_x0(ToolBtnId id) {
|
||||
// Mirrors render.cpp toolbar button layout exactly
|
||||
int bx = 4; // start
|
||||
|
||||
// Open, Save (icon buttons: 24px wide, 4px gap)
|
||||
if (id == TB_OPEN) return bx; bx += 24 + 4;
|
||||
if (id == TB_SAVE) return bx; bx += 24 + 4;
|
||||
bx += 8; // separator after Save
|
||||
|
||||
// Cut, Copy, Paste (icon buttons)
|
||||
if (id == TB_CUT) return bx; bx += 24 + 4;
|
||||
if (id == TB_COPY) return bx; bx += 24 + 4;
|
||||
if (id == TB_PASTE) return bx; bx += 24 + 4;
|
||||
bx += 8; // separator after Paste
|
||||
|
||||
// Bold (24px)
|
||||
if (id == TB_BOLD) return bx; bx += 24 + 4;
|
||||
bx += 8; // separator after Bold
|
||||
|
||||
// AL, AC, AR (24px each)
|
||||
if (id == TB_AL) return bx; bx += 24 + 4;
|
||||
if (id == TB_AC) return bx; bx += 24 + 4;
|
||||
if (id == TB_AR) return bx; bx += 24 + 4;
|
||||
bx += 8; // separator after AR
|
||||
|
||||
// FMT (64px)
|
||||
if (id == TB_FMT) return bx; bx += 64 + 4;
|
||||
bx += 8; // separator after FMT
|
||||
|
||||
// Undo, Redo (36px each)
|
||||
if (id == TB_UNDO) return bx; bx += 36 + 4;
|
||||
if (id == TB_REDO) return bx; bx += 36 + 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tb_btn_x1(ToolBtnId id) {
|
||||
return tb_btn_x0(static_cast<ToolBtnId>(id + 1));
|
||||
}
|
||||
|
||||
bool handle_toolbar_click(int mx, int my) {
|
||||
if (my >= TOOLBAR_H || my < TB_BTN_Y || my >= TB_BTN_Y + TB_BTN_SIZE) return false;
|
||||
|
||||
if (g_fmt_dropdown_open && !(mx >= TB_FMT_X0 && mx < TB_FMT_X1)) {
|
||||
if (g_fmt_dropdown_open && !(mx >= tb_btn_x0(TB_FMT) && mx < tb_btn_x1(TB_FMT))) {
|
||||
g_fmt_dropdown_open = false;
|
||||
}
|
||||
|
||||
if (mx >= TB_OPEN_X0 && mx < TB_OPEN_X1) {
|
||||
if (mx >= tb_btn_x0(TB_OPEN) && mx < tb_btn_x1(TB_OPEN)) {
|
||||
if (g_editing) commit_edit();
|
||||
open_file_dialog();
|
||||
} else if (mx >= TB_SAVE_X0 && mx < TB_SAVE_X1) {
|
||||
} else if (mx >= tb_btn_x0(TB_SAVE) && mx < tb_btn_x1(TB_SAVE)) {
|
||||
if (g_editing) commit_edit();
|
||||
save_file_dialog();
|
||||
} else if (mx >= TB_CUT_X0 && mx < TB_CUT_X1) {
|
||||
} else if (mx >= tb_btn_x0(TB_CUT) && mx < tb_btn_x1(TB_CUT)) {
|
||||
if (!g_editing) cut_selection();
|
||||
} else if (mx >= TB_COPY_X0 && mx < TB_COPY_X1) {
|
||||
} else if (mx >= tb_btn_x0(TB_COPY) && mx < tb_btn_x1(TB_COPY)) {
|
||||
if (!g_editing) copy_selection();
|
||||
} else if (mx >= TB_PASTE_X0 && mx < TB_PASTE_X1) {
|
||||
} else if (mx >= tb_btn_x0(TB_PASTE) && mx < tb_btn_x1(TB_PASTE)) {
|
||||
if (!g_editing) paste_at_cursor();
|
||||
} else if (mx >= TB_BOLD_X0 && mx < TB_BOLD_X1) {
|
||||
} else if (mx >= tb_btn_x0(TB_BOLD) && mx < tb_btn_x1(TB_BOLD)) {
|
||||
if (!g_editing) apply_bold_toggle();
|
||||
} else if (mx >= TB_AL_X0 && mx < TB_AL_X1) {
|
||||
} else if (mx >= tb_btn_x0(TB_AL) && mx < tb_btn_x1(TB_AL)) {
|
||||
if (!g_editing) apply_align(ALIGN_LEFT);
|
||||
} else if (mx >= TB_AC_X0 && mx < TB_AC_X1) {
|
||||
} else if (mx >= tb_btn_x0(TB_AC) && mx < tb_btn_x1(TB_AC)) {
|
||||
if (!g_editing) apply_align(ALIGN_CENTER);
|
||||
} else if (mx >= TB_AR_X0 && mx < TB_AR_X1) {
|
||||
} else if (mx >= tb_btn_x0(TB_AR) && mx < tb_btn_x1(TB_AR)) {
|
||||
if (!g_editing) apply_align(ALIGN_RIGHT);
|
||||
} else if (mx >= TB_FMT_X0 && mx < TB_FMT_X1) {
|
||||
} else if (mx >= tb_btn_x0(TB_FMT) && mx < tb_btn_x1(TB_FMT)) {
|
||||
g_fmt_dropdown_open = !g_fmt_dropdown_open;
|
||||
} else if (mx >= TB_UNDO_X0 && mx < TB_UNDO_X1) {
|
||||
} else if (mx >= tb_btn_x0(TB_UNDO) && mx < tb_btn_x1(TB_UNDO)) {
|
||||
undo_do();
|
||||
} else if (mx >= TB_REDO_X0 && mx < TB_REDO_X1) {
|
||||
} else if (mx >= tb_btn_x0(TB_REDO) && mx < tb_btn_x1(TB_REDO)) {
|
||||
redo_do();
|
||||
} else {
|
||||
return false;
|
||||
@@ -237,7 +286,7 @@ bool handle_toolbar_click(int mx, int my) {
|
||||
|
||||
bool handle_fmt_dropdown_click(int mx, int my) {
|
||||
if (!g_fmt_dropdown_open) return false;
|
||||
int dx = TB_FMT_X0;
|
||||
int dx = tb_btn_x0(TB_FMT);
|
||||
int dy = TOOLBAR_H;
|
||||
int dw = 80;
|
||||
int item_h = 26;
|
||||
|
||||
@@ -379,7 +379,7 @@ void render(uint32_t* pixels) {
|
||||
|
||||
// ---- Format dropdown overlay ----
|
||||
if (g_fmt_dropdown_open && g_font) {
|
||||
int dx = TB_FMT_X0;
|
||||
int dx = tb_btn_x0(TB_FMT);
|
||||
int dy = TOOLBAR_H;
|
||||
int dw = 80;
|
||||
const char* items[] = { "Auto", "Decimal", "Currency $", "Percent %" };
|
||||
|
||||
@@ -118,21 +118,26 @@ struct UndoEntry {
|
||||
static constexpr int PATHBAR_H = 32;
|
||||
|
||||
// ============================================================================
|
||||
// Toolbar button positions
|
||||
// Toolbar button IDs (must match handle_toolbar_click and render order)
|
||||
// ============================================================================
|
||||
|
||||
static constexpr int TB_OPEN_X0 = 4, TB_OPEN_X1 = 40;
|
||||
static constexpr int TB_SAVE_X0 = 44, TB_SAVE_X1 = 80;
|
||||
static constexpr int TB_CUT_X0 = 92, TB_CUT_X1 = 120;
|
||||
static constexpr int TB_COPY_X0 = 124, TB_COPY_X1 = 160;
|
||||
static constexpr int TB_PASTE_X0 = 164, TB_PASTE_X1 = 200;
|
||||
static constexpr int TB_BOLD_X0 = 212, TB_BOLD_X1 = 236;
|
||||
static constexpr int TB_AL_X0 = 248, TB_AL_X1 = 272;
|
||||
static constexpr int TB_AC_X0 = 276, TB_AC_X1 = 300;
|
||||
static constexpr int TB_AR_X0 = 304, TB_AR_X1 = 328;
|
||||
static constexpr int TB_FMT_X0 = 340, TB_FMT_X1 = 404;
|
||||
static constexpr int TB_UNDO_X0 = 416, TB_UNDO_X1 = 452;
|
||||
static constexpr int TB_REDO_X0 = 456, TB_REDO_X1 = 492;
|
||||
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)
|
||||
@@ -215,6 +220,9 @@ 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
|
||||
|
||||
Reference in New Issue
Block a user