|
|
|
@@ -1,6 +1,6 @@
|
|
|
|
|
/*
|
|
|
|
|
* main.cpp
|
|
|
|
|
* MontaukOS Time Zone configuration app
|
|
|
|
|
* MontaukOS Time configuration app
|
|
|
|
|
* Copyright (c) 2026 Daniel Hammer
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
@@ -8,6 +8,7 @@
|
|
|
|
|
#include <montauk/heap.h>
|
|
|
|
|
#include <montauk/string.h>
|
|
|
|
|
#include <montauk/syscall.h>
|
|
|
|
|
#include <montauk/ntp.h>
|
|
|
|
|
#include <gui/gui.hpp>
|
|
|
|
|
#include <gui/canvas.hpp>
|
|
|
|
|
#include <gui/mtk.hpp>
|
|
|
|
@@ -23,13 +24,25 @@ using namespace gui;
|
|
|
|
|
|
|
|
|
|
static constexpr int INIT_W = 640;
|
|
|
|
|
static constexpr int INIT_H = 460;
|
|
|
|
|
static constexpr int HEADER_H = 14;
|
|
|
|
|
static constexpr int TAB_H = 36;
|
|
|
|
|
static constexpr int FOOTER_H = 58;
|
|
|
|
|
static constexpr int PAD = 16;
|
|
|
|
|
static constexpr int GAP = 12;
|
|
|
|
|
static constexpr int LABEL_H = 24;
|
|
|
|
|
static constexpr int ROW_H = 30;
|
|
|
|
|
static constexpr int MAX_COUNTRIES = 320;
|
|
|
|
|
static constexpr int NTP_SERVER_CAP = 128;
|
|
|
|
|
|
|
|
|
|
enum Tab {
|
|
|
|
|
TAB_TIME_ZONES = 0,
|
|
|
|
|
TAB_NTP = 1,
|
|
|
|
|
TAB_COUNT = 2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char* const kTabLabels[TAB_COUNT] = {
|
|
|
|
|
"Time Zones",
|
|
|
|
|
"NTP",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CountryEntry {
|
|
|
|
|
char key[64]; // Full TOML table key, e.g. countries.NO
|
|
|
|
@@ -43,6 +56,7 @@ struct CountryEntry {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static WsWindow g_win;
|
|
|
|
|
static Tab g_tab = TAB_TIME_ZONES;
|
|
|
|
|
static montauk::toml::Doc g_data;
|
|
|
|
|
static bool g_data_loaded = false;
|
|
|
|
|
static CountryEntry g_countries[MAX_COUNTRIES];
|
|
|
|
@@ -60,10 +74,20 @@ static int g_focus_pane = 0; // 0=country list, 1=zone list
|
|
|
|
|
static int g_mouse_x = -1;
|
|
|
|
|
static int g_mouse_y = -1;
|
|
|
|
|
static bool g_dirty = false;
|
|
|
|
|
static char g_ntp_server[NTP_SERVER_CAP] = "pool.ntp.org";
|
|
|
|
|
static char g_saved_ntp_server[NTP_SERVER_CAP] = "pool.ntp.org";
|
|
|
|
|
static mtk::TextInputState g_ntp_input = {};
|
|
|
|
|
static bool g_ntp_enabled = true;
|
|
|
|
|
static bool g_saved_ntp_enabled = true;
|
|
|
|
|
static bool g_ntp_dirty = false;
|
|
|
|
|
static bool g_ntp_syncing = false;
|
|
|
|
|
static uint64_t g_last_clock_render = 0;
|
|
|
|
|
static char g_status[160] = {};
|
|
|
|
|
static uint64_t g_status_time = 0;
|
|
|
|
|
static Color g_accent = colors::ACCENT;
|
|
|
|
|
|
|
|
|
|
static void render();
|
|
|
|
|
|
|
|
|
|
static void safe_copy(char* dst, int cap, const char* src) {
|
|
|
|
|
montauk::strncpy(dst, src ? src : "", cap);
|
|
|
|
|
}
|
|
|
|
@@ -217,8 +241,8 @@ static void clamp_scrolls() {
|
|
|
|
|
Rect country_list = {};
|
|
|
|
|
Rect zone_list = {};
|
|
|
|
|
int left_w = gui_min(250, (g_win.width - PAD * 2 - GAP) / 2);
|
|
|
|
|
int list_y = HEADER_H + LABEL_H;
|
|
|
|
|
int list_h = gui_max(g_win.height - HEADER_H - FOOTER_H - LABEL_H - PAD, ROW_H);
|
|
|
|
|
int list_y = TAB_H + LABEL_H;
|
|
|
|
|
int list_h = gui_max(g_win.height - TAB_H - FOOTER_H - LABEL_H - PAD, ROW_H);
|
|
|
|
|
country_list = {PAD, list_y, left_w, list_h};
|
|
|
|
|
zone_list = {PAD + left_w + GAP, list_y,
|
|
|
|
|
g_win.width - PAD * 2 - GAP - left_w, list_h};
|
|
|
|
@@ -235,8 +259,8 @@ static void clamp_scrolls() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ensure_country_visible() {
|
|
|
|
|
Rect list = {PAD, HEADER_H + LABEL_H, 250,
|
|
|
|
|
gui_max(g_win.height - HEADER_H - FOOTER_H - LABEL_H - PAD, ROW_H)};
|
|
|
|
|
Rect list = {PAD, TAB_H + LABEL_H, 250,
|
|
|
|
|
gui_max(g_win.height - TAB_H - FOOTER_H - LABEL_H - PAD, ROW_H)};
|
|
|
|
|
int rows = visible_rows(list);
|
|
|
|
|
if (g_selected_country < g_country_scroll)
|
|
|
|
|
g_country_scroll = g_selected_country;
|
|
|
|
@@ -246,9 +270,9 @@ static void ensure_country_visible() {
|
|
|
|
|
|
|
|
|
|
static void ensure_zone_visible() {
|
|
|
|
|
int left_w = gui_min(250, (g_win.width - PAD * 2 - GAP) / 2);
|
|
|
|
|
Rect list = {PAD + left_w + GAP, HEADER_H + LABEL_H,
|
|
|
|
|
Rect list = {PAD + left_w + GAP, TAB_H + LABEL_H,
|
|
|
|
|
g_win.width - PAD * 2 - GAP - left_w,
|
|
|
|
|
gui_max(g_win.height - HEADER_H - FOOTER_H - LABEL_H - PAD, ROW_H)};
|
|
|
|
|
gui_max(g_win.height - TAB_H - FOOTER_H - LABEL_H - PAD, ROW_H)};
|
|
|
|
|
int rows = visible_rows(list);
|
|
|
|
|
if (g_selected_zone < g_zone_scroll)
|
|
|
|
|
g_zone_scroll = g_selected_zone;
|
|
|
|
@@ -357,6 +381,73 @@ static void load_saved_selection() {
|
|
|
|
|
clamp_scrolls();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void load_ntp_settings() {
|
|
|
|
|
auto cfg = montauk::config::load("ntp");
|
|
|
|
|
g_ntp_enabled = cfg.get_bool("ntp.enabled", true);
|
|
|
|
|
safe_copy(g_ntp_server, sizeof(g_ntp_server),
|
|
|
|
|
cfg.get_string("ntp.server", "pool.ntp.org"));
|
|
|
|
|
cfg.destroy();
|
|
|
|
|
if (!g_ntp_server[0])
|
|
|
|
|
safe_copy(g_ntp_server, sizeof(g_ntp_server), "pool.ntp.org");
|
|
|
|
|
safe_copy(g_saved_ntp_server, sizeof(g_saved_ntp_server), g_ntp_server);
|
|
|
|
|
g_saved_ntp_enabled = g_ntp_enabled;
|
|
|
|
|
g_ntp_dirty = false;
|
|
|
|
|
mtk::text_input_reset(g_ntp_input, montauk::slen(g_ntp_server));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool ntp_settings_changed() {
|
|
|
|
|
return g_ntp_enabled != g_saved_ntp_enabled ||
|
|
|
|
|
!montauk::streq(g_ntp_server, g_saved_ntp_server);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void save_ntp_settings() {
|
|
|
|
|
if (!g_ntp_server[0]) {
|
|
|
|
|
set_status("Enter an NTP server");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto cfg = montauk::config::load("ntp");
|
|
|
|
|
montauk::config::set_bool(&cfg, "ntp.enabled", g_ntp_enabled);
|
|
|
|
|
montauk::config::set_string(&cfg, "ntp.server", g_ntp_server);
|
|
|
|
|
int result = montauk::config::save("ntp", &cfg);
|
|
|
|
|
cfg.destroy();
|
|
|
|
|
if (result < 0) {
|
|
|
|
|
set_status("Could not save NTP settings");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
safe_copy(g_saved_ntp_server, sizeof(g_saved_ntp_server), g_ntp_server);
|
|
|
|
|
g_saved_ntp_enabled = g_ntp_enabled;
|
|
|
|
|
g_ntp_dirty = false;
|
|
|
|
|
set_status("NTP settings saved");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void revert_ntp_settings() {
|
|
|
|
|
safe_copy(g_ntp_server, sizeof(g_ntp_server), g_saved_ntp_server);
|
|
|
|
|
g_ntp_enabled = g_saved_ntp_enabled;
|
|
|
|
|
g_ntp_dirty = false;
|
|
|
|
|
mtk::text_input_reset(g_ntp_input, montauk::slen(g_ntp_server));
|
|
|
|
|
set_status("NTP changes reverted");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ntp_progress(const char* message) {
|
|
|
|
|
set_status(message);
|
|
|
|
|
render();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void synchronize_ntp() {
|
|
|
|
|
if (g_ntp_syncing) return;
|
|
|
|
|
if (!g_ntp_server[0]) {
|
|
|
|
|
set_status("Enter an NTP server");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
g_ntp_syncing = true;
|
|
|
|
|
int result = montauk::ntp::synchronize(g_ntp_server, 5000, nullptr,
|
|
|
|
|
ntp_progress);
|
|
|
|
|
g_ntp_syncing = false;
|
|
|
|
|
set_status(montauk::ntp::result_string(result));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fit_text(char* out, int cap, const char* text, int max_w) {
|
|
|
|
|
safe_copy(out, cap, text);
|
|
|
|
|
if (text_width(out) <= max_w) return;
|
|
|
|
@@ -482,8 +573,8 @@ static void revert_selection() {
|
|
|
|
|
|
|
|
|
|
static Rect country_list_rect() {
|
|
|
|
|
int left_w = gui_min(250, (g_win.width - PAD * 2 - GAP) / 2);
|
|
|
|
|
return {PAD, HEADER_H + LABEL_H, left_w,
|
|
|
|
|
gui_max(g_win.height - HEADER_H - FOOTER_H - LABEL_H - PAD, ROW_H)};
|
|
|
|
|
return {PAD, TAB_H + LABEL_H, left_w,
|
|
|
|
|
gui_max(g_win.height - TAB_H - FOOTER_H - LABEL_H - PAD, ROW_H)};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Rect zone_list_rect() {
|
|
|
|
@@ -500,6 +591,30 @@ static Rect revert_button_rect() {
|
|
|
|
|
return {g_win.width - PAD - 104 - GAP - 92, g_win.height - FOOTER_H + 14, 92, 30};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Rect tab_bar_rect() {
|
|
|
|
|
return {0, 0, g_win.width, TAB_H};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ntp_server_field_y() {
|
|
|
|
|
return TAB_H + 24;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Rect ntp_server_input_rect() {
|
|
|
|
|
return mtk::labeled_text_input_rect(PAD, ntp_server_field_y(),
|
|
|
|
|
g_win.width - PAD * 2,
|
|
|
|
|
app_theme(), 34);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Rect ntp_enabled_rect() {
|
|
|
|
|
Rect input = ntp_server_input_rect();
|
|
|
|
|
return {PAD, input.y + input.h + 18, g_win.width - PAD * 2, 28};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Rect ntp_sync_button_rect() {
|
|
|
|
|
Rect revert = revert_button_rect();
|
|
|
|
|
return {revert.x - GAP - 112, revert.y, 112, revert.h};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool mouse_in_rect(const Rect& rect) {
|
|
|
|
|
return rect.contains(g_mouse_x, g_mouse_y);
|
|
|
|
|
}
|
|
|
|
@@ -644,50 +759,92 @@ static void draw_details(Canvas& canvas, const mtk::Theme& theme) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void draw_ntp_tab(Canvas& canvas, const mtk::Theme& theme) {
|
|
|
|
|
int field_y = ntp_server_field_y();
|
|
|
|
|
mtk::draw_labeled_text_field(canvas, PAD, field_y, g_win.width - PAD * 2,
|
|
|
|
|
"NTP Server", g_ntp_server,
|
|
|
|
|
g_ntp_input.cursor, true, false, theme, 34,
|
|
|
|
|
g_ntp_input.selection_anchor);
|
|
|
|
|
|
|
|
|
|
Rect enabled = ntp_enabled_rect();
|
|
|
|
|
mtk::draw_checkbox(canvas, enabled, "Synchronize time automatically",
|
|
|
|
|
mtk::check_state(g_ntp_enabled), theme, true,
|
|
|
|
|
enabled.contains(g_mouse_x, g_mouse_y));
|
|
|
|
|
|
|
|
|
|
canvas.text(PAD, enabled.y + enabled.h + 10,
|
|
|
|
|
"MontaukOS will synchronize at startup and periodically while enabled.",
|
|
|
|
|
theme.text_subtle);
|
|
|
|
|
|
|
|
|
|
montauk::abi::DateTime now = {};
|
|
|
|
|
montauk::gettime(&now);
|
|
|
|
|
char current[96];
|
|
|
|
|
snprintf(current, sizeof(current), "Current system time: %04u-%02u-%02u %02u:%02u:%02u",
|
|
|
|
|
(unsigned)now.Year, (unsigned)now.Month, (unsigned)now.Day,
|
|
|
|
|
(unsigned)now.Hour, (unsigned)now.Minute, (unsigned)now.Second);
|
|
|
|
|
int explanation_y = enabled.y + enabled.h + 10;
|
|
|
|
|
canvas.text(PAD, explanation_y + system_font_height() + 24,
|
|
|
|
|
current, theme.text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void render() {
|
|
|
|
|
mtk::StandaloneHost host(&g_win);
|
|
|
|
|
Canvas canvas = host.canvas();
|
|
|
|
|
mtk::Theme theme = app_theme();
|
|
|
|
|
|
|
|
|
|
canvas.fill(theme.window_bg);
|
|
|
|
|
mtk::draw_tab_bar(canvas, tab_bar_rect(), kTabLabels, TAB_COUNT,
|
|
|
|
|
(int)g_tab, theme);
|
|
|
|
|
|
|
|
|
|
if (g_country_count <= 0) {
|
|
|
|
|
canvas.text(PAD, HEADER_H + 24,
|
|
|
|
|
"No time zone data was found in 0:/config/timezonedata.toml",
|
|
|
|
|
theme.danger);
|
|
|
|
|
host.present();
|
|
|
|
|
return;
|
|
|
|
|
if (g_tab == TAB_TIME_ZONES) {
|
|
|
|
|
if (g_country_count <= 0) {
|
|
|
|
|
canvas.text(PAD, TAB_H + 24,
|
|
|
|
|
"No time zone data was found in 0:/config/timezonedata.toml",
|
|
|
|
|
theme.danger);
|
|
|
|
|
} else {
|
|
|
|
|
Rect country = country_list_rect();
|
|
|
|
|
Rect zone = zone_list_rect();
|
|
|
|
|
canvas.text(country.x, TAB_H + 6, "Country", theme.text_subtle);
|
|
|
|
|
canvas.text(zone.x, TAB_H + 6, "Time Zone", theme.text_subtle);
|
|
|
|
|
draw_country_list(canvas, country, theme);
|
|
|
|
|
draw_zone_list(canvas, zone, theme);
|
|
|
|
|
draw_details(canvas, theme);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
draw_ntp_tab(canvas, theme);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Rect country = country_list_rect();
|
|
|
|
|
Rect zone = zone_list_rect();
|
|
|
|
|
|
|
|
|
|
canvas.text(country.x, HEADER_H + 6, "Country", theme.text_subtle);
|
|
|
|
|
canvas.text(zone.x, HEADER_H + 6, "Time Zone", theme.text_subtle);
|
|
|
|
|
|
|
|
|
|
draw_country_list(canvas, country, theme);
|
|
|
|
|
draw_zone_list(canvas, zone, theme);
|
|
|
|
|
draw_details(canvas, theme);
|
|
|
|
|
|
|
|
|
|
Rect footer = {0, g_win.height - FOOTER_H, g_win.width, FOOTER_H};
|
|
|
|
|
canvas.fill_rect(footer.x, footer.y, footer.w, footer.h, theme.surface);
|
|
|
|
|
mtk::draw_separator(canvas, 0, footer.y, g_win.width, theme);
|
|
|
|
|
|
|
|
|
|
const char* footer_text = status_visible()
|
|
|
|
|
? g_status
|
|
|
|
|
: (g_dirty ? "Unsaved time zone selection" : "Selection saved");
|
|
|
|
|
int max_footer_text = revert_button_rect().x - PAD - GAP;
|
|
|
|
|
bool dirty = g_tab == TAB_TIME_ZONES ? g_dirty : g_ntp_dirty;
|
|
|
|
|
const char* footer_text = status_visible() ? g_status :
|
|
|
|
|
(g_tab == TAB_TIME_ZONES
|
|
|
|
|
? (g_dirty ? "Unsaved time zone selection" : "Selection saved")
|
|
|
|
|
: (g_ntp_dirty ? "Unsaved NTP changes" : "NTP settings ready"));
|
|
|
|
|
int max_footer_text = (g_tab == TAB_NTP ? ntp_sync_button_rect().x
|
|
|
|
|
: revert_button_rect().x) - PAD - GAP;
|
|
|
|
|
char footer_label[160];
|
|
|
|
|
fit_text(footer_label, sizeof(footer_label), footer_text, max_footer_text);
|
|
|
|
|
canvas.text(PAD, footer.y + (FOOTER_H - system_font_height()) / 2,
|
|
|
|
|
footer_label, g_dirty ? theme.text : theme.text_subtle);
|
|
|
|
|
footer_label, dirty ? theme.text : theme.text_subtle);
|
|
|
|
|
|
|
|
|
|
Rect revert = revert_button_rect();
|
|
|
|
|
Rect apply = apply_button_rect();
|
|
|
|
|
mtk::draw_button(canvas, revert, "Revert", mtk::BUTTON_SECONDARY,
|
|
|
|
|
button_state(revert, g_dirty), theme);
|
|
|
|
|
button_state(revert, dirty), theme);
|
|
|
|
|
mtk::draw_button(canvas, apply, "Apply", mtk::BUTTON_PRIMARY,
|
|
|
|
|
button_state(apply, g_dirty), theme);
|
|
|
|
|
button_state(apply, dirty), theme);
|
|
|
|
|
if (g_tab == TAB_NTP) {
|
|
|
|
|
Rect sync = ntp_sync_button_rect();
|
|
|
|
|
mtk::draw_button(canvas, sync, g_ntp_syncing ? "Syncing..." : "Sync Now",
|
|
|
|
|
mtk::BUTTON_PRIMARY,
|
|
|
|
|
button_state(sync, !g_ntp_syncing), theme);
|
|
|
|
|
mtk::draw_text_input_context_menu(
|
|
|
|
|
canvas, g_ntp_input, theme,
|
|
|
|
|
mtk::text_input_has_selection(g_ntp_input, g_ntp_server,
|
|
|
|
|
(int)sizeof(g_ntp_server)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
host.present();
|
|
|
|
|
}
|
|
|
|
@@ -698,6 +855,55 @@ static bool handle_mouse(const montauk::abi::WinEvent& ev) {
|
|
|
|
|
g_mouse_x = ev.mouse.x;
|
|
|
|
|
g_mouse_y = ev.mouse.y;
|
|
|
|
|
|
|
|
|
|
bool clicked = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1);
|
|
|
|
|
bool right_clicked = (ev.mouse.buttons & 2) && !(ev.mouse.prev_buttons & 2);
|
|
|
|
|
if (clicked) {
|
|
|
|
|
int tab = mtk::hit_tab_bar(tab_bar_rect(), TAB_COUNT,
|
|
|
|
|
g_mouse_x, g_mouse_y);
|
|
|
|
|
if (tab >= 0) {
|
|
|
|
|
g_tab = (Tab)tab;
|
|
|
|
|
mtk::context_menu_close(g_ntp_input.context);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_tab == TAB_NTP) {
|
|
|
|
|
Rect input = ntp_server_input_rect();
|
|
|
|
|
if (g_ntp_input.context.open || g_ntp_input.dragging ||
|
|
|
|
|
input.contains(g_mouse_x, g_mouse_y)) {
|
|
|
|
|
int result = mtk::text_input_handle_mouse(
|
|
|
|
|
g_ntp_input, input, g_ntp_server, (int)sizeof(g_ntp_server),
|
|
|
|
|
g_mouse_x, g_mouse_y, ev.mouse.buttons, ev.mouse.prev_buttons,
|
|
|
|
|
g_win.width, g_win.height, true);
|
|
|
|
|
if (result & mtk::TEXT_INPUT_CHANGED) {
|
|
|
|
|
g_ntp_dirty = ntp_settings_changed();
|
|
|
|
|
}
|
|
|
|
|
if (result != mtk::TEXT_INPUT_NONE) return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!clicked && !right_clicked)
|
|
|
|
|
return true;
|
|
|
|
|
if (clicked && ntp_enabled_rect().contains(g_mouse_x, g_mouse_y)) {
|
|
|
|
|
g_ntp_enabled = !g_ntp_enabled;
|
|
|
|
|
g_ntp_dirty = ntp_settings_changed();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (clicked && !g_ntp_syncing &&
|
|
|
|
|
ntp_sync_button_rect().contains(g_mouse_x, g_mouse_y)) {
|
|
|
|
|
synchronize_ntp();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (clicked && revert_button_rect().contains(g_mouse_x, g_mouse_y)) {
|
|
|
|
|
if (g_ntp_dirty) revert_ntp_settings();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (clicked && apply_button_rect().contains(g_mouse_x, g_mouse_y)) {
|
|
|
|
|
if (g_ntp_dirty) save_ntp_settings();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Rect country = country_list_rect();
|
|
|
|
|
Rect zone = zone_list_rect();
|
|
|
|
|
Rect revert = revert_button_rect();
|
|
|
|
@@ -745,7 +951,6 @@ static bool handle_mouse(const montauk::abi::WinEvent& ev) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool clicked = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1);
|
|
|
|
|
if (!clicked) return redraw;
|
|
|
|
|
|
|
|
|
|
if (!csb_track.empty() && csb_track.contains(g_mouse_x, g_mouse_y)) {
|
|
|
|
@@ -804,7 +1009,31 @@ static bool handle_mouse(const montauk::abi::WinEvent& ev) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool handle_key(const montauk::abi::KeyEvent& key) {
|
|
|
|
|
if (!key.pressed || g_country_count <= 0) return false;
|
|
|
|
|
if (!key.pressed) return false;
|
|
|
|
|
|
|
|
|
|
if (key.ascii == '\t') {
|
|
|
|
|
g_tab = g_tab == TAB_TIME_ZONES ? TAB_NTP : TAB_TIME_ZONES;
|
|
|
|
|
mtk::context_menu_close(g_ntp_input.context);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_tab == TAB_NTP) {
|
|
|
|
|
if (key.ascii == '\n' || key.ascii == '\r') {
|
|
|
|
|
synchronize_ntp();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (key.ascii == '\033') {
|
|
|
|
|
if (g_ntp_dirty) revert_ntp_settings();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
int result = mtk::text_input_key(g_ntp_input, g_ntp_server,
|
|
|
|
|
(int)sizeof(g_ntp_server), key);
|
|
|
|
|
if (result & mtk::TEXT_INPUT_CHANGED)
|
|
|
|
|
g_ntp_dirty = ntp_settings_changed();
|
|
|
|
|
return (result & mtk::TEXT_INPUT_CONSUMED) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_country_count <= 0) return false;
|
|
|
|
|
|
|
|
|
|
if (key.ascii == '\n' || key.ascii == '\r') {
|
|
|
|
|
if (g_dirty) save_selection();
|
|
|
|
@@ -851,10 +1080,11 @@ extern "C" void _start() {
|
|
|
|
|
load_accent();
|
|
|
|
|
load_timezone_data();
|
|
|
|
|
|
|
|
|
|
if (!g_win.create("Time Zone", INIT_W, INIT_H))
|
|
|
|
|
if (!g_win.create("Time", INIT_W, INIT_H))
|
|
|
|
|
montauk::exit(1);
|
|
|
|
|
|
|
|
|
|
load_saved_selection();
|
|
|
|
|
load_ntp_settings();
|
|
|
|
|
render();
|
|
|
|
|
|
|
|
|
|
while (g_win.id >= 0 && !g_win.closed) {
|
|
|
|
@@ -864,6 +1094,11 @@ extern "C" void _start() {
|
|
|
|
|
|
|
|
|
|
if (r < 0) break;
|
|
|
|
|
if (r == 0) {
|
|
|
|
|
uint64_t now = montauk::get_milliseconds();
|
|
|
|
|
if (g_tab == TAB_NTP && now - g_last_clock_render >= 1000) {
|
|
|
|
|
g_last_clock_render = now;
|
|
|
|
|
render();
|
|
|
|
|
}
|
|
|
|
|
montauk::sleep_ms(16);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|