feat: message box dynamic sizing, documentation page updates
This commit is contained in:
@@ -87,11 +87,6 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="introduction.html">Introduction</a></li>
|
<li><a href="introduction.html">Introduction</a></li>
|
||||||
<li><a href="#">Kernel</a></li>
|
|
||||||
<li><a href="#">Userspace</a></li>
|
|
||||||
<li><a href="#">Applications</a></li>
|
|
||||||
<li><a href="#">Building</a></li>
|
|
||||||
<li><a href="#">Contributing</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -114,6 +109,10 @@ operating system, its components, and how to use and develop for it.
|
|||||||
<a href="introduction.html">Introduction</a>
|
<a href="introduction.html">Introduction</a>
|
||||||
<p>Installation, running on emulator, and your first steps with MontaukOS.</p>
|
<p>Installation, running on emulator, and your first steps with MontaukOS.</p>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="dtinternals/dialogslib.html">Dialogs Library</a>
|
||||||
|
<p>Desktop internals: file, print, and message box dialogs exposed through the shared dialogs library.</p>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="#">Kernel Architecture</a>
|
<a href="#">Kernel Architecture</a>
|
||||||
<p>Overview of the preemptive multitasking kernel and its subsystems.</p>
|
<p>Overview of the preemptive multitasking kernel and its subsystems.</p>
|
||||||
@@ -130,10 +129,6 @@ operating system, its components, and how to use and develop for it.
|
|||||||
<a href="#">Building from Source</a>
|
<a href="#">Building from Source</a>
|
||||||
<p>How to compile and build MontaukOS yourself.</p>
|
<p>How to compile and build MontaukOS yourself.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<a href="#">Contributing</a>
|
|
||||||
<p>Guidelines for contributing to the project.</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|||||||
@@ -73,11 +73,6 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="introduction.html" class="current">Introduction</a></li>
|
<li><a href="introduction.html" class="current">Introduction</a></li>
|
||||||
<li><a href="#">Kernel</a></li>
|
|
||||||
<li><a href="#">Userspace</a></li>
|
|
||||||
<li><a href="#">Applications</a></li>
|
|
||||||
<li><a href="#">Building</a></li>
|
|
||||||
<li><a href="#">Contributing</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -166,7 +166,11 @@ extern "C" uint8_t dialogs_message_box(const char* title,
|
|||||||
const char* window_title = title && title[0] ? title : "Message";
|
const char* window_title = title && title[0] ? title : "Message";
|
||||||
messagebox::init(message ? message : "", buttons);
|
messagebox::init(message ? message : "", buttons);
|
||||||
|
|
||||||
if (!g_app.win.create(window_title, messagebox::MESSAGE_INIT_W, messagebox::MESSAGE_INIT_H)) {
|
int init_w = 0;
|
||||||
|
int init_h = 0;
|
||||||
|
messagebox::preferred_size(window_title, &init_w, &init_h);
|
||||||
|
|
||||||
|
if (!g_app.win.create(window_title, init_w, init_h)) {
|
||||||
cleanup();
|
cleanup();
|
||||||
return dlg::MESSAGE_BOX_RESULT_NONE;
|
return dlg::MESSAGE_BOX_RESULT_NONE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,6 +210,48 @@ bool is_space(char ch) {
|
|||||||
return ch == ' ' || ch == '\t' || ch == '\r';
|
return ch == ' ' || ch == '\t' || ch == '\r';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int clamp_int(int value, int min_value, int max_value) {
|
||||||
|
if (value < min_value) return min_value;
|
||||||
|
if (value > max_value) return max_value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int button_row_width(const MessageBoxState* st) {
|
||||||
|
if (!st || st->button_count <= 0) return 0;
|
||||||
|
int total_w = st->button_count * messagebox::BUTTON_W;
|
||||||
|
if (st->button_count > 1)
|
||||||
|
total_w += (st->button_count - 1) * messagebox::BUTTON_GAP;
|
||||||
|
return total_w;
|
||||||
|
}
|
||||||
|
|
||||||
|
int widest_explicit_message_line(const MessageBoxState* st, int max_px) {
|
||||||
|
if (!st || !st->text[0]) return 0;
|
||||||
|
|
||||||
|
char line[messagebox::MAX_LINE_LEN] = {};
|
||||||
|
int line_len = 0;
|
||||||
|
int widest = 0;
|
||||||
|
|
||||||
|
for (const char* p = st->text; ; p++) {
|
||||||
|
char ch = *p;
|
||||||
|
bool at_end = ch == '\0';
|
||||||
|
if (at_end || ch == '\n') {
|
||||||
|
line[line_len] = '\0';
|
||||||
|
int width = text_width(line);
|
||||||
|
if (width > widest) widest = width;
|
||||||
|
line_len = 0;
|
||||||
|
line[0] = '\0';
|
||||||
|
if (at_end) break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line_len >= messagebox::MAX_LINE_LEN - 1)
|
||||||
|
return max_px;
|
||||||
|
line[line_len++] = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
return widest > max_px ? max_px : widest;
|
||||||
|
}
|
||||||
|
|
||||||
void wrap_message(MessageBoxState* st, int max_px) {
|
void wrap_message(MessageBoxState* st, int max_px) {
|
||||||
if (!st) return;
|
if (!st) return;
|
||||||
if (max_px < 40) max_px = 40;
|
if (max_px < 40) max_px = 40;
|
||||||
@@ -267,11 +309,12 @@ MessageBoxLayout message_layout(const MessageBoxState* st) {
|
|||||||
lo.button_count = st ? st->button_count : 0;
|
lo.button_count = st ? st->button_count : 0;
|
||||||
lo.footer_rect = {0, g_app.win.height - messagebox::FOOTER_H, g_app.win.width, messagebox::FOOTER_H};
|
lo.footer_rect = {0, g_app.win.height - messagebox::FOOTER_H, g_app.win.width, messagebox::FOOTER_H};
|
||||||
|
|
||||||
lo.text_rect = {20, 24, g_app.win.width - 40, lo.footer_rect.y - 32};
|
lo.text_rect = {messagebox::TEXT_X, messagebox::TEXT_Y,
|
||||||
|
g_app.win.width - messagebox::TEXT_X * 2,
|
||||||
|
lo.footer_rect.y - messagebox::TEXT_Y - messagebox::TEXT_BOTTOM_GAP};
|
||||||
|
|
||||||
int total_w = lo.button_count * messagebox::BUTTON_W;
|
int total_w = button_row_width(st);
|
||||||
if (lo.button_count > 1) total_w += (lo.button_count - 1) * messagebox::BUTTON_GAP;
|
int x = g_app.win.width - messagebox::BUTTON_RIGHT_PAD - total_w;
|
||||||
int x = g_app.win.width - 16 - total_w;
|
|
||||||
int y = lo.footer_rect.y + (messagebox::FOOTER_H - messagebox::BUTTON_H) / 2;
|
int y = lo.footer_rect.y + (messagebox::FOOTER_H - messagebox::BUTTON_H) / 2;
|
||||||
for (int i = 0; i < lo.button_count && i < messagebox::MAX_BUTTONS; i++) {
|
for (int i = 0; i < lo.button_count && i < messagebox::MAX_BUTTONS; i++) {
|
||||||
lo.buttons[i] = {x, y, messagebox::BUTTON_W, messagebox::BUTTON_H};
|
lo.buttons[i] = {x, y, messagebox::BUTTON_W, messagebox::BUTTON_H};
|
||||||
@@ -387,7 +430,34 @@ void init(const char* message, uint8_t buttons, uint8_t default_choice) {
|
|||||||
configure_buttons(st);
|
configure_buttons(st);
|
||||||
if (!has_choice(st, st->default_choice))
|
if (!has_choice(st, st->default_choice))
|
||||||
st->default_choice = default_choice_for(st->buttons);
|
st->default_choice = default_choice_for(st->buttons);
|
||||||
wrap_message(st, MESSAGE_INIT_W - 40);
|
wrap_message(st, messagebox::MESSAGE_MIN_W - messagebox::TEXT_X * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferred_size(const char* title, int* out_w, int* out_h) {
|
||||||
|
MessageBoxState* st = &g_message;
|
||||||
|
|
||||||
|
int max_text_w = messagebox::MESSAGE_MAX_W - messagebox::TEXT_X * 2;
|
||||||
|
int desired_text_w = widest_explicit_message_line(st, max_text_w);
|
||||||
|
if (title && title[0]) {
|
||||||
|
int title_w = text_width(title) + 120;
|
||||||
|
if (title_w > desired_text_w) desired_text_w = title_w;
|
||||||
|
}
|
||||||
|
|
||||||
|
int desired_w = desired_text_w + messagebox::TEXT_X * 2;
|
||||||
|
int buttons_w = button_row_width(st) + messagebox::BUTTON_RIGHT_PAD * 2;
|
||||||
|
if (buttons_w > desired_w) desired_w = buttons_w;
|
||||||
|
desired_w = clamp_int(desired_w, messagebox::MESSAGE_MIN_W, messagebox::MESSAGE_MAX_W);
|
||||||
|
|
||||||
|
wrap_message(st, desired_w - messagebox::TEXT_X * 2);
|
||||||
|
|
||||||
|
int line_h = system_font_height() + 5;
|
||||||
|
int text_h = st->line_count > 0 ? st->line_count * line_h : line_h;
|
||||||
|
int desired_h = messagebox::TEXT_Y + text_h + messagebox::TEXT_BOTTOM_GAP +
|
||||||
|
messagebox::FOOTER_H;
|
||||||
|
desired_h = clamp_int(desired_h, messagebox::MESSAGE_MIN_H, messagebox::MESSAGE_MAX_H);
|
||||||
|
|
||||||
|
if (out_w) *out_w = desired_w;
|
||||||
|
if (out_h) *out_h = desired_h;
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw() {
|
void draw() {
|
||||||
|
|||||||
@@ -19,9 +19,15 @@ struct MessageBoxLayout {
|
|||||||
|
|
||||||
namespace messagebox {
|
namespace messagebox {
|
||||||
|
|
||||||
constexpr int MESSAGE_INIT_W = 460;
|
constexpr int MESSAGE_MIN_W = 300;
|
||||||
constexpr int MESSAGE_INIT_H = 220;
|
constexpr int MESSAGE_MAX_W = 560;
|
||||||
|
constexpr int MESSAGE_MIN_H = 124;
|
||||||
|
constexpr int MESSAGE_MAX_H = 280;
|
||||||
constexpr int FOOTER_H = 56;
|
constexpr int FOOTER_H = 56;
|
||||||
|
constexpr int TEXT_X = 20;
|
||||||
|
constexpr int TEXT_Y = 24;
|
||||||
|
constexpr int TEXT_BOTTOM_GAP = 24;
|
||||||
|
constexpr int BUTTON_RIGHT_PAD = 16;
|
||||||
constexpr int BUTTON_W = 88;
|
constexpr int BUTTON_W = 88;
|
||||||
constexpr int BUTTON_H = 30;
|
constexpr int BUTTON_H = 30;
|
||||||
constexpr int BUTTON_GAP = 8;
|
constexpr int BUTTON_GAP = 8;
|
||||||
@@ -30,6 +36,7 @@ constexpr int MAX_LINES = 7;
|
|||||||
constexpr int MAX_LINE_LEN = 128;
|
constexpr int MAX_LINE_LEN = 128;
|
||||||
|
|
||||||
void init(const char* message, uint8_t buttons, uint8_t default_choice = 0);
|
void init(const char* message, uint8_t buttons, uint8_t default_choice = 0);
|
||||||
|
void preferred_size(const char* title, int* out_w, int* out_h);
|
||||||
void draw();
|
void draw();
|
||||||
void handle_mouse(const Montauk::WinEvent& ev);
|
void handle_mouse(const Montauk::WinEvent& ev);
|
||||||
void handle_key(const Montauk::KeyEvent& key);
|
void handle_key(const Montauk::KeyEvent& key);
|
||||||
|
|||||||
@@ -8,8 +8,13 @@
|
|||||||
#include <gui/dialogs.hpp>
|
#include <gui/dialogs.hpp>
|
||||||
|
|
||||||
extern "C" void _start() {
|
extern "C" void _start() {
|
||||||
gui::dialogs::message_box("Test Dialogs",
|
auto result = gui::dialogs::message_box(
|
||||||
"Hello from libdialogs::message_box.",
|
"Close Document",
|
||||||
gui::dialogs::MESSAGE_BOX_OK);
|
"Discard unsaved changes?",
|
||||||
|
gui::dialogs::MESSAGE_BOX_YES_NO_CANCEL);
|
||||||
|
|
||||||
|
if (result == gui::dialogs::MESSAGE_BOX_RESULT_YES) {
|
||||||
|
/* discard and close */
|
||||||
|
}
|
||||||
montauk::exit(0);
|
montauk::exit(0);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user