From e308d77b06405b91885cf6f97c0dc2a1b70679ef Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 11 May 2021 14:24:52 +0200 Subject: Improve file saving gui --- src/Body.cpp | 2 +- src/DownloadUtils.cpp | 1 + src/Entry.cpp | 22 +++- src/QuickMedia.cpp | 298 ++++++++++++++++++++++++++++++++++++-------- src/RoundedRectangle.cpp | 13 +- src/SearchBar.cpp | 39 +++--- src/Text.cpp | 7 +- src/gui/Button.cpp | 76 +++++++++++ src/plugins/FileManager.cpp | 16 +-- src/plugins/Mangadex.cpp | 2 +- 10 files changed, 381 insertions(+), 95 deletions(-) create mode 100644 src/gui/Button.cpp (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index 9494e80..c186b9c 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -335,7 +335,6 @@ namespace QuickMedia { void Body::clear_cache() { clear_text_cache(); clear_thumbnails(); - malloc_trim(0); } void Body::clear_text_cache() { @@ -348,6 +347,7 @@ namespace QuickMedia { void Body::clear_thumbnails() { item_thumbnail_textures.clear(); + malloc_trim(0); } BodyItem* Body::get_selected() const { diff --git a/src/DownloadUtils.cpp b/src/DownloadUtils.cpp index bb60ad6..248fda0 100644 --- a/src/DownloadUtils.cpp +++ b/src/DownloadUtils.cpp @@ -1,6 +1,7 @@ #include "../include/DownloadUtils.hpp" #include "../include/Program.hpp" #include "../include/Storage.hpp" +#include "../include/NetUtils.hpp" #include "../external/cppcodec/base64_url.hpp" #include #include diff --git a/src/Entry.cpp b/src/Entry.cpp index 96a34f3..5e18340 100644 --- a/src/Entry.cpp +++ b/src/Entry.cpp @@ -7,7 +7,7 @@ #include const float background_margin_horizontal = std::floor(5.0f * QuickMedia::get_ui_scale()); -const float padding_vertical = std::floor(3.0f * QuickMedia::get_ui_scale()); +const float padding_vertical = std::floor(5.0f * QuickMedia::get_ui_scale()); const float background_margin_vertical = std::floor(0.0f * QuickMedia::get_ui_scale()); namespace QuickMedia { @@ -16,7 +16,7 @@ namespace QuickMedia { draw_background(true), text("", false, std::floor(16 * get_ui_scale()), 0.0f), width(0.0f), - background(sf::Vector2f(1.0f, 1.0f), 7.0f, sf::Color(55, 60, 68), rounded_rectangle_shader), + background(sf::Vector2f(1.0f, 1.0f), 10.0f, sf::Color(55, 60, 68), rounded_rectangle_shader), placeholder(placeholder_text, *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(16 * get_ui_scale())), mouse_left_inside(false) { @@ -74,6 +74,10 @@ namespace QuickMedia { } } + void Entry::set_single_line(bool single_line) { + text.single_line_edit = single_line; + } + void Entry::set_editable(bool editable) { text.setEditable(editable); } @@ -93,8 +97,8 @@ namespace QuickMedia { void Entry::set_position(const sf::Vector2f &pos) { background.set_position(pos); - text.setPosition(pos + sf::Vector2f(background_margin_horizontal, background_margin_vertical - std::floor(3.0f * get_ui_scale()))); - placeholder.setPosition(pos + sf::Vector2f(background_margin_horizontal, background_margin_vertical + std::floor(3.0f * get_ui_scale()))); + text.setPosition(pos + sf::Vector2f(background_margin_horizontal, background_margin_vertical)); + placeholder.setPosition(pos + sf::Vector2f(background_margin_horizontal, background_margin_vertical)); } void Entry::set_max_width(float width) { @@ -102,8 +106,16 @@ namespace QuickMedia { text.setMaxWidth(this->width - background_margin_horizontal * 2.0f); } + bool Entry::is_editable() const { + return text.isEditable(); + } + float Entry::get_height() { text.updateGeometry(); - return std::floor(text.getHeight() + background_margin_vertical * 2.0f + padding_vertical *2.0f); + return std::floor(text.getHeight() + background_margin_vertical * 2.0f + padding_vertical * 2.0f); + } + + const sf::String& Entry::get_text() const { + return text.getString(); } } \ No newline at end of file diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index b4fa915..13b9369 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -29,6 +29,7 @@ #include "../include/ResourceLoader.hpp" #include "../include/Utils.hpp" #include "../include/Tabs.hpp" +#include "../include/gui/Button.hpp" #include "../external/hash-library/sha256.h" #include @@ -599,7 +600,7 @@ namespace QuickMedia { window.create(x11_window); - if(program_path.back() != '/') + if(!program_path.empty() && program_path.back() != '/') program_path += '/'; resources_root = "/usr/share/quickmedia/"; @@ -1531,6 +1532,7 @@ namespace QuickMedia { if(tabs[selected_tab].page->is_single_page()) { if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->clear(); if(new_tabs.size() == 1 && !new_tabs[0].page) { + tabs[selected_tab].body->clear_thumbnails(); tabs[selected_tab].body = std::move(new_tabs[0].body); tabs[selected_tab].page->submit_body_item = prev_selected_item; return; @@ -1854,6 +1856,7 @@ namespace QuickMedia { if(associated_data.fetch_status == FetchStatus::LOADING && associated_data.fetch_type == FetchType::SEARCH && associated_data.fetch_future.ready()) { if(!associated_data.search_text_updated) { FetchResult fetch_result = associated_data.fetch_future.get(); + tabs[i].body->clear_thumbnails(); tabs[i].body->items = std::move(fetch_result.body_items); tabs[i].body->select_first_item(); associated_data.fetched_page = 0; @@ -2270,7 +2273,7 @@ namespace QuickMedia { } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::C && event.key.control) { save_video_url_to_clipboard(); } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::S && event.key.control) { - download_async_gui(original_video_url, true, force_no_video); + download_async_gui(original_video_url, true, no_video); } } handle_window_close(); @@ -2287,7 +2290,7 @@ namespace QuickMedia { } else if(pressed_keysym == XK_f && pressing_ctrl) { window_set_fullscreen(disp, window.getSystemHandle(), WindowFullscreenState::TOGGLE); } else if(pressed_keysym == XK_s && pressing_ctrl) { - download_async_gui(original_video_url, true, force_no_video); + download_async_gui(original_video_url, true, no_video); } else if(pressed_keysym == XK_r && pressing_ctrl) { if(!cursor_visible) window.setMouseCursorVisible(true); @@ -2595,7 +2598,7 @@ namespace QuickMedia { }; } else if(website_url && website_url[0] != '\0') { std::string website_url_str = website_url; - if(website_url_str.back() != '/') + if(!website_url_str.empty() && website_url_str.back() != '/') website_url_str.push_back('/'); extra_args = { CommandArg { "-H", "referer: " + std::move(website_url_str) }, @@ -4733,7 +4736,7 @@ namespace QuickMedia { if(selected_item_message) { MessageType message_type = selected_item_message->type; if(!selected->url.empty() && (message_type == MessageType::VIDEO || message_type == MessageType::IMAGE || message_type == MessageType::AUDIO)) { - download_async_gui(selected->url, false, force_no_video); + download_async_gui(selected->url, false, no_video); return true; } } @@ -5919,60 +5922,57 @@ namespace QuickMedia { bool no_video; }; - static const char* get_filename(const char *path) { - const char *p = (const char*)memrchr(path, '/', strlen(path)); - return p ? p + 1 : path; + static int accumulate_string(char *data, int size, void *userdata) { + std::string *str = (std::string*)userdata; + if(str->size() + size > 1024 * 1024 * 100) // 100mb sane limit, TODO: make configurable + return 1; + str->append(data, size); + return 0; } - class ConfirmationPage : public Page { - public: - ConfirmationPage(Program *program, FileManagerPage *file_manager_page, bool *file_overwrite, const std::string &title) : Page(program), file_manager_page(file_manager_page), file_overwrite(file_overwrite), title(title) {} - const char* get_title() const override { return title.c_str(); } - PluginResult submit(const std::string &title, const std::string&, std::vector&) override { - if(title == "Yes") { - *file_overwrite = true; - file_manager_page->close = true; - } else { - *file_overwrite = false; + void Program::download_page(const char *url, bool download_use_youtube_dl) { + window.setTitle("QuickMedia - Select where you want to save " + std::string(url)); + + std::string filename; + TaskResult task_result = run_task_with_loading_screen([this, url, &filename]{ + std::string json_str; + std::vector args = { "youtube-dl", "--skip-download", "--print-json", "--no-warnings" }; + if(no_video) + args.push_back("-x"); + args.insert(args.end(), { "--", url, nullptr }); + if(exec_program(args.data(), accumulate_string, &json_str) != 0) + return false; + + Json::Value result; + Json::CharReaderBuilder json_builder; + std::unique_ptr json_reader(json_builder.newCharReader()); + std::string json_errors; + if(!json_reader->parse(json_str.data(), json_str.data() + json_str.size(), &result, &json_errors)) { + fprintf(stderr, "Failed to json response, error: %s\n", json_errors.c_str()); + return false; } - program->set_go_to_previous_page(); - return PluginResult::OK; - } - static void add_items(BodyItems &items) { - items.push_back(BodyItem::create("No")); - items.push_back(BodyItem::create("Yes")); - } - private: - FileManagerPage *file_manager_page; - bool *file_overwrite; - std::string title; - }; + const Json::Value &title_json = result["title"]; + const Json::Value &ext_json = result["ext"]; + if(title_json.isString()) + filename = title_json.asString(); - void Program::download_page(const char *url, bool download_use_youtube_dl) { - bool file_overwrite = true; - FileSelectionHandler overwrite_confirm_handler = [this, &file_overwrite](FileManagerPage *file_manager_page, const std::filesystem::path &path) { - file_overwrite = true; - std::vector tabs; - if(std::filesystem::exists(path)) { - auto body = create_body(); - ConfirmationPage::add_items(body->items); - tabs.push_back(Tab{ std::move(body), std::make_unique(this, file_manager_page, &file_overwrite, "Are you sure you want to overwrite " + path.string() + "?"), nullptr }); + if(ext_json.isString()) { + if(ext_json.asCString()[0] != '.' && (filename.empty() || filename.back() != '.')) + filename += "."; + filename += ext_json.asString(); } - return tabs; - }; - auto file_manager_page = std::make_unique(this, FILE_MANAGER_MIME_TYPE_ALL, std::move(overwrite_confirm_handler), true, "Where do you want to save the file? Current directory: "); - file_manager_page->set_current_directory(get_home_dir().data); - auto file_manager_body = create_body(); - file_manager_page->get_files_in_directory(file_manager_body->items); - std::vector file_manager_tabs; - file_manager_tabs.push_back(Tab{std::move(file_manager_body), std::move(file_manager_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + return !filename.empty(); + }); - selected_files.clear(); - page_loop(file_manager_tabs); + if(task_result == TaskResult::CANCEL) { + exit_code = 1; + return; + } - if(!window.isOpen() || selected_files.empty() || !file_overwrite) { + std::string output_filepath = file_save_page(filename); + if(!window.isOpen() || output_filepath.empty()) { exit_code = 1; return; } @@ -5998,7 +5998,6 @@ namespace QuickMedia { } window.setPosition(sf::Vector2i(focused_monitor_center.x - window_size.x * 0.5f, focused_monitor_center.y - window_size.y * 0.5f)); - std::string output_filepath = selected_files[0]; std::string output_filepath_s = output_filepath; char *output_dir = dirname(output_filepath_s.data()); if(create_directory_recursive(output_dir) != 0) { @@ -6022,7 +6021,7 @@ namespace QuickMedia { sf::Text progress_text("0kb/Unknown", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(20.0f * get_ui_scale())); sf::Text status_text("Downloading", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(20.0f * get_ui_scale())); - sf::Text filename_text(get_filename(output_filepath.c_str()), *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14.0f * get_ui_scale())); + sf::Text filename_text(filename.c_str(), *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14.0f * get_ui_scale())); filename_text.setFillColor(sf::Color(179, 179, 179)); sf::Text download_speed_text("0 bytes/s", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14.0f * get_ui_scale())); download_speed_text.setFillColor(sf::Color(179, 179, 179)); @@ -6032,7 +6031,7 @@ namespace QuickMedia { std::unique_ptr downloader; if(download_use_youtube_dl) - downloader = std::make_unique(url, output_filepath, force_no_video); + downloader = std::make_unique(url, output_filepath, no_video); else downloader = std::make_unique(url, output_filepath); @@ -6139,4 +6138,197 @@ namespace QuickMedia { } exit(exit_code); } + + class ConfirmationPage : public Page { + public: + ConfirmationPage(Program *program, bool *file_overwrite, const std::string &title) : Page(program), file_overwrite(file_overwrite), title(title) {} + const char* get_title() const override { return title.c_str(); } + PluginResult submit(const std::string &title, const std::string&, std::vector&) override { + if(title == "Yes") + *file_overwrite = true; + else + *file_overwrite = false; + + program->set_go_to_previous_page(); + return PluginResult::OK; + } + + static void add_items(BodyItems &items) { + items.push_back(BodyItem::create("No")); + items.push_back(BodyItem::create("Yes")); + } + private: + bool *file_overwrite; + std::string title; + }; + + std::string Program::file_save_page(const std::string &filename) { + sf::Vector2f body_pos; + sf::Vector2f body_size; + bool redraw = true; + sf::Event event; + + auto file_manager_page = std::make_unique(this); + std::string home_dir = get_home_dir().data; + file_manager_page->set_current_directory(home_dir); + auto file_manager_body = create_body(); + file_manager_page->get_files_in_directory(file_manager_body->items); + auto search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); + + Tabs ui_tabs(&rounded_rectangle_shader); + const int tab_path_index = ui_tabs.add_tab(home_dir); + + search_bar->onTextUpdateCallback = [&file_manager_body](const std::string &text) { + file_manager_body->filter_search_fuzzy(text); + file_manager_body->select_first_item(); + }; + + search_bar->onTextSubmitCallback = [this, &search_bar, &file_manager_body, &file_manager_page, &ui_tabs, tab_path_index](const std::string&) { + if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl) || sf::Keyboard::isKeyPressed(sf::Keyboard::RControl)) + return; + + BodyItem *selected = file_manager_body->get_selected(); + if(!selected) + return; + + std::vector new_tabs; + TaskResult task_result = run_task_with_loading_screen([selected, &file_manager_page, &new_tabs]() { + return file_manager_page->submit(selected->get_title(), selected->url, new_tabs) == PluginResult::OK; + }); + + if(task_result == TaskResult::TRUE) { + if(!new_tabs.empty()) { + file_manager_body->clear_thumbnails(); + file_manager_body->items = std::move(new_tabs[0].body->items); + } + } else if(task_result == TaskResult::FALSE) { + show_notification("QuickMedia", "Failed to change directory", Urgency::CRITICAL); + } + + search_bar->clear(); + ui_tabs.set_text(tab_path_index, file_manager_page->get_current_directory().string()); + }; + + const float bottom_panel_padding = 10.0f; + const float bottom_panel_spacing = 10.0f; + + Button cancel_button("Cancel", FontLoader::get_font(FontLoader::FontType::LATIN), 16, 100.0f, &rounded_rectangle_shader, get_ui_scale()); + cancel_button.set_background_color(sf::Color(104, 2, 2)); + + Button save_button("Save", FontLoader::get_font(FontLoader::FontType::LATIN), 16, 100.0f, &rounded_rectangle_shader, get_ui_scale()); + save_button.set_background_color(sf::Color(35, 35, 236)); + + sf::Text file_name_label("File name:", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(16.0f * get_ui_scale())); + + Entry file_name_entry("", &rounded_rectangle_shader); + file_name_entry.set_text(filename); + file_name_entry.set_single_line(true); + file_name_entry.set_editable(false); + + sf::RectangleShape bottom_panel_background; + bottom_panel_background.setFillColor(sf::Color(33, 37, 44)); + + auto save_file = [this, &file_name_entry, &file_manager_page]() -> std::string { + auto u8 = file_name_entry.get_text().toUtf8(); + std::string *filename = (std::string*)&u8; + + Path filename_full_path = file_manager_page->get_current_directory().string(); + filename_full_path.join(*filename); + + if(filename->empty()) { + show_notification("QuickMedia", "The file name can't be empty", Urgency::CRITICAL); + } else if(*filename == "." || *filename == ".." || filename->find('/') != std::string::npos) { + show_notification("QuickMedia", "Invalid file name. File can't be ., .. or contain /", Urgency::CRITICAL); + } else if(filename->size() >= 255 || filename_full_path.data.size() >= 4096) { + show_notification("QuickMedia", "The file name has to be less than 255 characters and the full path has to be less than 4096 characters", Urgency::CRITICAL); + } else { + if(std::filesystem::exists(filename_full_path.data)) { + bool overwrite = false; + std::vector tabs; + auto body = create_body(); + ConfirmationPage::add_items(body->items); + tabs.push_back(Tab{ std::move(body), std::make_unique(this, &overwrite, "Are you sure you want to overwrite " + filename_full_path.data + "?"), nullptr }); + page_loop(tabs); + if(overwrite) + return std::move(filename_full_path.data); + } else { + return std::move(filename_full_path.data); + } + } + + return ""; + }; + + while (window.isOpen()) { + while (window.pollEvent(event)) { + if(file_manager_body->on_event(window, event, !file_name_entry.is_editable())) + idle_active_handler(); + else + event_idle_handler(event); + + search_bar->on_event(event); + if(cancel_button.on_event(event) & BUTTON_EVENT_CLICKED) + return ""; + if(save_button.on_event(event) & BUTTON_EVENT_CLICKED) { + std::string save_path = save_file(); + if(!save_path.empty()) + return save_path; + } + file_name_entry.process_event(event); + + if(event.type == sf::Event::Resized) { + window_size.x = event.size.width; + window_size.y = event.size.height; + sf::FloatRect visible_area(0, 0, window_size.x, window_size.y); + window.setView(sf::View(visible_area)); + redraw = true; + idle_active_handler(); + } else if(event.type == sf::Event::GainedFocus) { + redraw = true; + } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Tab) { + file_name_entry.set_editable(!file_name_entry.is_editable()); + search_bar->set_editable(!file_name_entry.is_editable()); + } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Enter && event.key.control) { + std::string save_path = save_file(); + if(!save_path.empty()) + return save_path; + } + } + + update_idle_state(); + handle_window_close(); + search_bar->update(); + + if(redraw) { + redraw = false; + get_body_dimensions(window_size, search_bar.get(), body_pos, body_size); + body_pos.y += std::floor(10.0f * get_ui_scale()) + Tabs::get_height(); + body_size.y -= std::floor(10.0f * get_ui_scale()) + Tabs::get_height(); + save_button.set_position(window_size - sf::Vector2f(save_button.get_width(), save_button.get_height()) - sf::Vector2f(bottom_panel_padding, bottom_panel_padding)); + cancel_button.set_position(save_button.get_position() - sf::Vector2f(cancel_button.get_width() + bottom_panel_spacing, 0.0f)); + file_name_label.setPosition(sf::Vector2f(bottom_panel_spacing, std::floor(window_size.y - bottom_panel_padding - file_name_entry.get_height() * 0.5f - file_name_label.getLocalBounds().height * 0.5f - 5.0f * get_ui_scale()))); + file_name_entry.set_position(sf::Vector2f(file_name_label.getPosition().x + file_name_label.getLocalBounds().width + bottom_panel_spacing, window_size.y - file_name_entry.get_height() - bottom_panel_padding)); + file_name_entry.set_max_width(std::floor(cancel_button.get_position().x - bottom_panel_spacing - file_name_label.getLocalBounds().width - bottom_panel_spacing - bottom_panel_spacing)); + bottom_panel_background.setPosition(0.0f, window_size.y - std::floor(bottom_panel_padding * 2.0f + file_name_entry.get_height())); + bottom_panel_background.setSize(sf::Vector2f(window_size.x, std::floor(bottom_panel_padding * 2.0f + file_name_entry.get_height()))); + } + + window.clear(back_color); + + ui_tabs.draw(window, sf::Vector2f(0.0f, search_bar->getBottomWithoutShadow()), window_size.x); + search_bar->draw(window, window_size, true); + + file_manager_body->draw(window, body_pos, body_size - sf::Vector2f(0.0f, bottom_panel_background.getSize().y)); + + window.draw(bottom_panel_background); + window.draw(file_name_label); + cancel_button.draw(window); + save_button.draw(window); + file_name_entry.draw(window); + + window.display(); + } + + return ""; + } } diff --git a/src/RoundedRectangle.cpp b/src/RoundedRectangle.cpp index 6b956e8..4b06ea8 100644 --- a/src/RoundedRectangle.cpp +++ b/src/RoundedRectangle.cpp @@ -1,6 +1,6 @@ #include "../include/RoundedRectangle.hpp" #include -#include +#include #include namespace QuickMedia { @@ -30,6 +30,13 @@ namespace QuickMedia { set_position(pos); } + void RoundedRectangle::set_color(sf::Color color) { + vertices[0].color = color; + vertices[1].color = color; + vertices[2].color = color; + vertices[3].color = color; + } + sf::Vector2f RoundedRectangle::get_position() const { return pos; } @@ -38,9 +45,9 @@ namespace QuickMedia { return size; } - void RoundedRectangle::draw(sf::RenderWindow &window) { + void RoundedRectangle::draw(sf::RenderTarget &target) { rounded_rectangle_shader->setUniform("resolution", size); rounded_rectangle_shader->setUniform("radius", radius); - window.draw(vertices, 4, sf::Quads, rounded_rectangle_shader); + target.draw(vertices, 4, sf::Quads, rounded_rectangle_shader); } } \ No newline at end of file diff --git a/src/SearchBar.cpp b/src/SearchBar.cpp index 8362864..7d7f72d 100644 --- a/src/SearchBar.cpp +++ b/src/SearchBar.cpp @@ -82,7 +82,7 @@ namespace QuickMedia { caret.setPosition(text.findCharacterPos(text.getString().getSize()) + sf::Vector2f(0.0f, 2.0f)); } - if(caret_visible) + if(caret_visible && is_editable()) window.draw(caret); if(draw_logo) @@ -90,6 +90,22 @@ namespace QuickMedia { } void SearchBar::on_event(sf::Event &event) { + if(is_touch_enabled() && event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { + sf::FloatRect box(background.get_position(), background.get_size()); + if(box.contains(event.mouseButton.x, event.mouseButton.y)) + mouse_left_inside = true; + else + mouse_left_inside = false; + } else if(is_touch_enabled() && event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left) { + sf::FloatRect box(background.get_position(), background.get_size()); + if(mouse_left_inside && box.contains(event.mouseButton.x, event.mouseButton.y)) + show_virtual_keyboard(); + mouse_left_inside = false; + } + + if(!editable) + return; + if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Backspace) backspace_pressed = true; else if(event.type == sf::Event::KeyReleased && event.key.code == sf::Keyboard::Backspace) @@ -110,19 +126,6 @@ namespace QuickMedia { onTextEntered(event.text.unicode); else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Backspace) onTextEntered(8); - - if(is_touch_enabled() && event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { - sf::FloatRect box(background.get_position(), background.get_size()); - if(box.contains(event.mouseButton.x, event.mouseButton.y)) - mouse_left_inside = true; - else - mouse_left_inside = false; - } else if(is_touch_enabled() && event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left) { - sf::FloatRect box(background.get_position(), background.get_size()); - if(mouse_left_inside && box.contains(event.mouseButton.x, event.mouseButton.y)) - show_virtual_keyboard(); - mouse_left_inside = false; - } } void SearchBar::update() { @@ -303,6 +306,14 @@ namespace QuickMedia { } } + void SearchBar::set_editable(bool editable) { + this->editable = editable; + } + + bool SearchBar::is_editable() const { + return editable; + } + void SearchBar::clear_autocomplete_if_text_not_substring() { const sf::String &text_str = text.getString(); const sf::String &autocomplete_str = autocomplete_text.getString(); diff --git a/src/Text.cpp b/src/Text.cpp index 0431c4e..2940520 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -60,10 +60,11 @@ namespace QuickMedia { //if(str != this->str) //{ + size_t prev_str_size = this->str.getSize(); this->str = std::move(str); dirty = true; dirtyText = true; - if((int)this->str.getSize() < caretIndex) + if((int)this->str.getSize() < caretIndex || prev_str_size == 0) { caretIndex = this->str.getSize(); dirtyCaret = true; @@ -821,7 +822,7 @@ namespace QuickMedia } else if(event.key.code == sf::Keyboard::Enter) { - if(event.key.shift) + if(event.key.shift && !single_line_edit) { if(caretAtEnd) str += '\n'; @@ -849,7 +850,7 @@ namespace QuickMedia { stringToAdd = sf::Clipboard::getString(); } - else if(event.text.unicode >= 32 || event.text.unicode == 9) // 9 == tab + else if(event.text.unicode >= 32 || (event.text.unicode == 9 && !single_line_edit)) // 9 == tab stringToAdd = event.text.unicode; else return; diff --git a/src/gui/Button.cpp b/src/gui/Button.cpp new file mode 100644 index 0000000..ebbb8bb --- /dev/null +++ b/src/gui/Button.cpp @@ -0,0 +1,76 @@ +#include "../../include/gui/Button.hpp" +#include +#include +#include + +namespace QuickMedia { + static const float PADDING_Y = 10.0f; + + Button::Button(const std::string &label, sf::Font *font, unsigned int character_size, float width, sf::Shader *rounded_rectangle_shader, float scale) : + label(label, *font, character_size * scale), + background(sf::Vector2f(1.0f, 1.0f), 10.0f, sf::Color(33, 37, 44), rounded_rectangle_shader), + scale(scale) + { + background.set_size(sf::Vector2f(std::floor(width * scale), get_height())); + set_position(sf::Vector2f(0.0f, 0.0f)); + } + + ButtonEvent Button::on_event(sf::Event &event) { + ButtonEvent performed_event = BUTTON_EVENT_NONE; + if(event.type == sf::Event::MouseMoved) { + if(sf::FloatRect(background.get_position(), background.get_size()).contains(event.mouseMove.x, event.mouseMove.y)) { + const int inc = 20; + background.set_color(sf::Color( + std::min(255, (int)background_color.r + inc), + std::min(255, (int)background_color.g + inc), + std::min(255, (int)background_color.b + inc))); + } else { + background.set_color(background_color); + } + } else if(event.type == sf::Event::MouseButtonPressed) { + if(event.mouseButton.button == sf::Mouse::Left && sf::FloatRect(background.get_position(), background.get_size()).contains(event.mouseButton.x, event.mouseButton.y)) { + clicked_inside = true; + } else { + clicked_inside = false; + } + } else if(event.type == sf::Event::MouseButtonReleased) { + if(clicked_inside && event.mouseButton.button == sf::Mouse::Left && sf::FloatRect(background.get_position(), background.get_size()).contains(event.mouseButton.x, event.mouseButton.y)) { + performed_event = BUTTON_EVENT_CLICKED; + } + clicked_inside = false; + } + return performed_event; + } + + void Button::draw(sf::RenderTarget &target) { + background.draw(target); + target.draw(label); + } + + void Button::set_background_color(sf::Color color) { + background_color = color; + background.set_color(background_color); + } + + void Button::set_position(sf::Vector2f pos) { + background.set_position(pos); + + const auto label_bounds = label.getLocalBounds(); + sf::Vector2f label_pos(pos + background.get_size() * 0.5f - sf::Vector2f(label_bounds.width * 0.5f, label_bounds.height * 0.5f) - sf::Vector2f(0.0f, 5.0f * scale)); + label_pos.x = std::floor(label_pos.x); + label_pos.y = std::floor(label_pos.y); + label.setPosition(label_pos); + } + + sf::Vector2f Button::get_position() const { + return background.get_position(); + } + + float Button::get_width() const { + return background.get_size().x; + } + + float Button::get_height() const { + return std::floor((PADDING_Y * 2.0f) * scale + label.getLocalBounds().height); + } +} \ No newline at end of file diff --git a/src/plugins/FileManager.cpp b/src/plugins/FileManager.cpp index e1f3b04..6ee7e71 100644 --- a/src/plugins/FileManager.cpp +++ b/src/plugins/FileManager.cpp @@ -39,18 +39,10 @@ namespace QuickMedia { return PluginResult::OK; } - if(!std::filesystem::is_directory(new_path)) { - if(allow_empty_match_submit) { - program->select_file(new_path); - if(selection_handler) - result_tabs = selection_handler(this, new_path); - return PluginResult::OK; - } + if(!std::filesystem::is_directory(new_path)) return PluginResult::ERR; - } current_dir = std::move(new_path); - this->title = title_prefix + current_dir.string(); BodyItems result_items; PluginResult result = get_files_in_directory(result_items); @@ -63,16 +55,10 @@ namespace QuickMedia { return PluginResult::OK; } - void FileManagerPage::on_navigate_to_page(Body*) { - if(close) - program->set_go_to_previous_page(); - } - bool FileManagerPage::set_current_directory(const std::string &path) { if(!std::filesystem::is_directory(path)) return false; current_dir = path; - title = title_prefix + current_dir.string(); return true; } diff --git a/src/plugins/Mangadex.cpp b/src/plugins/Mangadex.cpp index f69484b..0b50366 100644 --- a/src/plugins/Mangadex.cpp +++ b/src/plugins/Mangadex.cpp @@ -216,7 +216,7 @@ namespace QuickMedia { return PluginResult::ERR; std::string base_url = base_url_json.asString(); - if(base_url.back() != '/') + if(!base_url.empty() && base_url.back() != '/') base_url += '/'; auto image_urls = static_cast(submit_body_item->extra.get())->image_urls; -- cgit v1.2.3