Compare commits

..

5 Commits

Author SHA1 Message Date
Your Name d2f9dd97d8 step 2026-07-01 16:52:15 +03:00
kolo fcff19de4c step 2026-07-01 16:47:48 +03:00
kolo e5031a3de0 step 2026-07-01 16:44:48 +03:00
kolo eea3c039eb step 2026-06-17 13:31:56 +03:00
kolo d0e306118f step 2026-06-17 13:29:00 +03:00
11 changed files with 294 additions and 68 deletions
-1
View File
@@ -1,3 +1,2 @@
build
.tools
output
+1
View File
@@ -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
+1
View File
@@ -8,6 +8,7 @@
#include "OperationsHistory.hpp"
#include "ProgressMap.hpp"
#include "SortHistory.hpp"
#include "Theme.hpp"
class App {
public:
+73
View File
@@ -0,0 +1,73 @@
#pragma once
#include <SFML/Graphics.hpp>
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; // Цвет для отсортированных элементов
sf::Color separator;
sf::Color histogramLow; // Нижняя часть градиента гистограммы
sf::Color histogramHigh; // Верхняя часть градиента гистограммы
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_;
};
Binary file not shown.
+8 -4
View File
@@ -23,10 +23,14 @@ WizardStyle=modern
[Files]
Source: "build\SortLab.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\libsfml-graphics-2.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\libsfml-window-2.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\libsfml-system-2.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\libsfml-audio-2.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\sfml-graphics-2.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\sfml-window-2.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\sfml-system-2.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\sfml-audio-2.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\openal32.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\libgcc_s_seh-1.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\libstdc++-6.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\libwinpthread-1.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "assets\*"; DestDir: "{app}\assets"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "assets\icon.ico"; DestDir: "{app}"; Flags: ignoreversion
+20 -13
View File
@@ -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<sf::Uint8>(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<float>(deltaHistory[i]) / static_cast<float>(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<sf::Uint8>(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);
}
+12 -7
View File
@@ -1,10 +1,13 @@
#include "ProgressMap.hpp"
#include "Theme.hpp"
#include <cmath>
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;
}
}
+117
View File
@@ -0,0 +1,117 @@
#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_;
}
+60 -39
View File
@@ -1,5 +1,6 @@
#pragma execution_character_set("utf-8")
#include "UI.hpp"
#include "Theme.hpp"
#include <iostream>
#include <cmath>
@@ -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,18 @@ 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 +165,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 +177,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 +347,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 +359,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 +383,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 +396,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 +406,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 +421,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 +440,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 +454,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);
+1 -3
View File
@@ -27,7 +27,7 @@ void HeapSorter::step(Array& array) {
}
heapifyIndex_ = buildIndex_;
phase_ = Phase::HEAPIFY_DOWN;
needSwap_ = false; // Используем как флаг, что мы в контексте BUILD
needSwap_ = false;
}
else if (phase_ == Phase::HEAPIFY_DOWN || phase_ == Phase::EXTRACT_HEAPIFY) {
leftChild_ = 2 * heapifyIndex_ + 1;
@@ -63,9 +63,7 @@ void HeapSorter::step(Array& array) {
array.incrementSwaps();
heapifyIndex_ = largest_;
// Остаемся в текущей фазе, чтобы продолжить просеивание вниз
} else {
// Элемент на своем месте, просеивание закончено
if (phase_ == Phase::HEAPIFY_DOWN) {
buildIndex_--;
phase_ = Phase::BUILDING_HEAP;