From d0e306118f7b5cbab652ecf1e40d0af9f0e882a7 Mon Sep 17 00:00:00 2001 From: kolo Date: Wed, 17 Jun 2026 13:29:00 +0300 Subject: [PATCH] step --- CMakeLists.txt | 1 + include/App.hpp | 1 + include/Theme.hpp | 81 ++++++++++++++++++++++++++++++ src/App.cpp | 33 +++++++----- src/ProgressMap.cpp | 19 ++++--- src/Theme.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++++ src/UI.cpp | 100 ++++++++++++++++++++++--------------- 7 files changed, 295 insertions(+), 59 deletions(-) create mode 100644 include/Theme.hpp create mode 100644 src/Theme.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 30e987a..2c3b288 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ set(SORTLAB_SOURCES src/Array.cpp src/Sorter.cpp src/UI.cpp + src/Theme.cpp src/OperationsHistory.cpp src/ProgressMap.cpp src/SortHistory.cpp diff --git a/include/App.hpp b/include/App.hpp index 7bb353a..f179aea 100644 --- a/include/App.hpp +++ b/include/App.hpp @@ -8,6 +8,7 @@ #include "OperationsHistory.hpp" #include "ProgressMap.hpp" #include "SortHistory.hpp" +#include "Theme.hpp" class App { public: diff --git a/include/Theme.hpp b/include/Theme.hpp new file mode 100644 index 0000000..66d4a57 --- /dev/null +++ b/include/Theme.hpp @@ -0,0 +1,81 @@ +#pragma once +#include + +enum class ThemeType { + DARK, + LIGHT +}; + +struct ColorPalette { + // Основные цвета фона + sf::Color windowBackground; + sf::Color panelBackground; + sf::Color bottomPanelBackground; + sf::Color overlayBackground; + + // Цвета текста + sf::Color textPrimary; + sf::Color textSecondary; + sf::Color textTertiary; + sf::Color textAccent; + + // Цвета для состояний элементов массива + sf::Color stateNormalLow; // Нижняя часть градиента для обычных элементов + sf::Color stateNormalHigh; // Верхняя часть градиента для обычных элементов + sf::Color stateCompare; // Цвет для сравниваемых элементов + sf::Color stateSwap; // Цвет для переставляемых элементов + sf::Color stateSorted; // Цвет для отсортированных элементов + + // Цвета UI элементов + sf::Color separator; + sf::Color histogramLow; // Нижняя часть градиента гистограммы + sf::Color histogramHigh; // Верхняя часть градиента гистограммы + + // Цвета для ProgressMap + sf::Color progressMapNormal; + + // Цвета для оверлеев + sf::Color overlayTitle; + sf::Color overlaySubtitle; + sf::Color overlaySection; + sf::Color overlayBody; + sf::Color overlayFooter; + + // Цвета для истории + sf::Color historyTableHeader; + sf::Color historyRowEven; + sf::Color historyRowOdd; + sf::Color historyNewestHighlight; + sf::Color historyNewestText; + sf::Color historySpeedFastest; + sf::Color historySpeedSlow; + + // Цвета статусов + sf::Color statusFinished; + sf::Color statusPlaying; + sf::Color statusPaused; +}; + +class Theme { +public: + static Theme& getInstance(); + + void setTheme(ThemeType type); + ThemeType getThemeType() const; + void toggleTheme(); + + const ColorPalette& getPalette() const; + +private: + Theme(); + Theme(const Theme&) = delete; + Theme& operator=(const Theme&) = delete; + + void initDarkTheme(); + void initLightTheme(); + + ThemeType currentTheme_; + ColorPalette darkPalette_; + ColorPalette lightPalette_; + ColorPalette* currentPalette_; +}; diff --git a/src/App.cpp b/src/App.cpp index 6f9d25d..557e98f 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -148,6 +148,10 @@ void App::handleEvents() { } break; + case sf::Keyboard::T: + Theme::getInstance().toggleTheme(); + break; + default: break; } @@ -230,7 +234,8 @@ void App::update(float dt) { } void App::render() { - window_.clear(sf::Color(10, 12, 20)); + const ColorPalette& palette = Theme::getInstance().getPalette(); + window_.clear(palette.windowBackground); const float topUIHeight = 80.0f; const float bottomPanelHeight = 140.0f; @@ -256,20 +261,20 @@ void App::render() { useGradient = true; break; case Array::State::COMPARE: - barColor = sf::Color(0, 220, 255); + barColor = palette.stateCompare; break; case Array::State::SWAP: - barColor = sf::Color(255, 120, 30); + barColor = palette.stateSwap; break; case Array::State::SORTED: - barColor = sf::Color(50, 220, 120); + barColor = palette.stateSorted; break; } if (useGradient) { float normalizedValue = array_.getValue(i) / maxVal; - sf::Color bottomColor(60, 80, 140); - sf::Color topColor(160, 180, 255); + sf::Color bottomColor = palette.stateNormalLow; + sf::Color topColor = palette.stateNormalHigh; sf::Color gradientTop( static_cast(bottomColor.r + (topColor.r - bottomColor.r) * normalizedValue), @@ -299,7 +304,7 @@ void App::render() { sf::RectangleShape separator(sf::Vector2f(window_.getSize().x, 1.0f)); separator.setPosition(0.0f, mainAreaBottom); - separator.setFillColor(sf::Color(40, 45, 60)); + separator.setFillColor(palette.separator); window_.draw(separator); renderDeltaHistogram(); @@ -307,7 +312,7 @@ void App::render() { sf::RectangleShape verticalSeparator(sf::Vector2f(1.0f, bottomPanelHeight)); verticalSeparator.setPosition(1066.0f, mainAreaBottom); - verticalSeparator.setFillColor(sf::Color(40, 45, 60)); + verticalSeparator.setFillColor(palette.separator); window_.draw(verticalSeparator); ui_.draw(window_); @@ -324,6 +329,8 @@ void App::render() { } void App::renderDeltaHistogram() { + const ColorPalette& palette = Theme::getInstance().getPalette(); + const float startX = 0.0f; const float startY = 760.0f; const float width = 1066.0f; @@ -331,7 +338,7 @@ void App::renderDeltaHistogram() { sf::RectangleShape background(sf::Vector2f(width, height)); background.setPosition(startX, startY); - background.setFillColor(sf::Color(12, 15, 25)); + background.setFillColor(palette.bottomPanelBackground); window_.draw(background); const auto& deltaHistory = opsHistory_.getDeltaHistory(); @@ -350,8 +357,8 @@ void App::renderDeltaHistogram() { float y = startY + height - barHeight; float normalizedValue = static_cast(deltaHistory[i]) / static_cast(maxDelta); - sf::Color lowColor(0, 80, 200); - sf::Color highColor(0, 240, 255); + sf::Color lowColor = palette.histogramLow; + sf::Color highColor = palette.histogramHigh; sf::Color barColor( static_cast(lowColor.r + (highColor.r - lowColor.r) * normalizedValue), @@ -370,7 +377,7 @@ void App::renderDeltaHistogram() { sf::RectangleShape baseline(sf::Vector2f(width, 1.0f)); baseline.setPosition(startX, startY + height - 1.0f); - baseline.setFillColor(sf::Color(60, 70, 90)); + baseline.setFillColor(palette.separator); window_.draw(baseline); if (bottomPanelFontLoaded_) { @@ -378,7 +385,7 @@ void App::renderDeltaHistogram() { label.setFont(bottomPanelFont_); label.setString("Delta Comparisons / step"); label.setCharacterSize(13); - label.setFillColor(sf::Color(180, 180, 180)); + label.setFillColor(palette.textTertiary); label.setPosition(startX + 10.0f, startY + 5.0f); window_.draw(label); } diff --git a/src/ProgressMap.cpp b/src/ProgressMap.cpp index 135a3de..af45ebd 100644 --- a/src/ProgressMap.cpp +++ b/src/ProgressMap.cpp @@ -1,10 +1,13 @@ #include "ProgressMap.hpp" +#include "Theme.hpp" #include ProgressMap::ProgressMap() { } void ProgressMap::draw(sf::RenderWindow& window, const Array& array, sf::Font& font, bool fontLoaded) { + const ColorPalette& palette = Theme::getInstance().getPalette(); + const float startX = 1066.0f; const float startY = 760.0f; const float width = 534.0f; @@ -12,7 +15,7 @@ void ProgressMap::draw(sf::RenderWindow& window, const Array& array, sf::Font& f sf::RectangleShape background(sf::Vector2f(width, height)); background.setPosition(startX, startY); - background.setFillColor(sf::Color(12, 15, 25)); + background.setFillColor(palette.bottomPanelBackground); window.draw(background); if (fontLoaded) { @@ -20,7 +23,7 @@ void ProgressMap::draw(sf::RenderWindow& window, const Array& array, sf::Font& f label.setFont(font); label.setString("Progress Map"); label.setCharacterSize(13); - label.setFillColor(sf::Color(180, 180, 180)); + label.setFillColor(palette.textTertiary); label.setPosition(startX + 10.0f, startY + 5.0f); window.draw(label); } @@ -67,16 +70,18 @@ void ProgressMap::draw(sf::RenderWindow& window, const Array& array, sf::Font& f } sf::Color ProgressMap::getColorForState(Array::State state) const { + const ColorPalette& palette = Theme::getInstance().getPalette(); + switch (state) { case Array::State::NORMAL: - return sf::Color(100, 120, 150); + return palette.progressMapNormal; case Array::State::COMPARE: - return sf::Color(0, 220, 255); + return palette.stateCompare; case Array::State::SWAP: - return sf::Color(255, 120, 30); + return palette.stateSwap; case Array::State::SORTED: - return sf::Color(50, 220, 120); + return palette.stateSorted; default: - return sf::Color(100, 120, 150); + return palette.progressMapNormal; } } diff --git a/src/Theme.cpp b/src/Theme.cpp new file mode 100644 index 0000000..768ed71 --- /dev/null +++ b/src/Theme.cpp @@ -0,0 +1,119 @@ +#include "Theme.hpp" + +Theme& Theme::getInstance() { + static Theme instance; + return instance; +} + +Theme::Theme() : currentTheme_(ThemeType::DARK) { + initDarkTheme(); + initLightTheme(); + currentPalette_ = &darkPalette_; +} + +void Theme::initDarkTheme() { + // Основные цвета фона + darkPalette_.windowBackground = sf::Color(10, 12, 20); + darkPalette_.panelBackground = sf::Color(0, 0, 0, 180); + darkPalette_.bottomPanelBackground = sf::Color(12, 15, 25); + darkPalette_.overlayBackground = sf::Color(8, 10, 18, 230); + + // Цвета текста + darkPalette_.textPrimary = sf::Color::White; + darkPalette_.textSecondary = sf::Color(220, 220, 220); + darkPalette_.textTertiary = sf::Color(160, 160, 160); + darkPalette_.textAccent = sf::Color(0, 220, 255); + + darkPalette_.stateNormalLow = sf::Color(60, 80, 140); + darkPalette_.stateNormalHigh = sf::Color(160, 180, 255); + darkPalette_.stateCompare = sf::Color(0, 220, 255); + darkPalette_.stateSwap = sf::Color(255, 120, 30); + darkPalette_.stateSorted = sf::Color(50, 220, 120); + + darkPalette_.separator = sf::Color(40, 45, 60); + darkPalette_.histogramLow = sf::Color(0, 80, 200); + darkPalette_.histogramHigh = sf::Color(0, 240, 255); + + darkPalette_.progressMapNormal = sf::Color(100, 120, 150); + + darkPalette_.overlayTitle = sf::Color::White; + darkPalette_.overlaySubtitle = sf::Color(160, 160, 160); + darkPalette_.overlaySection = sf::Color(0, 220, 255); + darkPalette_.overlayBody = sf::Color(200, 200, 200); + darkPalette_.overlayFooter = sf::Color(100, 100, 100); + + darkPalette_.historyTableHeader = sf::Color(0, 220, 255); + darkPalette_.historyRowEven = sf::Color(0, 0, 0, 0); + darkPalette_.historyRowOdd = sf::Color(15, 18, 25, 100); + darkPalette_.historyNewestHighlight = sf::Color(30, 60, 90, 150); + darkPalette_.historyNewestText = sf::Color(100, 255, 150); + darkPalette_.historySpeedFastest = sf::Color(100, 255, 120); + darkPalette_.historySpeedSlow = sf::Color(255, 160, 60); + + darkPalette_.statusFinished = sf::Color::Green; + darkPalette_.statusPlaying = sf::Color::Yellow; + darkPalette_.statusPaused = sf::Color::White; +} + +void Theme::initLightTheme() { + lightPalette_.windowBackground = sf::Color(245, 247, 250); + lightPalette_.panelBackground = sf::Color(255, 255, 255, 200); + lightPalette_.bottomPanelBackground = sf::Color(235, 238, 245); + lightPalette_.overlayBackground = sf::Color(250, 252, 255, 240); + + lightPalette_.textPrimary = sf::Color(20, 20, 30); + lightPalette_.textSecondary = sf::Color(40, 40, 50); + lightPalette_.textTertiary = sf::Color(100, 100, 120); + lightPalette_.textAccent = sf::Color(0, 120, 200); + + lightPalette_.stateNormalLow = sf::Color(140, 160, 200); + lightPalette_.stateNormalHigh = sf::Color(80, 120, 200); + lightPalette_.stateCompare = sf::Color(0, 180, 255); + lightPalette_.stateSwap = sf::Color(255, 100, 20); + lightPalette_.stateSorted = sf::Color(40, 180, 80); + + lightPalette_.separator = sf::Color(200, 205, 215); + lightPalette_.histogramLow = sf::Color(100, 150, 255); + lightPalette_.histogramHigh = sf::Color(0, 100, 200); + + lightPalette_.progressMapNormal = sf::Color(160, 170, 190); + + lightPalette_.overlayTitle = sf::Color(20, 20, 30); + lightPalette_.overlaySubtitle = sf::Color(100, 100, 120); + lightPalette_.overlaySection = sf::Color(0, 120, 200); + lightPalette_.overlayBody = sf::Color(40, 40, 50); + lightPalette_.overlayFooter = sf::Color(140, 140, 150); + + lightPalette_.historyTableHeader = sf::Color(0, 120, 200); + lightPalette_.historyRowEven = sf::Color(0, 0, 0, 0); + lightPalette_.historyRowOdd = sf::Color(230, 235, 245, 150); + lightPalette_.historyNewestHighlight = sf::Color(200, 230, 255, 180); + lightPalette_.historyNewestText = sf::Color(0, 150, 80); + lightPalette_.historySpeedFastest = sf::Color(40, 180, 80); + lightPalette_.historySpeedSlow = sf::Color(255, 130, 40); + + lightPalette_.statusFinished = sf::Color(0, 150, 60); + lightPalette_.statusPlaying = sf::Color(200, 150, 0); + lightPalette_.statusPaused = sf::Color(60, 60, 80); +} + +void Theme::setTheme(ThemeType type) { + currentTheme_ = type; + currentPalette_ = (type == ThemeType::DARK) ? &darkPalette_ : &lightPalette_; +} + +ThemeType Theme::getThemeType() const { + return currentTheme_; +} + +void Theme::toggleTheme() { + if (currentTheme_ == ThemeType::DARK) { + setTheme(ThemeType::LIGHT); + } else { + setTheme(ThemeType::DARK); + } +} + +const ColorPalette& Theme::getPalette() const { + return *currentPalette_; +} diff --git a/src/UI.cpp b/src/UI.cpp index 26ec61c..c4e1393 100644 --- a/src/UI.cpp +++ b/src/UI.cpp @@ -1,5 +1,6 @@ #pragma execution_character_set("utf-8") #include "UI.hpp" +#include "Theme.hpp" #include #include @@ -12,56 +13,58 @@ UI::UI() : fontLoaded_(false), historyOpen_(false) { font_.setSmooth(true); fontLoaded_ = true; + const ColorPalette& palette = Theme::getInstance().getPalette(); + algorithmText_.setFont(font_); algorithmText_.setCharacterSize(56); algorithmText_.setScale(0.5f, 0.5f); - algorithmText_.setFillColor(sf::Color::White); + algorithmText_.setFillColor(palette.textPrimary); algorithmText_.setPosition(15.0f, 15.0f); stateText_.setFont(font_); stateText_.setCharacterSize(40); stateText_.setScale(0.5f, 0.5f); - stateText_.setFillColor(sf::Color::White); + stateText_.setFillColor(palette.textPrimary); stateText_.setPosition(15.0f, 50.0f); timeComplexityText_.setFont(font_); timeComplexityText_.setCharacterSize(32); timeComplexityText_.setScale(0.5f, 0.5f); - timeComplexityText_.setFillColor(sf::Color(160, 160, 160)); + timeComplexityText_.setFillColor(palette.textTertiary); timeComplexityText_.setPosition(15.0f, 80.0f); spaceComplexityText_.setFont(font_); spaceComplexityText_.setCharacterSize(32); spaceComplexityText_.setScale(0.5f, 0.5f); - spaceComplexityText_.setFillColor(sf::Color(160, 160, 160)); + spaceComplexityText_.setFillColor(palette.textTertiary); spaceComplexityText_.setPosition(15.0f, 105.0f); comparisonsText_.setFont(font_); comparisonsText_.setCharacterSize(36); comparisonsText_.setScale(0.5f, 0.5f); - comparisonsText_.setFillColor(sf::Color(220, 220, 220)); + comparisonsText_.setFillColor(palette.textSecondary); comparisonsText_.setPosition(15.0f, 135.0f); swapsText_.setFont(font_); swapsText_.setCharacterSize(36); swapsText_.setScale(0.5f, 0.5f); - swapsText_.setFillColor(sf::Color(220, 220, 220)); + swapsText_.setFillColor(palette.textSecondary); swapsText_.setPosition(15.0f, 160.0f); speedText_.setFont(font_); speedText_.setCharacterSize(36); speedText_.setScale(0.5f, 0.5f); - speedText_.setFillColor(sf::Color(220, 220, 220)); + speedText_.setFillColor(palette.textSecondary); speedText_.setPosition(15.0f, 185.0f); controlsText_.setFont(font_); controlsText_.setCharacterSize(30); controlsText_.setScale(0.5f, 0.5f); - controlsText_.setFillColor(sf::Color(200, 200, 200)); - controlsText_.setString("[1-8] Algorithms [Space] Play/Pause [Right] Step [Up/Down] Speed [R] Shuffle"); + controlsText_.setFillColor(palette.textSecondary); + controlsText_.setString("[1-8] Algorithms [Space] Play/Pause [Right] Step [Up/Down] Speed [R] Shuffle [T] Theme"); - leftBackground_.setFillColor(sf::Color(0, 0, 0, 180)); - rightBackground_.setFillColor(sf::Color(0, 0, 0, 180)); + leftBackground_.setFillColor(palette.panelBackground); + rightBackground_.setFillColor(palette.panelBackground); } void UI::update(const Sorter& sorter, bool isPlaying, bool isFinished, int stepsPerFrame, const Array& array) { @@ -69,18 +72,20 @@ void UI::update(const Sorter& sorter, bool isPlaying, bool isFinished, int steps return; } + const ColorPalette& palette = Theme::getInstance().getPalette(); + algorithmText_.setString("Algorithm: " + sorter.getName()); std::string state; if (isFinished) { state = "Status: Finished"; - stateText_.setFillColor(sf::Color::Green); + stateText_.setFillColor(palette.statusFinished); } else if (isPlaying) { state = "Status: Playing"; - stateText_.setFillColor(sf::Color::Yellow); + stateText_.setFillColor(palette.statusPlaying); } else { state = "Status: Paused"; - stateText_.setFillColor(sf::Color::White); + stateText_.setFillColor(palette.statusPaused); } stateText_.setString(state); @@ -97,6 +102,19 @@ void UI::draw(sf::RenderWindow& window) { return; } + const ColorPalette& palette = Theme::getInstance().getPalette(); + + // Обновляем цвета текста и фона при каждой отрисовке (на случай смены темы) + algorithmText_.setFillColor(palette.textPrimary); + timeComplexityText_.setFillColor(palette.textTertiary); + spaceComplexityText_.setFillColor(palette.textTertiary); + comparisonsText_.setFillColor(palette.textSecondary); + swapsText_.setFillColor(palette.textSecondary); + speedText_.setFillColor(palette.textSecondary); + controlsText_.setFillColor(palette.textSecondary); + leftBackground_.setFillColor(palette.panelBackground); + rightBackground_.setFillColor(palette.panelBackground); + float maxWidth = 0.0f; sf::FloatRect algoBounds = algorithmText_.getGlobalBounds(); @@ -148,6 +166,8 @@ void UI::drawInfoOverlay(sf::RenderWindow& window) { return; } + const ColorPalette& palette = Theme::getInstance().getPalette(); + auto toSfStr = [](const char* utf8) -> sf::String { std::string s(utf8); return sf::String::fromUtf8(s.begin(), s.end()); @@ -158,85 +178,85 @@ void UI::drawInfoOverlay(sf::RenderWindow& window) { sf::RectangleShape overlay(sf::Vector2f(windowWidth, windowHeight)); overlay.setPosition(0.0f, 0.0f); - overlay.setFillColor(sf::Color(8, 10, 18, 230)); + overlay.setFillColor(palette.overlayBackground); window.draw(overlay); sf::Text title; title.setFont(font_); title.setCharacterSize(80); title.setScale(0.5f, 0.5f); - title.setFillColor(sf::Color::White); + title.setFillColor(palette.overlayTitle); title.setString(toSfStr(u8"SortLab — визуализатор алгоритмов сортировки")); sf::Text subtitle; subtitle.setFont(font_); subtitle.setCharacterSize(38); subtitle.setScale(0.5f, 0.5f); - subtitle.setFillColor(sf::Color(160, 160, 160)); + subtitle.setFillColor(palette.overlaySubtitle); subtitle.setString(toSfStr(u8"Учебный инструмент для наглядного изучения алгоритмов сортировки")); sf::Text section1; section1.setFont(font_); section1.setCharacterSize(42); section1.setScale(0.5f, 0.5f); - section1.setFillColor(sf::Color(0, 220, 255)); + section1.setFillColor(palette.overlaySection); section1.setString(toSfStr(u8"О программе")); sf::Text body1; body1.setFont(font_); body1.setCharacterSize(32); body1.setScale(0.5f, 0.5f); - body1.setFillColor(sf::Color(200, 200, 200)); + body1.setFillColor(palette.overlayBody); body1.setString(toSfStr(u8"SortLab визуализирует работу алгоритмов сортировки в реальном времени.\nКаждый столбик — это элемент массива. Высота = значение элемента.\nЦвета: серый — обычный, голубой — сравнение, оранжевый — перестановка, зелёный — готово.")); sf::Text section2; section2.setFont(font_); section2.setCharacterSize(42); section2.setScale(0.5f, 0.5f); - section2.setFillColor(sf::Color(0, 220, 255)); + section2.setFillColor(palette.overlaySection); section2.setString(toSfStr(u8"Алгоритмы и сложность")); sf::Text body2; body2.setFont(font_); body2.setCharacterSize(32); body2.setScale(0.5f, 0.5f); - body2.setFillColor(sf::Color(200, 200, 200)); + body2.setFillColor(palette.overlayBody); body2.setString(toSfStr(u8"[1] Bubble Sort Время: O(n) / O(n^2) / O(n^2) Память: O(1)\n[2] Selection Sort Время: O(n^2) / O(n^2) / O(n^2) Память: O(1)\n[3] Insertion Sort Время: O(n) / O(n^2) / O(n^2) Память: O(1)\n[4] Merge Sort Время: O(n log n) / O(n log n) / O(n log n) Память: O(n)\n[5] Quick Sort Время: O(n log n) / O(n log n) / O(n^2) Память: O(log n)\n[6] Heap Sort Время: O(n log n) Память: O(1)\n[7] Shell Sort Время: O(n log^2 n) Память: O(1)\n[8] Radix Sort Время: O(n*k) Память: O(n + k)")); sf::Text section3; section3.setFont(font_); section3.setCharacterSize(42); section3.setScale(0.5f, 0.5f); - section3.setFillColor(sf::Color(0, 220, 255)); + section3.setFillColor(palette.overlaySection); section3.setString(toSfStr(u8"Гистограмма (внизу слева)")); sf::Text body3; body3.setFont(font_); body3.setCharacterSize(32); body3.setScale(0.5f, 0.5f); - body3.setFillColor(sf::Color(200, 200, 200)); + body3.setFillColor(palette.overlayBody); body3.setString(toSfStr(u8"Показывает количество сравнений на каждом шаге сортировки.\nВысокий пик = много сравнений за один шаг.\nBubble Sort даёт ровную линию, Quick Sort — резкие пики в начале.")); sf::Text section4; section4.setFont(font_); section4.setCharacterSize(42); section4.setScale(0.5f, 0.5f); - section4.setFillColor(sf::Color(0, 220, 255)); + section4.setFillColor(palette.overlaySection); section4.setString(toSfStr(u8"Карта прогресса (внизу справа)")); sf::Text body4; body4.setFont(font_); body4.setCharacterSize(32); body4.setScale(0.5f, 0.5f); - body4.setFillColor(sf::Color(200, 200, 200)); + body4.setFillColor(palette.overlayBody); body4.setString(toSfStr(u8"Миниатюрная копия всего массива в виде сетки цветных квадратиков.\nПозволяет видеть глобальный прогресс сортировки даже при большом массиве.\nЗелёные квадраты = отсортированные элементы.")); sf::Text footer; footer.setFont(font_); footer.setCharacterSize(30); footer.setScale(0.5f, 0.5f); - footer.setFillColor(sf::Color(100, 100, 100)); - footer.setString(toSfStr(u8"Нажми [I] чтобы закрыть | [H] история | [Q] выход | [Space] старт/пауза | [R] перемешать")); + footer.setFillColor(palette.overlayFooter); + footer.setString(toSfStr(u8"Нажми [I] чтобы закрыть | [H] история | [Q] выход | [Space] старт/пауза | [R] перемешать | [T] тема")); float totalHeight = 0.0f; totalHeight += title.getGlobalBounds().height + 10.0f; @@ -328,6 +348,8 @@ void UI::drawHistoryOverlay(sf::RenderWindow& window, const SortHistory& history return; } + const ColorPalette& palette = Theme::getInstance().getPalette(); + auto toSfStr = [](const char* utf8) -> sf::String { std::string s(utf8); return sf::String::fromUtf8(s.begin(), s.end()); @@ -338,14 +360,14 @@ void UI::drawHistoryOverlay(sf::RenderWindow& window, const SortHistory& history sf::RectangleShape overlay(sf::Vector2f(windowWidth, windowHeight)); overlay.setPosition(0.0f, 0.0f); - overlay.setFillColor(sf::Color(8, 10, 18, 230)); + overlay.setFillColor(palette.overlayBackground); window.draw(overlay); sf::Text title; title.setFont(font_); title.setCharacterSize(80); title.setScale(0.5f, 0.5f); - title.setFillColor(sf::Color::White); + title.setFillColor(palette.overlayTitle); title.setString(toSfStr(u8"История сортировок [H — закрыть]")); const auto& records = history.getRecords(); @@ -362,7 +384,7 @@ void UI::drawHistoryOverlay(sf::RenderWindow& window, const SortHistory& history emptyText.setFont(font_); emptyText.setCharacterSize(40); emptyText.setScale(0.5f, 0.5f); - emptyText.setFillColor(sf::Color(160, 160, 160)); + emptyText.setFillColor(palette.overlaySubtitle); emptyText.setString(toSfStr(u8"Нет завершённых сортировок")); sf::FloatRect emptyBounds = emptyText.getGlobalBounds(); @@ -375,7 +397,7 @@ void UI::drawHistoryOverlay(sf::RenderWindow& window, const SortHistory& history header.setFont(font_); header.setCharacterSize(36); header.setScale(0.5f, 0.5f); - header.setFillColor(sf::Color(0, 220, 255)); + header.setFillColor(palette.historyTableHeader); header.setString(toSfStr(u8"Алгоритм Размер Сравнений Свапов Скорость")); float tableX = 100.0f; @@ -385,7 +407,7 @@ void UI::drawHistoryOverlay(sf::RenderWindow& window, const SortHistory& history sf::RectangleShape separator(sf::Vector2f(windowWidth - 200.0f, 1.0f)); separator.setPosition(tableX, startY); - separator.setFillColor(sf::Color(60, 70, 90)); + separator.setFillColor(palette.separator); window.draw(separator); startY += 10.0f; @@ -400,11 +422,11 @@ void UI::drawHistoryOverlay(sf::RenderWindow& window, const SortHistory& history rowBg.setPosition(tableX, startY); if (isNewest) { - rowBg.setFillColor(sf::Color(30, 60, 90, 150)); + rowBg.setFillColor(palette.historyNewestHighlight); } else if (displayCount % 2 == 1) { - rowBg.setFillColor(sf::Color(15, 18, 25, 100)); + rowBg.setFillColor(palette.historyRowOdd); } else { - rowBg.setFillColor(sf::Color(0, 0, 0, 0)); + rowBg.setFillColor(palette.historyRowEven); } window.draw(rowBg); @@ -419,7 +441,7 @@ void UI::drawHistoryOverlay(sf::RenderWindow& window, const SortHistory& history rowText.setFont(font_); rowText.setCharacterSize(32); rowText.setScale(0.5f, 0.5f); - rowText.setFillColor(isNewest ? sf::Color(100, 255, 150) : sf::Color(200, 200, 200)); + rowText.setFillColor(isNewest ? palette.historyNewestText : palette.overlayBody); rowText.setString(algoBuffer); rowText.setPosition(tableX, startY + 2.0f); window.draw(rowText); @@ -433,11 +455,11 @@ void UI::drawHistoryOverlay(sf::RenderWindow& window, const SortHistory& history speedText.setScale(0.5f, 0.5f); if (record.relativeSpeed == 1.0f) { - speedText.setFillColor(sf::Color(100, 255, 120)); + speedText.setFillColor(palette.historySpeedFastest); } else if (record.relativeSpeed >= 2.0f) { - speedText.setFillColor(sf::Color(255, 160, 60)); + speedText.setFillColor(palette.historySpeedSlow); } else { - speedText.setFillColor(isNewest ? sf::Color(100, 255, 150) : sf::Color(200, 200, 200)); + speedText.setFillColor(isNewest ? palette.historyNewestText : palette.overlayBody); } speedText.setString(speedBuffer);