Fix the volume slider visual
This commit is contained in:
+56
-20
@@ -7,23 +7,6 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::string buildVolumeBar(int volume_0_to_100) {
|
|
||||||
int totalBlocks = 10;
|
|
||||||
int filled = (volume_0_to_100 * totalBlocks + 50) / 100;
|
|
||||||
filled = std::clamp(filled, 0, totalBlocks);
|
|
||||||
|
|
||||||
std::string bar = "[";
|
|
||||||
for (int i = 0; i < totalBlocks; ++i) {
|
|
||||||
if (i < filled) {
|
|
||||||
bar += "\u2588"; // Solid block
|
|
||||||
} else {
|
|
||||||
bar += "\u2591"; // Light shade block
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bar += "] " + std::to_string(volume_0_to_100) + "%";
|
|
||||||
return bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case-insensitive lexicographic comparison for alphabetical list ordering.
|
// Case-insensitive lexicographic comparison for alphabetical list ordering.
|
||||||
int ciCompare(const std::string& a, const std::string& b) {
|
int ciCompare(const std::string& a, const std::string& b) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@@ -241,6 +224,8 @@ void AudioSettingsPage::destroyTextures() {
|
|||||||
deviceText_.destroy();
|
deviceText_.destroy();
|
||||||
statusMsgText_.destroy();
|
statusMsgText_.destroy();
|
||||||
footerText_.destroy();
|
footerText_.destroy();
|
||||||
|
volumeLabelText_.destroy();
|
||||||
|
volumePercentText_.destroy();
|
||||||
for (auto& row : menuRows_) row.destroy();
|
for (auto& row : menuRows_) row.destroy();
|
||||||
menuRows_.clear();
|
menuRows_.clear();
|
||||||
|
|
||||||
@@ -561,8 +546,58 @@ void AudioSettingsPage::render(SDL_Renderer* renderer) {
|
|||||||
: ((currentTrackIndex_ >= 0 && currentTrackIndex_ < static_cast<int>(tracks_.size()))
|
: ((currentTrackIndex_ >= 0 && currentTrackIndex_ < static_cast<int>(tracks_.size()))
|
||||||
? tracks_[currentTrackIndex_].display_name : "Original Audio");
|
? tracks_[currentTrackIndex_].display_name : "Original Audio");
|
||||||
|
|
||||||
|
// Volume row is drawn specially: a fixed percentage label to the left
|
||||||
|
// of a full-width outlined bar whose solid fill tracks the volume.
|
||||||
|
int volume = state_->audio.getVolume();
|
||||||
|
SDL_Color volumeColor = (selectedItem_ == 0) ? yellow : white;
|
||||||
|
volumeLabelText_.ensure(renderer, fontBody_, "Volume:", volumeColor);
|
||||||
|
volumePercentText_.ensure(renderer, fontBody_, std::to_string(volume) + "%", volumeColor);
|
||||||
|
|
||||||
|
float labelX = 100.0f;
|
||||||
|
float textY = listY + (rowHeight - volumeLabelText_.height) / 2.0f;
|
||||||
|
if (volumeLabelText_.texture) {
|
||||||
|
SDL_FRect dst{labelX, textY, volumeLabelText_.width, volumeLabelText_.height};
|
||||||
|
SDL_RenderTexture(renderer, volumeLabelText_.texture, nullptr, &dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
float pctX = labelX + volumeLabelText_.width + 12.0f;
|
||||||
|
if (volumePercentText_.texture) {
|
||||||
|
SDL_FRect dst{pctX, textY, volumePercentText_.width, volumePercentText_.height};
|
||||||
|
SDL_RenderTexture(renderer, volumePercentText_.texture, nullptr, &dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The bar outline spans the remaining full width (right edge matching
|
||||||
|
// the menu's 100px right margin) and never moves: its left edge is
|
||||||
|
// reserved from the widest percentage text ("100%"). Only the fill
|
||||||
|
// grows and shrinks with the volume.
|
||||||
|
int widestPctW = 0;
|
||||||
|
TTF_GetStringSize(fontBody_, "100%", 0, &widestPctW, nullptr);
|
||||||
|
float barLeft = pctX + static_cast<float>(widestPctW) + 20.0f;
|
||||||
|
float barRight = fw - 100.0f;
|
||||||
|
float barTop = listY + (rowHeight - 24.0f) / 2.0f;
|
||||||
|
float barH = 24.0f;
|
||||||
|
float barW = barRight - barLeft;
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(renderer, 150, 160, 180, 255);
|
||||||
|
SDL_FRect barOutline{barLeft, barTop, barW, barH};
|
||||||
|
SDL_RenderRect(renderer, &barOutline);
|
||||||
|
|
||||||
|
float fillW = barW * static_cast<float>(volume) / 100.0f;
|
||||||
|
if (fillW > 0.0f) {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 200, 120, 255);
|
||||||
|
SDL_FRect fill{barLeft + 1.0f, barTop + 1.0f, std::max(0.0f, fillW - 2.0f), barH - 2.0f};
|
||||||
|
SDL_RenderFillRect(renderer, &fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItem_ == 0) {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
||||||
|
SDL_FRect selLine{labelX, listY + volumeLabelText_.height + 2.0f, barRight - labelX, 6.0f};
|
||||||
|
SDL_RenderFillRect(renderer, &selLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
listY += rowHeight;
|
||||||
|
|
||||||
std::vector<std::string> rowTexts = {
|
std::vector<std::string> rowTexts = {
|
||||||
"Volume: " + buildVolumeBar(state_->audio.getVolume()),
|
|
||||||
"Output Device: [" + devName + "]",
|
"Output Device: [" + devName + "]",
|
||||||
"Audio Track: [" + trackName + "]",
|
"Audio Track: [" + trackName + "]",
|
||||||
std::string("Audio Status: [") + (state_->audio.isAudioEnabled() ? "ON" : "OFF") + "]",
|
std::string("Audio Status: [") + (state_->audio.isAudioEnabled() ? "ON" : "OFF") + "]",
|
||||||
@@ -571,13 +606,14 @@ void AudioSettingsPage::render(SDL_Renderer* renderer) {
|
|||||||
|
|
||||||
if (menuRows_.size() != rowTexts.size()) menuRows_.resize(rowTexts.size());
|
if (menuRows_.size() != rowTexts.size()) menuRows_.resize(rowTexts.size());
|
||||||
for (int i = 0; i < static_cast<int>(rowTexts.size()); ++i) {
|
for (int i = 0; i < static_cast<int>(rowTexts.size()); ++i) {
|
||||||
SDL_Color color = (selectedItem_ == i) ? yellow : white;
|
int rowIndex = i + 1; // row 0 is the volume slider
|
||||||
|
SDL_Color color = (selectedItem_ == rowIndex) ? yellow : white;
|
||||||
menuRows_[i].ensure(renderer, fontBody_, rowTexts[i], color);
|
menuRows_[i].ensure(renderer, fontBody_, rowTexts[i], color);
|
||||||
if (!menuRows_[i].texture) { listY += rowHeight; continue; }
|
if (!menuRows_[i].texture) { listY += rowHeight; continue; }
|
||||||
SDL_FRect dst{100.0f, listY, menuRows_[i].width, menuRows_[i].height};
|
SDL_FRect dst{100.0f, listY, menuRows_[i].width, menuRows_[i].height};
|
||||||
SDL_RenderTexture(renderer, menuRows_[i].texture, nullptr, &dst);
|
SDL_RenderTexture(renderer, menuRows_[i].texture, nullptr, &dst);
|
||||||
|
|
||||||
if (selectedItem_ == i) {
|
if (selectedItem_ == rowIndex) {
|
||||||
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
||||||
SDL_FRect selLine{100.0f, listY + menuRows_[i].height + 2.0f, menuRows_[i].width, 6.0f};
|
SDL_FRect selLine{100.0f, listY + menuRows_[i].height + 2.0f, menuRows_[i].width, 6.0f};
|
||||||
SDL_RenderFillRect(renderer, &selLine);
|
SDL_RenderFillRect(renderer, &selLine);
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ private:
|
|||||||
CachedText deviceText_;
|
CachedText deviceText_;
|
||||||
CachedText statusMsgText_;
|
CachedText statusMsgText_;
|
||||||
CachedText footerText_;
|
CachedText footerText_;
|
||||||
|
CachedText volumeLabelText_;
|
||||||
|
CachedText volumePercentText_;
|
||||||
std::vector<CachedText> menuRows_;
|
std::vector<CachedText> menuRows_;
|
||||||
|
|
||||||
CachedText modalTitleText_;
|
CachedText modalTitleText_;
|
||||||
|
|||||||
Reference in New Issue
Block a user