openMSX
ImGuiSoundChip.cc
Go to the documentation of this file.
1#include "ImGuiSoundChip.hh"
2
3#include "ImGuiCpp.hh"
4#include "ImGuiManager.hh"
5#include "ImGuiUtils.hh"
6
7#include "MSXMixer.hh"
8#include "MSXMotherBoard.hh"
9#include "SoundDevice.hh"
10#include "StringSetting.hh"
11
12#include <imgui.h>
13
14using namespace std::literals;
15
16
17namespace openmsx {
18
19void ImGuiSoundChip::save(ImGuiTextBuffer& buf)
20{
22 for (const auto& [name, enabled] : channels) {
23 buf.appendf("showChannels.%s=%d\n", name.c_str(), enabled);
24 }
25}
26
27void ImGuiSoundChip::loadLine(std::string_view name, zstring_view value)
28{
29 if (loadOnePersistent(name, value, *this, persistentElements)) {
30 // already handled
31 } else if (name.starts_with("showChannels.")) {
32 channels[std::string(name.substr(13))] = StringOp::stringToBool(value);
33 }
34}
35
37{
38 if (!motherBoard) return;
40 showChipSettings(*motherBoard);
41 }
42
43 // Show sound chip channel settings
44 const auto& msxMixer = motherBoard->getMSXMixer();
45 auto& infos = msxMixer.getDeviceInfos();
46 for (const auto& info : infos) {
47 const auto& name = info.device->getName();
48 auto [it, inserted] = channels.try_emplace(name, false);
49 auto& enabled = it->second;
50 if (enabled) {
51 showChannelSettings(*motherBoard, name, &enabled);
52 }
53 }
54}
55
56[[nodiscard]] static bool anySpecialChannelSettings(const MSXMixer::SoundDeviceInfo& info)
57{
58 return ranges::any_of(info.channelSettings, [&](const auto& channel) {
59 return channel.mute->getBoolean() || !channel.record->getString().empty();
60 });
61}
62
63void ImGuiSoundChip::showChipSettings(MSXMotherBoard& motherBoard)
64{
65 auto restoreDefaultPopup = [](const char* label, Setting& setting) {
67 if (ImGui::Button(label)) {
68 setting.setValue(setting.getDefaultValue());
69 ImGui::CloseCurrentPopup();
70 }
71 });
72 };
73
74 im::Window("Sound chip settings", &showSoundChipSettings, [&]{
75 const auto& msxMixer = motherBoard.getMSXMixer();
76 auto& infos = msxMixer.getDeviceInfos(); // TODO sort on name
77 im::Table("table", narrow<int>(infos.size()), ImGuiTableFlags_ScrollX, [&]{
78 for (auto& info : infos) {
79 if (ImGui::TableNextColumn()) {
80 const auto& device = *info.device;
81 ImGui::TextUnformatted(device.getName());
82 simpleToolTip(device.getDescription());
83 }
84 }
85 for (auto& info : infos) {
86 if (ImGui::TableNextColumn()) {
87 auto& volumeSetting = *info.volumeSetting;
88 int volume = volumeSetting.getInt();
89 int min = volumeSetting.getMinValue();
90 int max = volumeSetting.getMaxValue();
91 ImGui::TextUnformatted("volume"sv);
92 std::string id = "##volume-" + info.device->getName();
93 if (ImGui::VSliderInt(id.c_str(), ImVec2(18, 120), &volume, min, max)) {
94 volumeSetting.setInt(volume);
95 }
96 restoreDefaultPopup("Set default", volumeSetting);
97 }
98 }
99 for (auto& info : infos) {
100 if (ImGui::TableNextColumn()) {
101 auto& balanceSetting = *info.balanceSetting;
102 int balance = balanceSetting.getInt();
103 int min = balanceSetting.getMinValue();
104 int max = balanceSetting.getMaxValue();
105 ImGui::TextUnformatted("balance"sv);
106 std::string id = "##balance-" + info.device->getName();
107 if (ImGui::SliderInt(id.c_str(), &balance, min, max)) {
108 balanceSetting.setInt(balance);
109 }
110 restoreDefaultPopup("Set center", balanceSetting);
111 }
112 }
113 for (auto& info : infos) {
114 if (ImGui::TableNextColumn()) {
115 bool special = anySpecialChannelSettings(info);
116 if (special) {
117 ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, getColor(imColor::YELLOW));
118 }
119 im::StyleColor(special, ImGuiCol_Text, getColor(imColor::BLACK), []{
120 ImGui::TextUnformatted("channels"sv);
121 });
122 const auto& name = info.device->getName();
123 std::string id = "##channels-" + name;
124 auto [it, inserted] = channels.try_emplace(name, false);
125 auto& enabled = it->second;
126 ImGui::Checkbox(id.c_str(), &enabled);
127 }
128 }
129 });
130 });
131}
132
133void ImGuiSoundChip::showChannelSettings(MSXMotherBoard& motherBoard, const std::string& name, bool* enabled)
134{
135 const auto& msxMixer = motherBoard.getMSXMixer();
136 auto* info = msxMixer.findDeviceInfo(name);
137 if (!info) return;
138
139 std::string label = name + " channel settings";
140 ImGui::SetNextWindowSize(gl::vec2{40, 0} * ImGui::GetFontSize(), ImGuiCond_FirstUseEver);
141 im::Window(label.c_str(), enabled, [&]{
142 const auto& hotKey = manager.getReactor().getHotKey();
143 int flags = ImGuiTableFlags_ScrollY |
144 ImGuiTableFlags_RowBg |
145 ImGuiTableFlags_SizingStretchProp;
146 im::Table("table", 3, flags, [&]{
147 ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
148 ImGui::TableSetupColumn("ch.", ImGuiTableColumnFlags_WidthFixed);
149 ImGui::TableSetupColumn("mute", ImGuiTableColumnFlags_WidthFixed);
150 ImGui::TableSetupColumn("file to record to", ImGuiTableColumnFlags_WidthStretch);
151 ImGui::TableHeadersRow();
152 im::ID_for_range(info->channelSettings.size(), [&](int i) {
153 auto& channel = info->channelSettings[i];
154 if (ImGui::TableNextColumn()) {
155 ImGui::StrCat(i + 1);
156 }
157 if (ImGui::TableNextColumn()) {
158 Checkbox(hotKey, "##mute", *channel.mute);
159 }
160 if (ImGui::TableNextColumn()) {
161 // TODO: use a file browser (in "create mode")
162 ImGui::SetNextItemWidth(-FLT_MIN);
163 InputText("##rec", *channel.record);
164 }
165 });
166 });
167 });
168}
169
170} // namespace openmsx
BaseSetting * setting
void paint(MSXMotherBoard *motherBoard) override
static constexpr auto persistentElements
void save(ImGuiTextBuffer &buf) override
void loadLine(std::string_view name, zstring_view value) override
const auto & getDeviceInfos() const
Definition MSXMixer.hh:141
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
void TextUnformatted(const std::string &str)
Definition ImGuiUtils.hh:26
bool stringToBool(string_view str)
Definition StringOp.cc:16
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition gl_vec.hh:431
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition gl_vec.hh:449
void Table(const char *str_id, int column, ImGuiTableFlags flags, const ImVec2 &outer_size, float inner_width, std::invocable<> auto next)
Definition ImGuiCpp.hh:455
void Window(const char *name, bool *p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:63
void PopupContextItem(const char *str_id, ImGuiPopupFlags popup_flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:421
void StyleColor(bool active, Args &&...args)
Definition ImGuiCpp.hh:175
This file implemented 3 utility functions:
Definition Autofire.cc:11
bool loadOnePersistent(std::string_view name, zstring_view value, C &c, const std::tuple< Elements... > &tup)
void savePersistent(ImGuiTextBuffer &buf, C &c, const std::tuple< Elements... > &tup)
ImU32 getColor(imColor col)
constexpr bool any_of(InputRange &&range, UnaryPredicate pred)
Definition ranges.hh:200
dynarray< ChannelSettings > channelSettings
Definition MSXMixer.hh:51