From 7cf3b5bdb58d279d2cc2aa7770c09afeeeebb5b7 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 8 Feb 2021 22:50:21 +0100 Subject: Matrix: add room list on the left side when in a room --- src/Body.cpp | 4 +- src/QuickMedia.cpp | 286 ++++++++++++++++++++++++++++------------------------- src/SearchBar.cpp | 2 +- 3 files changed, 157 insertions(+), 135 deletions(-) (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index 8eeee49..8abd2b3 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -706,7 +706,7 @@ namespace QuickMedia { item_separator.setPosition(item_pos + sf::Vector2f(10.0f, std::floor(item_height + spacing_y * 0.5f))); window.draw(item_separator); - if(item_index == selected_item) { + if(item_index == selected_item && render_selection) { item_background.setPosition(item_pos); item_background.setSize(sf::Vector2f(size.x, item_height)); window.draw(item_background); @@ -837,7 +837,7 @@ namespace QuickMedia { if(!item->reactions.empty() && include_embedded_item) { sf::RoundedRectangleShape reaction_background(sf::Vector2f(1.0f, 1.0f), 10.0f, 10); - reaction_background.setFillColor(sf::Color(33, 38, 44)); + reaction_background.setFillColor(sf::Color(31, 35, 41)); float reaction_offset_x = 0.0f; item_pos.y += reaction_padding_y; float reaction_max_height = 0.0f; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 76bd084..7e487d1 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -346,7 +346,8 @@ namespace QuickMedia { window(sf::VideoMode(1280, 720, 24), "QuickMedia", sf::Style::Default), window_size(1280, 720), current_page(PageType::EXIT), - image_index(0) + image_index(0), + tab_background(sf::Vector2f(1.0f, 1.0f), 10.0f, 10) { disp = XOpenDisplay(NULL); if (!disp) @@ -919,12 +920,63 @@ namespace QuickMedia { go_to_previous_page = true; } - static void select_body_item_by_room(Body *body, RoomData *room) { - for(size_t i = 0; i < body->items.size(); ++i) { - auto &body_item = body->items[i]; - if(body_item->userdata == room) { - body->set_selected_item(i, false); - return; + void Program::page_loop_render(sf::RenderWindow &window, std::vector &tabs, int selected_tab, TabAssociatedData &tab_associated_data, const Json::Value *json_chapters) { + if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->draw(window, false); + + { + float shade_extra_height = 0.0f; + if(!tabs[selected_tab].search_bar) + shade_extra_height = 10.0f; + + const float width_per_tab = window_size.x / tabs.size(); + tab_background.setSize(sf::Vector2f(std::floor(width_per_tab - tab_margin_x * 2.0f), tab_height)); + + float tab_vertical_offset = tabs[selected_tab].search_bar ? tabs[selected_tab].search_bar->getBottomWithoutShadow() : 0.0f; + tabs[selected_tab].body->draw(window, body_pos, body_size, *json_chapters); + const float tab_y = std::floor(tab_vertical_offset + tab_height * 0.5f - (tab_text_size + 5.0f) * 0.5f) + shade_extra_height; + + tab_shade.setPosition(0.0f, std::floor(tab_vertical_offset)); + tab_shade.setSize(sf::Vector2f(window_size.x, shade_extra_height + tab_height + 10.0f)); + window.draw(tab_shade); + + int i = 0; + // TODO: Dont show tabs if there is only one tab + for(Tab &tab : tabs) { + if(i == selected_tab) { + tab_background.setPosition(std::floor(i * width_per_tab + tab_margin_x), std::floor(tab_vertical_offset) + shade_extra_height); + window.draw(tab_background); + } + const float center = (i * width_per_tab) + (width_per_tab * 0.5f); + // TODO: Optimize. Only set once for each tab! + tab_text.setString(tab.page->get_title()); + tab_text.setPosition(std::floor(center - tab_text.getLocalBounds().width * 0.5f), tab_y); + window.draw(tab_text); + ++i; + } + } + + if(tab_associated_data.fetching_next_page_running) + window.draw(gradient_points, 4, sf::Quads); // Note: sf::Quads doesn't work with egl + + if(!tab_associated_data.search_result_text.getString().isEmpty()) { + auto search_result_text_bounds = tab_associated_data.search_result_text.getLocalBounds(); + tab_associated_data.search_result_text.setPosition( + std::floor(body_pos.x + body_size.x * 0.5f - search_result_text_bounds.width * 0.5f), + std::floor(body_pos.y + body_size.y * 0.5f - search_result_text_bounds.height * 0.5f)); + window.draw(tab_associated_data.search_result_text); + } + + if(matrix && !matrix->is_initial_sync_finished()) { + // if(is_login_sync) { + load_sprite.setPosition(body_pos.x + body_size.x * 0.5f, body_pos.y + body_size.y * 0.5f); + load_sprite.setRotation(load_sprite_timer.getElapsedTime().asSeconds() * 400.0); + window.draw(load_sprite); + // } + std::string err_msg; + if(matrix->did_initial_sync_fail(err_msg)) { + show_notification("QuickMedia", "Initial matrix sync failed, error: " + err_msg, Urgency::CRITICAL); + window.close(); + exit(0); } } } @@ -947,30 +999,6 @@ namespace QuickMedia { json_chapters = &chapters_json; } - enum class FetchType { - SEARCH, - LAZY - }; - - struct FetchResult { - BodyItems body_items; - PluginResult result; - }; - - struct TabAssociatedData { - std::string update_search_text; - bool search_text_updated = false; - FetchStatus fetch_status = FetchStatus::NONE; - bool lazy_fetch_finished = false; - FetchType fetch_type; - bool typing = false; - bool fetching_next_page_running = false; - int fetched_page = 0; - sf::Text search_result_text; - std::future fetch_future; - std::future next_page_future; - }; - std::vector tab_associated_data; for(size_t i = 0; i < tabs.size(); ++i) { TabAssociatedData data; @@ -983,9 +1011,8 @@ namespace QuickMedia { double gradient_inc = 0.0; const float gradient_height = 5.0f; - sf::Vertex gradient_points[4]; - sf::Text tab_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), tab_text_size); + tab_text = sf::Text("", *FontLoader::get_font(FontLoader::FontType::LATIN), tab_text_size); int selected_tab = std::min(std::max(0, start_tab_index), (int)tabs.size() - 1); bool loop_running = true; @@ -995,7 +1022,7 @@ namespace QuickMedia { window_size.x = window_size_u.x; window_size.y = window_size_u.y; - auto submit_handler = [this, &after_submit_handler, &json_chapters, &tabs, &selected_tab, &loop_running, &redraw]() { + auto submit_handler = [this, &after_submit_handler, &json_chapters, &tabs, &tab_associated_data, &selected_tab, &loop_running, &redraw]() { BodyItem *selected_item = tabs[selected_tab].body->get_selected(); if(!selected_item) return; @@ -1082,7 +1109,16 @@ namespace QuickMedia { } else if(new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::CHAT) { current_page = PageType::CHAT; current_chat_room = matrix->get_room_by_id(selected_item->url); - chat_page(static_cast(new_tabs[0].page.get()), current_chat_room); + while(window.isOpen()) { + bool move_room = chat_page(static_cast(new_tabs[0].page.get()), current_chat_room, tabs, selected_tab, tab_associated_data[selected_tab]); + if(!move_room) + break; + BodyItem *selected_item = tabs[selected_tab].body->get_selected(); + if(!selected_item) + break; + current_chat_room = matrix->get_room_by_id(selected_item->url); + } + tabs[selected_tab].body->render_selection = true; //select_body_item_by_room(tabs[selected_tab].body.get(), current_chat_room); current_chat_room = nullptr; } else { @@ -1129,16 +1165,9 @@ namespace QuickMedia { }; } - sf::Vector2f body_pos; - sf::Vector2f body_size; sf::Event event; - - const float tab_spacer_height = 0.0f; - sf::RectangleShape tab_shade; - tab_shade.setFillColor(sf::Color(33, 38, 44)); - - sf::RoundedRectangleShape tab_background(sf::Vector2f(1.0f, 1.0f), 10.0f, 10); + tab_shade.setFillColor(sf::Color(31, 35, 41)); tab_background.setFillColor(tab_selected_color); sf::Clock frame_timer; @@ -1259,6 +1288,17 @@ namespace QuickMedia { gradient_points[3].position.y = window_size.y; } + if(tab_associated_data[selected_tab].fetching_next_page_running) { + double progress = 0.5 + std::sin(std::fmod(gradient_inc, 360.0) * 0.017453292519943295 - 1.5707963267948966*0.5) * 0.5; + gradient_inc += (frame_time_ms * 0.5); + sf::Color bottom_color = interpolate_colors(back_color, sf::Color(175, 180, 188), progress); + + gradient_points[0].color = back_color; + gradient_points[1].color = back_color; + gradient_points[2].color = bottom_color; + gradient_points[3].color = bottom_color; + } + if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->update(); if(tabs[selected_tab].page->is_lazy_fetch_page() && tab_associated_data[selected_tab].fetch_status == FetchStatus::NONE && !tab_associated_data[selected_tab].lazy_fetch_finished) { @@ -1337,74 +1377,7 @@ namespace QuickMedia { } window.clear(back_color); - if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->draw(window, false); - - { - float shade_extra_height = 0.0f; - if(!tabs[selected_tab].search_bar) - shade_extra_height = 10.0f; - - const float width_per_tab = window_size.x / tabs.size(); - tab_background.setSize(sf::Vector2f(std::floor(width_per_tab - tab_margin_x * 2.0f), tab_height)); - - float tab_vertical_offset = tabs[selected_tab].search_bar ? tabs[selected_tab].search_bar->getBottomWithoutShadow() : 0.0f; - tabs[selected_tab].body->draw(window, body_pos, body_size, *json_chapters); - const float tab_y = tab_spacer_height + std::floor(tab_vertical_offset + tab_height * 0.5f - (tab_text_size + 5.0f) * 0.5f) + shade_extra_height; - - tab_shade.setPosition(0.0f, tab_spacer_height + std::floor(tab_vertical_offset)); - tab_shade.setSize(sf::Vector2f(window_size.x, shade_extra_height + tab_height + 10.0f)); - window.draw(tab_shade); - - int i = 0; - // TODO: Dont show tabs if there is only one tab - for(Tab &tab : tabs) { - if(i == selected_tab) { - tab_background.setPosition(std::floor(i * width_per_tab + tab_margin_x), tab_spacer_height + std::floor(tab_vertical_offset) + shade_extra_height); - window.draw(tab_background); - } - const float center = (i * width_per_tab) + (width_per_tab * 0.5f); - // TODO: Optimize. Only set once for each tab! - tab_text.setString(tab.page->get_title()); - tab_text.setPosition(std::floor(center - tab_text.getLocalBounds().width * 0.5f), tab_y); - window.draw(tab_text); - ++i; - } - } - - if(tab_associated_data[selected_tab].fetching_next_page_running) { - double progress = 0.5 + std::sin(std::fmod(gradient_inc, 360.0) * 0.017453292519943295 - 1.5707963267948966*0.5) * 0.5; - gradient_inc += (frame_time_ms * 0.5); - sf::Color bottom_color = interpolate_colors(back_color, sf::Color(175, 180, 188), progress); - - gradient_points[0].color = back_color; - gradient_points[1].color = back_color; - gradient_points[2].color = bottom_color; - gradient_points[3].color = bottom_color; - window.draw(gradient_points, 4, sf::Quads); // Note: sf::Quads doesn't work with egl - } - - if(!tab_associated_data[selected_tab].search_result_text.getString().isEmpty()) { - auto search_result_text_bounds = tab_associated_data[selected_tab].search_result_text.getLocalBounds(); - tab_associated_data[selected_tab].search_result_text.setPosition( - std::floor(body_pos.x + body_size.x * 0.5f - search_result_text_bounds.width * 0.5f), - std::floor(body_pos.y + body_size.y * 0.5f - search_result_text_bounds.height * 0.5f)); - window.draw(tab_associated_data[selected_tab].search_result_text); - } - - if(matrix && !matrix->is_initial_sync_finished()) { - // if(is_login_sync) { - load_sprite.setPosition(body_pos.x + body_size.x * 0.5f, body_pos.y + body_size.y * 0.5f); - load_sprite.setRotation(load_sprite_timer.getElapsedTime().asSeconds() * 400.0); - window.draw(load_sprite); - // } - std::string err_msg; - if(matrix->did_initial_sync_fail(err_msg)) { - show_notification("QuickMedia", "Initial matrix sync failed, error: " + err_msg, Urgency::CRITICAL); - window.close(); - goto page_end; - } - } - + page_loop_render(window, tabs, selected_tab, tab_associated_data[selected_tab], json_chapters); window.display(); if(go_to_previous_page) { @@ -2642,7 +2615,7 @@ namespace QuickMedia { }; sf::RectangleShape comment_input_shade; - comment_input_shade.setFillColor(sf::Color(33, 38, 44)); + comment_input_shade.setFillColor(sf::Color(31, 35, 41)); sf::Sprite logo_sprite(plugin_logo); logo_sprite.setScale(0.8f, 0.8f); @@ -3138,11 +3111,17 @@ namespace QuickMedia { Message *message = nullptr; }; - void Program::chat_page(MatrixChatPage *matrix_chat_page, RoomData *current_room) { + bool Program::chat_page(MatrixChatPage *matrix_chat_page, RoomData *current_room, std::vector &room_tabs, int room_selected_tab, TabAssociatedData &room_tab_associated_data) { + assert(current_room); assert(strcmp(plugin_name, "matrix") == 0); + if(!current_room) { + show_notification("QuickMedia", "Bug: current room empty", Urgency::CRITICAL); + abort(); + } window.setTitle("QuickMedia - matrix - " + current_room->get_name()); auto video_page = std::make_unique(this); + bool move_room = false; std::vector tabs; @@ -3215,6 +3194,7 @@ namespace QuickMedia { bool setting_read_marker = false; bool redraw = true; + bool draw_room_list = true; // TODO: Optimize with hash map? auto find_body_item_by_event_id = [](std::shared_ptr *body_items, size_t num_body_items, const std::string &event_id, size_t *index_result = nullptr) -> std::shared_ptr { @@ -3815,7 +3795,7 @@ namespace QuickMedia { sf::Event event; sf::RectangleShape tab_shade; - tab_shade.setFillColor(sf::Color(33, 38, 44)); + tab_shade.setFillColor(sf::Color(31, 35, 41)); sf::RoundedRectangleShape tab_background(sf::Vector2f(1.0f, 1.0f), 10.0f, 10); tab_background.setFillColor(tab_selected_color); @@ -3854,7 +3834,7 @@ namespace QuickMedia { more_messages_below_rect.setFillColor(sf::Color(128, 50, 50)); sf::RectangleShape chat_input_shade; - chat_input_shade.setFillColor(sf::Color(33, 38, 44)); + chat_input_shade.setFillColor(sf::Color(31, 35, 41)); sf::Clock start_typing_timer; const double typing_timeout_seconds = 3.0; @@ -4134,6 +4114,29 @@ namespace QuickMedia { while (window.pollEvent(event)) { base_event_handler(event, PageType::EXIT, tabs[selected_tab].body.get(), nullptr, false, false); + if(event.type == sf::Event::KeyPressed && event.key.control && event.key.alt && (chat_state == ChatState::NAVIGATING || chat_state == ChatState::URL_SELECTION)) { + if(event.key.code == sf::Keyboard::Up || (event.key.control && event.key.code == sf::Keyboard::K)) { + room_tabs[room_selected_tab].body->select_previous_item(); + } else if(event.key.code == sf::Keyboard::Down || (event.key.control && event.key.code == sf::Keyboard::J)) { + room_tabs[room_selected_tab].body->select_next_item(); + } else if(event.key.code == sf::Keyboard::PageUp) { + room_tabs[room_selected_tab].body->select_previous_page(); + } else if(event.key.code == sf::Keyboard::PageDown) { + room_tabs[room_selected_tab].body->select_next_page(); + } else if(event.key.code == sf::Keyboard::Home) { + room_tabs[room_selected_tab].body->select_first_item(); + } else if(event.key.code == sf::Keyboard::End) { + room_tabs[room_selected_tab].body->select_last_item(); + } else if(event.key.code == sf::Keyboard::Escape) { + move_room = false; + goto chat_page_end; + } else if(event.key.code == sf::Keyboard::Enter) { + move_room = true; + goto chat_page_end; + } + continue; + } + if(event.type == sf::Event::GainedFocus) { is_window_focused = true; redraw = true; @@ -4142,20 +4145,20 @@ namespace QuickMedia { } else if(event.type == sf::Event::Resized || event.type == sf::Event::GainedFocus) { redraw = true; } else if(event.type == sf::Event::KeyPressed && chat_state == ChatState::NAVIGATING) { - if(event.key.code == sf::Keyboard::Up || event.key.code == sf::Keyboard::PageUp || event.key.code == sf::Keyboard::Home || (event.key.control && event.key.code == sf::Keyboard::K)){ + if(event.key.code == sf::Keyboard::Up || event.key.code == sf::Keyboard::PageUp || event.key.code == sf::Keyboard::Home || (event.key.control && event.key.code == sf::Keyboard::K)) { bool hit_top = false; switch(event.key.code) { case sf::Keyboard::Up: - hit_top = !tabs[selected_tab].body->select_previous_item(); + hit_top = !tabs[selected_tab].body.get()->select_previous_item(); break; case sf::Keyboard::K: - hit_top = !tabs[selected_tab].body->select_previous_item(); + hit_top = !tabs[selected_tab].body.get()->select_previous_item(); break; case sf::Keyboard::PageUp: - hit_top = !tabs[selected_tab].body->select_previous_page(); + hit_top = !tabs[selected_tab].body.get()->select_previous_page(); break; case sf::Keyboard::Home: - tabs[selected_tab].body->select_first_item(); + tabs[selected_tab].body.get()->select_first_item(); hit_top = true; break; default: @@ -4172,11 +4175,11 @@ namespace QuickMedia { }; } } else if(event.key.code == sf::Keyboard::Down || (event.key.control && event.key.code == sf::Keyboard::J)) { - tabs[selected_tab].body->select_next_item(); + tabs[selected_tab].body.get()->select_next_item(); } else if(event.key.code == sf::Keyboard::PageDown) { - tabs[selected_tab].body->select_next_page(); + tabs[selected_tab].body.get()->select_next_page(); } else if(event.key.code == sf::Keyboard::End) { - tabs[selected_tab].body->select_last_item(); + tabs[selected_tab].body.get()->select_last_item(); } else if((event.key.code == sf::Keyboard::Left || (event.key.control && event.key.code == sf::Keyboard::H)) && selected_tab > 0) { tabs[selected_tab].body->clear_cache(); --selected_tab; @@ -4476,9 +4479,6 @@ namespace QuickMedia { tab_shade_height = tab_spacer_height + std::floor(tab_vertical_offset) + tab_height + room_name_padding_y + padding_bottom; - chat_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x)); - chat_input.set_position(sf::Vector2f(std::floor(logo_padding_x + logo_size.x + chat_input_padding_x), window_size.y - chat_height - chat_input_padding_y)); - float body_padding_horizontal = 25.0f; float body_padding_vertical = 5.0f; float body_width = window_size.x - body_padding_horizontal * 2.0f; @@ -4487,16 +4487,28 @@ namespace QuickMedia { body_padding_horizontal = 0.0f; } - chat_input_shade.setSize(sf::Vector2f(window_size.x, chat_input_height_full)); - chat_input_shade.setPosition(0.0f, window_size.y - chat_input_shade.getSize().y); + this->body_pos = sf::Vector2f(0.0f, body_padding_vertical + tab_shade_height); + if(body_width > 640.0f) { + this->body_size = sf::Vector2f(250.0f, window_size.y - body_padding_vertical - tab_shade_height); + draw_room_list = true; + } else { + this->body_size = sf::Vector2f(0.0f, 0.0f); + draw_room_list = false; + } + + body_pos = sf::Vector2f(this->body_pos.x + this->body_size.x + body_padding_horizontal, body_padding_vertical + tab_shade_height); + body_size = sf::Vector2f(body_width - this->body_pos.x - this->body_size.x, window_size.y - chat_input_height_full - body_padding_vertical - tab_shade_height); - body_pos = sf::Vector2f(body_padding_horizontal, body_padding_vertical + tab_shade_height); - body_size = sf::Vector2f(body_width, window_size.y - chat_input_shade.getSize().y - body_padding_vertical - tab_shade_height); + chat_input_shade.setSize(sf::Vector2f(window_size.x - (body_pos.x - body_padding_horizontal), chat_input_height_full)); + chat_input_shade.setPosition(body_pos.x - body_padding_horizontal, window_size.y - chat_input_shade.getSize().y); + + chat_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x + body_pos.x - body_padding_horizontal)); + chat_input.set_position(sf::Vector2f(std::floor(body_pos.x - body_padding_horizontal + logo_padding_x + logo_size.x + chat_input_padding_x), window_size.y - chat_height - chat_input_padding_y)); more_messages_below_rect.setSize(sf::Vector2f(window_size.x, gradient_height)); - more_messages_below_rect.setPosition(0.0f, std::floor(window_size.y - chat_input_shade.getSize().y - gradient_height)); + more_messages_below_rect.setPosition(0.0f, std::floor(window_size.y - chat_input_height_full - gradient_height)); - logo_sprite.setPosition(logo_padding_x, std::floor(window_size.y - chat_input_shade.getSize().y * 0.5f - logo_size.y * 0.5f)); + logo_sprite.setPosition(body_pos.x - body_padding_horizontal + logo_padding_x, std::floor(window_size.y - chat_input_height_full * 0.5f - logo_size.y * 0.5f)); } while((provisional_message = provisional_message_queue.pop_if_available()) != std::nullopt) { @@ -4598,6 +4610,15 @@ namespace QuickMedia { window.clear(back_color); + room_tabs[room_selected_tab].body->render_selection = sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt) && (chat_state == ChatState::NAVIGATING || chat_state == ChatState::URL_SELECTION); + if(draw_room_list) { + sf::RectangleShape room_list_background(this->body_size); + room_list_background.setPosition(this->body_pos); + room_list_background.setFillColor(sf::Color(31, 35, 41)); + window.draw(room_list_background); + page_loop_render(window, room_tabs, room_selected_tab, room_tab_associated_data, &Json::Value::nullSingleton()); + } + const float width_per_tab = window_size.x / tabs.size(); tab_background.setSize(sf::Vector2f(std::floor(width_per_tab - tab_margin_x * 2.0f), tab_height)); @@ -4802,6 +4823,7 @@ namespace QuickMedia { previous_messages_future.cancel(); cleanup_tasks(); window.setTitle("QuickMedia - matrix"); + return move_room; } void Program::after_matrix_login_page() { diff --git a/src/SearchBar.cpp b/src/SearchBar.cpp index 739a0b6..5c5b860 100644 --- a/src/SearchBar.cpp +++ b/src/SearchBar.cpp @@ -46,7 +46,7 @@ namespace QuickMedia { //background.setCornersRadius(5); background_shadow.setFillColor(sf::Color(23, 25, 27)); //background_shadow.setPosition(background.getPosition() + sf::Vector2f(5.0f, 5.0f)); - shade.setFillColor(sf::Color(33, 38, 44)); + shade.setFillColor(sf::Color(31, 35, 41)); //background.setOutlineThickness(1.0f); //background.setOutlineColor(sf::Color(13, 15, 17)); if(plugin_logo && plugin_logo->getNativeHandle() != 0) -- cgit v1.2.3