diff --git a/app.cpp b/app.cpp index e26e4ee..2ef920b 100644 --- a/app.cpp +++ b/app.cpp @@ -20,6 +20,8 @@ #include #include +#include + void DrawMenu(); void DrawToolbar(ImVec2 buttonSize); void DrawDroppedFilesPrompt(); @@ -238,7 +240,7 @@ std::string otio_error_string(otio::ErrorStatus const& error_status) { } void LoadTimeline(otio::Timeline* timeline) { - appState.timeline = timeline; + appState.root = timeline; DetectPlayheadLimits(); appState.playhead = appState.playhead_limit.start_time(); FitZoomWholeTimeline(); @@ -275,9 +277,8 @@ void LoadFile(std::string path) { auto start = std::chrono::high_resolution_clock::now(); otio::ErrorStatus error_status; - auto timeline = dynamic_cast( - otio::Timeline::from_json_file(path, &error_status)); - if (!timeline || otio::is_error(error_status)) { + auto root = otio::Timeline::from_json_file(path, &error_status); + if (!root || otio::is_error(error_status)) { Message( "Error loading \"%s\": %s", path.c_str(), @@ -285,7 +286,26 @@ void LoadFile(std::string path) { return; } - LoadTimeline(timeline); + std::string file_name; + if (root->schema_name() == "Timeline") { + auto timeline = dynamic_cast(root); + LoadTimeline(timeline); + file_name = timeline->name(); + } else if (root->schema_name() == "Clip") { + auto clip = dynamic_cast(root); + file_name = clip->name(); + appState.root = clip; + + auto timeline = new otio::Timeline(); + SelectObject(clip); + } else{ + Message( + "Error loading \"%s\": Unsupported root schema: %s", + path.c_str(), + root->schema_name().c_str() + ); + return; + } appState.file_path = path; @@ -294,12 +314,12 @@ void LoadFile(std::string path) { double elapsed_seconds = elapsed.count(); Message( "Loaded \"%s\" in %.3f seconds", - timeline->name().c_str(), + file_name.c_str(), elapsed_seconds); } void SaveFile(std::string path) { - auto timeline = appState.timeline; + auto timeline = appState.root; if (!timeline) return; @@ -390,6 +410,12 @@ bool IconButton(const char* label, const ImVec2 size = ImVec2(0, 0)) { void AppUpdate() { } +void DrawRoot(){ + if (appState.root->schema_name() == "Timeline") { + DrawTimeline(dynamic_cast(appState.root)); + } +} + void MainGui() { AppUpdate(); @@ -532,12 +558,14 @@ void MainGui() { contentSize.y -= ImGui::GetTextLineHeightWithSpacing() + 7; ImGui::BeginChild("##TimelineContainer", contentSize); - DrawTimeline(appState.timeline); + DrawRoot(); ImGui::EndChild(); - if (DrawTransportControls(appState.timeline)) { - appState.scroll_to_playhead = true; + if (appState.root->schema_name() == "Timeline"){ + if (DrawTransportControls(dynamic_cast(appState.root))) { + appState.scroll_to_playhead = true; + } } } ImGui::End(); @@ -687,8 +715,8 @@ void DrawMenu() { if (ImGui::MenuItem("Revert")) { LoadFile(appState.file_path); } - if (ImGui::MenuItem("Close", NULL, false, appState.timeline)) { - appState.timeline = NULL; + if (ImGui::MenuItem("Close", NULL, false, appState.root)) { + appState.root = NULL; SelectObject(NULL); } #ifndef EMSCRIPTEN @@ -889,7 +917,7 @@ void SelectObject( appState.selected_text = "No selection"; } else { otio::ErrorStatus error_status; - appState.selected_text = object->to_json_string(&error_status); + //appState.selected_text = object->to_json_string(&error_status); if (otio::is_error(error_status)) { appState.selected_text = otio_error_string(error_status); } @@ -914,14 +942,19 @@ void SnapPlayhead() { } void DetectPlayheadLimits() { - const auto timeline = appState.timeline; - appState.playhead_limit = otio::TimeRange( - timeline->global_start_time().value_or(otio::RationalTime()), - timeline->duration()); + if (appState.root->schema_name() == "Timeline"){ + const auto timeline = dynamic_cast(appState.root); + appState.playhead_limit = otio::TimeRange( + timeline->global_start_time().value_or(otio::RationalTime()), + timeline->duration()); + } } void FitZoomWholeTimeline() { - appState.scale = appState.timeline_width / appState.timeline->duration().to_seconds(); + if (appState.root->schema_name() == "Timeline"){ + const auto timeline = dynamic_cast(appState.root); + appState.scale = appState.timeline_width / timeline->duration().to_seconds(); + } } // GUI utility to add dynamic height to GUI elements diff --git a/app.h b/app.h index 8522e73..a72841e 100644 --- a/app.h +++ b/app.h @@ -83,7 +83,7 @@ struct AppState { // This holds the main timeline object. // Pretty much everything drills into this one entry point. - otio::SerializableObject::Retainer timeline; + otio::SerializableObjectWithMetadata* root; // Timeline display settings float timeline_width = 100.0f; // automatically calculated (pixels) diff --git a/editing.cpp b/editing.cpp index 20335f7..12b6711 100644 --- a/editing.cpp +++ b/editing.cpp @@ -8,8 +8,8 @@ #include void DeleteSelectedObject() { - if (appState.selected_object == appState.timeline) { - appState.timeline = NULL; + if (appState.selected_object == appState.root) { + appState.root = NULL; SelectObject(NULL); return; } @@ -57,10 +57,16 @@ void DeleteSelectedObject() { void AddMarkerAtPlayhead(otio::Item* item, std::string name, std::string color) { auto playhead = appState.playhead; + + + if (!appState.root) + return; - const auto& timeline = appState.timeline; - if (!timeline) + if (appState.root->schema_name() != "Timeline"){ return; + } + + const auto& timeline = dynamic_cast(appState.root); // Default to the selected item, or the top-level timeline. if (item == NULL) { @@ -91,10 +97,15 @@ void AddMarkerAtPlayhead(otio::Item* item, std::string name, std::string color) } void AddTrack(std::string kind) { - const auto& timeline = appState.timeline; - if (!timeline) + if (!appState.root) return; + if (appState.root->schema_name() != "Timeline"){ + return; + } + + const auto& timeline = dynamic_cast(appState.root); + // Fall back to the top level stack. int insertion_index = -1; otio::Stack* stack = timeline->tracks(); @@ -150,7 +161,7 @@ void AddTrack(std::string kind) { } void FlattenTrackDown() { - const auto& timeline = appState.timeline; + const auto& timeline = appState.root; if (!timeline) { Message("Cannot flatten: No timeline."); return; diff --git a/inspector.cpp b/inspector.cpp index ec4f9ff..3b0512a 100644 --- a/inspector.cpp +++ b/inspector.cpp @@ -616,20 +616,27 @@ void DrawMarkersInspector() { typedef std::pair, otio::SerializableObject::Retainer> marker_parent_pair; std::vector pairs; - auto root = appState.timeline->tracks(); - auto global_start = appState.timeline->global_start_time().value_or(otio::RationalTime()); + auto root = new otio::Stack(); + auto global_start = otio::RationalTime(0.0); - for (const auto& marker : root->markers()) { - pairs.push_back(marker_parent_pair(marker, root)); - } + if (appState.root->schema_name() == "Timeline"){ + const auto& timeline = dynamic_cast(appState.root); - for (const auto& child : - appState.timeline->tracks()->find_children()) - { - if (const auto& item = dynamic_cast(&*child)) + root = timeline->tracks(); + global_start = timeline->global_start_time().value_or(otio::RationalTime()); + + for (const auto& marker : root->markers()) { + pairs.push_back(marker_parent_pair(marker, root)); + } + + for (const auto& child : + timeline->tracks()->find_children()) { - for (const auto& marker : item->markers()) { - pairs.push_back(marker_parent_pair(marker, item)); + if (const auto& item = dynamic_cast(&*child)) + { + for (const auto& marker : item->markers()) { + pairs.push_back(marker_parent_pair(marker, item)); + } } } } @@ -714,20 +721,27 @@ void DrawEffectsInspector() { typedef std::pair, otio::SerializableObject::Retainer> effect_parent_pair; std::vector pairs; - auto root = appState.timeline->tracks(); - auto global_start = appState.timeline->global_start_time().value_or(otio::RationalTime()); + auto root = new otio::Stack(); + auto global_start = otio::RationalTime(0.0); - for (const auto& effect : root->effects()) { - pairs.push_back(effect_parent_pair(effect, root)); - } + if (appState.root->schema_name() == "Timeline"){ + const auto& timeline = dynamic_cast(appState.root); - for (const auto& child : - appState.timeline->tracks()->find_children()) - { - if (const auto& item = dynamic_cast(&*child)) + root = timeline->tracks(); + global_start = timeline->global_start_time().value_or(otio::RationalTime()); + + for (const auto& effect : root->effects()) { + pairs.push_back(effect_parent_pair(effect, root)); + } + + for (const auto& child : + timeline->tracks()->find_children()) { - for (const auto& effect : item->effects()) { - pairs.push_back(effect_parent_pair(effect, item)); + if (const auto& item = dynamic_cast(&*child)) + { + for (const auto& effect : item->effects()) { + pairs.push_back(effect_parent_pair(effect, item)); + } } } } diff --git a/timeline.cpp b/timeline.cpp index ccddf0e..e0baf99 100644 --- a/timeline.cpp +++ b/timeline.cpp @@ -46,7 +46,7 @@ void TopLevelTimeRangeMap( std::map& range_map, otio::Item* context) { auto zero = otio::RationalTime(); - auto top = appState.timeline->tracks(); + auto top = dynamic_cast(appState.root)->tracks(); auto offset = context->transformed_time(zero, top); for (auto& pair : range_map) {