From 7b48ab891023d76de6b13b56a8d5e205f62bc37d Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 28 May 2021 15:48:43 +0200 Subject: Improve body navigation --- src/Body.cpp | 789 +++++++++++++++++-------------------------------- src/QuickMedia.cpp | 61 ++-- src/Text.cpp | 2 +- src/plugins/Matrix.cpp | 8 +- 4 files changed, 307 insertions(+), 553 deletions(-) (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index e219e58..8cc139c 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -27,6 +27,10 @@ static const float reaction_padding_y = std::floor(7.0f * QuickMedia::get_ui_sca static const int embedded_item_font_size = std::floor(14 * QuickMedia::get_ui_scale()); namespace QuickMedia { + static float clamp(float value, float min, float max) { + return std::min(max, std::max(min, value)); + } + BodyItem::BodyItem(std::string _title) : visible(true), dirty(false), @@ -35,7 +39,6 @@ namespace QuickMedia { dirty_timestamp(false), thumbnail_is_local(false), userdata(nullptr), - last_drawn_time(0.0), timestamp(0), title_color(sf::Color::White), author_color(sf::Color::White), @@ -62,7 +65,9 @@ namespace QuickMedia { replies = other.replies; post_number = other.post_number; userdata = other.userdata; - last_drawn_time = other.last_drawn_time; + prev_last_loaded_height = other.prev_last_loaded_height; + last_loaded_height = other.last_loaded_height; + current_loaded_height = other.current_loaded_height; embedded_item_status = other.embedded_item_status; if(other.embedded_item) { embedded_item.reset(new BodyItem("")); @@ -87,6 +92,7 @@ namespace QuickMedia { author_color = other.author_color; description_color = other.description_color; extra = other.extra; + keep_alive_frames = other.keep_alive_frames; return *this; } @@ -103,20 +109,16 @@ namespace QuickMedia { replies_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14 * get_ui_scale())), embedded_item_load_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), embedded_item_font_size), draw_thumbnails(true), - wrap_around(false), line_separator_color(sf::Color(32, 37, 43, 255)), body_item_render_callback(nullptr), thumbnail_mask_shader(nullptr), program(program), selected_item(0), prev_selected_item(0), - page_scroll(0.0f), loading_icon(loading_icon_texture), num_visible_items(0), - first_item_fully_visible(true), - last_item_fully_visible(true), - first_fully_visible_item(-1), - last_fully_visible_item(-1), + top_cut_off(false), + bottom_cut_off(false), item_background(sf::Vector2f(1.0f, 1.0f), 10.0f, sf::Color(55, 60, 68), rounded_rectangle_shader), reaction_background(sf::Vector2f(1.0f, 1.0f), 10.0f, sf::Color(33, 37, 44), rounded_rectangle_shader) { @@ -138,7 +140,7 @@ namespace QuickMedia { // TODO: Make this work with wraparound enabled? // TODO: For plugins with different sized body items this can be weird, because after scrolling down thumbnails could load and they could move items up/down until we see items we haven't seen bool Body::select_previous_page() { - if(!selected_line_top_visible) + if(!selected_item_fits_in_body) return select_previous_item(false); for(int i = 0; i < num_visible_items - 1; ++i) { @@ -151,7 +153,7 @@ namespace QuickMedia { // TODO: Make this work with wraparound enabled? // TODO: For plugins with different sized body items this can be weird, because after scrolling down thumbnails could load and they could move items up/down until we see items we haven't seen bool Body::select_next_page() { - if(!selected_line_bottom_visible) + if(!selected_item_fits_in_body) return select_next_item(false); for(int i = 0; i < num_visible_items - 1; ++i) { @@ -165,32 +167,13 @@ namespace QuickMedia { if(items.empty()) return false; - clamp_selected_item_to_body_count = 1; - - if(scroll_page_if_large_item && !selected_line_top_visible) { - page_scroll += 128.0f; + if(scroll_page_if_large_item && !selected_item_fits_in_body && !selected_line_top_visible) { + selected_scrolled += 128.0f; return true; } - int new_selected_item = selected_item; - int num_items = (int)items.size(); - - for(int i = 0; i < num_items; ++i) { - if(new_selected_item - 1 < 0) { - if(wrap_around) - new_selected_item = num_items - 1; - else { - new_selected_item = selected_item; - break; - } - } else { - --new_selected_item; - } - if(items[new_selected_item]->visible) - break; - } - - if(selected_item == new_selected_item) + const int new_selected_item = get_previous_visible_item(selected_item); + if(new_selected_item == -1) return false; selected_item = new_selected_item; @@ -201,32 +184,13 @@ namespace QuickMedia { if(items.empty()) return false; - clamp_selected_item_to_body_count = 1; - - if(scroll_page_if_large_item && !selected_line_bottom_visible) { - page_scroll -= 128.0f; + if(scroll_page_if_large_item && !selected_item_fits_in_body && !selected_line_bottom_visible) { + selected_scrolled -= 128.0f; return true; } - int new_selected_item = selected_item; - int num_items = (int)items.size(); - - for(int i = 0; i < num_items; ++i) { - if(new_selected_item + 1 == num_items) { - if(wrap_around) { - new_selected_item = 0; - } else { - new_selected_item = selected_item; - break; - } - } else { - ++new_selected_item; - } - if(items[new_selected_item]->visible) - break; - } - - if(selected_item == new_selected_item) + const int new_selected_item = get_next_visible_item(selected_item); + if(new_selected_item == -1) return false; selected_item = new_selected_item; @@ -237,9 +201,8 @@ namespace QuickMedia { //assert(item >= 0 && item < (int)items.size()); selected_item = item; clamp_selection(); - if(reset_prev_selected_item) - prev_selected_item = selected_item; - clamp_selected_item_to_body_count = 1; + //if(reset_prev_selected_item) + // prev_selected_item = selected_item; //page_scroll = 0.0f; } @@ -257,26 +220,18 @@ namespace QuickMedia { void Body::select_first_item() { selected_item = 0; - if(attach_side == AttachSide::TOP) { - prev_selected_item = selected_item; - page_scroll = 0.0f; - } + //if(attach_side == AttachSide::TOP) { + // prev_selected_item = selected_item; + // page_scroll = 0.0f; + //} clamp_selection(); - clamp_selected_item_to_body_count = 1; - //item_background_target_pos_y = body_pos.y; - //item_background.set_position(sf::Vector2f(body_pos.x, item_background_target_pos_y)); } - void Body::select_last_item(bool reset_prev_select) { + void Body::select_last_item() { int new_selected_item = std::max(0, (int)items.size() - 1); selected_item = new_selected_item; - if(reset_prev_select) - prev_selected_item = selected_item; //page_scroll = 0.0f; clamp_selection(); - clamp_selected_item_to_body_count = 1; - //item_background_target_pos_y = body_pos.y + body_size.y - item_background.get_size().y; - //item_background.set_position(sf::Vector2f(body_pos.x, item_background_target_pos_y)); } void Body::clear_items() { @@ -284,9 +239,6 @@ namespace QuickMedia { selected_item = 0; prev_selected_item = selected_item; page_scroll = 0.0f; - clamp_selected_item_to_body_count = 1; - //item_background_target_pos_y = body_pos.y; - //item_background.set_position(sf::Vector2f(body_pos.x, item_background_target_pos_y)); } void Body::prepend_items_reverse(BodyItems new_items) { @@ -300,22 +252,34 @@ namespace QuickMedia { } // TODO: Binary search and use hint to start search from start or end (for example when adding "previous" items or "next" items) - void Body::insert_item_by_timestamp(std::shared_ptr body_item) { + size_t Body::insert_item_by_timestamp(std::shared_ptr body_item) { for(size_t i = 0; i < items.size(); ++i) { if(body_item->get_timestamp() < items[i]->get_timestamp()) { items.insert(items.begin() + i, std::move(body_item)); - return; + return i; } } items.push_back(std::move(body_item)); + return items.size() - 1; } // TODO: Optimize by resizing |items| before insert void Body::insert_items_by_timestamps(BodyItems new_items) { + int new_selected_item = selected_item; + for(auto &new_item : new_items) { insert_item_by_timestamp(new_item); + if(attach_side == AttachSide::TOP) { + new_selected_item = get_previous_visible_item(new_selected_item); + } else { + new_selected_item = get_next_visible_item(new_selected_item); + } } + + selected_item = new_selected_item; + clamp_selection(); items_set_dirty(); + prev_selected_item = selected_item; } void Body::clear_cache() { @@ -343,18 +307,6 @@ namespace QuickMedia { return items[selected_item]; } - BodyItem* Body::get_last_fully_visible_item() { - if(last_fully_visible_item < 0 || last_fully_visible_item >= (int)items.size() || !items[last_fully_visible_item]->visible) - return nullptr; - return items[last_fully_visible_item].get(); - } - - BodyItem* Body::get_last_visible_item() { - if(last_visible_item < 0 || last_visible_item >= (int)items.size() || !items[last_visible_item]->visible) - return nullptr; - return items[last_visible_item].get(); - } - void Body::clamp_selection() { int num_items = (int)items.size(); if(items.empty()) { @@ -386,13 +338,13 @@ namespace QuickMedia { if(keyboard_navigation && event.type == sf::Event::KeyPressed && !event.key.alt) { if(event.key.code == sf::Keyboard::Up || (event.key.control && event.key.code == sf::Keyboard::K)) { render_selected_item_bg = true; - bool top_reached = select_previous_item(); + bool top_reached = select_previous_item(true); if(!top_reached && on_top_reached) on_top_reached(); return true; } else if(event.key.code == sf::Keyboard::Down || (event.key.control && event.key.code == sf::Keyboard::J)) { render_selected_item_bg = true; - bool bottom_reached = select_next_item(); + bool bottom_reached = select_next_item(true); if(!bottom_reached && on_bottom_reached) on_bottom_reached(); return true; @@ -423,9 +375,6 @@ namespace QuickMedia { } } - if(event.type == sf::Event::Resized) - clamp_selected_item_to_body_count = 1; - if(!is_touch_enabled()) return false; @@ -467,7 +416,7 @@ namespace QuickMedia { void Body::draw(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size, const Json::Value &content_progress) { if(items_dirty != DirtyState::FALSE) { if(using_filter || items_dirty == DirtyState::FORCE_TRUE) - filter_search_fuzzy(current_filter, false); + filter_search_fuzzy(current_filter); items_dirty = DirtyState::FALSE; } @@ -475,467 +424,229 @@ namespace QuickMedia { const float scissor_y = pos.y; pos.y = 0.0f; - const float start_y = pos.y; float frame_time = frame_timer.restart().asSeconds(); - if(frame_time > 2.0f) - frame_time = 2.0f; + if(frame_time > 1.0f) + frame_time = 1.0f; if(selected_item >= (int)items.size()) selected_item = (int)items.size() - 1; if(selected_item < 0) - selected_item = 0; + selected_item = 0; if(prev_selected_item < 0 || prev_selected_item >= (int)items.size()) { prev_selected_item = selected_item; } bool body_size_changed = std::abs(size.x - body_size.x) > 0.1f || std::abs(size.y - body_size.y) > 0.1f; - if(body_size_changed) { + if(body_size_changed) body_size = size; - shit_hack_body_size_change = 2; - } - - if(shit_hack_body_size_change > 0) - body_size_changed = true; - - shit_hack_body_size_change--; - if(shit_hack_body_size_change < 0) - shit_hack_body_size_change = 0; elapsed_time_sec = draw_timer.getElapsedTime().asSeconds(); - const bool scroll_past_first = first_item_fully_visible && offset_to_top > 0.1f; - const bool scroll_past_last = last_item_fully_visible && offset_to_bottom > 0.1f; - - if(std::abs(mouse_scroll_accel.y) > 0.1) { - if((attach_side == AttachSide::BOTTOM && scroll_past_first) || (attach_side == AttachSide::TOP && scroll_past_last)) - body_size_changed = true; - } else { - if((attach_side == AttachSide::TOP && scroll_past_first) || (attach_side == AttachSide::BOTTOM && scroll_past_last)) - body_size_changed = true; - } - - bool keep_selected_inside_body = clamp_selected_item_to_body_count > 0 || offset_to_top > 0.1f || offset_to_bottom > 0.1f; - clamp_selected_item_to_body_count--; - if(clamp_selected_item_to_body_count < 0) - clamp_selected_item_to_body_count = 0; - - if(is_touch_enabled()) { - const sf::Vector2f mouse_pos_diff(mouse_pos_raw.x - mouse_pos.x, mouse_pos_raw.y - mouse_pos.y); - const float move_speed = 35.0f; - sf::Vector2f prev_mouse_pos = mouse_pos; - mouse_pos.x += (mouse_pos_diff.x * std::min(1.0f, frame_time * move_speed)); - mouse_pos.y += (mouse_pos_diff.y * std::min(1.0f, frame_time * move_speed)); - const sf::Vector2f mouse_pos_diff_smooth = mouse_pos - prev_mouse_pos; - - sf::Vector2f mouse_pos_raw_diff(mouse_pos_raw.x - prev_mouse_pos_raw.x, mouse_pos_raw.y - prev_mouse_pos_raw.y); - prev_mouse_pos_raw = mouse_pos_raw; - - if(items_cut_off) { - if(mouse_left_pressed) { - page_scroll += mouse_pos_diff_smooth.y; - mouse_scroll_accel = sf::Vector2f(mouse_pos_raw_diff.x, mouse_pos_raw_diff.y); - mouse_scroll_accel *= (float)((double)frame_time * 120.0); - } else { - page_scroll += mouse_scroll_accel.y; - } - } - - if(mouse_scroll_accel.y > 0.1 && first_fully_visible_item == -1) { - keep_selected_inside_body = true; - } else if(mouse_scroll_accel.y < -0.1 && last_fully_visible_item == -1) { - keep_selected_inside_body = true; - } - - if(mouse_scroll_accel.y > 0.1f && first_fully_visible_item != -1) { - selected_item = first_fully_visible_item; - clamp_selection(); - // TODO: Cache this - if(on_top_reached) { - int first_visible_item_n = -1; - for(int i = 0; i <= selected_item; ++i) { - if(items[i]->visible) { - first_visible_item_n = i; - break; - } - } - if(first_visible_item_n == first_fully_visible_item) - on_top_reached(); - } - } else if(mouse_scroll_accel.y < -0.1f && last_fully_visible_item != -1) { - selected_item = last_fully_visible_item; - clamp_selection(); - // TODO: Cache this - if(on_bottom_reached) { - int last_visible_item_n = -1; - for(int i = items.size() - 1; i >= selected_item; --i) { - if(items[i]->visible) { - last_visible_item_n = i; - break; - } - } - if(last_visible_item_n == last_fully_visible_item) - on_bottom_reached(); - } - } - - if(!mouse_left_pressed) { - const float scroll_deaccel = 1.02f; - double deaccel = scroll_deaccel * (1.0 + frame_time); - if(deaccel > 0.0001) { - mouse_scroll_accel.x /= deaccel; - if(fabs(mouse_scroll_accel.x) < 0.0001) - mouse_scroll_accel.x = 0.0; - - mouse_scroll_accel.y /= deaccel; - if(fabs(mouse_scroll_accel.y) < 0.0001) - mouse_scroll_accel.y = 0.0; - } else { - deaccel = 0.0; - mouse_scroll_accel.x = 0.0; - mouse_scroll_accel.y = 0.0; - } - } - } - - const int prev_body_item_index = get_previous_visible_item(selected_item); - bool selected_merge_with_previous = !items.empty() && body_item_merge_handler && body_item_merge_handler(prev_body_item_index == -1 ? nullptr : items[prev_body_item_index].get(), items[selected_item].get()); - - double target_scroll = extra_scroll_target; - if(selected_merge_with_previous) - target_scroll += spacing_y; - if(selected_item == last_visible_item) - target_scroll -= selected_item_height; - const double scroll_diff = target_scroll - extra_scroll_current; - const double scroll_move_speed = (frame_time > 0.010f ? 10.0f : 15.0f); - extra_scroll_current += (scroll_diff * std::min(1.0, frame_time * scroll_move_speed)); - - double scroll_smooth_diff = extra_scroll_current - prev_extra_scroll; - prev_extra_scroll = extra_scroll_current; - - if(body_size_changed) { - extra_scroll_current = extra_scroll_target; - prev_extra_scroll = extra_scroll_current; - } - - bool selected_item_fits_on_screen = selected_item_height <= size.y; - if(shit_hack_body_size_change == 0 && selected_item_fits_on_screen && render_selected_item_bg && !first_item_fully_visible && !last_item_fully_visible && items_cut_off && (selected_item == first_visible_item || selected_item == last_visible_item)) { - page_scroll += scroll_smooth_diff; - if(selected_item != first_fully_visible_item && selected_item != last_fully_visible_item) - keep_selected_inside_body = false; - } - - //item_separator.setFillColor(line_separator_color); const int prev_num_visible_items = num_visible_items; num_visible_items = 0; - first_fully_visible_item = -1; - last_fully_visible_item = -1; first_visible_item = -1; last_visible_item = -1; selected_line_top_visible = true; selected_line_bottom_visible = true; + selected_item_fits_in_body = true; + top_cut_off = false; + bottom_cut_off = false; + + const int selected_item_diff = selected_item - prev_selected_item; + prev_selected_item = selected_item; + + const int num_items = items.size(); + if(num_items == 0 || size.x <= 0.001f || size.y <= 0.001f) { + if(num_items == 0) + page_scroll = 0.0f; - int num_items = items.size(); - if(num_items == 0 || size.y <= 0.001f) { for(auto &body_item : items) { clear_body_item_cache(body_item.get()); if(body_item->embedded_item) clear_body_item_cache(body_item->embedded_item.get()); } - first_item_fully_visible = true; - last_item_fully_visible = true; - items_cut_off = false; - offset_to_top = 0.0f; - offset_to_bottom = 0.0f; + mouse_left_clicked = false; - //item_background_target_pos_y = body_pos.y; - //item_background.set_position(sf::Vector2f(body_pos.x, item_background_target_pos_y)); return; } - // TODO: Optimize this, especially when scrolling to top/bottom. - // TODO: If the thumbnail fallback size is larger than the real thumbnail size then the scroll will be incorrect when scrolling down - // because first we scroll by a larger value and then the thumbnail size changes when the thumbnail has finished loading - // and the selected item will no longer be exactly at the bottom of the window, and we will see parts of then next item. - // To fix this, we should detect when the selected item is at the bottom of the screen and the thumbnail changes from image fallback to the real thumbnail - // and add the difference in size to scroll, if the real thumbnail size is smaller than the image fallback. - int selected_item_diff = selected_item - prev_selected_item; - int selected_int_diff_abs = std::abs(selected_item_diff); - if(selected_item_diff > 0) { - int num_items_scrolled = 0; - int i = prev_selected_item; - const int prev_body_item_index = get_previous_visible_item(i); - BodyItem *prev_body_item = prev_body_item_index == -1 ? nullptr : items[prev_body_item_index].get(); - double scroll_before = page_scroll; - while(num_items_scrolled < selected_int_diff_abs && i < num_items) { - if(items[i]->visible) { - const bool merge_with_previous = body_item_merge_handler && body_item_merge_handler(prev_body_item, items[i].get()); - page_scroll += get_item_height(items[i].get(), size.x, selected_int_diff_abs < 50, true, merge_with_previous, i); - if(merge_with_previous) - page_scroll -= spacing_y; - page_scroll += spacing_y; - prev_body_item = items[i].get(); - } - ++num_items_scrolled; - ++i; - } - prev_selected_item = selected_item; - if(selected_item_fits_on_screen) - extra_scroll_target -= (page_scroll - scroll_before); - } else if(selected_item_diff < 0) { - int num_items_scrolled = 0; - int i = prev_selected_item - 1; - BodyItem *prev_body_item; - double scroll_before = page_scroll; - while(num_items_scrolled < selected_int_diff_abs && i >= 0) { - if(items[i]->visible) { - const int prev_body_item_index = get_previous_visible_item(i); - prev_body_item = prev_body_item_index == -1 ? nullptr : items[prev_body_item_index].get(); - const bool merge_with_previous = body_item_merge_handler && body_item_merge_handler(prev_body_item, items[i].get()); - page_scroll -= get_item_height(items[i].get(), size.x, selected_int_diff_abs < 50, true, merge_with_previous, i); - if(merge_with_previous) - page_scroll += spacing_y; - page_scroll -= spacing_y; - } - ++num_items_scrolled; - --i; - } - prev_selected_item = selected_item; - if(selected_item_fits_on_screen) - extra_scroll_target -= (page_scroll - scroll_before); - } - - if(keep_selected_inside_body) { - if(!first_item_fully_visible && !last_item_fully_visible) { - if(offset_to_top > 0.0f) - page_scroll -= offset_to_top; - else if(offset_to_bottom > 0.0f) - page_scroll += offset_to_bottom; - } else { - if(attach_side == AttachSide::TOP) { - if(first_item_fully_visible) { - page_scroll -= offset_to_top; - } else if(last_item_fully_visible && !first_item_fully_visible && body_size_changed) { - page_scroll += offset_to_bottom; - //page_scroll = get_offset_to_first_visible_item(size); - } - } else if(attach_side == AttachSide::BOTTOM) { - if(last_item_fully_visible) { - page_scroll += offset_to_bottom; - } else if(first_item_fully_visible && !last_item_fully_visible && body_size_changed) { - page_scroll -= offset_to_top; - //page_scroll = get_offset_to_last_visible_item(size); - } - } - } - } - - selected_item_height = get_item_height(items[selected_item].get(), size.x, true, true, selected_merge_with_previous, selected_item); - selected_item_height += spacing_y; - selected_item_fits_on_screen = selected_item_height <= size.y; - selected_line_top_visible = pos.y - start_y + page_scroll >= 0.0f; - selected_line_bottom_visible = pos.y - start_y + page_scroll + selected_item_height <= size.y; - - if(keep_selected_inside_body) { - if(pos.y - start_y + page_scroll >= size.y && !selected_item_fits_on_screen) - page_scroll = 0.0f; - else if(pos.y - start_y + page_scroll + selected_item_height <= 0.0f && !selected_item_fits_on_screen) - page_scroll = size.y - selected_item_height; - } - - selected_line_top_visible |= selected_item_fits_on_screen; - selected_line_bottom_visible |= selected_item_fits_on_screen; - - if(keep_selected_inside_body) { - if(page_scroll > size.y - selected_item_height && selected_item_fits_on_screen) { - page_scroll = size.y - selected_item_height; - if(selected_merge_with_previous) - page_scroll += spacing_y*2.0f; - - int next_body_item_index = get_next_visible_item(selected_item); - const bool merge_with_next = next_body_item_index != -1 && body_item_merge_handler && body_item_merge_handler(items[selected_item].get(), items[next_body_item_index].get()); - if(!selected_merge_with_previous && merge_with_next) - page_scroll += spacing_y; - } else if(page_scroll < (selected_merge_with_previous ? spacing_y : 0.0f) && selected_line_top_visible && selected_item_fits_on_screen) { - if(selected_merge_with_previous) - page_scroll = spacing_y; - else - page_scroll = 0.0f; - } - } - - //page_scroll = std::floor(page_scroll); - pos.y += page_scroll; + const int selected_prev_item = get_previous_visible_item(selected_item); + const bool selected_merge_with_previous = selected_prev_item != -1 && body_item_merge_handler && body_item_merge_handler(items[selected_prev_item].get(), items[selected_item].get()); + get_item_height(items[selected_item].get(), size.x, true, true, selected_merge_with_previous, selected_item); + selected_item_fits_in_body = items[selected_item]->last_loaded_height < body_size.y; + if(selected_item_fits_in_body) + selected_scrolled = 0.0f; - first_item_fully_visible = true; - bool last_item_fully_visible_set = false; - bool items_cut_off_set = false; + const sf::Vector2u window_size = window.getSize(); + const sf::View prev_view = window.getView(); - sf::Vector2u window_size = window.getSize(); - - sf::View prev_view = window.getView(); sf::View new_view(sf::FloatRect(0.0f, 0.0f, window_size.x, size.y)); new_view.setViewport(sf::FloatRect(0.0f, scissor_y / (float)window_size.y, 1.0f, size.y / (float)window_size.y)); window.setView(new_view); - if(prev_num_visible_items > 0) { - bool instant_move = false; - if(target_y_set == TargetSetState::SET) { - target_y_set = TargetSetState::APPLIED; - instant_move = true; - } - - const float speed = frame_time > 0.010f ? 35.0f : 50.0f; - - const float item_background_prev_pos_y = item_background.get_position().y; - const float item_background_pos_diff = item_background_target_pos_y - item_background_prev_pos_y; - const float item_background_move_speed = instant_move ? 1000.0f : speed; - item_background.set_position(sf::Vector2f(pos.x, item_background_prev_pos_y + (item_background_pos_diff * std::min(1.0f, frame_time * item_background_move_speed)))); - - const float item_background_prev_height = item_background.get_size().y; - const float item_background_height_diff = item_background_target_height - item_background_prev_height; - const float item_background_height_speed = instant_move ? 1000.0f : speed; - item_background.set_size(sf::Vector2f(size.x, item_background_prev_height + (item_background_height_diff * std::min(1.0f, frame_time * item_background_height_speed)))); - - if(render_selected_item_bg) - item_background.draw(window); + bool instant_move = body_size_changed; + if(target_y_set == TargetSetState::SET) { + target_y_set = TargetSetState::APPLIED; + instant_move = true; } - sf::Vector2f prev_pos = pos; - int i; - for(i = selected_item - 1; i >= 0;) { - auto &item = items[i]; - - // TODO: Find a better solution? - if(!item->visible) { - --i; - continue; - } - - int prev_body_item_index = get_previous_visible_item(i); - const bool merge_with_previous = body_item_merge_handler && body_item_merge_handler(prev_body_item_index == -1 ? nullptr : items[prev_body_item_index].get(), item.get()); + const float speed = 30.0f; - item->last_drawn_time = elapsed_time_sec; - float item_height = get_item_height(item.get(), size.x, true, true, merge_with_previous, i); - float item_height_with_merge = item_height + spacing_y; - prev_pos.y -= item_height_with_merge; + const float item_background_prev_height = item_background.get_size().y; + const float item_background_height_diff = item_background_target_height - item_background_prev_height; + const float item_background_height_speed = instant_move ? 1000.0f : speed; + const float item_background_new_height = item_background_prev_height + (item_background_height_diff * std::min(1.0f, frame_time * item_background_height_speed)); + item_background.set_size(sf::Vector2f(size.x, item_background_new_height)); - if(prev_pos.y < start_y) { - items_cut_off = true; - items_cut_off_set = true; - first_item_fully_visible = false; - } - - if(prev_pos.y + item_height_with_merge <= start_y) - break; - - draw_item(window, item.get(), prev_pos, size, item_height, i, content_progress, true, merge_with_previous); - ++num_visible_items; - first_visible_item = i; - last_visible_item = i; - - if(first_item_fully_visible) - first_fully_visible_item = i; + const float item_background_prev_pos_y = item_background.get_position().y; + const float item_background_pos_diff = item_background_target_pos_y - item_background_prev_pos_y; + const float item_background_move_speed = instant_move ? 1000.0f : speed; + float item_background_new_pos_y = item_background_prev_pos_y + (item_background_pos_diff * std::min(1.0f, frame_time * item_background_move_speed)); + if(selected_item_fits_in_body) { + item_background_new_pos_y = std::min(item_background_new_pos_y, body_size.y - item_background_new_height - spacing_y); + item_background_new_pos_y = std::max(item_background_new_pos_y, 0.0f); + } + item_background.set_position(sf::Vector2f(pos.x, item_background_new_pos_y)); - if(merge_with_previous) - prev_pos.y += spacing_y; + if(prev_num_visible_items > 0 && render_selected_item_bg) + item_background.draw(window); + + int index; + if(attach_side == AttachSide::TOP) { + if(page_scroll > 0.0) + page_scroll = 0.0; + pos.y += page_scroll; + index = get_next_visible_item(-1); - i = prev_body_item_index; + if(pos.y + selected_scrolled > 0.0f) + selected_scrolled = 0.0f; + else + pos.y += selected_scrolled; + } else { + if(page_scroll < 0.0) + page_scroll = 0.0; + pos.y += body_size.y; + pos.y += page_scroll; + index = get_previous_visible_item(num_items); + + if(pos.y + selected_scrolled < body_size.y) + selected_scrolled = 0.0f; + else + pos.y += selected_scrolled; } - offset_to_top = prev_pos.y - start_y; + pos.y += selected_scrolled; - BodyItem *prev_body_item = prev_body_item_index == -1 ? nullptr : items[prev_body_item_index].get(); - bool after_merge_with_previous = false; + BodyItem *prev_body_item = nullptr; + const double height_move_speed = 1000.0f; - sf::Vector2f after_pos = pos; - for(int i = selected_item; i < num_items;) { - auto &item = items[i]; + // TODO: Improve performance. Skip items that are obviously not visible or anywhere near the body. Limit loop to 100-200 items around the selected item + while(index != -1) { + BodyItem *item = items[index].get(); + assert(item->visible); - // TODO: Find a better solution? - if(!item->visible) { - ++i; - continue; + int prev_index; + if(attach_side == AttachSide::BOTTOM) { + prev_index = get_previous_visible_item(index); + if(prev_index == -1) + prev_body_item = nullptr; + else + prev_body_item = items[prev_index].get(); } - after_merge_with_previous = body_item_merge_handler && body_item_merge_handler(prev_body_item, item.get()); - if(after_merge_with_previous) - after_pos.y -= spacing_y; + const bool merge_with_previous = body_item_merge_handler && body_item_merge_handler(prev_body_item, item); + if(attach_side == AttachSide::TOP && merge_with_previous) + pos.y -= spacing_y; + + get_item_height(item, size.x, false, true, merge_with_previous, index); + const float item_height_diff = item->last_loaded_height - item->current_loaded_height; + const float add_height = item_height_diff * std::min(1.0, frame_time * height_move_speed); + item->current_loaded_height += add_height; + //page_scroll += add_height; - float item_height = get_item_height(item.get(), size.x, true, true, after_merge_with_previous, i); + float top_y; + if(attach_side == AttachSide::TOP) + top_y = pos.y; + else + top_y = pos.y - (item->current_loaded_height + spacing_y); - if(after_pos.y < start_y) { - items_cut_off = true; - first_item_fully_visible = false; + if(top_y < 0.0f) { + top_cut_off = true; + if(index == selected_item) + selected_line_top_visible = false; } - if(after_pos.y - start_y >= size.y) { - if(first_fully_visible_item == -1) - first_item_fully_visible = false; - last_item_fully_visible = false; - items_cut_off = true; - last_item_fully_visible_set = true; - items_cut_off_set = true; - break; + if(top_y + item->current_loaded_height > body_size.y) { + bottom_cut_off = true; + if(index == selected_item) + selected_line_bottom_visible = false; } - item->last_drawn_time = elapsed_time_sec; + const bool is_item_visible_in_body = top_y + item->current_loaded_height >= 0.0f && top_y <= body_size.y; + if(is_item_visible_in_body || index == selected_item) { + get_item_height(item, size.x, true, true, merge_with_previous, index); + const float item_height_diff = item->last_loaded_height - item->current_loaded_height; + const float add_height = item_height_diff * std::min(1.0, frame_time * height_move_speed); + item->current_loaded_height += add_height; + if(attach_side == AttachSide::BOTTOM) + pos.y -= (item->current_loaded_height + spacing_y); + //page_scroll += add_height; + + //const float top_y_clamped = clamp(pos.y, 0.0f, body_size.y); + //const float bottom_y_clamped = std::min(pos.y + item->current_loaded_height, body_size.y); + + //float offset_y = 0.0f; + //if(pos.y < 0.0f) + // offset_y = pos.y; + //else if(pos.y > body_size.y) + // offset_y = body_size.y - pos.y; + + //sf::View new_view(sf::FloatRect(0.0f, 0.0f, window_size.x, scissor_y + bottom_y_clamped)); + //new_view.setViewport(sf::FloatRect(0.0f, (scissor_y + top_y_clamped) / (float)window_size.y, 1.0f, (scissor_y + bottom_y_clamped) / (float)window_size.y)); + //window.setView(new_view); + + draw_item(window, item, pos/*sf::Vector2f(pos.x, offset_y)*/, size, item->current_loaded_height, index, content_progress, true, merge_with_previous); + handle_item_render(item, pos, size, item->current_loaded_height, index); + ++num_visible_items; + + if(first_visible_item == -1 || index < first_visible_item) + first_visible_item = index; + if(last_visible_item == -1 || index > last_visible_item) + last_visible_item = index; + + if(attach_side == AttachSide::TOP) + pos.y += (item->current_loaded_height + spacing_y); + } else { + if(attach_side == AttachSide::TOP) + pos.y += (item->current_loaded_height + spacing_y); + else + pos.y -= (item->current_loaded_height + spacing_y); - draw_item(window, item.get(), after_pos, size, item_height, i, content_progress, true, after_merge_with_previous); - after_pos.y += item_height; - after_pos.y += spacing_y; - ++num_visible_items; - if(first_visible_item == -1) - first_visible_item = i; - last_visible_item = i; + if(item->keep_alive_frames == 0) { + clear_body_item_cache(item); + // TODO: Make sure the embedded item is not referencing another item in the |items| list + if(item->embedded_item) + clear_body_item_cache(item->embedded_item.get()); + } else { + --item->keep_alive_frames; + } + } - int next_body_item_index = get_next_visible_item(i); - const bool merge_with_next = next_body_item_index != -1 && body_item_merge_handler && body_item_merge_handler(item.get(), next_body_item_index == -1 ? nullptr : items[next_body_item_index].get()); + if(attach_side == AttachSide::BOTTOM && merge_with_previous) + pos.y += spacing_y; - if(after_pos.y - start_y - (merge_with_next ? 0.0f : spacing_y) > size.y) { - last_item_fully_visible = false; - items_cut_off = true; - last_item_fully_visible_set = true; - items_cut_off_set = true; + if(attach_side == AttachSide::TOP) { + prev_body_item = item; + index = get_next_visible_item(index); } else { - last_fully_visible_item = i; + index = prev_index; } - - if(first_item_fully_visible && first_fully_visible_item == -1) - first_fully_visible_item = i; - - prev_body_item = items[i].get(); - - i = next_body_item_index; - if(i == -1) - break; } window.setView(prev_view); - if(first_fully_visible_item == -1) - first_fully_visible_item = selected_item; - if(last_fully_visible_item == -1) - last_fully_visible_item = selected_item; - - offset_to_bottom = size.y - (after_pos.y - start_y - (last_item_fully_visible && after_merge_with_previous ? spacing_y : 0.0f)); - - if(!last_item_fully_visible_set) - last_item_fully_visible = true; - if(!items_cut_off_set) - items_cut_off = false; - - // TODO: Only do this for items that are not visible, do not loop all items. - // TODO: Improve performance! right now it can use up to 5-7% cpu with a lot of items! - for(auto &body_item : items) { - if(elapsed_time_sec - body_item->last_drawn_time >= 1.5) - clear_body_item_cache(body_item.get()); - // The embedded item might or might not refer to another item in |items|, so we have to make sure we also check it - if(body_item->embedded_item && elapsed_time_sec - body_item->embedded_item->last_drawn_time >= 1.5) - clear_body_item_cache(body_item->embedded_item.get()); - } - mouse_left_clicked = false; if(clicked_body_item) { auto clicked_body_item_tmp = clicked_body_item; // tmp because below call to body_item_select_callback may call this same draw function @@ -943,6 +654,37 @@ namespace QuickMedia { if(body_item_select_callback) body_item_select_callback(clicked_body_item_tmp.get()); } + + const float item_target_top_diff = item_background_target_pos_y; + const float item_target_bottom_diff = (item_background_target_pos_y + item_background_target_height + spacing_y) - body_size.y; + if(((body_size_changed && attach_side == AttachSide::BOTTOM) || selected_item_diff < 0) && item_target_top_diff < 0.0f) { + //extra_scroll_target -= item_target_top_diff; + stuck_direction = StuckDirection::TOP; + } else if(((body_size_changed && attach_side == AttachSide::TOP) || selected_item_diff > 0) && item_target_bottom_diff > 0.0) { + //extra_scroll_target -= item_target_bottom_diff; + stuck_direction = StuckDirection::BOTTOM; + } + + if(stuck_direction == StuckDirection::TOP && selected_item_diff > 0 && item_target_top_diff > -0.0001f/* && scroll_diff > -0.0001f*/) + stuck_direction = StuckDirection::NONE; + + if(stuck_direction == StuckDirection::BOTTOM && selected_item_diff < 0 && item_target_bottom_diff < 0.0001f/* && scroll_diff < 0.0001f*/) + stuck_direction = StuckDirection::NONE; + + const float page_scroll_speed = std::min(1.0f, frame_time * speed); + if(stuck_direction == StuckDirection::TOP) { + if(body_size_changed) + page_scroll -= item_target_top_diff; + else + page_scroll -= item_target_top_diff*page_scroll_speed; + } + + if(stuck_direction == StuckDirection::BOTTOM) { + if(body_size_changed) + page_scroll -= item_target_bottom_diff; + else + page_scroll -= item_target_bottom_diff*page_scroll_speed; + } } void Body::update_dirty_state(BodyItem *body_item, float width) { @@ -1029,6 +771,8 @@ namespace QuickMedia { body_item->timestamp_text.reset(); body_item->dirty_timestamp = true; } + + body_item->keep_alive_frames = 0; } sf::Vector2i Body::get_item_thumbnail_size(BodyItem *item) const { @@ -1064,7 +808,7 @@ namespace QuickMedia { } void Body::draw_item(sf::RenderWindow &window, BodyItem *item, sf::Vector2f pos, sf::Vector2f size, bool include_embedded_item, bool is_embedded) { - item->last_drawn_time = draw_timer.getElapsedTime().asMilliseconds(); + item->keep_alive_frames = 3; get_item_height(item, size.x, true, false, false, -1); draw_item(window, item, pos, size, size.y + spacing_y, -1, Json::Value::nullSingleton(), include_embedded_item); } @@ -1085,6 +829,23 @@ namespace QuickMedia { return ""; } + void Body::handle_item_render(BodyItem *item, const sf::Vector2f pos, const sf::Vector2f size, const float item_height, int item_index) { + if(body_item_select_callback && mouse_left_clicked && !clicked_body_item && click_counts && std::abs(mouse_scroll_accel.y) < 5.0f) { + sf::FloatRect item_box(pos + body_pos, sf::Vector2f(size.x, item_height)); + if(item_box.contains(mouse_click_pos) && item_box.contains(mouse_release_pos) && mouse_press_pixels_moved_abs <= 25.0) { + clicked_body_item = items[item_index]; + set_selected_item(item_index, false); + } + } + + if(item_index == selected_item) { + item_background_target_pos_y = pos.y; + item_background_target_height = item_height; + if(target_y_set == TargetSetState::NOT_SET) + target_y_set = TargetSetState::SET; + } + } + void Body::draw_item(sf::RenderWindow &window, BodyItem *item, const sf::Vector2f &pos, const sf::Vector2f &size, const float item_height, const int item_index, const Json::Value &content_progress, bool include_embedded_item, bool merge_with_previous) { sf::Vector2i thumbnail_size = get_item_thumbnail_size(item); std::shared_ptr item_thumbnail; @@ -1100,25 +861,6 @@ namespace QuickMedia { item_pos.x = std::floor(pos.x); item_pos.y = std::floor(pos.y); - if(body_item_select_callback && mouse_left_clicked && !clicked_body_item && click_counts && std::abs(mouse_scroll_accel.y) < 5.0f) { - sf::FloatRect item_box(pos + body_pos, sf::Vector2f(size.x, item_height)); - if(item_box.contains(mouse_click_pos) && item_box.contains(mouse_release_pos) && mouse_press_pixels_moved_abs <= 25.0) { - clicked_body_item = items[item_index]; - set_selected_item(item_index, false); - } - } - - //item_separator.setSize(sf::Vector2f(std::max(0.0f, size.x - 20.0f), 1.0f)); - //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) { - item_background_target_pos_y = item_pos.y; - item_background_target_height = item_height; - if(target_y_set == TargetSetState::NOT_SET) - target_y_set = TargetSetState::SET; - } - float text_offset_x = padding_x; if(item_thumbnail && !merge_with_previous) { // TODO: Verify if this is safe. The thumbnail is being modified in another thread @@ -1281,9 +1023,6 @@ namespace QuickMedia { } float Body::get_item_height(BodyItem *item, float width, bool load_texture, bool include_embedded_item, bool merge_with_previous, int item_index) { - if(load_texture) - item->last_drawn_time = elapsed_time_sec; - sf::Vector2i content_size = get_item_thumbnail_size(item); float image_height = 0.0f; @@ -1357,6 +1096,22 @@ namespace QuickMedia { item_height = std::max(item_height, image_height); item_height += (padding_y * 2.0f); + const bool first_height_set = item->last_loaded_height < 0.01f; + if(item_index != -1 && (first_height_set || load_texture)) { + const float height_diff = item_height - item->prev_last_loaded_height; + //if(attach_side == AttachSide::TOP) { + // if(item_index < selected_item) + // extra_scroll_target -= height_diff; + //} else if(attach_side == AttachSide::BOTTOM) { + // if(item_index > selected_item) + // extra_scroll_target += height_diff; + //} + item->last_loaded_height = item_height; + item->prev_last_loaded_height = item_height; + if(first_height_set) + item->current_loaded_height = item_height; + } + return item_height; } @@ -1388,16 +1143,13 @@ namespace QuickMedia { return full_match; } - void Body::filter_search_fuzzy(const std::string &text, bool select_first_if_empty) { + void Body::filter_search_fuzzy(const std::string &text) { current_filter = text; if(text.empty()) { for(auto &item : items) { item->visible = true; } - - if(select_first_if_empty) - select_first_item(); return; } @@ -1405,7 +1157,7 @@ namespace QuickMedia { filter_search_fuzzy_item(text, item.get()); } - select_first_item(); + clamp_selection(); using_filter = true; } @@ -1437,7 +1189,6 @@ namespace QuickMedia { void Body::set_page_scroll(float scroll) { page_scroll = scroll; - clamp_selected_item_to_body_count = 1; } void Body::items_set_dirty(bool force) { diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 0c2e872..7dbccae 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -648,8 +648,8 @@ namespace QuickMedia { window.setVerticalSyncEnabled(true); monitor_hz = get_monitor_max_hz(disp); - window.setFramerateLimit(FPS_IDLE); - idle = true; + window.setFramerateLimit(monitor_hz); + idle = false; vsync_set = false; /* if(enable_vsync(disp, window.getSystemHandle())) { @@ -1537,9 +1537,8 @@ namespace QuickMedia { return; } - window.setFramerateLimit(FPS_IDLE); malloc_trim(0); - idle = true; + idle_active_handler(); bool loop_running = true; bool redraw = true; @@ -1615,6 +1614,8 @@ namespace QuickMedia { return; } + idle_active_handler(); + if(tabs[selected_tab].page->clear_search_after_submit() && tabs[selected_tab].search_bar) { if(!tabs[selected_tab].search_bar->get_text().empty()) { tabs[selected_tab].search_bar->clear(); @@ -1660,7 +1661,7 @@ namespace QuickMedia { select_episode(selected_item.get(), false); Body *chapters_body = tabs[selected_tab].body.get(); tabs[selected_tab].search_bar->clear(); - chapters_body->filter_search_fuzzy("", false); // Needed (or not really) to go to the next chapter when reaching the last page of a chapter + chapters_body->filter_search_fuzzy(""); // Needed (or not really) to go to the next chapter when reaching the last page of a chapter MangaImagesPage *manga_images_page = static_cast(new_tabs[0].page.get()); window.setKeyRepeatEnabled(false); downloading_chapter_url.clear(); @@ -1983,9 +1984,12 @@ namespace QuickMedia { if(body_was_empty) { tabs[i].body->select_last_item(); } else { + // TODO: Use select_next_item in a loop instead for |num_new_messages|? tabs[i].body->set_selected_item(prev_selected_item + num_new_messages, true); } } + + idle_active_handler(); } if(associated_data.search_text_updated && associated_data.fetch_status == FetchStatus::NONE && !associated_data.fetching_next_page_running) { @@ -2020,6 +2024,7 @@ namespace QuickMedia { associated_data.search_result_text.setString("No results found"); else associated_data.search_result_text.setString(""); + idle_active_handler(); } else { associated_data.fetch_future.get(); } @@ -2031,6 +2036,9 @@ namespace QuickMedia { FetchResult fetch_result = associated_data.fetch_future.get(); tabs[i].body->items = std::move(fetch_result.body_items); if(tabs[i].search_bar) tabs[i].body->filter_search_fuzzy(tabs[i].search_bar->get_text()); + if(tabs[i].body->attach_side == AttachSide::TOP) { + tabs[i].body->select_first_item(); + } if(tabs[i].body->attach_side == AttachSide::BOTTOM) { std::reverse(tabs[i].body->items.begin(), tabs[i].body->items.end()); tabs[i].body->select_last_item(); @@ -2043,6 +2051,7 @@ namespace QuickMedia { else associated_data.search_result_text.setString(""); associated_data.fetch_status = FetchStatus::NONE; + idle_active_handler(); } } @@ -2071,9 +2080,9 @@ namespace QuickMedia { window.display(); if(!tabs[selected_tab].body->items.empty()) { - if(tabs[selected_tab].body->attach_side == AttachSide::TOP && tabs[selected_tab].body->is_last_item_fully_visible()) + if(tabs[selected_tab].body->attach_side == AttachSide::TOP && !tabs[selected_tab].body->is_bottom_cut_off()) on_reached_end(); - else if(tabs[selected_tab].body->attach_side == AttachSide::BOTTOM && tabs[selected_tab].body->is_first_item_fully_visible()) + else if(tabs[selected_tab].body->attach_side == AttachSide::BOTTOM && !tabs[selected_tab].body->is_top_cut_off()) on_reached_end(); } @@ -2222,6 +2231,8 @@ namespace QuickMedia { TaskResult Program::run_task_with_loading_screen(std::function callback) { assert(std::this_thread::get_id() == main_thread_id); + idle_active_handler(); + AsyncTask task = callback; window_size.x = window.getSize().x; @@ -4456,8 +4467,8 @@ namespace QuickMedia { } }; - auto upload_file = [this, &tabs, ¤t_room, MESSAGES_TAB_INDEX](const std::string &filepath) { - TaskResult post_file_result = run_task_with_loading_screen([this, ¤t_room, filepath]() { + auto upload_file = [this, ¤t_room](const std::string &filepath) { + run_task_with_loading_screen([this, ¤t_room, filepath]() { std::string event_id_response; std::string err_msg; if(matrix->post_file(current_room, filepath, event_id_response, err_msg) == PluginResult::OK) { @@ -4467,11 +4478,6 @@ namespace QuickMedia { return false; } }); - - if(post_file_result == TaskResult::TRUE) { - if(tabs[MESSAGES_TAB_INDEX].body->is_last_item_fully_visible()) - tabs[MESSAGES_TAB_INDEX].body->select_last_item(); - } }; struct Mention { @@ -4490,6 +4496,7 @@ namespace QuickMedia { filter_updated = false; filter.clear(); users_tab_body->filter_search_fuzzy(""); + users_tab_body->select_first_item(); users_tab_body->clear_cache(); } @@ -4505,9 +4512,9 @@ namespace QuickMedia { } } else if(event.type == sf::Event::KeyPressed) { if(event.key.code == sf::Keyboard::Up || (event.key.control && event.key.code == sf::Keyboard::K)) { - users_tab_body->select_previous_item(); + users_tab_body->select_previous_item(true); } else if(event.key.code == sf::Keyboard::Down || (event.key.control && event.key.code == sf::Keyboard::J)) { - users_tab_body->select_next_item(); + users_tab_body->select_next_item(true); } else if(event.key.code == sf::Keyboard::Enter && event.key.shift) { hide(); } else if(event.key.code == sf::Keyboard::Backspace) { @@ -4531,6 +4538,7 @@ namespace QuickMedia { // TODO: Use std::string instead of sf::String auto u8 = filter.toUtf8(); users_tab_body->filter_search_fuzzy(*(std::string*)&u8); + users_tab_body->select_first_item(); } } }; @@ -4954,17 +4962,11 @@ namespace QuickMedia { scroll_to_end = true; } - BodyItem *selected_item = tabs[MESSAGES_TAB_INDEX].body->get_selected(); auto new_body_items = messages_to_body_items(current_room, messages, current_room->get_user_display_name(me), me->user_id); messages_load_cached_related_embedded_item(new_body_items, tabs[MESSAGES_TAB_INDEX].body->items, me, current_room); tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(std::move(new_body_items)); - if(selected_item && !scroll_to_end) { - int selected_item_index = tabs[MESSAGES_TAB_INDEX].body->get_index_by_body_item(selected_item); - if(selected_item_index != -1) - tabs[MESSAGES_TAB_INDEX].body->set_selected_item(selected_item_index); - } else if(scroll_to_end) { + if(scroll_to_end) tabs[MESSAGES_TAB_INDEX].body->select_last_item(); - } }; auto display_url_or_image = [this, matrix_chat_page, &ui_tabs, &redraw, &video_page, &launch_url, &chat_state, &url_selection_body, &avatar_applied, PINNED_TAB_INDEX, MESSAGES_TAB_INDEX](BodyItem *selected) { @@ -5201,11 +5203,11 @@ namespace QuickMedia { 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)) { - matrix_chat_page->rooms_page->body->select_previous_item(); + matrix_chat_page->rooms_page->body->select_previous_item(true); move_room = true; goto chat_page_end; } else if(event.key.code == sf::Keyboard::Down || (event.key.control && event.key.code == sf::Keyboard::J)) { - matrix_chat_page->rooms_page->body->select_next_item(); + matrix_chat_page->rooms_page->body->select_next_item(true); move_room = true; goto chat_page_end; } else if(event.key.code == sf::Keyboard::PageUp) { @@ -5487,6 +5489,7 @@ namespace QuickMedia { upload_file(selected_files[0]); } redraw = true; + avatar_applied = false; break; } case PageType::CHAT_LOGIN: { @@ -5808,7 +5811,7 @@ namespace QuickMedia { } if(selected_tab == MESSAGES_TAB_INDEX && current_room && current_room->body_item && !current_room->last_message_read && matrix->is_initial_sync_finished()) { - if(last_visible_timeline_message && tabs[selected_tab].body->is_last_item_fully_visible() && is_window_focused && chat_state != ChatState::URL_SELECTION && !setting_read_marker && read_marker_timer.getElapsedTime().asMilliseconds() >= read_marker_timeout_ms) { + if(last_visible_timeline_message && !tabs[selected_tab].body->is_bottom_cut_off() && is_window_focused && chat_state != ChatState::URL_SELECTION && !setting_read_marker && read_marker_timer.getElapsedTime().asMilliseconds() >= read_marker_timeout_ms) { std::string room_desc = current_room->body_item->get_description(); if(strncmp(room_desc.c_str(), "Unread: ", 8) == 0) room_desc = room_desc.substr(8); @@ -5847,7 +5850,7 @@ namespace QuickMedia { } }); } - } else if(!tabs[selected_tab].body->is_last_item_fully_visible()) { + } else if(tabs[selected_tab].body->is_bottom_cut_off()) { window.draw(more_messages_below_rect); } } @@ -5926,8 +5929,7 @@ namespace QuickMedia { process_reactions(all_messages_new); if(current_room->initial_prev_messages_fetch) { current_room->initial_prev_messages_fetch = false; - if(selected_tab == MESSAGES_TAB_INDEX) - tabs[MESSAGES_TAB_INDEX].body->select_last_item(); + tabs[MESSAGES_TAB_INDEX].body->select_last_item(); } std::vector pinned_events; @@ -6583,6 +6585,7 @@ namespace QuickMedia { } ui_tabs.set_text(tab_path_index, file_manager_page->get_current_directory().string()); + idle_active_handler(); }; const float bottom_panel_padding = 10.0f; diff --git a/src/Text.cpp b/src/Text.cpp index 0834048..2e735ab 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -379,7 +379,7 @@ namespace QuickMedia sf::Vector2f glyphPos; sf::Uint32 prevCodePoint = 0; - // TODO: Only do this if dirtyText + // TODO: Only do this if dirtyText (then the Text object shouldn't be reset in Body. There should be a cleanup function in text instead) for(usize textElementIndex = 0; textElementIndex < textElements.size(); ++textElementIndex) { TextElement &textElement = textElements[textElementIndex]; diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index de50049..552762a 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -614,7 +614,7 @@ namespace QuickMedia { bool is_window_focused = program->is_window_focused(); RoomData *current_room = program->get_current_chat_room(); Body *chat_body = chat_page ? chat_page->chat_body : nullptr; - bool set_room_as_unread = !is_window_focused || room != current_room || (!chat_body || !chat_body->is_last_item_fully_visible()) || (chat_page && !chat_page->messages_tab_visible); + bool set_room_as_unread = !is_window_focused || room != current_room || (!chat_body || chat_body->is_bottom_cut_off()) || (chat_page && !chat_page->messages_tab_visible); std::string room_desc; if(set_room_as_unread) @@ -692,7 +692,7 @@ namespace QuickMedia { body->items.insert(body->items.begin() + (i - 1), std::move(body_item_to_insert)); if((int)i < selected_item && room_body_index > selected_item && body->items.size() > 1 && i != body->items.size() - 1) { body->select_first_item(); - body->set_selected_item(selected_item + 1, false); + body->select_next_item(); } return; } @@ -719,6 +719,7 @@ namespace QuickMedia { void MatrixRoomsPage::clear_search() { search_bar->clear(); body->filter_search_fuzzy(""); + body->select_first_item(); } void MatrixRoomsPage::clear_data() { @@ -1107,9 +1108,8 @@ namespace QuickMedia { //int prev_selected_item = notifications_body->get_selected_item(); //notifications_body->items.push_back(notification_to_body_item(notifications_body, notification)); //notifications_body->set_selected_item(prev_selected_item - 1); - int prev_selected_item = notifications_body->get_selected_item(); notifications_body->items.insert(notifications_body->items.begin(), notification_to_body_item(notifications_body, notification)); - notifications_body->set_selected_item(prev_selected_item + 1, false); + notifications_body->select_next_item(); } void MatrixNotificationsPage::set_room_as_read(RoomData *room) { -- cgit v1.2.3