Fix the volume slider visual
This commit is contained in:
+56
-20
@@ -7,23 +7,6 @@
|
||||
|
||||
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.
|
||||
int ciCompare(const std::string& a, const std::string& b) {
|
||||
size_t i = 0;
|
||||
@@ -241,6 +224,8 @@ void AudioSettingsPage::destroyTextures() {
|
||||
deviceText_.destroy();
|
||||
statusMsgText_.destroy();
|
||||
footerText_.destroy();
|
||||
volumeLabelText_.destroy();
|
||||
volumePercentText_.destroy();
|
||||
for (auto& row : menuRows_) row.destroy();
|
||||
menuRows_.clear();
|
||||
|
||||
@@ -561,8 +546,58 @@ void AudioSettingsPage::render(SDL_Renderer* renderer) {
|
||||
: ((currentTrackIndex_ >= 0 && currentTrackIndex_ < static_cast<int>(tracks_.size()))
|
||||
? 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 = {
|
||||
"Volume: " + buildVolumeBar(state_->audio.getVolume()),
|
||||
"Output Device: [" + devName + "]",
|
||||
"Audio Track: [" + trackName + "]",
|
||||
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());
|
||||
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);
|
||||
if (!menuRows_[i].texture) { listY += rowHeight; continue; }
|
||||
SDL_FRect dst{100.0f, listY, menuRows_[i].width, menuRows_[i].height};
|
||||
SDL_RenderTexture(renderer, menuRows_[i].texture, nullptr, &dst);
|
||||
|
||||
if (selectedItem_ == i) {
|
||||
if (selectedItem_ == rowIndex) {
|
||||
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
||||
SDL_FRect selLine{100.0f, listY + menuRows_[i].height + 2.0f, menuRows_[i].width, 6.0f};
|
||||
SDL_RenderFillRect(renderer, &selLine);
|
||||
|
||||
@@ -66,6 +66,8 @@ private:
|
||||
CachedText deviceText_;
|
||||
CachedText statusMsgText_;
|
||||
CachedText footerText_;
|
||||
CachedText volumeLabelText_;
|
||||
CachedText volumePercentText_;
|
||||
std::vector<CachedText> menuRows_;
|
||||
|
||||
CachedText modalTitleText_;
|
||||
|
||||
Reference in New Issue
Block a user