From 77bb76e83b4d49f2f6f4f925f86c2ac6f0df278a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Sat, 11 Jul 2015 07:38:11 -0700 Subject: [PATCH] Updated imgui. --- 3rdparty/ocornut-imgui/imgui.cpp | 81 +++++----- 3rdparty/ocornut-imgui/imgui.h | 5 +- 3rdparty/ocornut-imgui/memory_editor.h | 210 +++++++++++++++++++++++++ 3 files changed, 260 insertions(+), 36 deletions(-) create mode 100644 3rdparty/ocornut-imgui/memory_editor.h diff --git a/3rdparty/ocornut-imgui/imgui.cpp b/3rdparty/ocornut-imgui/imgui.cpp index 32fe2b40c..cc645d039 100644 --- a/3rdparty/ocornut-imgui/imgui.cpp +++ b/3rdparty/ocornut-imgui/imgui.cpp @@ -136,6 +136,7 @@ Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix. Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. + - 2015/07/10 (1.43) - changed SameLine() parameters from int to float. - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount. - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence @@ -1289,7 +1290,7 @@ struct ImGuiState bool ActiveIdIsJustActivated; // Set at the time of activation for one frame bool ActiveIdIsFocusedOnly; // Set only by active widget. Denote focus but no active interaction ImGuiWindow* ActiveIdWindow; - ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Only valid if ActiveID is the "#MOVE" identifier of a window. + ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Pointer is only valid if ActiveID is the "#MOVE" identifier of a window. float SettingsDirtyTimer; ImVector Settings; int DisableHideTextAfterDoubleHash; @@ -2400,13 +2401,14 @@ void ImGui::Render() ImGui::End(); // Click to focus window and start moving (after we're done with all our widgets) + if (!g.ActiveId) + g.MovedWindow = NULL; if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0]) { if (!(g.FocusedWindow && !g.FocusedWindow->WasActive && g.FocusedWindow->Active)) // Unless we just made a popup appear { if (g.HoveredRootWindow != NULL) { - IM_ASSERT(g.MovedWindow == NULL); g.MovedWindow = g.HoveredWindow; SetActiveId(g.HoveredRootWindow->MoveID, g.HoveredRootWindow); } @@ -6161,7 +6163,7 @@ static bool SliderFloatN(const char* label, float* v, int components, float v_mi { ImGui::PushID(i); value_changed |= ImGui::SliderFloat("##v", &v[i], v_min, v_max, display_format, power); - ImGui::SameLine(0, (int)g.Style.ItemInnerSpacing.x); + ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); ImGui::PopID(); ImGui::PopItemWidth(); } @@ -6203,7 +6205,7 @@ static bool SliderIntN(const char* label, int* v, int components, int v_min, int { ImGui::PushID(i); value_changed |= ImGui::SliderInt("##v", &v[i], v_min, v_max, display_format); - ImGui::SameLine(0, (int)g.Style.ItemInnerSpacing.x); + ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); ImGui::PopID(); ImGui::PopItemWidth(); } @@ -6387,7 +6389,7 @@ static bool DragFloatN(const char* label, float* v, int components, float v_spee { ImGui::PushID(i); value_changed |= ImGui::DragFloat("##v", &v[i], v_speed, v_min, v_max, display_format, power); - ImGui::SameLine(0, (int)g.Style.ItemInnerSpacing.x); + ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); ImGui::PopID(); ImGui::PopItemWidth(); } @@ -6427,10 +6429,10 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu bool value_changed = ImGui::DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format, power); ImGui::PopItemWidth(); - ImGui::SameLine(0, (int)g.Style.ItemInnerSpacing.x); + ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); value_changed |= ImGui::DragFloat("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? FLT_MAX : v_max, display_format_max ? display_format_max : display_format, power); ImGui::PopItemWidth(); - ImGui::SameLine(0, (int)g.Style.ItemInnerSpacing.x); + ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); ImGui::EndGroup(); @@ -6465,7 +6467,7 @@ static bool DragIntN(const char* label, int* v, int components, float v_speed, i { ImGui::PushID(i); value_changed |= ImGui::DragInt("##v", &v[i], v_speed, v_min, v_max, display_format); - ImGui::SameLine(0, (int)g.Style.ItemInnerSpacing.x); + ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); ImGui::PopID(); ImGui::PopItemWidth(); } @@ -6505,10 +6507,10 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ bool value_changed = ImGui::DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? IM_INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format); ImGui::PopItemWidth(); - ImGui::SameLine(0, (int)g.Style.ItemInnerSpacing.x); + ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); value_changed |= ImGui::DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? IM_INT_MAX : v_max, display_format_max ? display_format_max : display_format); ImGui::PopItemWidth(); - ImGui::SameLine(0, (int)g.Style.ItemInnerSpacing.x); + ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); ImGui::EndGroup(); @@ -6672,7 +6674,7 @@ bool ImGui::Checkbox(const char* label, bool* v) ImRect total_bb = check_bb; if (label_size.x > 0) - SameLine(0, (int)style.ItemInnerSpacing.x); + SameLine(0, style.ItemInnerSpacing.x); const ImRect text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + label_size); if (label_size.x > 0) { @@ -6730,7 +6732,7 @@ bool ImGui::RadioButton(const char* label, bool active) ImRect total_bb = check_bb; if (label_size.x > 0) - SameLine(0, (int)style.ItemInnerSpacing.x); + SameLine(0, style.ItemInnerSpacing.x); const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size); if (label_size.x > 0) { @@ -7121,6 +7123,8 @@ static bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 edit_state.StbState.select_start = ImMin(edit_state.StbState.select_start, edit_state.CurLenW); edit_state.StbState.select_end = ImMin(edit_state.StbState.select_end, edit_state.CurLenW); } + if (flags & ImGuiInputTextFlags_AlwaysInsertMode) + edit_state.StbState.insert_mode = true; if (!is_multiline && (focus_requested_by_tab || (user_clicked && is_ctrl_down))) select_all = true; } @@ -7420,11 +7424,18 @@ static bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (edit_state.CursorFollow) { // Horizontal scroll in chunks of quarter width - const float scroll_increment_x = size.x * 0.25f; - if (cursor_offset.x < edit_state.ScrollX) - edit_state.ScrollX = ImMax(0.0f, cursor_offset.x - scroll_increment_x); - else if (cursor_offset.x - size.x >= edit_state.ScrollX) - edit_state.ScrollX = cursor_offset.x - size.x + scroll_increment_x; + if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll)) + { + const float scroll_increment_x = size.x * 0.25f; + if (cursor_offset.x < edit_state.ScrollX) + edit_state.ScrollX = ImMax(0.0f, cursor_offset.x - scroll_increment_x); + else if (cursor_offset.x - size.x >= edit_state.ScrollX) + edit_state.ScrollX = cursor_offset.x - size.x + scroll_increment_x; + } + else + { + edit_state.ScrollX = 0.0f; + } // Vertical scroll if (is_multiline) @@ -7566,13 +7577,13 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, if (step > 0.0f) { ImGui::PopItemWidth(); - ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + ImGui::SameLine(0, style.ItemInnerSpacing.x); if (ButtonEx("-", button_sz, ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) { *v -= g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step; value_changed = true; } - ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + ImGui::SameLine(0, style.ItemInnerSpacing.x); if (ButtonEx("+", button_sz, ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) { *v += g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step; @@ -7583,7 +7594,7 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, if (label_size.x > 0) { - ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + ImGui::SameLine(0, style.ItemInnerSpacing.x); RenderText(ImVec2(window->DC.CursorPos.x, window->DC.CursorPos.y + style.FramePadding.y), label); ItemSize(label_size, style.FramePadding.y); } @@ -7616,7 +7627,7 @@ static bool InputFloatN(const char* label, float* v, int components, int decimal { ImGui::PushID(i); value_changed |= ImGui::InputFloat("##v", &v[i], 0, 0, decimal_precision, extra_flags); - ImGui::SameLine(0, (int)g.Style.ItemInnerSpacing.x); + ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); ImGui::PopID(); ImGui::PopItemWidth(); } @@ -7659,7 +7670,7 @@ static bool InputIntN(const char* label, int* v, int components, ImGuiInputTextF { ImGui::PushID(i); value_changed |= ImGui::InputInt("##v", &v[i], 0, 0, extra_flags); - ImGui::SameLine(0, (int)g.Style.ItemInnerSpacing.x); + ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); ImGui::PopID(); ImGui::PopItemWidth(); } @@ -8333,7 +8344,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) for (int n = 0; n < components; n++) { if (n > 0) - ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + ImGui::SameLine(0, style.ItemInnerSpacing.x); if (n + 1 == components) ImGui::PushItemWidth(w_item_last); value_changed |= ImGui::DragInt(ids[n], &i[n], 1.0f, 0, 255, fmt[n]); @@ -8368,7 +8379,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) break; } - ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + ImGui::SameLine(0, style.ItemInnerSpacing.x); const ImVec4 col_display(col[0], col[1], col[2], 1.0f); if (ImGui::ColorButton(col_display)) @@ -8376,7 +8387,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) if (window->DC.ColorEditMode == ImGuiColorEditMode_UserSelectShowButton) { - ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + ImGui::SameLine(0, style.ItemInnerSpacing.x); const char* button_titles[3] = { "RGB", "HSV", "HEX" }; if (ButtonEx(button_titles[edit_mode], ImVec2(0,0), ImGuiButtonFlags_DontClosePopups)) g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away! @@ -8384,7 +8395,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) } else { - ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + ImGui::SameLine(0, style.ItemInnerSpacing.x); } ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); @@ -8606,11 +8617,11 @@ void ImGui::EndGroup() } // Gets back to previous line and continue with horizontal layout -// column_x == 0 : follow on previous item -// columm_x != 0 : align to specified column +// pos_x == 0 : follow on previous item +// pos_x != 0 : align to specified column // spacing_w < 0 : use default spacing if column_x==0, no spacing if column_x!=0 // spacing_w >= 0 : enforce spacing -void ImGui::SameLine(int column_x, int spacing_w) +void ImGui::SameLine(float pos_x, float spacing_w) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -8618,16 +8629,16 @@ void ImGui::SameLine(int column_x, int spacing_w) return; float x, y; - if (column_x != 0) + if (pos_x != 0.0f) { - if (spacing_w < 0) spacing_w = 0; - x = window->Pos.x + (float)column_x + (float)spacing_w; + if (spacing_w < 0.0f) spacing_w = 0.0f; + x = window->Pos.x + pos_x + spacing_w; y = window->DC.CursorPosPrevLine.y; } else { - if (spacing_w < 0) spacing_w = (int)g.Style.ItemSpacing.x; - x = window->DC.CursorPosPrevLine.x + (float)spacing_w; + if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x; + x = window->DC.CursorPosPrevLine.x + spacing_w; y = window->DC.CursorPosPrevLine.y; } window->DC.CurrentLineHeight = window->DC.PrevLineHeight; @@ -11368,7 +11379,7 @@ void ImGui::ShowTestWindow(bool* opened) } } ImGui::PlotLines("##Graph", &values.front(), (int)values.Size, values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,80)); - ImGui::SameLine(0, (int)ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::BeginGroup(); ImGui::Text("Graph"); ImGui::Checkbox("pause", &pause); diff --git a/3rdparty/ocornut-imgui/imgui.h b/3rdparty/ocornut-imgui/imgui.h index 07efa0de4..b2bcb7104 100644 --- a/3rdparty/ocornut-imgui/imgui.h +++ b/3rdparty/ocornut-imgui/imgui.h @@ -170,7 +170,7 @@ namespace ImGui IMGUI_API void BeginGroup(); // once closing a group it is seen as a single item (so you can use IsItemHovered() on a group, SameLine() between groups, etc. IMGUI_API void EndGroup(); IMGUI_API void Separator(); // horizontal line - IMGUI_API void SameLine(int column_x = 0, int spacing_w = -1); // call between widgets or groups to layout them horizontally + IMGUI_API void SameLine(float pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally IMGUI_API void Spacing(); // add spacing IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing pixels @@ -461,6 +461,8 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, // Call user function to filter character. Modify data->EventChar to replace/filter input, or return 1 to discard character. ImGuiInputTextFlags_AllowTabInput = 1 << 10, // Pressing TAB input a '\t' character into the text field ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, allow exiting edition by pressing Enter. Ctrl+Enter to add new line (by default adds new lines with Enter). + ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally + ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13, // Insert mode // [Internal] ImGuiInputTextFlags_Multiline = 1 << 20 // For internal use by InputTextMultiline() }; @@ -920,6 +922,7 @@ struct ImGuiTextEditCallbackData // NB: calling those function loses selection. void DeleteChars(int pos, int bytes_count); void InsertChars(int pos, const char* text, const char* text_end = NULL); + bool HasSelection() const { return SelectionStart != SelectionEnd; } }; // ImColor() is just a helper that implicity converts to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float) diff --git a/3rdparty/ocornut-imgui/memory_editor.h b/3rdparty/ocornut-imgui/memory_editor.h new file mode 100644 index 000000000..540923571 --- /dev/null +++ b/3rdparty/ocornut-imgui/memory_editor.h @@ -0,0 +1,210 @@ +// Mini memory editor for ImGui (to embed in your game/tools) +// v0.10 +// +// You can adjust the keyboard repeat delay/rate in ImGuiIO. +// The code assume a mono-space font for simplicity! If you don't use the default font, use ImGui::PushFont()/PopFont() to switch to a mono-space font before caling this. +// +// Usage: +// static MemoryEditor memory_editor; // save your state somewhere +// memory_editor.Draw("Memory Editor", mem_block, mem_block_size, (size_t)mem_block); // run +// +// TODO: better resizing policy (ImGui doesn't have flexible window resizing constraints yet) + +struct MemoryEditor +{ + bool Open; + bool AllowEdits; + int Rows; + int DataEditingAddr; + bool DataEditingTakeFocus; + char DataInput[32]; + char AddrInput[32]; + + MemoryEditor() + { + Open = true; + Rows = 16; + DataEditingAddr = -1; + DataEditingTakeFocus = false; + strcpy(DataInput, ""); + strcpy(AddrInput, ""); + AllowEdits = true; + } + + void Draw(const char* title, unsigned char* mem_data, int mem_size, size_t base_display_addr = 0) + { + if (ImGui::Begin(title, &Open)) + { + ImGui::BeginChild("##scrolling", ImVec2(0, -ImGui::GetItemsLineHeightWithSpacing())); + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); + + int addr_digits_count = 0; + for (int n = base_display_addr + mem_size - 1; n > 0; n >>= 4) + addr_digits_count++; + + float glyph_width = ImGui::CalcTextSize("F").x; + float cell_width = glyph_width * 3; // "FF " we include trailing space in the width to easily catch clicks everywhere + + float line_height = ImGui::GetTextLineHeight(); + int line_total_count = (int)((mem_size + Rows-1) / Rows); + ImGuiListClipper clipper(line_total_count, line_height); + int visible_start_addr = clipper.DisplayStart * Rows; + int visible_end_addr = clipper.DisplayEnd * Rows; + + bool data_next = false; + + if (!AllowEdits || DataEditingAddr >= mem_size) + DataEditingAddr = -1; + + int data_editing_addr_backup = DataEditingAddr; + if (DataEditingAddr != -1) + { + if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && DataEditingAddr >= Rows) { DataEditingAddr -= Rows; DataEditingTakeFocus = true; } + else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && DataEditingAddr < mem_size - Rows) { DataEditingAddr += Rows; DataEditingTakeFocus = true; } + else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && DataEditingAddr > 0) { DataEditingAddr -= 1; DataEditingTakeFocus = true; } + else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)) && DataEditingAddr < mem_size - 1) { DataEditingAddr += 1; DataEditingTakeFocus = true; } + } + if ((DataEditingAddr / Rows) != (data_editing_addr_backup / Rows)) + { + // Track cursor movements + float scroll_offset = ((DataEditingAddr / Rows) - (data_editing_addr_backup / Rows)) * line_height; + bool scroll_desired = (scroll_offset < 0.0f && DataEditingAddr < visible_start_addr + Rows*2) || (scroll_offset > 0.0f && DataEditingAddr > visible_end_addr - Rows*2); + if (scroll_desired) + ImGui::SetScrollY(ImGui::GetScrollY() + scroll_offset); + } + + bool draw_separator = true; + for (int line_i = clipper.DisplayStart; line_i < clipper.DisplayEnd; line_i++) // display only visible items + { + int addr = line_i * Rows; + ImGui::Text("%0*X: ", addr_digits_count, base_display_addr+addr); + ImGui::SameLine(); + + // Draw Hexadecimal + float line_start_x = ImGui::GetCursorPosX(); + for (int n = 0; n < Rows && addr < mem_size; n++, addr++) + { + ImGui::SameLine(line_start_x + cell_width * n); + + if (DataEditingAddr == addr) + { + // Display text input on current byte + ImGui::PushID(addr); + struct FuncHolder + { + // FIXME: We should have a way to retrieve the text edit cursor position more easily in the API, this is rather tedious. + static int Callback(ImGuiTextEditCallbackData* data) + { + int* p_cursor_pos = (int*)data->UserData; + if (!data->HasSelection()) + *p_cursor_pos = data->CursorPos; + return 0; + } + }; + int cursor_pos = -1; + bool data_write = false; + if (DataEditingTakeFocus) + { + ImGui::SetKeyboardFocusHere(); + sprintf(AddrInput, "%0*X", addr_digits_count, base_display_addr+addr); + sprintf(DataInput, "%02X", mem_data[addr]); + } + ImGui::PushItemWidth(ImGui::CalcTextSize("FF").x); + ImGuiInputTextFlags flags = ImGuiInputTextFlags_CharsHexadecimal|ImGuiInputTextFlags_EnterReturnsTrue|ImGuiInputTextFlags_AutoSelectAll|ImGuiInputTextFlags_NoHorizontalScroll|ImGuiInputTextFlags_AlwaysInsertMode|ImGuiInputTextFlags_CallbackAlways; + if (ImGui::InputText("##data", DataInput, 32, flags, FuncHolder::Callback, &cursor_pos)) + data_write = data_next = true; + else if (!DataEditingTakeFocus && !ImGui::IsItemActive()) + DataEditingAddr = -1; + DataEditingTakeFocus = false; + ImGui::PopItemWidth(); + if (cursor_pos >= 2) + data_write = data_next = true; + if (data_write) + { + int data; + if (sscanf(DataInput, "%X", &data) == 1) + mem_data[addr] = (unsigned char)data; + } + ImGui::PopID(); + } + else + { + ImGui::Text("%02X ", mem_data[addr]); + if (AllowEdits && ImGui::IsItemHovered() && ImGui::IsMouseClicked(0)) + { + DataEditingTakeFocus = true; + DataEditingAddr = addr; + } + } + } + + ImGui::SameLine(line_start_x + cell_width * Rows + glyph_width * 2); + + if (draw_separator) + { + ImVec2 screen_pos = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddLine(ImVec2(screen_pos.x - glyph_width, screen_pos.y - 9999), ImVec2(screen_pos.x - glyph_width, screen_pos.y + 9999), ImColor(ImGui::GetStyle().Colors[ImGuiCol_Border])); + draw_separator = false; + } + + // Draw ASCII values + addr = line_i * Rows; + for (int n = 0; n < Rows && addr < mem_size; n++, addr++) + { + if (n > 0) ImGui::SameLine(); + int c = mem_data[addr]; + ImGui::Text("%c", (c >= 32 && c < 128) ? c : '.'); + } + } + clipper.End(); + ImGui::PopStyleVar(2); + + ImGui::EndChild(); + + if (data_next && DataEditingAddr < mem_size) + { + DataEditingAddr = DataEditingAddr + 1; + DataEditingTakeFocus = true; + } + + ImGui::Separator(); + + ImGui::AlignFirstTextHeightToWidgets(); + ImGui::PushItemWidth(50); + ImGui::PushAllowKeyboardFocus(false); + int rows_backup = Rows; + if (ImGui::DragInt("##rows", &Rows, 0.2f, 4, 32, "%.0f rows")) + { + ImVec2 new_window_size = ImGui::GetWindowSize(); + new_window_size.x += (Rows - rows_backup) * (cell_width + glyph_width); + ImGui::SetWindowSize(new_window_size); + } + ImGui::PopAllowKeyboardFocus(); + ImGui::PopItemWidth(); + ImGui::SameLine(); + ImGui::Text("Range %0*X..%0*X", addr_digits_count, (int)base_display_addr, addr_digits_count, (int)base_display_addr+mem_size-1); + ImGui::SameLine(); + ImGui::PushItemWidth(70); + if (ImGui::InputText("##addr", AddrInput, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_EnterReturnsTrue)) + { + int goto_addr; + if (sscanf(AddrInput, "%X", &goto_addr) == 1) + { + goto_addr -= base_display_addr; + if (goto_addr >= 0 && goto_addr < mem_size) + { + ImGui::BeginChild("##scrolling"); + ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + (goto_addr / Rows) * ImGui::GetTextLineHeight()); + ImGui::EndChild(); + DataEditingAddr = goto_addr; + DataEditingTakeFocus = true; + } + } + } + ImGui::PopItemWidth(); + } + ImGui::End(); + } +};