This commit is contained in:
2026-03-05 11:34:43 +03:00
parent 5a942f935f
commit e6bdeaef50
7 changed files with 242 additions and 3 deletions
+2
View File
@@ -25,6 +25,7 @@ if(WIN32)
src/UI.cpp
src/OperationsHistory.cpp
src/ProgressMap.cpp
src/SortHistory.cpp
src/sorters/BubbleSorter.cpp
src/sorters/SelectionSorter.cpp
src/sorters/InsertionSorter.cpp
@@ -45,6 +46,7 @@ else()
src/UI.cpp
src/OperationsHistory.cpp
src/ProgressMap.cpp
src/SortHistory.cpp
src/sorters/BubbleSorter.cpp
src/sorters/SelectionSorter.cpp
src/sorters/InsertionSorter.cpp
+5
View File
@@ -7,6 +7,7 @@
#include "UI.hpp"
#include "OperationsHistory.hpp"
#include "ProgressMap.hpp"
#include "SortHistory.hpp"
class App {
public:
@@ -46,4 +47,8 @@ private:
sf::Font bottomPanelFont_;
bool bottomPanelFontLoaded_;
bool showInfo_;
SortHistory history_;
sf::Clock sortTimer_;
bool recordedThisRun_;
};
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <string>
#include <deque>
struct SortRecord {
std::string algorithmName;
int arraySize;
int comparisons;
int swaps;
float normalizedTime;
float relativeSpeed;
SortRecord() : arraySize(0), comparisons(0), swaps(0), normalizedTime(0.0f), relativeSpeed(1.0f) {}
};
class SortHistory {
public:
SortHistory();
void add(const SortRecord& record);
const std::deque<SortRecord>& getRecords() const;
void clear();
private:
std::deque<SortRecord> records_;
static const size_t MAX_RECORDS = 20;
};
+6
View File
@@ -1,6 +1,7 @@
#pragma once
#include <SFML/Graphics.hpp>
#include "Sorter.hpp"
#include "SortHistory.hpp"
#include <string>
class UI {
@@ -10,6 +11,10 @@ public:
void update(const Sorter& sorter, bool isPlaying, bool isFinished, int stepsPerFrame, const Array& array);
void draw(sf::RenderWindow& window);
void drawInfoOverlay(sf::RenderWindow& window);
void drawHistoryOverlay(sf::RenderWindow& window, const SortHistory& history);
void toggleHistory();
void closeHistory();
bool isHistoryOpen() const;
private:
sf::Font font_;
@@ -24,4 +29,5 @@ private:
sf::RectangleShape leftBackground_;
sf::RectangleShape rightBackground_;
bool fontLoaded_;
bool historyOpen_;
};
+31 -1
View File
@@ -25,7 +25,8 @@ App::App()
, lastComparisons_(0)
, lastSwaps_(0)
, bottomPanelFontLoaded_(false)
, showInfo_(false) {
, showInfo_(false)
, recordedThisRun_(false) {
window_.setFramerateLimit(60);
generateBeepSound();
beepSound_.setBuffer(beepBuffer_);
@@ -125,6 +126,8 @@ void App::handleEvents() {
lastComparisons_ = 0;
lastSwaps_ = 0;
stepsPerFrame_ = 1;
sortTimer_.restart();
recordedThisRun_ = false;
break;
case sf::Keyboard::Q:
@@ -133,6 +136,16 @@ void App::handleEvents() {
case sf::Keyboard::I:
showInfo_ = !showInfo_;
if (showInfo_) {
ui_.closeHistory();
}
break;
case sf::Keyboard::H:
ui_.toggleHistory();
if (ui_.isHistoryOpen()) {
showInfo_ = false;
}
break;
default:
@@ -201,6 +214,17 @@ void App::update(float dt) {
isSweeping_ = true;
sweepIndex_ = 0;
sweepTimer_ = 0.0f;
if (!recordedThisRun_) {
SortRecord record;
record.algorithmName = currentSorter_->getName();
record.arraySize = array_.getSize();
record.comparisons = array_.getComparisons();
record.swaps = array_.getSwaps();
record.normalizedTime = sortTimer_.getElapsedTime().asSeconds() * static_cast<float>(stepsPerFrame_);
history_.add(record);
recordedThisRun_ = true;
}
}
}
}
@@ -292,6 +316,10 @@ void App::render() {
ui_.drawInfoOverlay(window_);
}
if (ui_.isHistoryOpen()) {
ui_.drawHistoryOverlay(window_, history_);
}
window_.display();
}
@@ -369,4 +397,6 @@ void App::switchSorter(std::unique_ptr<Sorter> newSorter) {
lastComparisons_ = 0;
lastSwaps_ = 0;
stepsPerFrame_ = 1;
sortTimer_.restart();
recordedThisRun_ = false;
}
+31
View File
@@ -0,0 +1,31 @@
#include "SortHistory.hpp"
#include <limits>
SortHistory::SortHistory() {
}
void SortHistory::add(const SortRecord& record) {
records_.push_back(record);
if (records_.size() > MAX_RECORDS) {
records_.pop_front();
}
float minNormalizedTime = std::numeric_limits<float>::max();
for (const auto& rec : records_) {
if (rec.normalizedTime < minNormalizedTime) {
minNormalizedTime = rec.normalizedTime;
}
}
for (auto& rec : records_) {
rec.relativeSpeed = rec.normalizedTime / minNormalizedTime;
}
}
const std::deque<SortRecord>& SortHistory::getRecords() const {
return records_;
}
void SortHistory::clear() {
records_.clear();
}
+140 -2
View File
@@ -3,7 +3,7 @@
#include <iostream>
#include <cmath>
UI::UI() : fontLoaded_(false) {
UI::UI() : fontLoaded_(false), historyOpen_(false) {
if (!font_.loadFromFile("assets/fonts/JetBrainsMono-Regular.ttf")) {
std::cerr << "Failed to load font" << std::endl;
return;
@@ -236,7 +236,7 @@ void UI::drawInfoOverlay(sf::RenderWindow& window) {
footer.setCharacterSize(30);
footer.setScale(0.5f, 0.5f);
footer.setFillColor(sf::Color(100, 100, 100));
footer.setString(toSfStr(u8"Нажми [I] чтобы закрыть | [Q] выход | [Space] старт/пауза | [R] перемешать"));
footer.setString(toSfStr(u8"Нажми [I] чтобы закрыть | [H] история | [Q] выход | [Space] старт/пауза | [R] перемешать"));
float totalHeight = 0.0f;
totalHeight += title.getGlobalBounds().height + 10.0f;
@@ -310,3 +310,141 @@ void UI::drawInfoOverlay(sf::RenderWindow& window) {
footer.setPosition(std::floor((windowWidth - footerBounds.width) * 0.5f), std::floor(currentY));
window.draw(footer);
}
void UI::toggleHistory() {
historyOpen_ = !historyOpen_;
}
void UI::closeHistory() {
historyOpen_ = false;
}
bool UI::isHistoryOpen() const {
return historyOpen_;
}
void UI::drawHistoryOverlay(sf::RenderWindow& window, const SortHistory& history) {
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(80);
title.setScale(0.5f, 0.5f);
title.setFillColor(sf::Color::White);
title.setString(toSfStr(u8"История сортировок [H — закрыть]"));
const auto& records = history.getRecords();
float startY = 80.0f;
sf::FloatRect titleBounds = title.getGlobalBounds();
title.setPosition(std::floor((windowWidth - titleBounds.width) * 0.5f), std::floor(startY));
window.draw(title);
startY += titleBounds.height + 30.0f;
if (records.empty()) {
sf::Text emptyText;
emptyText.setFont(font_);
emptyText.setCharacterSize(40);
emptyText.setScale(0.5f, 0.5f);
emptyText.setFillColor(sf::Color(160, 160, 160));
emptyText.setString(toSfStr(u8"Нет завершённых сортировок"));
sf::FloatRect emptyBounds = emptyText.getGlobalBounds();
emptyText.setPosition(std::floor((windowWidth - emptyBounds.width) * 0.5f), std::floor(windowHeight * 0.5f));
window.draw(emptyText);
return;
}
sf::Text header;
header.setFont(font_);
header.setCharacterSize(36);
header.setScale(0.5f, 0.5f);
header.setFillColor(sf::Color(0, 220, 255));
header.setString(toSfStr(u8"Алгоритм Размер Сравнений Свапов Скорость"));
float tableX = 100.0f;
header.setPosition(tableX, startY);
window.draw(header);
startY += header.getGlobalBounds().height + 15.0f;
sf::RectangleShape separator(sf::Vector2f(windowWidth - 200.0f, 1.0f));
separator.setPosition(tableX, startY);
separator.setFillColor(sf::Color(60, 70, 90));
window.draw(separator);
startY += 10.0f;
int displayCount = 0;
for (auto it = records.rbegin(); it != records.rend() && displayCount < 15; ++it, ++displayCount) {
const SortRecord& record = *it;
float rowHeight = 25.0f;
bool isNewest = (displayCount == 0);
sf::RectangleShape rowBg(sf::Vector2f(windowWidth - 200.0f, rowHeight));
rowBg.setPosition(tableX, startY);
if (isNewest) {
rowBg.setFillColor(sf::Color(30, 60, 90, 150));
} else if (displayCount % 2 == 1) {
rowBg.setFillColor(sf::Color(15, 18, 25, 100));
} else {
rowBg.setFillColor(sf::Color(0, 0, 0, 0));
}
window.draw(rowBg);
char algoBuffer[256];
snprintf(algoBuffer, sizeof(algoBuffer), "%-20s %6d %9d %6d ",
record.algorithmName.c_str(),
record.arraySize,
record.comparisons,
record.swaps);
sf::Text rowText;
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.setString(algoBuffer);
rowText.setPosition(tableX, startY + 2.0f);
window.draw(rowText);
char speedBuffer[32];
snprintf(speedBuffer, sizeof(speedBuffer), "%.2fx", record.relativeSpeed);
sf::Text speedText;
speedText.setFont(font_);
speedText.setCharacterSize(32);
speedText.setScale(0.5f, 0.5f);
if (record.relativeSpeed == 1.0f) {
speedText.setFillColor(sf::Color(100, 255, 120));
} else if (record.relativeSpeed >= 2.0f) {
speedText.setFillColor(sf::Color(255, 160, 60));
} else {
speedText.setFillColor(isNewest ? sf::Color(100, 255, 150) : sf::Color(200, 200, 200));
}
speedText.setString(speedBuffer);
float speedX = tableX + rowText.getGlobalBounds().width;
speedText.setPosition(speedX, startY + 2.0f);
window.draw(speedText);
startY += rowHeight;
}
}