#include "../include/Tabs.hpp" #include "../include/Body.hpp" #include "../include/ResourceLoader.hpp" #include "../include/Config.hpp" #include "../include/Theme.hpp" #include #include #include #include namespace QuickMedia { static const float tab_text_size = std::floor(get_config().tab.font_size * get_config().scale * get_config().font_scale); static const float tab_height = tab_text_size + std::floor(10.0f * get_config().scale); 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_config().scale); } Tabs::Tabs(sf::Shader *rounded_rectangle_shader, sf::Color shade_color) : background(sf::Vector2f(1.0f, 1.0f), 10.0f, get_current_theme().selected_color, rounded_rectangle_shader), shade_color(shade_color) { shade.setFillColor(shade_color); } Tabs::Tabs(sf::Shader *rounded_rectangle_shader) : Tabs(rounded_rectangle_shader, get_current_theme().shade_color) {} int Tabs::add_tab(const std::string &title, Body *body) { assert(body); tabs.push_back({ sf::Text(title, *FontLoader::get_font(FontLoader::FontType::LATIN), tab_text_size), title, body} ); return tabs.size() - 1; } void Tabs::move_selected_tab(int new_tab) { const int tab_diff = new_tab - selected_tab; if(tab_diff > 0) { while(selected_tab < new_tab) { ++selected_tab; const 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; } } else if(tab_diff < 0) { while(selected_tab > new_tab) { --selected_tab; const 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; } } else { return; } if(on_change_tab) on_change_tab(selected_tab); } void Tabs::on_event(sf::Event &event) { if(event.type == sf::Event::KeyPressed && event.key.control && !tabs.empty()) { bool move_left = (event.key.code == sf::Keyboard::Left || (event.key.alt && event.key.code == sf::Keyboard::H)); move_left |= (event.key.code == sf::Keyboard::Tab && event.key.shift); bool move_right = (event.key.code == sf::Keyboard::Right || (event.key.alt && event.key.code == sf::Keyboard::L)); move_right |= (event.key.code == sf::Keyboard::Tab && !event.key.shift); if(move_left) { if(selected_tab > 0) move_selected_tab(selected_tab - 1); } else if(move_right) { if(selected_tab < (int)tabs.size() - 1) move_selected_tab(selected_tab + 1); } else if(event.key.code >= sf::Keyboard::Num1 && event.key.code <= sf::Keyboard::Num9) { const int tab_target = event.key.code - sf::Keyboard::Num1; if(tab_target < (int)tabs.size()) move_selected_tab(tab_target); } } } void Tabs::draw(sf::RenderWindow &window, sf::Vector2f pos, float width) { if(width - tab_margin_x < 0.0f || tabs.empty()) return; auto window_size = window.getSize(); container_width = width; const int num_visible_tabs = std::min((int)tabs.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_config().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)); if(shade_color != sf::Color::Transparent) { 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(tabs.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 < tabs.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 = tabs[index].text; 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_config().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_config().scale), std::floor(2.0f * get_config().scale))); line.setFillColor(get_current_theme().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_config().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_config().scale), std::floor(2.0f * get_config().scale))); line.setFillColor(get_current_theme().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_config().scale))); window.draw(line); } } void Tabs::set_text(int index, const std::string &text) { if(index < 0 || index >= (int)tabs.size() || text == tabs[index].label_utf8) return; tabs[index].text.setString(sf::String::fromUtf8(text.begin(), text.end())); tabs[index].label_utf8 = text; } void Tabs::set_selected(int index) { move_selected_tab(index); } 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); } }