#include "../include/Tabs.hpp" #include "../include/ResourceLoader.hpp" #include "../include/Utils.hpp" #include #include #include #include namespace QuickMedia { static const float tab_text_size = std::floor(16.0f * QuickMedia::get_ui_scale()); static const float tab_height = tab_text_size + std::floor(10.0f * QuickMedia::get_ui_scale()); static const sf::Color tab_selected_color(55, 60, 68); static const sf::Color arrow_color(255, 255, 255, 175); static const float tab_min_width = 250.0f; static const float tab_margin_x = 10.0f; // static float Tabs::get_height() { return tab_height; } // static float Tabs::get_shade_height() { return tab_height + std::floor(10.0f * get_ui_scale()); } Tabs::Tabs(sf::Shader *rounded_rectangle_shader, sf::Color shade_color) : background(sf::Vector2f(1.0f, 1.0f), 10.0f, tab_selected_color, rounded_rectangle_shader), shade_color(shade_color) { shade.setFillColor(shade_color); } int Tabs::add_tab(const std::string &title) { tab_texts.push_back(sf::Text(title, *FontLoader::get_font(FontLoader::FontType::LATIN), tab_text_size)); tab_labels_utf8.push_back(title); return tab_texts.size() - 1; } void Tabs::on_event(sf::Event &event) { if(event.type == sf::Event::KeyPressed) { if(event.key.code == sf::Keyboard::Left || (event.key.control && event.key.code == sf::Keyboard::H)) { if(selected_tab > 0) { --selected_tab; float scroll_fixed = scroll + (tab_offset * width_per_tab); if(scroll_fixed + tab_index_to_x_offset(selected_tab) + tab_background_width < tab_margin_x) tab_offset++; if(on_change_tab) on_change_tab(selected_tab); } } else if(event.key.code == sf::Keyboard::Right || (event.key.control && event.key.code == sf::Keyboard::L)) { if(selected_tab < (int)tab_texts.size() - 1) { ++selected_tab; float scroll_fixed = scroll + (tab_offset * width_per_tab); if(scroll_fixed + tab_index_to_x_offset(selected_tab) + tab_background_width > container_width - tab_margin_x) tab_offset--; if(on_change_tab) on_change_tab(selected_tab); } } } } void Tabs::draw(sf::RenderWindow &window, sf::Vector2f pos, float width) { if(width - tab_margin_x < 0.0f || tab_texts.empty()) return; auto window_size = window.getSize(); container_width = width; const int num_visible_tabs = std::min((int)tab_texts.size(), std::max(1, (int)(width / tab_min_width))); width_per_tab = std::floor(width / num_visible_tabs); const float tab_text_y = std::floor(pos.y + tab_height*0.5f - (tab_text_size + 5.0f*get_ui_scale())*0.5f); tab_background_width = std::floor(width_per_tab - tab_margin_x*2.0f); background.set_size(sf::Vector2f(tab_background_width, tab_height)); shade.setSize(sf::Vector2f(width, get_shade_height())); shade.setPosition(std::floor(pos.x), std::floor(pos.y)); window.draw(shade); float scroll_fixed = scroll + (tab_offset * width_per_tab); float overflow_last = (scroll_fixed + tab_index_to_x_offset(tab_texts.size() - 1) + tab_background_width) - (width - tab_margin_x); if(overflow_last < 0.0f) scroll_fixed -= overflow_last; float overflow = (scroll_fixed + tab_index_to_x_offset(selected_tab) + tab_background_width) - (width - tab_margin_x); float underflow = scroll_fixed + tab_index_to_x_offset(selected_tab); if(overflow > 0.0f) scroll_fixed -= overflow; else if(underflow < 0.0f) scroll_fixed -= underflow; bool tabs_cutoff_left = false; bool tabs_cutoff_right = false; const auto start_pos = pos; pos.x += scroll_fixed; for(size_t i = 0; i < tab_texts.size(); ++i) { const int index = i; const float background_pos_x = std::floor(pos.x + tab_index_to_x_offset(i)); if(background_pos_x - start_pos.x >= width - tab_margin_x) { tabs_cutoff_right = true; break; } else if(background_pos_x + tab_background_width - start_pos.x <= tab_margin_x) { tabs_cutoff_left = true; continue; } if((int)index == selected_tab) { background.set_position(sf::Vector2f(background_pos_x, std::floor(pos.y))); background.draw(window); } sf::Text &tab_text = tab_texts[index]; float text_pos_x = std::floor(pos.x + i*width_per_tab + width_per_tab*0.5f - tab_text.getLocalBounds().width*0.5f); text_pos_x = std::max(text_pos_x, background_pos_x); tab_text.setPosition(text_pos_x, tab_text_y); glEnable(GL_SCISSOR_TEST); glScissor(text_pos_x, (int)window_size.y - (int)tab_text_y - (int)tab_height, tab_background_width, tab_height); window.draw(tab_text); glDisable(GL_SCISSOR_TEST); } float lw = std::floor(25.0f * get_ui_scale()); float lh = background.get_size().y; float line_offset_y = std::floor(lw * 0.35f); if(tabs_cutoff_left) { sf::Vertex gradient_points[4]; gradient_points[0].position = sf::Vector2f(start_pos.x + tab_margin_x, start_pos.y); gradient_points[1].position = sf::Vector2f(start_pos.x + tab_margin_x + lw, start_pos.y); gradient_points[2].position = sf::Vector2f(start_pos.x + tab_margin_x + lw, start_pos.y + lh); gradient_points[3].position = sf::Vector2f(start_pos.x + tab_margin_x, start_pos.y + lh); gradient_points[0].color = shade_color; gradient_points[1].color = sf::Color(shade_color.r, shade_color.g, shade_color.b, 10); gradient_points[2].color = sf::Color(shade_color.r, shade_color.g, shade_color.b, 10); gradient_points[3].color = shade_color; window.draw(gradient_points, 4, sf::Quads); sf::RectangleShape line(sf::Vector2f(std::floor(10.0f * get_ui_scale()), std::floor(2.0f * get_ui_scale()))); line.setFillColor(arrow_color); line.setOrigin(line.getSize().x * 0.5f, line.getSize().y * 0.5f); line.rotate(-45.0f); line.setPosition(std::floor(start_pos.x + line.getLocalBounds().width), std::floor(pos.y + background.get_size().y * 0.5f - lh * 0.5f + line_offset_y)); window.draw(line); line.rotate(-90.0f); line.setPosition(std::floor(start_pos.x + line.getLocalBounds().width), std::floor(pos.y + background.get_size().y * 0.5f - lh * 0.5f + line_offset_y + std::floor(7.0f * get_ui_scale()))); window.draw(line); } if(tabs_cutoff_right) { sf::Vertex gradient_points[4]; gradient_points[0].position = sf::Vector2f(start_pos.x + width - lw - tab_margin_x, start_pos.y); gradient_points[1].position = sf::Vector2f(start_pos.x + width, start_pos.y); gradient_points[2].position = sf::Vector2f(start_pos.x + width, start_pos.y + lh); gradient_points[3].position = sf::Vector2f(start_pos.x + width - lw - tab_margin_x, start_pos.y + lh); gradient_points[0].color = sf::Color(shade_color.r, shade_color.g, shade_color.b, 10); gradient_points[1].color = shade_color; gradient_points[2].color = shade_color; gradient_points[3].color = sf::Color(shade_color.r, shade_color.g, shade_color.b, 10); window.draw(gradient_points, 4, sf::Quads); sf::RectangleShape line(sf::Vector2f(std::floor(10.0f * get_ui_scale()), std::floor(2.0f * get_ui_scale()))); line.setFillColor(arrow_color); line.setOrigin(line.getSize().x * 0.5f, line.getSize().y * 0.5f); line.rotate(45.0f); line.setPosition(std::floor(start_pos.x + width - lw*0.75f + line.getLocalBounds().width), std::floor(pos.y + background.get_size().y * 0.5f - lh * 0.5f + line_offset_y)); window.draw(line); line.rotate(-90.0f); line.setPosition(std::floor(start_pos.x + width - lw*0.75f + line.getLocalBounds().width), std::floor(pos.y + background.get_size().y * 0.5f - lh * 0.5f + line_offset_y + std::floor(7.0f * get_ui_scale()))); window.draw(line); } } void Tabs::set_text(int index, const std::string &text) { if(index < 0 || index >= (int)tab_texts.size() || text == tab_labels_utf8[index]) return; tab_texts[index].setString(sf::String::fromUtf8(text.begin(), text.end())); tab_labels_utf8[index] = text; } void Tabs::set_selected(int index) { if(tab_texts.empty()) { selected_tab = 0; } else { selected_tab = std::min(std::max(index, 0), (int)tab_texts.size() - 1); } } int Tabs::get_selected() const { return selected_tab; } float Tabs::tab_index_to_x_offset(int index) { return std::floor(index*width_per_tab + tab_margin_x); } }