Compare commits
3 Commits
05bf792dbd
...
fd26f40938
Author | SHA1 | Date | |
---|---|---|---|
fd26f40938 | |||
fd2fe16538 | |||
38fcd8e3e1 |
@ -10,10 +10,12 @@
|
|||||||
#include "EditorWidget.h"
|
#include "EditorWidget.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <luna/PathParser.h>
|
#include <luna/PathParser.h>
|
||||||
|
#include <luna/RefString.h>
|
||||||
#include <luna/Utf8.h>
|
#include <luna/Utf8.h>
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
#include <os/FileSystem.h>
|
#include <os/FileSystem.h>
|
||||||
#include <ui/App.h>
|
#include <ui/App.h>
|
||||||
|
#include <ui/Dialog.h>
|
||||||
|
|
||||||
EditorWidget::EditorWidget(SharedPtr<ui::Font> font) : ui::TextInput(), m_font(font)
|
EditorWidget::EditorWidget(SharedPtr<ui::Font> font) : ui::TextInput(), m_font(font)
|
||||||
{
|
{
|
||||||
@ -27,7 +29,8 @@ Result<void> EditorWidget::load_file(const os::Path& path)
|
|||||||
|
|
||||||
if (!rc.has_error() && !S_ISREG(st.st_mode))
|
if (!rc.has_error() && !S_ISREG(st.st_mode))
|
||||||
{
|
{
|
||||||
os::eprintln("editor: not loading %s as it is not a regular file", path.name().chars());
|
auto message = TRY(RefString::format("%s is not a regular file", path.name().chars()));
|
||||||
|
ui::Dialog::show_message("Error", message.view());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,9 +44,9 @@ Result<void> EditorWidget::load_file(const os::Path& path)
|
|||||||
|
|
||||||
m_cursor = m_data.size();
|
m_cursor = m_data.size();
|
||||||
|
|
||||||
m_path = path;
|
m_path = TRY(String::from_string_view(path.name()));
|
||||||
|
|
||||||
auto basename = TRY(PathParser::basename(m_path.name()));
|
auto basename = TRY(PathParser::basename(m_path.view()));
|
||||||
|
|
||||||
String title = TRY(String::format("Text Editor - %s"_sv, basename.chars()));
|
String title = TRY(String::format("Text Editor - %s"_sv, basename.chars()));
|
||||||
window()->set_title(title.view());
|
window()->set_title(title.view());
|
||||||
@ -126,15 +129,38 @@ Result<ui::EventResult> EditorWidget::handle_key_event(const ui::KeyEventRequest
|
|||||||
return ui::EventResult::DidHandle;
|
return ui::EventResult::DidHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<void> EditorWidget::save_file_as()
|
||||||
|
{
|
||||||
|
ui::Dialog::show_input_dialog(
|
||||||
|
"Save file as...", "Please enter the path to save this file to:", [this](StringView path) {
|
||||||
|
m_path = String::from_string_view(path).release_value();
|
||||||
|
auto rc = save_file();
|
||||||
|
if (rc.has_error())
|
||||||
|
{
|
||||||
|
os::eprintln("Failed to save file %s: %s", m_path.chars(), rc.error_string());
|
||||||
|
ui::Dialog::show_message("Error", "Failed to save file");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto basename = PathParser::basename(m_path.view()).release_value();
|
||||||
|
|
||||||
|
String title = String::format("Text Editor - %s"_sv, basename.chars()).release_value();
|
||||||
|
window()->set_title(title.view());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> EditorWidget::save_file()
|
Result<void> EditorWidget::save_file()
|
||||||
{
|
{
|
||||||
if (m_path.is_empty_path())
|
if (m_path.is_empty())
|
||||||
{
|
{
|
||||||
os::eprintln("editor: no file to save buffer to!");
|
TRY(save_file_as());
|
||||||
return err(ENOENT);
|
return err(ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto file = TRY(os::File::open(m_path, os::File::WriteOnly));
|
auto file = TRY(os::File::open_or_create(m_path.view(), os::File::WriteOnly));
|
||||||
return file->write(m_data);
|
return file->write(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,14 +21,15 @@ class EditorWidget : public ui::TextInput
|
|||||||
Result<void> load_file(const os::Path& path);
|
Result<void> load_file(const os::Path& path);
|
||||||
|
|
||||||
Result<void> save_file();
|
Result<void> save_file();
|
||||||
|
Result<void> save_file_as();
|
||||||
|
|
||||||
Result<ui::EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
Result<ui::EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
||||||
|
|
||||||
Result<void> draw(ui::Canvas& canvas) override;
|
Result<void> draw(ui::Canvas& canvas) override;
|
||||||
|
|
||||||
os::Path& path()
|
os::Path path()
|
||||||
{
|
{
|
||||||
return m_path;
|
return m_path.view();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -41,7 +42,7 @@ class EditorWidget : public ui::TextInput
|
|||||||
};
|
};
|
||||||
Vector<Line> m_lines;
|
Vector<Line> m_lines;
|
||||||
|
|
||||||
os::Path m_path { AT_FDCWD };
|
String m_path;
|
||||||
|
|
||||||
Result<void> recalculate_lines();
|
Result<void> recalculate_lines();
|
||||||
void recalculate_cursor_position();
|
void recalculate_cursor_position();
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <os/ArgumentParser.h>
|
#include <os/ArgumentParser.h>
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
#include <ui/App.h>
|
#include <ui/App.h>
|
||||||
|
#include <ui/Dialog.h>
|
||||||
|
|
||||||
Result<int> luna_main(int argc, char** argv)
|
Result<int> luna_main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
@ -32,15 +33,20 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
auto* editor = TRY(make<EditorWidget>(ui::Font::default_font()));
|
auto* editor = TRY(make<EditorWidget>(ui::Font::default_font()));
|
||||||
window->set_main_widget(*editor);
|
window->set_main_widget(*editor);
|
||||||
if (!path.is_empty()) TRY(editor->load_file(path));
|
if (!path.is_empty()) editor->load_file(path);
|
||||||
|
|
||||||
TRY(window->add_keyboard_shortcut({ moon::K_CH26, ui::Mod_Ctrl }, true, [&](ui::Shortcut) {
|
TRY(window->add_keyboard_shortcut({ moon::K_CH26, ui::Mod_Ctrl }, true, [&](ui::Shortcut) {
|
||||||
auto result = editor->save_file();
|
auto result = editor->save_file();
|
||||||
if (result.has_error()) os::eprintln("editor: failed to save file: %s", result.error_string());
|
if (result.has_error())
|
||||||
else
|
{
|
||||||
os::println("editor: buffer saved to %s successfully", editor->path().name().chars());
|
os::eprintln("Failed to save file %s: %s", editor->path().name().chars(), result.error_string());
|
||||||
|
ui::Dialog::show_message("Error", "Failed to save file");
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
TRY(window->add_keyboard_shortcut({ moon::K_CH26, ui::Mod_Ctrl | ui::Mod_Shift }, true,
|
||||||
|
[&](ui::Shortcut) { editor->save_file_as(); }));
|
||||||
|
|
||||||
window->draw();
|
window->draw();
|
||||||
|
|
||||||
return app.run();
|
return app.run();
|
||||||
|
@ -19,6 +19,7 @@ set(SOURCES
|
|||||||
src/Label.cpp
|
src/Label.cpp
|
||||||
src/InputField.cpp
|
src/InputField.cpp
|
||||||
src/TextInput.cpp
|
src/TextInput.cpp
|
||||||
|
src/Dialog.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(ui ${SOURCES})
|
add_library(ui ${SOURCES})
|
||||||
|
22
gui/libui/include/ui/Dialog.h
Normal file
22
gui/libui/include/ui/Dialog.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* @file Window.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief UI window dialogs.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <os/Action.h>
|
||||||
|
#include <ui/Window.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
namespace Dialog
|
||||||
|
{
|
||||||
|
Result<void> show_message(StringView title, StringView message);
|
||||||
|
|
||||||
|
Result<void> show_input_dialog(StringView title, StringView message, os::Function<StringView> callback);
|
||||||
|
}
|
||||||
|
}
|
82
gui/libui/src/Dialog.cpp
Normal file
82
gui/libui/src/Dialog.cpp
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* @file Dialog.cpp
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief UI window dialogs.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <luna/Alloc.h>
|
||||||
|
#include <ui/App.h>
|
||||||
|
#include <ui/Dialog.h>
|
||||||
|
#include <ui/InputField.h>
|
||||||
|
#include <ui/Label.h>
|
||||||
|
#include <ui/Layout.h>
|
||||||
|
|
||||||
|
namespace ui::Dialog
|
||||||
|
{
|
||||||
|
Result<void> show_message(StringView title, StringView message)
|
||||||
|
{
|
||||||
|
auto rect = ui::App::the().main_window()->canvas().rect();
|
||||||
|
int text_length = (int)message.length() * ui::Font::default_font()->width();
|
||||||
|
int text_height = ui::Font::default_font()->height();
|
||||||
|
|
||||||
|
ui::Rect dialog_rect = { 0, 0, text_length + 20, text_height + 20 };
|
||||||
|
|
||||||
|
auto* dialog = TRY(ui::Window::create(
|
||||||
|
ui::align(rect, dialog_rect, ui::VerticalAlignment::Center, ui::HorizontalAlignment::Center)));
|
||||||
|
|
||||||
|
dialog->set_background(ui::GRAY);
|
||||||
|
dialog->set_title(title);
|
||||||
|
|
||||||
|
ui::Label* text = TRY(make<ui::Label>(message));
|
||||||
|
text->set_color(ui::BLACK);
|
||||||
|
dialog->set_main_widget(*text);
|
||||||
|
|
||||||
|
dialog->on_close([text] { delete text; });
|
||||||
|
|
||||||
|
dialog->draw();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> show_input_dialog(StringView title, StringView message, os::Function<StringView> callback)
|
||||||
|
{
|
||||||
|
auto rect = ui::App::the().main_window()->canvas().rect();
|
||||||
|
int text_length = (int)message.length() * ui::Font::default_font()->width();
|
||||||
|
int text_height = ui::Font::default_font()->height();
|
||||||
|
|
||||||
|
ui::Rect dialog_rect = { 0, 0, max(text_length + 20, 300), text_height * 2 + 30 };
|
||||||
|
|
||||||
|
auto* dialog = TRY(ui::Window::create(
|
||||||
|
ui::align(rect, dialog_rect, ui::VerticalAlignment::Center, ui::HorizontalAlignment::Center)));
|
||||||
|
|
||||||
|
dialog->set_background(ui::GRAY);
|
||||||
|
dialog->set_title(title);
|
||||||
|
|
||||||
|
ui::VerticalLayout* layout = TRY(make<ui::VerticalLayout>());
|
||||||
|
dialog->set_main_widget(*layout);
|
||||||
|
|
||||||
|
ui::Label* text = TRY(make<ui::Label>((message)));
|
||||||
|
text->set_color(ui::BLACK);
|
||||||
|
layout->add_widget(*text);
|
||||||
|
|
||||||
|
ui::InputField* input = TRY(make<ui::InputField>(ui::Font::default_font()));
|
||||||
|
input->on_submit([dialog, callback](StringView s) {
|
||||||
|
callback(s);
|
||||||
|
dialog->close();
|
||||||
|
});
|
||||||
|
layout->add_widget(*input);
|
||||||
|
|
||||||
|
dialog->on_close([layout, text, input] {
|
||||||
|
delete text;
|
||||||
|
delete input;
|
||||||
|
delete layout;
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog->draw();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
@ -110,6 +110,10 @@ namespace os
|
|||||||
|
|
||||||
Timer::~Timer()
|
Timer::~Timer()
|
||||||
{
|
{
|
||||||
if (m_timerid >= 0) timer_delete(m_timerid);
|
if (m_timerid >= 0)
|
||||||
|
{
|
||||||
|
if (!m_stopped) stop();
|
||||||
|
timer_delete(m_timerid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user