feat: add common dialogs, i.e. open/save dialog
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
# Makefile for shared dialogs (standalone Window Server app) on MontaukOS
|
||||
# Copyright (c) 2026 Daniel Hammer
|
||||
|
||||
MAKEFLAGS += -rR
|
||||
.SUFFIXES:
|
||||
|
||||
TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-elf-
|
||||
ifneq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),)
|
||||
CXX := $(TOOLCHAIN_PREFIX)g++
|
||||
else
|
||||
CXX := g++
|
||||
endif
|
||||
|
||||
PROG_INC := ../../include
|
||||
LINK_LD := ../../link.ld
|
||||
BINDIR := ../../bin
|
||||
OBJDIR := obj
|
||||
LIBDIR := ../../lib
|
||||
|
||||
CXXFLAGS := \
|
||||
-std=gnu++20 \
|
||||
-g -O2 -pipe \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-unused-function \
|
||||
-nostdinc \
|
||||
-ffreestanding \
|
||||
-fno-stack-protector \
|
||||
-fno-stack-check \
|
||||
-fno-PIC \
|
||||
-fno-rtti \
|
||||
-fno-exceptions \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-m64 \
|
||||
-march=x86-64 \
|
||||
-msse \
|
||||
-msse2 \
|
||||
-mno-red-zone \
|
||||
-mcmodel=small \
|
||||
-MMD -MP \
|
||||
-I $(PROG_INC) \
|
||||
-isystem $(PROG_INC)/libc \
|
||||
-I ../../lib/bearssl/inc \
|
||||
-isystem ../../../kernel/freestnd-c-hdrs/x86_64/include \
|
||||
-isystem ../../../kernel/freestnd-cxx-hdrs/x86_64/include
|
||||
|
||||
LDFLAGS := \
|
||||
-nostdlib \
|
||||
-static \
|
||||
-Wl,--build-id=none \
|
||||
-Wl,--gc-sections \
|
||||
-Wl,-m,elf_x86_64 \
|
||||
-z max-page-size=0x1000 \
|
||||
-T $(LINK_LD)
|
||||
|
||||
SRCS := main.cpp stb_truetype_impl.cpp font_data.cpp
|
||||
OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o))
|
||||
|
||||
TARGET := $(BINDIR)/apps/dialogs/dialogs.elf
|
||||
LIBS := $(LIBDIR)/tls/libtls.a $(LIBDIR)/bearssl/libbearssl.a $(LIBDIR)/libc/liblibc.a
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBS)
|
||||
mkdir -p $(BINDIR)/apps/dialogs
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp Makefile
|
||||
mkdir -p $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(TARGET)
|
||||
@@ -0,0 +1 @@
|
||||
#include "../desktop/font_data.cpp"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
[app]
|
||||
name = "Dialogs"
|
||||
binary = "dialogs.elf"
|
||||
icon = "system-file-manager.svg"
|
||||
|
||||
[menu]
|
||||
category = "System"
|
||||
visible = false
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* stb_truetype_impl.cpp
|
||||
* Single compilation unit for stb_truetype in MontaukOS freestanding environment
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <montauk/heap.h>
|
||||
#include <montauk/string.h>
|
||||
#include <gui/stb_math.h>
|
||||
|
||||
#define STBTT_ifloor(x) ((int) stb_floor(x))
|
||||
#define STBTT_iceil(x) ((int) stb_ceil(x))
|
||||
#define STBTT_sqrt(x) stb_sqrt(x)
|
||||
#define STBTT_pow(x,y) stb_pow(x,y)
|
||||
#define STBTT_fmod(x,y) stb_fmod(x,y)
|
||||
#define STBTT_cos(x) stb_cos(x)
|
||||
#define STBTT_acos(x) stb_acos(x)
|
||||
#define STBTT_fabs(x) stb_fabs(x)
|
||||
|
||||
#define STBTT_malloc(x,u) ((void)(u), montauk::malloc(x))
|
||||
#define STBTT_free(x,u) ((void)(u), montauk::mfree(x))
|
||||
|
||||
#define STBTT_memcpy(d,s,n) montauk::memcpy(d,s,n)
|
||||
#define STBTT_memset(d,v,n) montauk::memset(d,v,n)
|
||||
|
||||
#define STBTT_strlen(x) montauk::slen(x)
|
||||
#define STBTT_assert(x) ((void)(x))
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include <gui/stb_truetype.h>
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "pdfviewer.h"
|
||||
#include <gui/dialogs.hpp>
|
||||
#include <gui/standalone.hpp>
|
||||
|
||||
// ============================================================================
|
||||
@@ -37,14 +38,15 @@ char g_status_msg[128] = {};
|
||||
// Toolbar hit-testing constants
|
||||
// ============================================================================
|
||||
|
||||
// Toolbar buttons: Open | < > | - +
|
||||
// Toolbar buttons: Open | Print | < > | - +
|
||||
static constexpr int TB_OPEN_X0 = 4, TB_OPEN_X1 = 40;
|
||||
// separator at 48
|
||||
static constexpr int TB_PREV_X0 = 56, TB_PREV_X1 = 80;
|
||||
static constexpr int TB_NEXT_X0 = 84, TB_NEXT_X1 = 108;
|
||||
// separator at 116
|
||||
static constexpr int TB_ZOUT_X0 = 124, TB_ZOUT_X1 = 148;
|
||||
static constexpr int TB_ZIN_X0 = 152, TB_ZIN_X1 = 176;
|
||||
static constexpr int TB_PRINT_X0 = 44, TB_PRINT_X1 = 80;
|
||||
// separator at 88
|
||||
static constexpr int TB_PREV_X0 = 96, TB_PREV_X1 = 120;
|
||||
static constexpr int TB_NEXT_X0 = 124, TB_NEXT_X1 = 148;
|
||||
// separator at 156
|
||||
static constexpr int TB_ZOUT_X0 = 164, TB_ZOUT_X1 = 188;
|
||||
static constexpr int TB_ZIN_X0 = 192, TB_ZIN_X1 = 216;
|
||||
|
||||
// ============================================================================
|
||||
// Helpers
|
||||
@@ -66,6 +68,15 @@ static void clamp_scroll() {
|
||||
if (g_scroll_y > ms) g_scroll_y = ms;
|
||||
}
|
||||
|
||||
static const char* file_basename(const char* path) {
|
||||
if (!path || !path[0]) return "";
|
||||
const char* name = path;
|
||||
for (int i = 0; path[i]; i++) {
|
||||
if (path[i] == '/') name = path + i + 1;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static void go_to_page(int page) {
|
||||
if (page < 0) page = 0;
|
||||
if (page >= g_doc.page_count) page = g_doc.page_count - 1;
|
||||
@@ -99,6 +110,40 @@ static void open_file(const char* path) {
|
||||
}
|
||||
}
|
||||
|
||||
static void open_inline_pathbar(const char* initial_text) {
|
||||
g_pathbar_open = true;
|
||||
if (!initial_text) initial_text = "";
|
||||
str_cpy(g_pathbar_text, initial_text, sizeof(g_pathbar_text));
|
||||
g_pathbar_len = str_len(g_pathbar_text);
|
||||
g_pathbar_cursor = g_pathbar_len;
|
||||
}
|
||||
|
||||
static void open_file_dialog() {
|
||||
char path[256] = {};
|
||||
if (dialogs::open_file("Open PDF", g_filepath, path, sizeof(path), g_status_msg, sizeof(g_status_msg))) {
|
||||
open_file(path);
|
||||
} else if (g_status_msg[0]) {
|
||||
open_inline_pathbar(g_filepath);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_file_dialog() {
|
||||
if (!g_filepath[0]) {
|
||||
str_cpy(g_status_msg, "Open a PDF before printing", sizeof(g_status_msg));
|
||||
return;
|
||||
}
|
||||
|
||||
char job_id[64] = {};
|
||||
char msg[128] = {};
|
||||
if (dialogs::print_file("Print PDF", g_filepath, file_basename(g_filepath),
|
||||
job_id, sizeof(job_id), msg, sizeof(msg))) {
|
||||
if (msg[0]) str_cpy(g_status_msg, msg, sizeof(g_status_msg));
|
||||
else str_cpy(g_status_msg, "Print job queued", sizeof(g_status_msg));
|
||||
} else if (msg[0]) {
|
||||
str_cpy(g_status_msg, msg, sizeof(g_status_msg));
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Entry point
|
||||
// ============================================================================
|
||||
@@ -126,9 +171,7 @@ extern "C" void _start() {
|
||||
// Build window title
|
||||
char title[64] = "PDF Viewer";
|
||||
if (g_filepath[0]) {
|
||||
const char* fname = g_filepath;
|
||||
for (int i = 0; g_filepath[i]; i++)
|
||||
if (g_filepath[i] == '/') fname = g_filepath + i + 1;
|
||||
const char* fname = file_basename(g_filepath);
|
||||
snprintf(title, 64, "%s - PDF Viewer", fname);
|
||||
}
|
||||
|
||||
@@ -211,10 +254,12 @@ extern "C" void _start() {
|
||||
}
|
||||
// Ctrl+O: open file
|
||||
else if (key.ctrl && (key.ascii == 'o' || key.ascii == 'O' || key.ascii == 15)) {
|
||||
g_pathbar_open = true;
|
||||
g_pathbar_text[0] = '\0';
|
||||
g_pathbar_len = 0;
|
||||
g_pathbar_cursor = 0;
|
||||
open_file_dialog();
|
||||
redraw = true;
|
||||
}
|
||||
// Ctrl+P: print file
|
||||
else if (key.ctrl && (key.ascii == 'p' || key.ascii == 'P' || key.ascii == 16)) {
|
||||
print_file_dialog();
|
||||
redraw = true;
|
||||
}
|
||||
// Page Down / Right arrow: next page
|
||||
@@ -288,10 +333,10 @@ extern "C" void _start() {
|
||||
|
||||
if (clicked && my < TOOLBAR_H && my >= TB_BTN_Y && my < TB_BTN_Y + TB_BTN_SIZE) {
|
||||
if (mx >= TB_OPEN_X0 && mx < TB_OPEN_X1) {
|
||||
g_pathbar_open = true;
|
||||
g_pathbar_text[0] = '\0';
|
||||
g_pathbar_len = 0;
|
||||
g_pathbar_cursor = 0;
|
||||
open_file_dialog();
|
||||
redraw = true;
|
||||
} else if (mx >= TB_PRINT_X0 && mx < TB_PRINT_X1) {
|
||||
print_file_dialog();
|
||||
redraw = true;
|
||||
} else if (mx >= TB_PREV_X0 && mx < TB_PREV_X1 && g_doc.valid) {
|
||||
go_to_page(g_current_page - 1);
|
||||
|
||||
@@ -180,8 +180,9 @@ void render(uint32_t* pixels) {
|
||||
bx += 8;
|
||||
};
|
||||
|
||||
// Open
|
||||
// Open / Print
|
||||
tb_btn(36, false, "Open");
|
||||
tb_btn(36, false, "Print");
|
||||
tb_sep();
|
||||
|
||||
// Navigation
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "spreadsheet.h"
|
||||
#include <gui/dialogs.hpp>
|
||||
#include <gui/standalone.hpp>
|
||||
|
||||
// ============================================================================
|
||||
@@ -131,6 +132,41 @@ bool hit_fill_handle(int mx, int my) {
|
||||
my >= fhy - 3 && my <= fhy + FILL_HANDLE_SIZE + 3;
|
||||
}
|
||||
|
||||
static void open_inline_pathbar(bool save_mode, const char* initial_text) {
|
||||
g_pathbar_open = true;
|
||||
g_pathbar_save = save_mode;
|
||||
if (!initial_text) initial_text = "";
|
||||
str_cpy(g_pathbar_text, initial_text, sizeof(g_pathbar_text));
|
||||
g_pathbar_len = str_len(g_pathbar_text);
|
||||
g_pathbar_cursor = g_pathbar_len;
|
||||
}
|
||||
|
||||
static void open_file_dialog() {
|
||||
char path[256] = {};
|
||||
char msg[128] = {};
|
||||
if (dialogs::open_file("Open Spreadsheet", g_filepath, path, sizeof(path), msg, sizeof(msg))) {
|
||||
load_file(path);
|
||||
} else if (msg[0]) {
|
||||
open_inline_pathbar(false, g_filepath);
|
||||
}
|
||||
}
|
||||
|
||||
static void save_file_dialog() {
|
||||
if (g_filepath[0]) {
|
||||
save_file();
|
||||
return;
|
||||
}
|
||||
|
||||
char path[256] = {};
|
||||
char msg[128] = {};
|
||||
if (dialogs::save_file("Save Spreadsheet", "", "untitled.mss", path, sizeof(path), msg, sizeof(msg))) {
|
||||
str_cpy(g_filepath, path, 256);
|
||||
save_file();
|
||||
} else if (msg[0]) {
|
||||
open_inline_pathbar(true, "untitled.mss");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -140,22 +176,10 @@ bool handle_toolbar_click(int mx, int my) {
|
||||
|
||||
if (mx >= TB_OPEN_X0 && mx < TB_OPEN_X1) {
|
||||
if (g_editing) commit_edit();
|
||||
g_pathbar_open = true;
|
||||
g_pathbar_save = false;
|
||||
g_pathbar_text[0] = '\0';
|
||||
g_pathbar_len = 0;
|
||||
g_pathbar_cursor = 0;
|
||||
open_file_dialog();
|
||||
} else if (mx >= TB_SAVE_X0 && mx < TB_SAVE_X1) {
|
||||
if (g_editing) commit_edit();
|
||||
if (g_filepath[0]) {
|
||||
save_file();
|
||||
} else {
|
||||
g_pathbar_open = true;
|
||||
g_pathbar_save = true;
|
||||
str_cpy(g_pathbar_text, "0:/", 256);
|
||||
g_pathbar_len = str_len(g_pathbar_text);
|
||||
g_pathbar_cursor = g_pathbar_len;
|
||||
}
|
||||
save_file_dialog();
|
||||
} else if (mx >= TB_CUT_X0 && mx < TB_CUT_X1) {
|
||||
if (!g_editing) cut_selection();
|
||||
} else if (mx >= TB_COPY_X0 && mx < TB_COPY_X1) {
|
||||
@@ -556,24 +580,12 @@ extern "C" void _start() {
|
||||
// Ctrl+S: save (or Save As if no path)
|
||||
else if (key.ctrl && (key.ascii == 's' || key.ascii == 'S' || key.ascii == 19)) {
|
||||
if (g_editing) commit_edit();
|
||||
if (g_filepath[0]) {
|
||||
save_file();
|
||||
} else {
|
||||
g_pathbar_open = true;
|
||||
g_pathbar_save = true;
|
||||
str_cpy(g_pathbar_text, "0:/", 256);
|
||||
g_pathbar_len = str_len(g_pathbar_text);
|
||||
g_pathbar_cursor = g_pathbar_len;
|
||||
}
|
||||
save_file_dialog();
|
||||
redraw = true;
|
||||
}
|
||||
// Ctrl+O: open
|
||||
else if (key.ctrl && (key.ascii == 'o' || key.ascii == 'O' || key.ascii == 15) && !g_editing) {
|
||||
g_pathbar_open = true;
|
||||
g_pathbar_save = false;
|
||||
g_pathbar_text[0] = '\0';
|
||||
g_pathbar_len = 0;
|
||||
g_pathbar_cursor = 0;
|
||||
open_file_dialog();
|
||||
redraw = true;
|
||||
}
|
||||
// Printable character: start editing or insert
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <gui/gui.hpp>
|
||||
#include <gui/truetype.hpp>
|
||||
#include <gui/svg.hpp>
|
||||
#include <gui/dialogs.hpp>
|
||||
#include <gui/stb_math.h>
|
||||
|
||||
extern "C" {
|
||||
@@ -87,6 +88,7 @@ int g_scroll_y = 0; // first visible line
|
||||
int g_scroll_x = 0; // horizontal scroll in pixels
|
||||
bool g_modified = false;
|
||||
bool g_cursor_moved = true;
|
||||
char g_status_msg[128] = {};
|
||||
|
||||
// File
|
||||
char g_filepath[256] = {};
|
||||
@@ -434,24 +436,76 @@ static void ensure_cursor_visible(int visible_lines, int text_area_w) {
|
||||
// File I/O
|
||||
// ============================================================================
|
||||
|
||||
static void load_file(const char* path) {
|
||||
static void set_status(const char* msg) {
|
||||
if (!msg) msg = "";
|
||||
montauk::strncpy(g_status_msg, msg, sizeof(g_status_msg) - 1);
|
||||
g_status_msg[sizeof(g_status_msg) - 1] = '\0';
|
||||
}
|
||||
|
||||
static bool looks_binary(const char* data, int len) {
|
||||
if (!data || len <= 0) return false;
|
||||
|
||||
int control_count = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
unsigned char ch = (unsigned char)data[i];
|
||||
if (ch == 0) return true;
|
||||
if (ch < 32 && ch != '\n' && ch != '\r' && ch != '\t' && ch != '\f')
|
||||
control_count++;
|
||||
}
|
||||
|
||||
return control_count * 20 > len;
|
||||
}
|
||||
|
||||
static bool load_file(const char* path) {
|
||||
int fd = montauk::open(path);
|
||||
if (fd < 0) return;
|
||||
if (fd < 0) {
|
||||
set_status("Failed to open file");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t size = montauk::getsize(fd);
|
||||
if (size > (uint64_t)MAX_CAP) size = MAX_CAP;
|
||||
if (size > (uint64_t)MAX_CAP) {
|
||||
montauk::close(fd);
|
||||
set_status("File is too large for Text Editor");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((int)size >= g_buf_cap) {
|
||||
int new_cap = (int)size + 1024;
|
||||
int read_len = (int)size;
|
||||
int temp_cap = read_len + 1;
|
||||
if (temp_cap < 1024) temp_cap = 1024;
|
||||
char* temp = (char*)montauk::malloc(temp_cap);
|
||||
if (!temp) {
|
||||
montauk::close(fd);
|
||||
set_status("Out of memory while opening file");
|
||||
return false;
|
||||
}
|
||||
|
||||
int got = montauk::read(fd, (uint8_t*)temp, 0, size);
|
||||
montauk::close(fd);
|
||||
if (got < 0) {
|
||||
montauk::mfree(temp);
|
||||
set_status("Failed to read file");
|
||||
return false;
|
||||
}
|
||||
|
||||
temp[got] = '\0';
|
||||
if (looks_binary(temp, got)) {
|
||||
montauk::mfree(temp);
|
||||
set_status("Binary files cannot be opened in Text Editor");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (got >= g_buf_cap) {
|
||||
int new_cap = got + 1024;
|
||||
if (new_cap > MAX_CAP) new_cap = MAX_CAP;
|
||||
g_buffer = (char*)montauk::realloc(g_buffer, new_cap);
|
||||
g_buf_cap = new_cap;
|
||||
}
|
||||
|
||||
montauk::read(fd, (uint8_t*)g_buffer, 0, size);
|
||||
montauk::close(fd);
|
||||
montauk::memcpy(g_buffer, temp, (uint64_t)(got + 1));
|
||||
montauk::mfree(temp);
|
||||
|
||||
g_buf_len = (int)size;
|
||||
g_buf_len = got;
|
||||
g_cursor_pos = 0;
|
||||
g_scroll_y = 0;
|
||||
g_scroll_x = 0;
|
||||
@@ -468,21 +522,28 @@ static void load_file(const char* path) {
|
||||
montauk::strncpy(g_filename, path, 63);
|
||||
|
||||
g_syntax_language = syn_detect_language(g_filepath);
|
||||
clear_selection();
|
||||
set_status("");
|
||||
|
||||
recompute_lines();
|
||||
update_cursor_pos();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void save_file() {
|
||||
if (g_filepath[0] == '\0') return;
|
||||
|
||||
int fd = montauk::fcreate(g_filepath);
|
||||
if (fd < 0) return;
|
||||
if (fd < 0) {
|
||||
set_status("Failed to save file");
|
||||
return;
|
||||
}
|
||||
|
||||
montauk::fwrite(fd, (const uint8_t*)g_buffer, 0, g_buf_len);
|
||||
montauk::close(fd);
|
||||
|
||||
g_modified = false;
|
||||
set_status("");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -734,10 +795,16 @@ static void render(uint32_t* pixels) {
|
||||
|
||||
// Left: filename
|
||||
char status_left[128];
|
||||
if (g_filename[0])
|
||||
if (g_status_msg[0]) {
|
||||
if (g_filename[0])
|
||||
snprintf(status_left, 128, " %s%s | %s", g_filename, g_modified ? " [modified]" : "", g_status_msg);
|
||||
else
|
||||
snprintf(status_left, 128, " Untitled%s | %s", g_modified ? " [modified]" : "", g_status_msg);
|
||||
} else if (g_filename[0]) {
|
||||
snprintf(status_left, 128, " %s%s", g_filename, g_modified ? " [modified]" : "");
|
||||
else
|
||||
} else {
|
||||
snprintf(status_left, 128, " Untitled%s", g_modified ? " [modified]" : "");
|
||||
}
|
||||
if (g_font)
|
||||
g_font->draw_to_buffer(pixels, W, H, 4, sty, status_left, STATUS_TEXT, FONT_SIZE);
|
||||
|
||||
@@ -778,20 +845,41 @@ static void pathbar_confirm(int win_id) {
|
||||
g_pathbar_open = false;
|
||||
}
|
||||
|
||||
static void open_pathbar_open() {
|
||||
static void open_inline_pathbar(bool save_mode, const char* initial_text) {
|
||||
g_pathbar_open = true;
|
||||
g_pathbar_save = false;
|
||||
montauk::strncpy(g_pathbar_text, g_filepath, 255);
|
||||
g_pathbar_save = save_mode;
|
||||
if (!initial_text) initial_text = "";
|
||||
montauk::strncpy(g_pathbar_text, initial_text, 255);
|
||||
g_pathbar_len = montauk::slen(g_pathbar_text);
|
||||
g_pathbar_cursor = g_pathbar_len;
|
||||
}
|
||||
|
||||
static void open_pathbar_open() {
|
||||
char path[256] = {};
|
||||
char msg[128] = {};
|
||||
if (dialogs::open_file("Open File", g_filepath, path, sizeof(path), msg, sizeof(msg))) {
|
||||
load_file(path);
|
||||
} else if (msg[0]) {
|
||||
open_inline_pathbar(false, g_filepath);
|
||||
}
|
||||
}
|
||||
|
||||
static void open_pathbar_save() {
|
||||
g_pathbar_open = true;
|
||||
g_pathbar_save = true;
|
||||
g_pathbar_text[0] = '\0';
|
||||
g_pathbar_len = 0;
|
||||
g_pathbar_cursor = 0;
|
||||
char path[256] = {};
|
||||
const char* initial_path = g_filepath[0] ? g_filepath : "";
|
||||
const char* suggested_name = g_filename[0] ? g_filename : "untitled.txt";
|
||||
char msg[128] = {};
|
||||
if (dialogs::save_file("Save File", initial_path, suggested_name, path, sizeof(path), msg, sizeof(msg))) {
|
||||
montauk::strncpy(g_filepath, path, 255);
|
||||
const char* name = path;
|
||||
for (int i = 0; path[i]; i++)
|
||||
if (path[i] == '/') name = path + i + 1;
|
||||
montauk::strncpy(g_filename, name, 63);
|
||||
g_syntax_language = syn_detect_language(g_filepath);
|
||||
save_file();
|
||||
} else if (msg[0]) {
|
||||
open_inline_pathbar(true, initial_path[0] ? initial_path : suggested_name);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "wordprocessor.hpp"
|
||||
#include <gui/dialogs.hpp>
|
||||
|
||||
static inline int wp_min_int(int a, int b) {
|
||||
return a < b ? a : b;
|
||||
@@ -1203,14 +1204,29 @@ void wp_set_filepath(WordProcessorState* wp, const char* path) {
|
||||
montauk::strncpy(wp->filename, path, 63);
|
||||
}
|
||||
|
||||
void wp_open_save_pathbar(WordProcessorState* wp) {
|
||||
void wp_start_pathbar(WordProcessorState* wp, bool save_mode, const char* initial_text) {
|
||||
if (!initial_text) initial_text = "";
|
||||
wp->show_pathbar = true;
|
||||
wp->pathbar_save_mode = true;
|
||||
montauk::strncpy(wp->pathbar_text, wp->filepath, 255);
|
||||
wp->pathbar_save_mode = save_mode;
|
||||
montauk::strncpy(wp->pathbar_text, initial_text, 255);
|
||||
wp->pathbar_text[255] = '\0';
|
||||
wp->pathbar_len = montauk::slen(wp->pathbar_text);
|
||||
wp->pathbar_cursor = wp->pathbar_len;
|
||||
}
|
||||
|
||||
void wp_open_save_pathbar(WordProcessorState* wp) {
|
||||
char path[256] = {};
|
||||
const char* initial_path = wp->filepath[0] ? wp->filepath : "";
|
||||
const char* suggested_name = wp->filename[0] ? wp->filename : "document.mwp";
|
||||
char msg[160] = {};
|
||||
if (dialogs::save_file("Save Document", initial_path, suggested_name, path, sizeof(path), msg, sizeof(msg))) {
|
||||
wp_set_filepath(wp, path);
|
||||
wp_save_file(wp);
|
||||
} else if (msg[0]) {
|
||||
wp_start_pathbar(wp, true, initial_path[0] ? initial_path : suggested_name);
|
||||
}
|
||||
}
|
||||
|
||||
static int wp_serialized_size(WordProcessorState* wp) {
|
||||
int size = 4 + 2 + 1 + 1 + 1 + 2 + 2;
|
||||
for (int i = 0; i < wp->run_count; i++)
|
||||
|
||||
@@ -5,14 +5,15 @@
|
||||
*/
|
||||
|
||||
#include "wordprocessor.hpp"
|
||||
#include <gui/dialogs.hpp>
|
||||
|
||||
static void wp_open_pathbar_for_open(WordProcessorState* wp) {
|
||||
wp->show_pathbar = !wp->show_pathbar;
|
||||
wp->pathbar_save_mode = false;
|
||||
if (wp->show_pathbar) {
|
||||
montauk::strncpy(wp->pathbar_text, wp->filepath, 255);
|
||||
wp->pathbar_len = montauk::slen(wp->pathbar_text);
|
||||
wp->pathbar_cursor = wp->pathbar_len;
|
||||
char path[256] = {};
|
||||
char msg[160] = {};
|
||||
if (dialogs::open_file("Open Document", wp->filepath, path, sizeof(path), msg, sizeof(msg))) {
|
||||
wp_load_file(wp, path);
|
||||
} else if (msg[0]) {
|
||||
wp_start_pathbar(wp, false, wp->filepath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -346,6 +346,7 @@ int wp_wrap_line_start(WordProcessorState* wp, int line_idx);
|
||||
void wp_ensure_cursor_visible(WordProcessorState* wp, int view_h);
|
||||
|
||||
void wp_set_filepath(WordProcessorState* wp, const char* path);
|
||||
void wp_start_pathbar(WordProcessorState* wp, bool save_mode, const char* initial_text);
|
||||
void wp_open_save_pathbar(WordProcessorState* wp);
|
||||
void wp_save_file(WordProcessorState* wp);
|
||||
void wp_load_file(WordProcessorState* wp, const char* path);
|
||||
|
||||
Reference in New Issue
Block a user