diff --git a/.gitmodules b/.gitmodules index a425b63..c3401a1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,7 +15,7 @@ url = https://github.com/ocornut/imgui.git [submodule "libs/ImGuiColorTextEdit"] path = libs/ImGuiColorTextEdit - url = https://github.com/jminor/ImGuiColorTextEdit.git + url = https://github.com/goossens/ImGuiColorTextEdit.git [submodule "libs/minizip-ng"] path = libs/minizip-ng url = https://github.com/zlib-ng/minizip-ng.git diff --git a/inspector.cpp b/inspector.cpp index 5b4eadc..848b525 100644 --- a/inspector.cpp +++ b/inspector.cpp @@ -23,67 +23,56 @@ #include #include +#include + static const char* marker_color_names[] = { "PINK", "RED", "ORANGE", "YELLOW", "GREEN", "CYAN", "BLUE", "PURPLE", "MAGENTA", "BLACK", "WHITE" }; -const TextEditor::LanguageDefinition& OTIOLanguageDef() +const TextEditor::Language* OTIOLanguage() { - static bool inited = false; - static TextEditor::LanguageDefinition langDef; - if (!inited) - { - static const char* const keywords[] = { - "true", "false", "null" - }; - - for (auto& k : keywords) - langDef.mKeywords.insert(k); - - static const char* const identifiers[] = { - "\"OTIO_SCHEMA\"" - }; - for (auto& k : identifiers) - { - TextEditor::Identifier id; - id.mDeclaration = "OpenTimelineIO Schema"; - langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); - } - - langDef.mTokenRegexStrings.push_back(std::make_pair("\\\"OTIO_SCHEMA\\\"", TextEditor::PaletteIndex::Identifier)); - langDef.mTokenRegexStrings.push_back(std::make_pair("\\\"(\\\\.|[^\\\"])*\\\"", TextEditor::PaletteIndex::String)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?", TextEditor::PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[a-zA-Z_][a-zA-Z0-9_]*", TextEditor::PaletteIndex::Identifier)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[\\[\\]\\{\\}\\,\\:]", TextEditor::PaletteIndex::Punctuation)); - - langDef.mCommentStart = "/*"; - langDef.mCommentEnd = "*/"; - langDef.mSingleLineComment = "//"; + static bool initialized = false; + static TextEditor::Language language; - langDef.mCaseSensitive = true; - langDef.mAutoIndentation = true; - - langDef.mName = "JSON"; - - inited = true; + if (!initialized) + { + const TextEditor::Language* jsonLang = TextEditor::Language::Json(); + language = *jsonLang; + language.name = "OTIO/JSON"; + + // TODO: Special highlighting for "OTIO_SCHEMA" strings + // Old jminor fork: used mTokenRegexStrings with pattern \\\"OTIO_SCHEMA\\\" + // New goossens fork: removed regex API, requires custom tokenizer wrapper + // The problem: "OTIO_SCHEMA" appears quoted in JSON. keywords/identifiers only match bare + // tokens. Recoloring string content requires intercepting with customTokenizer + // before the string state machine consumes it. Too complex for minimal benefit. + + initialized = true; } - return langDef; + + return &language; } TextEditor jsonEditor; -TextEditor::LanguageDefinition otioLangDef = OTIOLanguageDef(); bool json_rendered = false; bool json_edited = false; std::string json_error_message; int json_error_line = -1; void UpdateJSONInspector() { - jsonEditor.SetReadOnly(false); - jsonEditor.SetLanguageDefinition(otioLangDef); + // Ensure palette is set (fixes static initialization order issue) + static bool paletteInitialized = false; + if (!paletteInitialized) { + jsonEditor.SetPalette(TextEditor::GetDarkPalette()); + paletteInitialized = true; + } + + jsonEditor.SetReadOnlyEnabled(false); + jsonEditor.SetLanguage(OTIOLanguage()); jsonEditor.SetText(appState.selected_text); - jsonEditor.SetErrorMarkers({}); + jsonEditor.ClearMarkers(); json_rendered = false; json_edited = false; json_error_message = ""; @@ -122,10 +111,13 @@ void SetJSONErrorMessage(std::string message) { wrapped_message += c; } + jsonEditor.ClearMarkers(); if (json_error_line >= 0) { - jsonEditor.SetErrorMarkers({ { json_error_line, wrapped_message } }); - } else { - jsonEditor.SetErrorMarkers({}); + jsonEditor.AddMarker(json_error_line, + IM_COL32(255, 0, 0, 255), + IM_COL32(255, 100, 100, 50), + wrapped_message.c_str(), + ""); } json_error_message = wrapped_message; @@ -222,17 +214,17 @@ void DrawJSONApplyEditButtons() { } void DrawJSONInspector() { - // Check if the text was edited this frame. - // Note that IsTextChanged() is true only until Render is called. - // We have to also check if Render was called since the text - // was last set via SetText() inside UpdateJSONInspector(). - if (json_rendered && jsonEditor.IsTextChanged()) { + // Check if the text was edited. + // We use CanUndo() to detect if there are any edits since SetText() was called, + // as SetText() clears the undo stack. We also check json_rendered to ensure + // Render() was called at least once since UpdateJSONInspector(). + if (json_rendered && jsonEditor.CanUndo()) { json_edited = true; } auto available_size = ImGui::GetContentRegionAvail(); available_size.y -= ImGui::GetFrameHeightWithSpacing(); - jsonEditor.Render("JSON",false, available_size); + jsonEditor.Render("JSON", available_size); json_rendered = true; if (json_edited) { @@ -571,7 +563,7 @@ void DrawLinearTimeWarp(otio::LinearTimeWarp* timewarp, otio::Item* item) { const ImColor knot_color = appTheme.colors[AppThemeCol_ItemSelected]; ImPlotFlags plot_flags = ImPlotFlags_NoTitle | ImPlotFlags_NoLegend | ImPlotFlags_NoInputs - | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect | ImPlotFlags_NoChild + | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect | ImPlotFlags_NoFrame | ImPlotFlags_Equal | ImPlotFlags_None; ImPlotDragToolFlags drag_flags = ImPlotDragToolFlags_NoInputs | ImPlotDragToolFlags_None; @@ -585,35 +577,34 @@ void DrawLinearTimeWarp(otio::LinearTimeWarp* timewarp, otio::Item* item) { fmax(start->y, end->y), ImGuiCond_Always); - ImPlot::SetNextLineStyle(line_color, line_width); + ImPlotSpec line_spec; + line_spec.LineColor = line_color; + line_spec.LineWeight = line_width; + line_spec.Stride = sizeof(ImPlotPoint); ImPlot::PlotLine( "##Line", &start->x, &start->y, 2, - 0, - 0, - sizeof(ImPlotPoint)); + line_spec); // start handle - ImPlot::SetNextLineStyle(knot_color); if (ImPlot::DragPoint( 0, &start->x, &start->y, - ImVec4(0, 0.9f, 0, 1), + knot_color, knot_radius, drag_flags)) { ; } // end handle - ImPlot::SetNextLineStyle(knot_color); if (ImPlot::DragPoint( 3, &end->x, &end->y, - ImVec4(0, 0.9f, 0, 1), + knot_color, knot_radius, drag_flags)) { ; @@ -918,7 +909,7 @@ void DrawMarkersInspector() { } } - auto selectable_flags = ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap; + auto selectable_flags = ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap; if (ImGui::BeginTable("Markers", 5, @@ -1032,7 +1023,7 @@ void DrawEffectsInspector() { } } - auto selectable_flags = ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap; + auto selectable_flags = ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap; if (ImGui::BeginTable("Effects", 4, @@ -1181,7 +1172,7 @@ void DrawTreeInspector() { // instead of only the 1st column with the tree node. ImGui::TableNextColumn(); bool just_clicked = ImGui::IsItemClicked(); - bool just_selected = ImGui::Selectable(composable->schema_name().c_str(), is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap); + bool just_selected = ImGui::Selectable(composable->schema_name().c_str(), is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap); if (just_clicked || just_selected) { SelectObject(composable); appState.active_tab->playhead = global_time; diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 3801c7f..9956ef6 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -35,7 +35,7 @@ endif() add_library(IMGUI STATIC) -set_property(TARGET IMGUI PROPERTY CXX_STANDARD 14) +set_property(TARGET IMGUI PROPERTY CXX_STANDARD 17) set(IMGUI_DIR imgui) set(IMPLOT_DIR implot) diff --git a/libs/ImGuiColorTextEdit b/libs/ImGuiColorTextEdit index 7dec5d8..a74fb09 160000 --- a/libs/ImGuiColorTextEdit +++ b/libs/ImGuiColorTextEdit @@ -1 +1 @@ -Subproject commit 7dec5d81ca529ea674ee7d7cd9dc32a108650248 +Subproject commit a74fb090d2ea9276ae6c35c2f6ab39491c7d404f diff --git a/libs/imgui b/libs/imgui index 9937660..b61e563 160000 --- a/libs/imgui +++ b/libs/imgui @@ -1 +1 @@ -Subproject commit 9937660b1cdf79a98b74647608f0e57a62a36e62 +Subproject commit b61e56346a92cfcaf1f43a545ca37b0b32239654 diff --git a/libs/implot b/libs/implot index 33c5a96..524f9fc 160000 --- a/libs/implot +++ b/libs/implot @@ -1 +1 @@ -Subproject commit 33c5a965f55f80057f197257d1d1cdb06523e963 +Subproject commit 524f9fcd48d76c13fdf94c5ffbba8787a1ff7e39 diff --git a/main_emscripten.cpp b/main_emscripten.cpp index 7cd3a2a..f17aae6 100644 --- a/main_emscripten.cpp +++ b/main_emscripten.cpp @@ -75,6 +75,7 @@ int main(int argc, char** argv) IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigDebugHighlightIdConflicts = false; // Disable ID conflict warnings introduced in ImGui v1.91.2 (pre-existing issues from before update) io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking diff --git a/main_glfw.cpp b/main_glfw.cpp index a2e3d81..834375a 100644 --- a/main_glfw.cpp +++ b/main_glfw.cpp @@ -121,6 +121,7 @@ int main(int argc, char** argv) ImGui::CreateContext(); ImPlot::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigDebugHighlightIdConflicts = false; // Disable ID conflict warnings introduced in ImGui v1.91.2 (pre-existing issues from before update) //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking diff --git a/main_macos.mm b/main_macos.mm index 481dd77..4e94781 100644 --- a/main_macos.mm +++ b/main_macos.mm @@ -35,6 +35,7 @@ int main(int argc, char** argv) ImGui::CreateContext(); ImPlot::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigDebugHighlightIdConflicts = false; // Disable ID conflict warnings introduced in ImGui v1.91.2 (pre-existing issues from before update) //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking diff --git a/main_win32.cpp b/main_win32.cpp index d8932c0..ce42d57 100644 --- a/main_win32.cpp +++ b/main_win32.cpp @@ -104,6 +104,7 @@ int main(int argc, char** argv) ImGui::CreateContext(); ImPlot::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigDebugHighlightIdConflicts = false; // Disable ID conflict warnings introduced in ImGui v1.91.2 (pre-existing issues from before update) //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking diff --git a/timeline.cpp b/timeline.cpp index 7bda8b6..d240fd9 100644 --- a/timeline.cpp +++ b/timeline.cpp @@ -125,6 +125,7 @@ void DrawItem( ImGui::PushID(item); ImGui::BeginGroup(); + ImGui::SetNextItemAllowOverlap(); ImGui::InvisibleButton("##Item", size); // Don't skip invisible item if it is the item we have just selected @@ -158,8 +159,6 @@ void DrawItem( return; } - ImGui::SetItemAllowOverlap(); - // Dragging... // if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) // { @@ -339,7 +338,7 @@ void DrawTransition( ImGui::SetCursorPos(old_pos); return; } - // ImGui::SetItemAllowOverlap(); + // ImGui::SetNextItemAllowOverlap(); if (ImGui::IsItemHovered()) { fill_color = hover_fill_color; @@ -454,7 +453,7 @@ void DrawEffects( ImGui::SetCursorPos(old_pos); return; } - // ImGui::SetItemAllowOverlap(); + // ImGui::SetNextItemAllowOverlap(); if (ImGui::IsItemHovered()) { fill_color = hover_fill_color; @@ -570,7 +569,7 @@ void DrawMarkers( continue; ; } - // ImGui::SetItemAllowOverlap(); + // ImGui::SetNextItemAllowOverlap(); if (ImGui::IsItemHovered()) { fill_color = hover_fill_color; @@ -813,10 +812,10 @@ void DrawTimecodeRuler( ImGui::PushID(ptr_id); ImGui::BeginGroup(); + ImGui::SetNextItemAllowOverlap(); ImGui::Dummy(size); const ImVec2 p0 = ImGui::GetItemRectMin(); const ImVec2 p1 = ImGui::GetItemRectMax(); - ImGui::SetItemAllowOverlap(); if (!ImGui::IsRectVisible(p0, p1)) { ImGui::EndGroup(); ImGui::PopID(); @@ -945,13 +944,13 @@ bool DrawTimecodeTrack( ImGui::PushID("##DrawTimecodeTrack"); ImGui::BeginGroup(); + ImGui::SetNextItemAllowOverlap(); if (interactive) { ImGui::InvisibleButton("##empty", size); } else { ImGui::Dummy(size); } const ImVec2 p0 = ImGui::GetItemRectMin(); - ImGui::SetItemAllowOverlap(); if (interactive && ImGui::IsItemActive()) // && // ImGui::IsMouseDragging(ImGuiMouseButton_Left)) @@ -1020,12 +1019,12 @@ float DrawPlayhead( ImGui::PushID("##Playhead"); ImGui::BeginGroup(); + ImGui::SetNextItemAllowOverlap(); ImGui::InvisibleButton("##Playhead2", size); // Compute where we are rendering in screen space for draw list functions. ImVec2 p0 = ImGui::GetItemRectMin(); ImVec2 p1 = ImGui::GetItemRectMax(); - ImGui::SetItemAllowOverlap(); // compute the playhead x position in the local (aka window) coordinate system // so that later we can use SetScrollFromPosX() to scroll the timeline.