12#include <imgui_stdlib.h>
19using namespace std::literals;
23 , symbolManager(manager.getReactor().getSymbolManager())
30 for (
const auto& watch : watches) {
31 auto out =
makeTclList(watch.description, watch.exprStr, watch.format);
32 buf.appendf(
"watch=%s\n", out.getString().c_str());
45 }
else if (name ==
"watch"sv) {
52 watches.push_back(std::move(result));
61 ImGui::SetNextWindowSize(
gl::vec2{35, 15} * ImGui::GetFontSize(), ImGuiCond_FirstUseEver);
63 const auto& style = ImGui::GetStyle();
64 auto width = style.ItemSpacing.x + 2.0f * style.FramePadding.x +
ImGui::CalcTextSize(
"Examples").x;
66 int flags = ImGuiTableFlags_Resizable
67 | ImGuiTableFlags_Reorderable
68 | ImGuiTableFlags_Hideable
69 | ImGuiTableFlags_Sortable
70 | ImGuiTableFlags_RowBg
71 | ImGuiTableFlags_BordersV
72 | ImGuiTableFlags_BordersOuter
73 | ImGuiTableFlags_SizingStretchProp
74 | ImGuiTableFlags_SortTristate
75 | ImGuiTableFlags_ScrollY;
77 ImGui::TableSetupScrollFreeze(0, 1);
78 ImGui::TableSetupColumn(
"description");
79 ImGui::TableSetupColumn(
"expression");
80 ImGui::TableSetupColumn(
"format");
81 ImGui::TableSetupColumn(
"result", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_NoHide);
82 ImGui::TableHeadersRow();
92 if (ImGui::Button(
"Add")) {
93 selectedRow = narrow<int>(watches.size());
94 watches.emplace_back();
96 im::Disabled(selectedRow < 0 || selectedRow >= narrow<int>(watches.size()), [&]{
97 if (ImGui::Button(
"Remove")) {
98 watches.erase(watches.begin() + selectedRow);
99 if (selectedRow == narrow<int>(watches.size())) {
104 ImGui::Dummy({0, 20});
105 if (ImGui::SmallButton(
"Examples")) {
106 watches.emplace_back(
107 "peek at fixed address",
110 watches.emplace_back(
111 "VDP command executing",
112 "[debug read \"VDP status regs\" 2] & 1",
114 watches.emplace_back(
115 "PSG enable-channel status",
116 "[debug read \"PSG regs\" 7]",
118 watches.emplace_back(
119 "The following 2 require an appropriate symbol file",
122 watches.emplace_back(
123 "value of 'myLabel'",
126 watches.emplace_back(
127 "peek at symbolic address",
128 "[peek16 $sym(numItems)]",
131 ImGui::Dummy({0, 0});
132 HelpMarker(R
"(The given (Tcl) expressions are continuously evaluated and displayed in a nicely formatted way.
133Press the 'Examples' button to see some examples.
136* description: optional description for the expression
137* expression: the actual Tcl expression, see below
138* format: optional format specifier, see below
139* result: this shows the result of evaluating 'expression'
141Add a new entry via the 'Add' button, then fill in the appropriate fields.
142To remove an entry, first select a row (e.g. click on the corresponding 'result' cell), then press the 'Remove' button.
144You can sort the table by clicking the column headers.
145You can reorder the columns by dragging the column headers.
146You can hide columns via the right-click context menu on a column header. For example, once configured, you may want to hide the 'expression' and 'format' columns.
148The expression can be any Tcl expression, some examples:
149* [peek 0x1234]: monitor a byte at a specific address
150* [reg SP] < 0xe000: check that stack hasn't grown too large
151 (below address 0xe000)
152If you have debug-symbols loaded (via the 'Symbol manager'), you can use them like:
153* [peek16 $sym(mySymbol)]: monitor 16-bit value at 'mySymbol'
154There's a shorthand notation to peek 8-bit values:
155* <integer> -> [peek <integer>]
156* <symbol> -> [peek $sym(<symbol>)]
158In the format column you can optionally enter a format-specifier (for the Tcl 'format' command). Some examples:
159* 0x%04x: 4-digit hex with leading zeros and '0x' prefix
160* %08b: 8-bit binary value
161* %d items: decimal value followed by the string " items"
167static void tooWideToolTip(
float available,
zstring_view str)
169 if (str.
empty())
return;
171 width += 2.0f * ImGui::GetStyle().FramePadding.x;
172 if (width >= available) {
177void ImGuiWatchExpr::refreshSymbols()
180 for (
auto& watch : watches) {
181 watch.expression.reset();
185ImGuiWatchExpr::EvalResult ImGuiWatchExpr::evalExpr(WatchExpr& watch,
Interpreter& interp)
const
188 if (watch.exprStr.empty())
return r;
190 if (!watch.expression) {
191 if (
auto addr = symbolManager.parseSymbolOrValue(watch.exprStr)) {
196 watch.expression = watch.exprStr;
199 assert(watch.expression);
202 r.result = watch.expression->eval(interp);
203 }
catch (CommandException& e) {
204 r.error =
e.getMessage();
209void ImGuiWatchExpr::drawRow(
int row)
211 auto& interp = manager.getInterpreter();
212 auto& watch = watches[row];
215 auto [result, exprError_] = evalExpr(watch, interp);
216 const auto& exprError = exprError_;
217 bool validExpr = exprError.empty();
220 TclObject frmtResult = result;
221 std::string frmtError;
222 if (!watch.format.getString().empty()) {
223 auto frmtCmd =
makeTclList(
"format", watch.format, validExpr ? result : TclObject(
"0"));
226 }
catch (CommandException& e) {
227 frmtError =
e.getMessage();
230 bool validFrmt = frmtError.empty();
232 if (ImGui::TableNextColumn()) {
233 auto pos = ImGui::GetCursorPos();
234 const auto& style = ImGui::GetStyle();
235 float rowHeight = 2.0f * style.FramePadding.y;
237 if (ImGui::Selectable(
"##selection", selectedRow == row,
238 ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap,
239 {0.0f, rowHeight})) {
242 ImGui::SetCursorPos(pos);
244 auto avail = ImGui::GetContentRegionAvail().x;
245 ImGui::SetNextItemWidth(-FLT_MIN);
246 ImGui::InputText(
"##desc", &watch.description);
247 tooWideToolTip(avail, watch.description);
249 if (ImGui::TableNextColumn()) {
252 auto avail = ImGui::GetContentRegionAvail().x;
253 ImGui::SetNextItemWidth(-FLT_MIN);
254 if (ImGui::InputText(
"##expr", &watch.exprStr)) {
255 watch.expression.reset();
257 tooWideToolTip(avail, watch.exprStr);
260 if (ImGui::TableNextColumn()) {
263 auto avail = ImGui::GetContentRegionAvail().x;
264 ImGui::SetNextItemWidth(-FLT_MIN);
265 auto str = std::string(watch.format.getString());
266 if (ImGui::InputText(
"##format", &str)) {
270 tooWideToolTip(avail, str);
276 if (ImGui::TableNextColumn()) {
278 auto avail = ImGui::GetContentRegionAvail().x;
280 const auto& str = frmtResult.getString();
282 tooWideToolTip(avail, str);
286 tooWideToolTip(avail, exprError);
292void ImGuiWatchExpr::checkSort()
294 auto* sortSpecs = ImGui::TableGetSortSpecs();
295 if (!sortSpecs->SpecsDirty)
return;
297 sortSpecs->SpecsDirty =
false;
298 if (sortSpecs->SpecsCount == 0)
return;
299 assert(sortSpecs->SpecsCount == 1);
300 assert(sortSpecs->Specs);
301 assert(sortSpecs->Specs->SortOrder == 0);
303 switch (sortSpecs->Specs->ColumnIndex) {
308 sortUpDown_String(watches, sortSpecs, [](
const auto& item) {
return item.exprStr; });
311 sortUpDown_String(watches, sortSpecs, [](
const auto& item) {
return item.format.getString(); });
void save(ImGuiTextBuffer &buf) override
ImGuiWatchExpr(ImGuiManager &manager)
void loadStart() override
void loadLine(std::string_view name, zstring_view value) override
void paint(MSXMotherBoard *motherBoard) override
TclObject executeCommand(Interpreter &interp, bool compile=false)
Interpret this TclObject as a command and execute it.
TclObject getListIndexUnchecked(unsigned index) const
zstring_view getString() const
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
constexpr auto empty() const
auto CalcTextSize(std::string_view str)
void TextUnformatted(const std::string &str)
void Table(const char *str_id, int column, ImGuiTableFlags flags, const ImVec2 &outer_size, float inner_width, std::invocable<> auto next)
void Window(const char *name, bool *p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
void StyleColor(bool active, Args &&...args)
void Child(const char *str_id, const ImVec2 &size, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags, std::invocable<> auto next)
void Disabled(bool b, std::invocable<> auto next)
void Group(std::invocable<> auto next)
void ID_for_range(std::integral auto count, std::invocable< int > auto next)
This file implemented 3 utility functions:
bool loadOnePersistent(std::string_view name, zstring_view value, C &c, const std::tuple< Elements... > &tup)
void sortUpDown_String(Range &range, const ImGuiTableSortSpecs *sortSpecs, Projection proj)
void simpleToolTip(std::string_view desc)
void savePersistent(ImGuiTextBuffer &buf, C &c, const std::tuple< Elements... > &tup)
void HelpMarker(std::string_view desc)
ImU32 getColor(imColor col)
TclObject makeTclList(Args &&... args)
TemporaryString tmpStrCat(Ts &&... ts)