mirror of
https://github.com/koloideal/SortLab.git
synced 2026-06-10 02:15:31 +03:00
skelet
This commit is contained in:
@@ -23,6 +23,7 @@ add_executable(SortLab
|
|||||||
src/Sorter.cpp
|
src/Sorter.cpp
|
||||||
src/UI.cpp
|
src/UI.cpp
|
||||||
src/OperationsHistory.cpp
|
src/OperationsHistory.cpp
|
||||||
|
src/ProgressMap.cpp
|
||||||
src/sorters/BubbleSorter.cpp
|
src/sorters/BubbleSorter.cpp
|
||||||
src/sorters/SelectionSorter.cpp
|
src/sorters/SelectionSorter.cpp
|
||||||
src/sorters/InsertionSorter.cpp
|
src/sorters/InsertionSorter.cpp
|
||||||
|
|||||||
+6
-3
@@ -6,6 +6,7 @@
|
|||||||
#include "Sorter.hpp"
|
#include "Sorter.hpp"
|
||||||
#include "UI.hpp"
|
#include "UI.hpp"
|
||||||
#include "OperationsHistory.hpp"
|
#include "OperationsHistory.hpp"
|
||||||
|
#include "ProgressMap.hpp"
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
public:
|
public:
|
||||||
@@ -16,7 +17,7 @@ private:
|
|||||||
void handleEvents();
|
void handleEvents();
|
||||||
void update(float dt);
|
void update(float dt);
|
||||||
void render();
|
void render();
|
||||||
void renderHistogram();
|
void renderDeltaHistogram();
|
||||||
void switchSorter(std::unique_ptr<Sorter> newSorter);
|
void switchSorter(std::unique_ptr<Sorter> newSorter);
|
||||||
void generateBeepSound();
|
void generateBeepSound();
|
||||||
void playBeep(float pitch);
|
void playBeep(float pitch);
|
||||||
@@ -26,6 +27,7 @@ private:
|
|||||||
std::unique_ptr<Sorter> currentSorter_;
|
std::unique_ptr<Sorter> currentSorter_;
|
||||||
UI ui_;
|
UI ui_;
|
||||||
OperationsHistory opsHistory_;
|
OperationsHistory opsHistory_;
|
||||||
|
ProgressMap progressMap_;
|
||||||
bool isPlaying_;
|
bool isPlaying_;
|
||||||
float timeSinceLastStep_;
|
float timeSinceLastStep_;
|
||||||
int stepsPerFrame_;
|
int stepsPerFrame_;
|
||||||
@@ -41,6 +43,7 @@ private:
|
|||||||
size_t lastComparisons_;
|
size_t lastComparisons_;
|
||||||
size_t lastSwaps_;
|
size_t lastSwaps_;
|
||||||
|
|
||||||
sf::Font histogramFont_;
|
sf::Font bottomPanelFont_;
|
||||||
bool histogramFontLoaded_;
|
bool bottomPanelFontLoaded_;
|
||||||
|
bool showInfo_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,14 +4,15 @@
|
|||||||
|
|
||||||
class OperationsHistory {
|
class OperationsHistory {
|
||||||
public:
|
public:
|
||||||
OperationsHistory(size_t maxSamples = 300);
|
OperationsHistory(size_t maxSamples = 400);
|
||||||
|
|
||||||
void record(size_t comparisons);
|
void record(size_t currentComparisons);
|
||||||
void reset();
|
void reset();
|
||||||
const std::deque<size_t>& getHistory() const;
|
const std::deque<size_t>& getDeltaHistory() const;
|
||||||
size_t getMaxValue() const;
|
size_t getMaxDelta() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::deque<size_t> compareHistory_;
|
std::deque<size_t> deltaHistory_;
|
||||||
size_t maxSamples_;
|
size_t maxSamples_;
|
||||||
|
size_t lastComparisons_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include "Array.hpp"
|
||||||
|
|
||||||
|
class ProgressMap {
|
||||||
|
public:
|
||||||
|
ProgressMap();
|
||||||
|
|
||||||
|
void draw(sf::RenderWindow& window, const Array& array, sf::Font& font, bool fontLoaded);
|
||||||
|
|
||||||
|
private:
|
||||||
|
sf::Color getColorForState(Array::State state) const;
|
||||||
|
};
|
||||||
@@ -9,6 +9,7 @@ public:
|
|||||||
|
|
||||||
void update(const Sorter& sorter, bool isPlaying, bool isFinished, int stepsPerFrame, const Array& array);
|
void update(const Sorter& sorter, bool isPlaying, bool isFinished, int stepsPerFrame, const Array& array);
|
||||||
void draw(sf::RenderWindow& window);
|
void draw(sf::RenderWindow& window);
|
||||||
|
void drawInfoOverlay(sf::RenderWindow& window);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sf::Font font_;
|
sf::Font font_;
|
||||||
|
|||||||
+72
-38
@@ -10,7 +10,8 @@ App::App()
|
|||||||
, array_(100)
|
, array_(100)
|
||||||
, currentSorter_(std::make_unique<BubbleSorter>())
|
, currentSorter_(std::make_unique<BubbleSorter>())
|
||||||
, ui_()
|
, ui_()
|
||||||
, opsHistory_(300)
|
, opsHistory_(400)
|
||||||
|
, progressMap_()
|
||||||
, isPlaying_(false)
|
, isPlaying_(false)
|
||||||
, timeSinceLastStep_(0.0f)
|
, timeSinceLastStep_(0.0f)
|
||||||
, stepsPerFrame_(1)
|
, stepsPerFrame_(1)
|
||||||
@@ -20,14 +21,15 @@ App::App()
|
|||||||
, sweepDelay_(0.005f)
|
, sweepDelay_(0.005f)
|
||||||
, lastComparisons_(0)
|
, lastComparisons_(0)
|
||||||
, lastSwaps_(0)
|
, lastSwaps_(0)
|
||||||
, histogramFontLoaded_(false) {
|
, bottomPanelFontLoaded_(false)
|
||||||
|
, showInfo_(false) {
|
||||||
window_.setFramerateLimit(60);
|
window_.setFramerateLimit(60);
|
||||||
generateBeepSound();
|
generateBeepSound();
|
||||||
beepSound_.setBuffer(beepBuffer_);
|
beepSound_.setBuffer(beepBuffer_);
|
||||||
beepSound_.setVolume(100.0f);
|
beepSound_.setVolume(100.0f);
|
||||||
|
|
||||||
if (histogramFont_.loadFromFile("assets/fonts/JetBrainsMono-Regular.ttf")) {
|
if (bottomPanelFont_.loadFromFile("assets/fonts/JetBrainsMono-Regular.ttf")) {
|
||||||
histogramFontLoaded_ = true;
|
bottomPanelFontLoaded_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +111,10 @@ void App::handleEvents() {
|
|||||||
window_.close();
|
window_.close();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::I:
|
||||||
|
showInfo_ = !showInfo_;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -182,8 +188,11 @@ void App::update(float dt) {
|
|||||||
void App::render() {
|
void App::render() {
|
||||||
window_.clear(sf::Color(10, 12, 20));
|
window_.clear(sf::Color(10, 12, 20));
|
||||||
|
|
||||||
const float histogramHeight = 120.0f;
|
const float topUIHeight = 80.0f;
|
||||||
const float availableHeight = window_.getSize().y - histogramHeight;
|
const float bottomPanelHeight = 140.0f;
|
||||||
|
const float mainAreaTop = topUIHeight;
|
||||||
|
const float mainAreaBottom = window_.getSize().y - bottomPanelHeight;
|
||||||
|
const float mainAreaHeight = mainAreaBottom - mainAreaTop;
|
||||||
|
|
||||||
float width = window_.getSize().x / static_cast<float>(array_.getSize());
|
float width = window_.getSize().x / static_cast<float>(array_.getSize());
|
||||||
float maxVal = static_cast<float>(array_.getSize());
|
float maxVal = static_cast<float>(array_.getSize());
|
||||||
@@ -191,9 +200,9 @@ void App::render() {
|
|||||||
sf::VertexArray vertices(sf::Quads);
|
sf::VertexArray vertices(sf::Quads);
|
||||||
|
|
||||||
for (int i = 0; i < array_.getSize(); ++i) {
|
for (int i = 0; i < array_.getSize(); ++i) {
|
||||||
float height = (array_.getValue(i) / maxVal) * (availableHeight * 0.75f);
|
float height = (array_.getValue(i) / maxVal) * (mainAreaHeight * 0.9f);
|
||||||
float x = i * width;
|
float x = i * width;
|
||||||
float y = availableHeight - height;
|
float y = mainAreaBottom - height;
|
||||||
|
|
||||||
sf::Color barColor;
|
sf::Color barColor;
|
||||||
bool useGradient = false;
|
bool useGradient = false;
|
||||||
@@ -230,51 +239,71 @@ void App::render() {
|
|||||||
static_cast<sf::Uint8>(bottomColor.b + (topColor.b - bottomColor.b) * normalizedValue * 0.6f)
|
static_cast<sf::Uint8>(bottomColor.b + (topColor.b - bottomColor.b) * normalizedValue * 0.6f)
|
||||||
);
|
);
|
||||||
|
|
||||||
vertices.append(sf::Vertex(sf::Vector2f(x, availableHeight), gradientBottom));
|
vertices.append(sf::Vertex(sf::Vector2f(x, mainAreaBottom), gradientBottom));
|
||||||
vertices.append(sf::Vertex(sf::Vector2f(x + width - 1.0f, availableHeight), gradientBottom));
|
vertices.append(sf::Vertex(sf::Vector2f(x + width - 1.0f, mainAreaBottom), gradientBottom));
|
||||||
vertices.append(sf::Vertex(sf::Vector2f(x + width - 1.0f, y), gradientTop));
|
vertices.append(sf::Vertex(sf::Vector2f(x + width - 1.0f, y), gradientTop));
|
||||||
vertices.append(sf::Vertex(sf::Vector2f(x, y), gradientTop));
|
vertices.append(sf::Vertex(sf::Vector2f(x, y), gradientTop));
|
||||||
} else {
|
} else {
|
||||||
vertices.append(sf::Vertex(sf::Vector2f(x, availableHeight), barColor));
|
vertices.append(sf::Vertex(sf::Vector2f(x, mainAreaBottom), barColor));
|
||||||
vertices.append(sf::Vertex(sf::Vector2f(x + width - 1.0f, availableHeight), barColor));
|
vertices.append(sf::Vertex(sf::Vector2f(x + width - 1.0f, mainAreaBottom), barColor));
|
||||||
vertices.append(sf::Vertex(sf::Vector2f(x + width - 1.0f, y), barColor));
|
vertices.append(sf::Vertex(sf::Vector2f(x + width - 1.0f, y), barColor));
|
||||||
vertices.append(sf::Vertex(sf::Vector2f(x, y), barColor));
|
vertices.append(sf::Vertex(sf::Vector2f(x, y), barColor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window_.draw(vertices);
|
window_.draw(vertices);
|
||||||
renderHistogram();
|
|
||||||
|
sf::RectangleShape separator(sf::Vector2f(window_.getSize().x, 1.0f));
|
||||||
|
separator.setPosition(0.0f, mainAreaBottom);
|
||||||
|
separator.setFillColor(sf::Color(40, 45, 60));
|
||||||
|
window_.draw(separator);
|
||||||
|
|
||||||
|
renderDeltaHistogram();
|
||||||
|
progressMap_.draw(window_, array_, bottomPanelFont_, bottomPanelFontLoaded_);
|
||||||
|
|
||||||
|
sf::RectangleShape verticalSeparator(sf::Vector2f(1.0f, bottomPanelHeight));
|
||||||
|
verticalSeparator.setPosition(1066.0f, mainAreaBottom);
|
||||||
|
verticalSeparator.setFillColor(sf::Color(40, 45, 60));
|
||||||
|
window_.draw(verticalSeparator);
|
||||||
|
|
||||||
ui_.draw(window_);
|
ui_.draw(window_);
|
||||||
|
|
||||||
|
if (showInfo_) {
|
||||||
|
ui_.drawInfoOverlay(window_);
|
||||||
|
}
|
||||||
|
|
||||||
window_.display();
|
window_.display();
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::renderHistogram() {
|
void App::renderDeltaHistogram() {
|
||||||
const float histogramHeight = 120.0f;
|
const float startX = 0.0f;
|
||||||
const float histogramY = window_.getSize().y - histogramHeight;
|
const float startY = 760.0f;
|
||||||
|
const float width = 1066.0f;
|
||||||
|
const float height = 140.0f;
|
||||||
|
|
||||||
sf::RectangleShape background(sf::Vector2f(window_.getSize().x, histogramHeight));
|
sf::RectangleShape background(sf::Vector2f(width, height));
|
||||||
background.setPosition(0.0f, histogramY);
|
background.setPosition(startX, startY);
|
||||||
background.setFillColor(sf::Color(15, 18, 30));
|
background.setFillColor(sf::Color(12, 15, 25));
|
||||||
window_.draw(background);
|
window_.draw(background);
|
||||||
|
|
||||||
const auto& history = opsHistory_.getHistory();
|
const auto& deltaHistory = opsHistory_.getDeltaHistory();
|
||||||
|
|
||||||
if (!history.empty()) {
|
if (!deltaHistory.empty()) {
|
||||||
size_t maxValue = opsHistory_.getMaxValue();
|
size_t maxDelta = opsHistory_.getMaxDelta();
|
||||||
if (maxValue == 0) maxValue = 1;
|
if (maxDelta == 0) maxDelta = 1;
|
||||||
|
|
||||||
float barWidth = window_.getSize().x / 300.0f;
|
float barWidth = width / 400.0f;
|
||||||
|
float availableHeight = height - 25.0f;
|
||||||
sf::VertexArray histogramBars(sf::Quads);
|
sf::VertexArray histogramBars(sf::Quads);
|
||||||
|
|
||||||
for (size_t i = 0; i < history.size(); ++i) {
|
for (size_t i = 0; i < deltaHistory.size(); ++i) {
|
||||||
float barHeight = (static_cast<float>(history[i]) / static_cast<float>(maxValue)) * (histogramHeight - 30.0f);
|
float barHeight = (static_cast<float>(deltaHistory[i]) / static_cast<float>(maxDelta)) * availableHeight;
|
||||||
float x = i * barWidth;
|
float x = startX + i * barWidth;
|
||||||
float y = histogramY + histogramHeight - barHeight - 5.0f;
|
float y = startY + height - barHeight;
|
||||||
|
|
||||||
float normalizedValue = static_cast<float>(history[i]) / static_cast<float>(maxValue);
|
float normalizedValue = static_cast<float>(deltaHistory[i]) / static_cast<float>(maxDelta);
|
||||||
sf::Color lowColor(0, 120, 255);
|
sf::Color lowColor(0, 80, 200);
|
||||||
sf::Color highColor(0, 220, 255);
|
sf::Color highColor(0, 240, 255);
|
||||||
|
|
||||||
sf::Color barColor(
|
sf::Color barColor(
|
||||||
static_cast<sf::Uint8>(lowColor.r + (highColor.r - lowColor.r) * normalizedValue),
|
static_cast<sf::Uint8>(lowColor.r + (highColor.r - lowColor.r) * normalizedValue),
|
||||||
@@ -282,8 +311,8 @@ void App::renderHistogram() {
|
|||||||
static_cast<sf::Uint8>(lowColor.b + (highColor.b - lowColor.b) * normalizedValue)
|
static_cast<sf::Uint8>(lowColor.b + (highColor.b - lowColor.b) * normalizedValue)
|
||||||
);
|
);
|
||||||
|
|
||||||
histogramBars.append(sf::Vertex(sf::Vector2f(x, histogramY + histogramHeight - 5.0f), barColor));
|
histogramBars.append(sf::Vertex(sf::Vector2f(x, startY + height), barColor));
|
||||||
histogramBars.append(sf::Vertex(sf::Vector2f(x + barWidth, histogramY + histogramHeight - 5.0f), barColor));
|
histogramBars.append(sf::Vertex(sf::Vector2f(x + barWidth, startY + height), barColor));
|
||||||
histogramBars.append(sf::Vertex(sf::Vector2f(x + barWidth, y), barColor));
|
histogramBars.append(sf::Vertex(sf::Vector2f(x + barWidth, y), barColor));
|
||||||
histogramBars.append(sf::Vertex(sf::Vector2f(x, y), barColor));
|
histogramBars.append(sf::Vertex(sf::Vector2f(x, y), barColor));
|
||||||
}
|
}
|
||||||
@@ -291,13 +320,18 @@ void App::renderHistogram() {
|
|||||||
window_.draw(histogramBars);
|
window_.draw(histogramBars);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (histogramFontLoaded_) {
|
sf::RectangleShape baseline(sf::Vector2f(width, 1.0f));
|
||||||
|
baseline.setPosition(startX, startY + height - 1.0f);
|
||||||
|
baseline.setFillColor(sf::Color(60, 70, 90));
|
||||||
|
window_.draw(baseline);
|
||||||
|
|
||||||
|
if (bottomPanelFontLoaded_) {
|
||||||
sf::Text label;
|
sf::Text label;
|
||||||
label.setFont(histogramFont_);
|
label.setFont(bottomPanelFont_);
|
||||||
label.setString("Comparisons over time");
|
label.setString("Delta Comparisons / step");
|
||||||
label.setCharacterSize(14);
|
label.setCharacterSize(13);
|
||||||
label.setFillColor(sf::Color(180, 180, 180));
|
label.setFillColor(sf::Color(180, 180, 180));
|
||||||
label.setPosition(10.0f, histogramY + 5.0f);
|
label.setPosition(startX + 10.0f, startY + 5.0f);
|
||||||
window_.draw(label);
|
window_.draw(label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-11
@@ -2,29 +2,36 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
OperationsHistory::OperationsHistory(size_t maxSamples)
|
OperationsHistory::OperationsHistory(size_t maxSamples)
|
||||||
: maxSamples_(maxSamples) {
|
: maxSamples_(maxSamples), lastComparisons_(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OperationsHistory::record(size_t comparisons) {
|
void OperationsHistory::record(size_t currentComparisons) {
|
||||||
compareHistory_.push_back(comparisons);
|
size_t delta = 0;
|
||||||
|
if (currentComparisons >= lastComparisons_) {
|
||||||
|
delta = currentComparisons - lastComparisons_;
|
||||||
|
}
|
||||||
|
|
||||||
if (compareHistory_.size() > maxSamples_) {
|
deltaHistory_.push_back(delta);
|
||||||
compareHistory_.pop_front();
|
lastComparisons_ = currentComparisons;
|
||||||
|
|
||||||
|
if (deltaHistory_.size() > maxSamples_) {
|
||||||
|
deltaHistory_.pop_front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OperationsHistory::reset() {
|
void OperationsHistory::reset() {
|
||||||
compareHistory_.clear();
|
deltaHistory_.clear();
|
||||||
|
lastComparisons_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::deque<size_t>& OperationsHistory::getHistory() const {
|
const std::deque<size_t>& OperationsHistory::getDeltaHistory() const {
|
||||||
return compareHistory_;
|
return deltaHistory_;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t OperationsHistory::getMaxValue() const {
|
size_t OperationsHistory::getMaxDelta() const {
|
||||||
if (compareHistory_.empty()) {
|
if (deltaHistory_.empty()) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *std::max_element(compareHistory_.begin(), compareHistory_.end());
|
return *std::max_element(deltaHistory_.begin(), deltaHistory_.end());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#include "ProgressMap.hpp"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
ProgressMap::ProgressMap() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressMap::draw(sf::RenderWindow& window, const Array& array, sf::Font& font, bool fontLoaded) {
|
||||||
|
const float startX = 1066.0f;
|
||||||
|
const float startY = 760.0f;
|
||||||
|
const float width = 534.0f;
|
||||||
|
const float height = 140.0f;
|
||||||
|
|
||||||
|
sf::RectangleShape background(sf::Vector2f(width, height));
|
||||||
|
background.setPosition(startX, startY);
|
||||||
|
background.setFillColor(sf::Color(12, 15, 25));
|
||||||
|
window.draw(background);
|
||||||
|
|
||||||
|
if (fontLoaded) {
|
||||||
|
sf::Text label;
|
||||||
|
label.setFont(font);
|
||||||
|
label.setString("Progress Map");
|
||||||
|
label.setCharacterSize(13);
|
||||||
|
label.setFillColor(sf::Color(180, 180, 180));
|
||||||
|
label.setPosition(startX + 10.0f, startY + 5.0f);
|
||||||
|
window.draw(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
int arraySize = array.getSize();
|
||||||
|
int cols = static_cast<int>(std::sqrt(arraySize));
|
||||||
|
int rows = (arraySize + cols - 1) / cols;
|
||||||
|
|
||||||
|
float availableWidth = width - 20.0f;
|
||||||
|
float availableHeight = height - 30.0f;
|
||||||
|
|
||||||
|
float squareSizeW = availableWidth / static_cast<float>(cols);
|
||||||
|
float squareSizeH = availableHeight / static_cast<float>(rows);
|
||||||
|
float squareSize = std::min(squareSizeW, squareSizeH);
|
||||||
|
|
||||||
|
if (squareSize < 1.0f) squareSize = 1.0f;
|
||||||
|
|
||||||
|
float gridWidth = cols * squareSize;
|
||||||
|
float gridHeight = rows * squareSize;
|
||||||
|
float offsetX = startX + (width - gridWidth) * 0.5f;
|
||||||
|
float offsetY = startY + 30.0f + (availableHeight - gridHeight) * 0.5f;
|
||||||
|
|
||||||
|
sf::VertexArray squares(sf::Quads);
|
||||||
|
|
||||||
|
for (int i = 0; i < arraySize; ++i) {
|
||||||
|
int col = i % cols;
|
||||||
|
int row = i / cols;
|
||||||
|
|
||||||
|
float x = offsetX + col * squareSize;
|
||||||
|
float y = offsetY + row * squareSize;
|
||||||
|
|
||||||
|
sf::Color color = getColorForState(array.getState(i));
|
||||||
|
|
||||||
|
float gap = 1.0f;
|
||||||
|
float actualSize = squareSize - gap;
|
||||||
|
|
||||||
|
squares.append(sf::Vertex(sf::Vector2f(x, y), color));
|
||||||
|
squares.append(sf::Vertex(sf::Vector2f(x + actualSize, y), color));
|
||||||
|
squares.append(sf::Vertex(sf::Vector2f(x + actualSize, y + actualSize), color));
|
||||||
|
squares.append(sf::Vertex(sf::Vector2f(x, y + actualSize), color));
|
||||||
|
}
|
||||||
|
|
||||||
|
window.draw(squares);
|
||||||
|
}
|
||||||
|
|
||||||
|
sf::Color ProgressMap::getColorForState(Array::State state) const {
|
||||||
|
switch (state) {
|
||||||
|
case Array::State::NORMAL:
|
||||||
|
return sf::Color(100, 120, 150);
|
||||||
|
case Array::State::COMPARE:
|
||||||
|
return sf::Color(0, 220, 255);
|
||||||
|
case Array::State::SWAP:
|
||||||
|
return sf::Color(255, 120, 30);
|
||||||
|
case Array::State::SORTED:
|
||||||
|
return sf::Color(50, 220, 120);
|
||||||
|
default:
|
||||||
|
return sf::Color(100, 120, 150);
|
||||||
|
}
|
||||||
|
}
|
||||||
+177
-1
@@ -1,3 +1,4 @@
|
|||||||
|
#pragma execution_character_set("utf-8")
|
||||||
#include "UI.hpp"
|
#include "UI.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@@ -86,7 +87,25 @@ void UI::draw(sf::RenderWindow& window) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float leftWidth = 350.0f;
|
float maxWidth = 0.0f;
|
||||||
|
|
||||||
|
sf::FloatRect algoBounds = algorithmText_.getLocalBounds();
|
||||||
|
sf::FloatRect stateBounds = stateText_.getLocalBounds();
|
||||||
|
sf::FloatRect timeBounds = timeComplexityText_.getLocalBounds();
|
||||||
|
sf::FloatRect spaceBounds = spaceComplexityText_.getLocalBounds();
|
||||||
|
sf::FloatRect compBounds = comparisonsText_.getLocalBounds();
|
||||||
|
sf::FloatRect swapBounds = swapsText_.getLocalBounds();
|
||||||
|
sf::FloatRect speedBounds = speedText_.getLocalBounds();
|
||||||
|
|
||||||
|
maxWidth = std::max(maxWidth, algoBounds.width);
|
||||||
|
maxWidth = std::max(maxWidth, stateBounds.width);
|
||||||
|
maxWidth = std::max(maxWidth, timeBounds.width);
|
||||||
|
maxWidth = std::max(maxWidth, spaceBounds.width);
|
||||||
|
maxWidth = std::max(maxWidth, compBounds.width);
|
||||||
|
maxWidth = std::max(maxWidth, swapBounds.width);
|
||||||
|
maxWidth = std::max(maxWidth, speedBounds.width);
|
||||||
|
|
||||||
|
float leftWidth = maxWidth + 24.0f;
|
||||||
float leftHeight = 215.0f;
|
float leftHeight = 215.0f;
|
||||||
leftBackground_.setSize(sf::Vector2f(leftWidth, leftHeight));
|
leftBackground_.setSize(sf::Vector2f(leftWidth, leftHeight));
|
||||||
leftBackground_.setPosition(5.0f, 5.0f);
|
leftBackground_.setPosition(5.0f, 5.0f);
|
||||||
@@ -113,3 +132,160 @@ void UI::draw(sf::RenderWindow& window) {
|
|||||||
window.draw(speedText_);
|
window.draw(speedText_);
|
||||||
window.draw(controlsText_);
|
window.draw(controlsText_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UI::drawInfoOverlay(sf::RenderWindow& window) {
|
||||||
|
if (!fontLoaded_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto toSfStr = [](const char* utf8) -> sf::String {
|
||||||
|
std::string s(utf8);
|
||||||
|
return sf::String::fromUtf8(s.begin(), s.end());
|
||||||
|
};
|
||||||
|
|
||||||
|
float windowWidth = static_cast<float>(window.getSize().x);
|
||||||
|
float windowHeight = static_cast<float>(window.getSize().y);
|
||||||
|
|
||||||
|
sf::RectangleShape overlay(sf::Vector2f(windowWidth, windowHeight));
|
||||||
|
overlay.setPosition(0.0f, 0.0f);
|
||||||
|
overlay.setFillColor(sf::Color(8, 10, 18, 230));
|
||||||
|
window.draw(overlay);
|
||||||
|
|
||||||
|
sf::Text title;
|
||||||
|
title.setFont(font_);
|
||||||
|
title.setCharacterSize(36);
|
||||||
|
title.setFillColor(sf::Color::White);
|
||||||
|
title.setString(toSfStr(u8"SortLab — визуализатор алгоритмов сортировки"));
|
||||||
|
|
||||||
|
sf::Text subtitle;
|
||||||
|
subtitle.setFont(font_);
|
||||||
|
subtitle.setCharacterSize(18);
|
||||||
|
subtitle.setFillColor(sf::Color(160, 160, 160));
|
||||||
|
subtitle.setString(toSfStr(u8"Учебный инструмент для наглядного изучения алгоритмов сортировки"));
|
||||||
|
|
||||||
|
sf::Text section1;
|
||||||
|
section1.setFont(font_);
|
||||||
|
section1.setCharacterSize(20);
|
||||||
|
section1.setFillColor(sf::Color(0, 220, 255));
|
||||||
|
section1.setString(toSfStr(u8"О программе"));
|
||||||
|
|
||||||
|
sf::Text body1;
|
||||||
|
body1.setFont(font_);
|
||||||
|
body1.setCharacterSize(16);
|
||||||
|
body1.setFillColor(sf::Color(200, 200, 200));
|
||||||
|
body1.setString(toSfStr(u8"SortLab визуализирует работу алгоритмов сортировки в реальном времени.\nКаждый столбик — это элемент массива. Высота = значение элемента.\nЦвета: серый — обычный, голубой — сравнение, оранжевый — перестановка, зелёный — готово."));
|
||||||
|
|
||||||
|
sf::Text section2;
|
||||||
|
section2.setFont(font_);
|
||||||
|
section2.setCharacterSize(20);
|
||||||
|
section2.setFillColor(sf::Color(0, 220, 255));
|
||||||
|
section2.setString(toSfStr(u8"Алгоритмы и сложность"));
|
||||||
|
|
||||||
|
sf::Text body2;
|
||||||
|
body2.setFont(font_);
|
||||||
|
body2.setCharacterSize(16);
|
||||||
|
body2.setFillColor(sf::Color(200, 200, 200));
|
||||||
|
body2.setString(toSfStr(u8"[1] Bubble Sort Время: O(n²) / O(n²) / O(n²) Память: O(1)\n[2] Selection Sort Время: O(n²) / O(n²) / O(n²) Память: O(1)\n[3] Insertion Sort Время: O(n) / O(n²) / O(n²) Память: O(1)\n[4] Merge Sort Время: O(n log n) / O(n log n) / ... Память: O(n)\n[5] Quick Sort Время: O(n log n) / O(n log n) / ... Память: O(log n)"));
|
||||||
|
|
||||||
|
sf::Text section3;
|
||||||
|
section3.setFont(font_);
|
||||||
|
section3.setCharacterSize(20);
|
||||||
|
section3.setFillColor(sf::Color(0, 220, 255));
|
||||||
|
section3.setString(toSfStr(u8"Δ Гистограмма (внизу слева)"));
|
||||||
|
|
||||||
|
sf::Text body3;
|
||||||
|
body3.setFont(font_);
|
||||||
|
body3.setCharacterSize(16);
|
||||||
|
body3.setFillColor(sf::Color(200, 200, 200));
|
||||||
|
body3.setString(toSfStr(u8"Показывает количество сравнений на каждом шаге сортировки.\nВысокий пик = много сравнений за один шаг.\nBubble Sort даёт ровную линию, Quick Sort — резкие пики в начале."));
|
||||||
|
|
||||||
|
sf::Text section4;
|
||||||
|
section4.setFont(font_);
|
||||||
|
section4.setCharacterSize(20);
|
||||||
|
section4.setFillColor(sf::Color(0, 220, 255));
|
||||||
|
section4.setString(toSfStr(u8"Карта прогресса (внизу справа)"));
|
||||||
|
|
||||||
|
sf::Text body4;
|
||||||
|
body4.setFont(font_);
|
||||||
|
body4.setCharacterSize(16);
|
||||||
|
body4.setFillColor(sf::Color(200, 200, 200));
|
||||||
|
body4.setString(toSfStr(u8"Миниатюрная копия всего массива в виде сетки цветных квадратиков.\nПозволяет видеть глобальный прогресс сортировки даже при большом массиве.\nЗелёные квадраты = отсортированные элементы."));
|
||||||
|
|
||||||
|
sf::Text footer;
|
||||||
|
footer.setFont(font_);
|
||||||
|
footer.setCharacterSize(15);
|
||||||
|
footer.setFillColor(sf::Color(100, 100, 100));
|
||||||
|
footer.setString(toSfStr(u8"Нажми [I] чтобы закрыть | [Q] выход | [Space] старт/пауза | [R] перемешать"));
|
||||||
|
|
||||||
|
float totalHeight = 0.0f;
|
||||||
|
totalHeight += title.getLocalBounds().height + 10.0f;
|
||||||
|
totalHeight += subtitle.getLocalBounds().height + 30.0f;
|
||||||
|
totalHeight += section1.getLocalBounds().height + 6.0f;
|
||||||
|
totalHeight += body1.getLocalBounds().height + 24.0f;
|
||||||
|
totalHeight += section2.getLocalBounds().height + 6.0f;
|
||||||
|
totalHeight += body2.getLocalBounds().height + 24.0f;
|
||||||
|
totalHeight += section3.getLocalBounds().height + 6.0f;
|
||||||
|
totalHeight += body3.getLocalBounds().height + 24.0f;
|
||||||
|
totalHeight += section4.getLocalBounds().height + 6.0f;
|
||||||
|
totalHeight += body4.getLocalBounds().height + 30.0f;
|
||||||
|
totalHeight += footer.getLocalBounds().height;
|
||||||
|
|
||||||
|
float startY = (windowHeight - totalHeight) * 0.5f;
|
||||||
|
if (startY < 20.0f) startY = 20.0f;
|
||||||
|
|
||||||
|
float currentY = startY;
|
||||||
|
|
||||||
|
sf::FloatRect titleBounds = title.getLocalBounds();
|
||||||
|
title.setPosition((windowWidth - titleBounds.width) * 0.5f, currentY);
|
||||||
|
window.draw(title);
|
||||||
|
currentY += titleBounds.height + 10.0f;
|
||||||
|
|
||||||
|
sf::FloatRect subtitleBounds = subtitle.getLocalBounds();
|
||||||
|
subtitle.setPosition((windowWidth - subtitleBounds.width) * 0.5f, currentY);
|
||||||
|
window.draw(subtitle);
|
||||||
|
currentY += subtitleBounds.height + 30.0f;
|
||||||
|
|
||||||
|
sf::FloatRect section1Bounds = section1.getLocalBounds();
|
||||||
|
section1.setPosition((windowWidth - section1Bounds.width) * 0.5f, currentY);
|
||||||
|
window.draw(section1);
|
||||||
|
currentY += section1Bounds.height + 6.0f;
|
||||||
|
|
||||||
|
sf::FloatRect body1Bounds = body1.getLocalBounds();
|
||||||
|
body1.setPosition((windowWidth - body1Bounds.width) * 0.5f, currentY);
|
||||||
|
window.draw(body1);
|
||||||
|
currentY += body1Bounds.height + 24.0f;
|
||||||
|
|
||||||
|
sf::FloatRect section2Bounds = section2.getLocalBounds();
|
||||||
|
section2.setPosition((windowWidth - section2Bounds.width) * 0.5f, currentY);
|
||||||
|
window.draw(section2);
|
||||||
|
currentY += section2Bounds.height + 6.0f;
|
||||||
|
|
||||||
|
sf::FloatRect body2Bounds = body2.getLocalBounds();
|
||||||
|
body2.setPosition((windowWidth - body2Bounds.width) * 0.5f, currentY);
|
||||||
|
window.draw(body2);
|
||||||
|
currentY += body2Bounds.height + 24.0f;
|
||||||
|
|
||||||
|
sf::FloatRect section3Bounds = section3.getLocalBounds();
|
||||||
|
section3.setPosition((windowWidth - section3Bounds.width) * 0.5f, currentY);
|
||||||
|
window.draw(section3);
|
||||||
|
currentY += section3Bounds.height + 6.0f;
|
||||||
|
|
||||||
|
sf::FloatRect body3Bounds = body3.getLocalBounds();
|
||||||
|
body3.setPosition((windowWidth - body3Bounds.width) * 0.5f, currentY);
|
||||||
|
window.draw(body3);
|
||||||
|
currentY += body3Bounds.height + 24.0f;
|
||||||
|
|
||||||
|
sf::FloatRect section4Bounds = section4.getLocalBounds();
|
||||||
|
section4.setPosition((windowWidth - section4Bounds.width) * 0.5f, currentY);
|
||||||
|
window.draw(section4);
|
||||||
|
currentY += section4Bounds.height + 6.0f;
|
||||||
|
|
||||||
|
sf::FloatRect body4Bounds = body4.getLocalBounds();
|
||||||
|
body4.setPosition((windowWidth - body4Bounds.width) * 0.5f, currentY);
|
||||||
|
window.draw(body4);
|
||||||
|
currentY += body4Bounds.height + 30.0f;
|
||||||
|
|
||||||
|
sf::FloatRect footerBounds = footer.getLocalBounds();
|
||||||
|
footer.setPosition((windowWidth - footerBounds.width) * 0.5f, currentY);
|
||||||
|
window.draw(footer);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user