21#include "imgui_stdlib.h"
33using namespace std::literals;
35static constexpr int MidColsCount = 8;
36static constexpr auto HighlightColor = IM_COL32(255, 255, 255, 50);
40 , symbolManager(manager.getReactor().getSymbolManager())
41 , title(
std::move(debuggableName_))
43 debuggableNameSize = title.size();
57 parseSearchString(searchString);
65DebuggableEditor::Sizes DebuggableEditor::calcSizes(
unsigned memSize)
const
68 const auto& style = ImGui::GetStyle();
70 s.addrDigitsCount = 0;
71 for (
unsigned n = memSize - 1; n > 0; n >>= 4) {
75 s.lineHeight = ImGui::GetTextLineHeight();
77 s.hexCellWidth = truncf(s.glyphWidth * 2.5f);
78 s.spacingBetweenMidCols = truncf(s.hexCellWidth * 0.25f);
79 s.posHexStart = float(s.addrDigitsCount + 2) * s.glyphWidth;
80 auto posHexEnd = s.posHexStart + (s.hexCellWidth * float(columns));
81 s.posAsciiStart = s.posAsciiEnd = posHexEnd;
83 int numMacroColumns = (columns + MidColsCount - 1) / MidColsCount;
84 s.posAsciiStart = posHexEnd + s.glyphWidth + float(numMacroColumns) * s.spacingBetweenMidCols;
85 s.posAsciiEnd = s.posAsciiStart + float(columns) * s.glyphWidth;
87 s.windowWidth = s.posAsciiEnd + style.ScrollbarSize + style.WindowPadding.x * 2 + s.glyphWidth;
93 if (!
open || !motherBoard)
return;
96 if (!debuggable)
return;
100 unsigned memSize = debuggable->getSize();
101 columns = std::min(columns, narrow<int>(memSize));
102 auto s = calcSizes(memSize);
103 ImGui::SetNextWindowSize(ImVec2(s.windowWidth, s.windowWidth * 0.60f), ImGuiCond_FirstUseEver);
105 im::Window(title.c_str(), &
open, ImGuiWindowFlags_NoScrollbar, [&]{
106 if (ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) &&
107 ImGui::IsMouseReleased(ImGuiMouseButton_Right)) {
108 ImGui::OpenPopup(
"context");
110 drawContents(s, *debuggable, memSize);
114[[nodiscard]]
static unsigned DataTypeGetSize(ImGuiDataType dataType)
116 std::array<unsigned, ImGuiDataType_COUNT - 2> sizes = { 1, 1, 2, 2, 4, 4, 8, 8 };
117 assert(dataType >= 0 && dataType < (ImGuiDataType_COUNT - 2));
118 return sizes[dataType];
121[[nodiscard]]
static std::optional<int> parseHexDigit(
char c)
123 if (
'0' <= c && c <=
'9')
return c -
'0';
124 if (
'a' <= c && c <=
'f')
return c -
'a' + 10;
125 if (
'A' <= c && c <=
'F')
return c -
'A' + 10;
129[[nodiscard]]
static std::optional<uint8_t> parseDataValue(std::string_view str)
131 if (str.size() == 1) {
132 return parseHexDigit(str[0]);
133 }
else if (str.size() == 2) {
134 if (
auto digit0 = parseHexDigit(str[0])) {
135 if (
auto digit1 = parseHexDigit(str[1])) {
136 return 16 * *digit0 + *digit1;
151 if (str.empty())
return r;
161 r.
addr = TclObject(str).eval(interp).getInt(interp);
162 }
catch (CommandException& e) {
168[[nodiscard]]
static std::string formatData(uint8_t val)
170 return strCat(hex_string<2, HexCase::upper>(val));
173[[nodiscard]]
static char formatAsciiData(uint8_t val)
175 return (val < 32 || val >= 128) ?
'.' : char(val);
178[[nodiscard]] std::string DebuggableEditor::formatAddr(
const Sizes& s,
unsigned addr)
const
180 return strCat(hex_string<HexCase::upper>(
Digits{size_t(s.addrDigitsCount)}, addr));
182void DebuggableEditor::setStrings(
const Sizes& s, Debuggable& debuggable)
184 addrStr =
strCat(
"0x", formatAddr(s, currentAddr));
185 auto b = debuggable.read(currentAddr);
186 if (dataEditingActive == HEX ) dataInput = formatData(b);
187 if (dataEditingActive == ASCII) dataInput = std::string(1, formatAsciiData(b));
189bool DebuggableEditor::setAddr(
const Sizes& s, Debuggable& debuggable,
unsigned memSize,
unsigned addr)
191 addr = std::min(addr, memSize - 1);
192 if (currentAddr == addr)
return false;
194 setStrings(s, debuggable);
197void DebuggableEditor::scrollAddr(
const Sizes& s, Debuggable& debuggable,
unsigned memSize,
unsigned addr,
bool forceScroll)
199 if (setAddr(s, debuggable, memSize, addr) || forceScroll) {
201 int row = narrow<int>(currentAddr) / columns;
202 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y +
float(row) * ImGui::GetTextLineHeight());
207void DebuggableEditor::drawContents(
const Sizes& s, Debuggable& debuggable,
unsigned memSize)
209 const auto& style = ImGui::GetStyle();
212 scrollAddr(s, debuggable, memSize, currentAddr,
true);
215 setAddr(s, debuggable, memSize, currentAddr);
218 float footerHeight = 0.0f;
220 footerHeight += style.ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
223 footerHeight += style.ItemSpacing.y + 2 * ImGui::GetFrameHeightWithSpacing();
225 if (showDataPreview) {
226 footerHeight += style.ItemSpacing.y + ImGui::GetFrameHeightWithSpacing() + 3 * ImGui::GetTextLineHeightWithSpacing();
230 int cFlags = ImGuiWindowFlags_NoMove;
235 cFlags |= ImGuiWindowFlags_HorizontalScrollbar;
236 ImGui::BeginChild(
"##scrolling", ImVec2(0, -footerHeight), ImGuiChildFlags_None, cFlags);
237 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
238 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
240 std::optional<unsigned> nextAddr;
242 if (addrMode == CURSOR) {
243 const auto& shortcuts = manager.getShortcuts();
244 if ((
int(currentAddr) >= columns) &&
245 shortcuts.checkShortcut({.keyChord = ImGuiKey_UpArrow, .repeat = true})) {
246 nextAddr = currentAddr - columns;
248 if ((
int(currentAddr) <
int(memSize - columns)) &&
249 shortcuts.checkShortcut({.keyChord = ImGuiKey_DownArrow, .repeat = true})) {
250 nextAddr = currentAddr + columns;
252 if ((
int(currentAddr) > 0) &&
253 shortcuts.checkShortcut({.keyChord = ImGuiKey_LeftArrow, .repeat = true})) {
254 nextAddr = currentAddr - 1;
256 if ((
int(currentAddr) <
int(memSize - 1)) &&
257 shortcuts.checkShortcut({.keyChord = ImGuiKey_RightArrow, .repeat = true})) {
258 nextAddr = currentAddr + 1;
263 auto* drawList = ImGui::GetWindowDrawList();
264 ImVec2 windowPos = ImGui::GetWindowPos();
266 drawList->AddLine(ImVec2(windowPos.x + s.posAsciiStart - s.glyphWidth, windowPos.y),
267 ImVec2(windowPos.x + s.posAsciiStart - s.glyphWidth, windowPos.y + 9999),
268 ImGui::GetColorU32(ImGuiCol_Border));
271 auto handleInput = [&](
unsigned addr,
int width,
auto formatData,
auto parseData,
int extraFlags = 0) {
273 if (dataEditingTakeFocus) {
274 ImGui::SetKeyboardFocusHere();
275 setStrings(s, debuggable);
279 static int Callback(ImGuiInputTextCallbackData* data) {
280 auto* userData =
static_cast<UserData*
>(data->UserData);
281 if (!data->HasSelection()) {
282 userData->cursorPos = data->CursorPos;
284 if (data->SelectionStart == 0 && data->SelectionEnd == data->BufTextLen) {
287 data->DeleteChars(0, data->BufTextLen);
288 userData->format(data);
291 data->SelectionStart = 0;
296 std::function<void(ImGuiInputTextCallbackData* data)>
format;
300 userData.format = formatData;
301 ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue
302 | ImGuiInputTextFlags_AutoSelectAll
303 | ImGuiInputTextFlags_NoHorizontalScroll
304 | ImGuiInputTextFlags_CallbackAlways
305 | ImGuiInputTextFlags_AlwaysOverwrite
307 ImGui::SetNextItemWidth(s.glyphWidth *
float(width));
308 bool dataWrite =
false;
310 if (ImGui::InputText(
"##data", &dataInput, flags, UserData::Callback, &userData)) {
312 }
else if (!ImGui::IsItemActive()) {
313 setStrings(s, debuggable);
316 dataEditingTakeFocus =
false;
317 dataWrite |= userData.cursorPos >= width;
318 if (nextAddr) dataWrite =
false;
320 if (
auto value = parseData(dataInput)) {
321 debuggable.write(addr, *value);
323 nextAddr = currentAddr + 1;
328 const auto totalLineCount = int((memSize + columns - 1) / columns);
330 auto addr = unsigned(line) * columns;
331 ImGui::StrCat(formatAddr(s, addr),
':');
333 auto previewDataTypeSize = DataTypeGetSize(previewDataType);
334 auto inside = [](unsigned a, unsigned start, unsigned size) {
335 return (start <= a) && (a < (start + size));
337 auto highLightDataPreview = [&](
unsigned a) {
338 return inside(a, currentAddr, previewDataTypeSize);
340 auto highLightSearch = [&](
unsigned a) {
341 if (!searchPattern)
return false;
342 auto len = narrow<unsigned>(searchPattern->size());
343 if (searchHighlight ==
static_cast<int>(SearchHighlight::SINGLE)) {
345 return inside(a, *searchResult, len);
347 }
else if (searchHighlight ==
static_cast<int>(SearchHighlight::ALL)) {
348 int start = std::max(0,
int(a - len + 1));
349 for (
unsigned i = start; i <= a; ++i) {
350 if (
match(debuggable, memSize, i))
return true;
355 auto highLight = [&](
unsigned a) {
356 return highLightDataPreview(a) || highLightSearch(a);
360 for (
int n = 0; n < columns && addr < memSize; ++n, ++addr) {
361 int macroColumn = n / MidColsCount;
362 float bytePosX = s.posHexStart + float(n) * s.hexCellWidth
363 + float(macroColumn) * s.spacingBetweenMidCols;
364 ImGui::SameLine(bytePosX);
367 if (highLight(addr)) {
368 ImVec2 pos = ImGui::GetCursorScreenPos();
369 float highlightWidth = s.glyphWidth * 2;
370 if (highLight(addr + 1)) {
371 highlightWidth = s.hexCellWidth;
372 if (n > 0 && (n + 1) < columns && ((n + 1) % MidColsCount) == 0) {
373 highlightWidth += s.spacingBetweenMidCols;
376 drawList->AddRectFilled(pos, ImVec2(pos.x + highlightWidth, pos.y + s.lineHeight), HighlightColor);
379 if (currentAddr == addr && (dataEditingActive == HEX)) {
381 [&](ImGuiInputTextCallbackData* data) {
382 auto valStr = formatData(debuggable.read(addr));
383 data->InsertChars(0, valStr.data(), valStr.data() + valStr.size());
384 data->SelectionEnd = 2;
386 [&](std::string_view data) {
387 return parseDataValue(data);
389 ImGuiInputTextFlags_CharsHexadecimal);
391 uint8_t b = debuggable.read(addr);
395 if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0)) {
396 dataEditingActive = HEX;
397 dataEditingTakeFocus =
true;
405 ImGui::SameLine(s.posAsciiStart);
406 gl::vec2 pos = ImGui::GetCursorPos();
407 gl::vec2 scrnPos = ImGui::GetCursorScreenPos();
408 addr = unsigned(line) * columns;
413 if (ImGui::InvisibleButton(
"ascii", ImVec2(s.posAsciiEnd - s.posAsciiStart, s.lineHeight))) {
414 dataEditingActive = ASCII;
415 dataEditingTakeFocus = true;
416 nextAddr = addr + unsigned((ImGui::GetIO().MousePos.x - scrnPos.x) / s.glyphWidth);
420 for (
int n = 0; n < columns && addr < memSize; ++n, ++addr) {
421 if (highLight(addr)) {
422 auto start = scrnPos +
gl::vec2(
float(n) * s.glyphWidth, 0.0f);
423 drawList->AddRectFilled(start, start +
gl::vec2(s.glyphWidth, s.lineHeight), ImGui::GetColorU32(HighlightColor));
426 ImGui::SetCursorPos(pos);
427 if (currentAddr == addr && (dataEditingActive == ASCII)) {
429 [&](ImGuiInputTextCallbackData* data) {
430 char valChar = formatAsciiData(debuggable.read(addr));
431 data->InsertChars(0, &valChar, &valChar + 1);
432 data->SelectionEnd = 1;
434 [&](std::string_view data) -> std::optional<uint8_t> {
435 if (data.empty())
return {};
437 if (b < 32 || b >= 128)
return {};
441 uint8_t c = debuggable.read(addr);
442 char display = formatAsciiData(c);
447 pos.x += s.glyphWidth;
451 ImGui::PopStyleVar(2);
455 setAddr(s, debuggable, memSize, *nextAddr);
456 dataEditingTakeFocus =
true;
461 bool forceScroll = ImGui::IsWindowAppearing();
464 ImGui::AlignTextToFramePadding();
467 ImGui::SetNextItemWidth(2.0f * style.FramePadding.x +
ImGui::CalcTextSize(
"Expression").x + ImGui::GetFrameHeight());
468 if (ImGui::Combo(
"##mode", &addrMode,
"Cursor\0Expression\0Link BC\0Link DE\0Link HL\0")) {
469 dataEditingTakeFocus =
true;
472 static constexpr std::array linkExpr = {
473 "[reg bc]",
"[reg de]",
"[reg hl]"
475 addrExpr = linkExpr[addrMode - 2];
476 addrMode = EXPRESSION;
481 std::string* as = addrMode == CURSOR ? &addrStr : &addrExpr;
482 auto r = parseAddressExpr(*as, symbolManager, manager.getInterpreter());
484 if (addrMode == EXPRESSION && r.
error.empty()) {
485 scrollAddr(s, debuggable, memSize, r.addr, forceScroll);
487 if (manager.getShortcuts().checkShortcut(Shortcuts::ID::HEX_GOTO_ADDR)) {
488 ImGui::SetKeyboardFocusHere();
490 ImGui::SetNextItemWidth(15.0f * ImGui::GetFontSize());
491 if (ImGui::InputText(
"##addr", as, ImGuiInputTextFlags_EnterReturnsTrue)) {
492 auto r2 = parseAddressExpr(addrStr, symbolManager, manager.getInterpreter());
493 if (r2.error.empty()) {
494 scrollAddr(s, debuggable, memSize, r2.addr, forceScroll);
495 dataEditingTakeFocus =
true;
504 HelpMarker(
"Address-mode:\n"
505 " Cursor: view the cursor position\n"
506 " Expression: continuously re-evaluate an expression and view that address\n"
508 "Addresses can be entered as:\n"
509 " Decimal or hexadecimal values (e.g. 0x1234)\n"
510 " A calculation like 0x1234 + 7*22\n"
511 " The name of a label (e.g. CHPUT)\n"
512 " A Tcl expression (e.g. [reg hl] to follow the content of register HL)\n"
514 "Right-click to configure this view.");
519 drawSearch(s, debuggable, memSize);
521 if (showDataPreview) {
523 drawPreviewLine(s, debuggable, memSize);
527 ImGui::SetNextItemWidth(7.5f * s.glyphWidth + 2.0f * style.FramePadding.x);
528 if (ImGui::InputInt(
"Columns", &columns, 1, 0)) {
529 columns = std::clamp(columns, 1, MAX_COLUMNS);
531 ImGui::Checkbox(
"Show Address bar", &showAddress);
532 ImGui::Checkbox(
"Show Search pane", &showSearch);
533 ImGui::Checkbox(
"Show Data Preview", &showDataPreview);
534 ImGui::Checkbox(
"Show Ascii", &showAscii);
535 ImGui::Checkbox(
"Grey out zeroes", &greyOutZeroes);
542[[nodiscard]]
static const char* DataTypeGetDesc(ImGuiDataType dataType)
544 std::array<
const char*, ImGuiDataType_COUNT - 2> desc = {
545 "Int8",
"Uint8",
"Int16",
"Uint16",
"Int32",
"Uint32",
"Int64",
"Uint64"
547 assert(dataType >= 0 && dataType < (ImGuiDataType_COUNT - 2));
548 return desc[dataType];
552[[nodiscard]]
static T read(std::span<const uint8_t> buf)
554 assert(buf.size() >=
sizeof(T));
556 memcpy(&
t, buf.data(),
sizeof(T));
560static void formatDec(std::span<const uint8_t> buf, ImGuiDataType dataType)
563 case ImGuiDataType_S8:
566 case ImGuiDataType_U8:
569 case ImGuiDataType_S16:
572 case ImGuiDataType_U16:
575 case ImGuiDataType_S32:
578 case ImGuiDataType_U32:
581 case ImGuiDataType_S64:
584 case ImGuiDataType_U64:
592static void formatHex(std::span<const uint8_t> buf, ImGuiDataType data_type)
595 case ImGuiDataType_S8:
596 case ImGuiDataType_U8:
599 case ImGuiDataType_S16:
600 case ImGuiDataType_U16:
603 case ImGuiDataType_S32:
604 case ImGuiDataType_U32:
607 case ImGuiDataType_S64:
608 case ImGuiDataType_U64:
616static void formatBin(std::span<const uint8_t> buf)
618 for (
int i =
int(buf.size()) - 1; i >= 0; --i) {
620 if (i != 0) ImGui::SameLine();
624void DebuggableEditor::parseSearchString(std::string_view str)
626 searchPattern.reset();
627 searchResult.reset();
628 std::vector<uint8_t> result;
630 if (searchType ==
static_cast<int>(SearchType::ASCII)) {
631 const auto*
begin = std::bit_cast<const uint8_t*>(str.data());
632 const auto*
end =
begin + str.size();
635 assert(searchType ==
static_cast<int>(SearchType::HEX));
636 std::optional<int> partial;
638 if (c ==
' ')
continue;
639 auto digit = parseHexDigit(c);
642 result.push_back(narrow<uint8_t>(16 * *partial + *digit));
651 searchPattern = std::move(result);
654void DebuggableEditor::drawSearch(
const Sizes& s, Debuggable& debuggable,
unsigned memSize)
656 const auto& style = ImGui::GetStyle();
658 bool doSearch =
false;
660 ImGui::SetNextItemWidth(-(buttonSize + style.WindowPadding.x));
662 auto callback = [](ImGuiInputTextCallbackData* data) {
663 if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit) {
664 auto& self = *
static_cast<DebuggableEditor*
>(data->UserData);
665 self.parseSearchString(std::string_view(data->Buf, data->BufTextLen));
669 ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue
670 | ImGuiInputTextFlags_CallbackEdit;
671 if (ImGui::InputText(
"##search_string", &searchString, flags, callback,
this)) {
677 doSearch |= ImGui::Button(
"Search");
679 if (!searchPattern) {
680 simpleToolTip(
"Must be an even number of hex digits, optionally separated by spaces");
682 if (searchPattern && doSearch) {
683 search(s, debuggable, memSize);
686 auto arrowSize = ImGui::GetFrameHeight();
687 auto extra = arrowSize + 2.0f * style.FramePadding.x;
688 ImGui::AlignTextToFramePadding();
692 if (ImGui::Combo(
"##search_type", &searchType,
"Hex\0Ascii\0\0")) {
693 parseSearchString(searchString);
696 ImGui::SameLine(0.0f, 2 * ImGui::GetFontSize());
700 ImGui::Combo(
"##search_direction", &searchDirection,
"Forwards\0Backwards\0\0");
702 ImGui::SameLine(0.0f, 2 * ImGui::GetFontSize());
706 ImGui::Combo(
"##search_highlight", &searchHighlight,
"None\0Single\0All\0\0");
709bool DebuggableEditor::match(Debuggable& debuggable,
unsigned memSize,
unsigned addr)
711 assert(searchPattern);
712 if ((addr + searchPattern->size()) > memSize)
return false;
713 for (
auto [i, c] :
enumerate(*searchPattern)) {
714 if (debuggable.read(narrow<unsigned>(addr + i)) != c)
return false;
719void DebuggableEditor::search(
const Sizes& s, Debuggable& debuggable,
unsigned memSize)
721 std::optional<unsigned> found;
722 auto test = [&](
unsigned addr) {
723 if (
match(debuggable, memSize, addr)) {
729 if (searchDirection ==
static_cast<int>(SearchDirection::FWD)) {
730 for (
unsigned addr = currentAddr + 1; addr < memSize; ++addr) {
731 if (
test(addr))
break;
734 for (
unsigned addr = 0; addr <= currentAddr; ++addr) {
735 if (
test(addr))
break;
739 for (
int addr = currentAddr - 1; addr > 0; --addr) {
740 if (
test(
unsigned(addr)))
break;
743 for (
int addr = memSize - 1; addr >= int(currentAddr); --addr) {
744 if (
test(
unsigned(addr)))
break;
749 searchResult = *found;
750 scrollAddr(s, debuggable, memSize, *found,
false);
751 dataEditingTakeFocus =
true;
754 searchResult.reset();
755 ImGui::OpenPopup(
"NotFound");
759void DebuggableEditor::drawPreviewLine(
const Sizes& s, Debuggable& debuggable,
unsigned memSize)
761 const auto& style = ImGui::GetStyle();
762 ImGui::AlignTextToFramePadding();
765 ImGui::SetNextItemWidth((s.glyphWidth * 10.0f) + style.FramePadding.x * 2.0f + style.ItemInnerSpacing.x);
766 if (ImGui::BeginCombo(
"##combo_type", DataTypeGetDesc(previewDataType), ImGuiComboFlags_HeightLargest)) {
767 for (ImGuiDataType n = 0; n < (ImGuiDataType_COUNT - 2); ++n) {
768 if (ImGui::Selectable(DataTypeGetDesc(n), previewDataType == n)) {
775 ImGui::SetNextItemWidth((s.glyphWidth * 6.0f) + style.FramePadding.x * 2.0f + style.ItemInnerSpacing.x);
776 ImGui::Combo(
"##combo_endianess", &previewEndianess,
"LE\0BE\0\0");
778 std::array<uint8_t, 8> dataBuf = {};
779 auto elemSize = DataTypeGetSize(previewDataType);
780 for (
auto i :
xrange(elemSize)) {
781 auto addr = currentAddr + i;
782 dataBuf[i] = (addr < memSize) ? debuggable.read(addr) : 0;
785 static constexpr bool nativeIsLittle = std::endian::native == std::endian::little;
786 if (
bool previewIsLittle = previewEndianess == LE;
787 nativeIsLittle != previewIsLittle) {
788 std::reverse(dataBuf.begin(), dataBuf.begin() + elemSize);
793 formatDec(dataBuf, previewDataType);
797 formatHex(dataBuf, previewDataType);
801 formatBin(
subspan(dataBuf, 0, elemSize));
void test(const IterableBitSet< N > &s, std::initializer_list< size_t > list)
void paint(MSXMotherBoard *motherBoard) override
DebuggableEditor(ImGuiManager &manager_, std::string debuggableName, size_t index)
std::string_view getDebuggableName() const
void loadLine(std::string_view name, zstring_view value) override
void save(ImGuiTextBuffer &buf) override
Debuggable * findDebuggable(std::string_view name)
std::optional< uint16_t > parseSymbolOrValue(std::string_view s) const
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
auto CalcTextSize(std::string_view str)
void TextUnformatted(const std::string &str)
void Window(const char *name, bool *p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
void ID(const char *str_id, 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 Font(ImFont *font, std::invocable<> auto next)
void ListClipper(size_t count, int forceIndex, float lineHeight, std::invocable< int > auto next)
void Popup(const char *str_id, ImGuiWindowFlags flags, std::invocable<> auto next)
void format(SectorAccessibleDisk &disk, MSXBootSectorType bootType)
Format the given disk (= a single partition).
This file implemented 3 utility functions:
bool loadOnePersistent(std::string_view name, zstring_view value, C &c, const std::tuple< Elements... > &tup)
void simpleToolTip(std::string_view desc)
void savePersistent(ImGuiTextBuffer &buf, C &c, const std::tuple< Elements... > &tup)
std::optional< bool > match(const BooleanInput &binding, const Event &event, function_ref< int(JoystickId)> getJoyDeadZone)
ImU32 getColor(imColor col)
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
void strAppend(std::string &result, Ts &&...ts)
constexpr auto xrange(T e)
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)