8 #include "sequencecurvetrackview_guiactions.h"
9 #include "sequenceguiutils.h"
12 #include <imguiutils.h>
20 assert(action!=
nullptr);
24 ImGui::OpenPopup(
"Curve Point Actions");
25 action->mOpened =
true;
28 if(ImGui::BeginPopup(
"Curve Point Actions"))
30 int curveIndex = action->mCurveIndex;
32 float value = action->mValue * (action->mMaximum[curveIndex] - action->mMinimum[curveIndex]) +
33 action->mMinimum[curveIndex];
34 if(ImGui::InputFloat(
"value", &value))
40 action->mControlPointIndex,
56 const auto *segment = curve_controller.
getSegment(action->mTrackID, action->mSegmentID);
57 assert(segment !=
nullptr);
59 double time = action->mTime * segment->mDuration + segment->mStartTime;
60 double min_time = segment->mStartTime;
61 double max_time = segment->mStartTime + segment->mDuration;
65 bool edit_time =
false;
70 edit_time = ImGui::InputInt3(
"Time (mm:ss:ms)", &time_array[0]);
71 time_array[0] = math::clamp<int>(time_array[0], 0, 99999);
72 time_array[1] = math::clamp<int>(time_array[1], 0, 59);
73 time_array[2] = math::clamp<int>(time_array[2], 0, 99);
78 new_time =
math::clamp(new_time, min_time, max_time);
80 float perc = (new_time - segment->mStartTime) / segment->mDuration;
85 action->mControlPointIndex,
99 action->mControlPointIndex,
100 action->mCurveIndex);
104 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
107 ImGui::CloseCurrentPopup();
114 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
115 ImGui::CloseCurrentPopup();
122 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
131 assert(action!=
nullptr);
135 ImGui::OpenPopup(
"Segment Value Actions");
136 action->mOpened =
true;
139 if(ImGui::BeginPopup(
"Segment Value Actions"))
141 int curveIndex = action->mCurveIndex;
144 action->mValue[curveIndex] * (action->mMaximum[curveIndex] - action->mMinimum[curveIndex]) +
145 action->mMinimum[curveIndex];
146 if(ImGui::InputFloat(
"value", &value))
148 float translated_value = (value - action->mMinimum[curveIndex]) /
149 (action->mMaximum[curveIndex] - action->mMinimum[curveIndex]);
164 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
166 ImGui::CloseCurrentPopup();
173 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
182 const ImVec2& trackTopLeft,
183 const float previousSegmentX,
184 const float segmentWidth,
185 const float segmentX,
186 ImDrawList* drawList)
191 bool needs_drawing = ImGui::IsRectVisible({trackTopLeft.x + previousSegmentX, trackTopLeft.y}, {
192 trackTopLeft.x + previousSegmentX + segmentWidth, trackTopLeft.y + track_height});
199 const long point_num = (int) (points_per_pixel * segmentWidth);
200 std::vector<std::vector<ImVec2>> curves;
201 for(
int v = 0; v < segment.mCurves.size(); v++)
203 std::vector<ImVec2> curve;
206 auto start_x = math::max<float>(trackTopLeft.x, 0);
212 for(; i <= point_num; i++)
214 float p = (float) i / (
float) point_num;
215 float x = trackTopLeft.x + previousSegmentX + segmentWidth * p;
218 float value = 1.0f - segment.mCurves[v]->evaluate(p);
223 trackTopLeft.y + value * track_height
225 curve.emplace_back(point);
236 curves.emplace_back(std::move(curve));
238 mCurveCache.emplace(segment.mID, std::move(curves));
242 int selected_curve = -1;
248 && ImGui::IsMouseHoveringRect(
249 {trackTopLeft.x + segmentX - segmentWidth, trackTopLeft.y},
250 {trackTopLeft.x + segmentX, trackTopLeft.y + track_height}))
253 ImVec2 mouse_pos = ImGui::GetMousePos();
255 ((mouse_pos.x - (trackTopLeft.x + segmentX - segmentWidth)) /
mState.
mStepSize) / segment.mDuration;
256 float y_in_segment = 1.0f - ((mouse_pos.y - trackTopLeft.y) / track_height);
258 for(
int i = 0; i < segment.mCurves.size(); i++)
261 float y_in_curve = segment.mCurves[i]->evaluate(x_in_segment);
264 const float maxDist = 0.1f;
265 if(std::abs(y_in_curve - y_in_segment) < maxDist)
267 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::HoveringCurve>(
272 if(ImGui::IsMouseClicked(1))
274 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::InsertingCurvePoint>(
283 if(selected_curve == -1)
285 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
290 segment, x_in_segment,
299 if(action->mSegmentID == segment.mID)
301 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
309 for(
int i = 0; i < segment.mCurves.size(); i++)
313 float thickness = selected_curve == i ? 3.0f : 1.0f;
315 drawList->AddPolyline
333 const ImVec2& trackTopLeft,
334 float previousSegmentX,
337 ImDrawList* drawList,
344 bool draw_selection_background =
false;
348 draw_selection_background = action->
mSegmentID == segment.
mID;
352 draw_selection_background = action->
mSegmentID == segment.
mID;
356 draw_selection_background = action->
mSegmentID == segment.
mID;
360 draw_selection_background = action->
mSegmentID == segment.
mID;
364 draw_selection_background = action->
mSegmentID == segment.
mID;
369 if(draw_selection_background)
371 drawList->AddRectFilled(
372 {trackTopLeft.x + segmentX - segmentWidth, trackTopLeft.y},
373 {trackTopLeft.x + segmentX, trackTopLeft.y + track_height},
374 ImGui::ColorConvertFloat4ToU32(ImVec4(1, 1, 1, 0.25f)));
388 drawList->AddRectFilled
390 {trackTopLeft.x + segmentX - segmentWidth, trackTopLeft.y},
391 {trackTopLeft.x + segmentX, trackTopLeft.y + track_height},
392 ImGui::ColorConvertFloat4ToU32(red)
410 drawControlPoints<T>(
429 sequencecurveenums::ESegmentValueTypes::BEGIN,
440 sequencecurveenums::ESegmentValueTypes::END,
450 T min = curve_track.mMinimum;
451 T max = curve_track.mMaximum;
454 ImGui::PushID(track.
mID.c_str());
456 float drag_float_x = ImGui::GetCursorPosX() + (40.0f *
mState.
mScale);
457 ImGui::SetCursorPos({ImGui::GetCursorPosX() + offset, ImGui::GetCursorPosY() + offset});
460 ImGui::PushID(
"min");
461 ImGui::SetCursorPosX(drag_float_x);
462 if(inputFloat<T>(min, 3))
464 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::ChangeMinMaxCurve<T>>(track.
mID, min, max);
467 ImGui::PopItemWidth();
468 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offset);
471 ImGui::PushID(
"max");
472 ImGui::SetCursorPosX(drag_float_x);
473 if(inputFloat<T>(max, 3))
475 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::ChangeMinMaxCurve<T>>(track.
mID, min, max);
478 ImGui::PopItemWidth();
487 const ImVec2& trackTopLeft,
488 const float segmentX,
489 const float segmentWidth,
491 ImDrawList* drawList)
521 for(
int v = 0; v < segment.mCurves.size(); v++)
524 ImVec2 segment_value_pos =
528 (
float) segment.mCurves[v]->mPoints[0].mPos.mValue :
529 (
float) segment.mCurves[v]->mPoints[
530 segment.mCurves[v]->mPoints.size() - 1].mPos.mValue) /
534 bool hovered =
false;
543 ImGui::IsMouseHoveringRect(
550 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::HoveringSegmentValue>(
556 if(ImGui::IsMouseDown(0))
558 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::DraggingSegmentValue>(
563 get_value_map[RTTI_OF(T)](segment, v, segmentType));
564 }
else if(ImGui::IsMouseDown(1))
569 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::EditingSegmentCurveValue<T>>(
574 (segmentType == sequencecurveenums::ESegmentValueTypes::BEGIN)
575 ? curve_segment.getStartValue() : curve_segment.getEndValue(),
576 curve_track.mMinimum,
577 curve_track.mMaximum);
593 if(action->mType == segmentType &&
594 action->mSegmentID == segment.mID &&
595 action->mCurveIndex == v)
597 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
614 if(action->mSegmentID == segment.mID)
616 if(action->mType == segmentType && action->mCurveIndex == v)
628 float value = get_value_map[RTTI_OF(T)](segment, v, segmentType) + drag_amount;
630 action->mNewValue = value;
649 const ImVec2& trackTopLeft,
650 const float segmentX,
651 const float segmentWidth,
652 ImDrawList* drawList)
659 if(track.
mSegments[0]->mID == segment.mID)
661 for(
int v = 0; v < segment.mCurves.size(); v++)
663 const auto &curve_point = segment.mCurves[v]->mPoints[0];
664 std::ostringstream string_stream;
665 string_stream << segment.mID <<
"_point_" << 0 <<
"_curve_" << v;
667 ImVec2 circle_point =
668 {(trackTopLeft.x + segmentX - segmentWidth) + segmentWidth * curve_point.mPos.mTime,
669 trackTopLeft.y + track_height * (1.0f - (
float) curve_point.mPos.mValue)};
676 segment, string_stream,
677 segmentWidth, curve_point, circle_point,
680 sequencecurveenums::ETanPointTypes::IN,
685 segment, string_stream,
686 segmentWidth, curve_point, circle_point,
689 sequencecurveenums::ETanPointTypes::OUT,
697 for(
int v = 0; v < segment.mCurves.size(); v++)
699 for(
int i = 1; i < segment.mCurves[v]->mPoints.size() - 1; i++)
702 const auto &curve_point = segment.mCurves[v]->mPoints[i];
703 std::ostringstream string_stream;
704 string_stream << segment.mID <<
"_point_" << i <<
"_curve_" << v;
705 std::string point_id = string_stream.str();
708 ImVec2 circle_point =
709 {(trackTopLeft.x + segmentX - segmentWidth) + segmentWidth * curve_point.mPos.mTime,
710 trackTopLeft.y + track_height * (1.0f - (
float) curve_point.mPos.mValue)};
713 bool hovered =
false;
720 && ImGui::IsMouseHoveringRect({circle_point.x - offset, circle_point.y - offset},
721 {circle_point.x + offset, circle_point.y + offset}))
730 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::HoveringControlPoint>(
739 segment, curve_point.mPos.mTime,
740 curve_point.mPos.mTime * segment.mDuration + segment.mStartTime,
744 if(ImGui::IsMouseDown(0))
746 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::DraggingControlPoint>(
751 curve_point.mPos.mTime,
752 curve_point.mPos.mValue);
755 else if(ImGui::IsMouseClicked(1))
757 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::CurvePointActionPopup<T>>(
762 curve_point.mPos.mValue,
763 curve_point.mPos.mTime,
773 if(action->mControlPointIndex == i && track.
mID == action->mTrackID &&
774 segment.mID == action->mSegmentID && v == action->mCurveIndex)
776 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
788 if(action->mSegmentID == segment.mID)
790 if(action->mControlPointIndex == i && action->mCurveIndex == v)
799 segment, curve_point.mPos.mTime,
800 curve_point.mPos.mTime * segment.mDuration + segment.mStartTime,
803 action->mNewValue += value_adjust;
804 action->mNewTime += time_adjust;
811 drawList->AddCircleFilled
822 segment, string_stream,
823 segmentWidth, curve_point, circle_point,
826 sequencecurveenums::ETanPointTypes::IN,
831 segment, string_stream,
832 segmentWidth, curve_point, circle_point,
835 sequencecurveenums::ETanPointTypes::OUT,
841 for(
int v = 0; v < segment.mCurves.size(); v++)
845 const int control_point_index = segment.mCurves[v]->mPoints.size() - 1;
846 const auto &curve_point = segment.mCurves[v]->mPoints[control_point_index];
848 std::ostringstream string_stream;
849 string_stream << segment.mID <<
"_point_" << control_point_index <<
"_curve_" << v;
850 std::string point_id = string_stream.str();
852 ImVec2 circle_point =
853 {(trackTopLeft.x + segmentX - segmentWidth) + segmentWidth * curve_point.mPos.mTime,
854 trackTopLeft.y + track_height * (1.0f - (
float) curve_point.mPos.mValue)};
860 segment, string_stream,
861 segmentWidth, curve_point, circle_point, control_point_index,
863 sequencecurveenums::ETanPointTypes::IN,
868 segment, string_stream,
869 segmentWidth, curve_point, circle_point, control_point_index,
871 sequencecurveenums::ETanPointTypes::OUT,
877 ImGui::SetCursorPosY(ImGui::GetCursorPosY() - track_height);
885 std::ostringstream& stringStream,
886 const float segmentWidth,
888 const ImVec2& circlePoint,
889 const int controlPointIndex,
890 const int curveIndex,
892 ImDrawList* drawList)
899 std::ostringstream tan_stream;
900 tan_stream << stringStream.str() << ((type == sequencecurveenums::ETanPointTypes::IN) ?
"inTan" :
"outTan");
908 ImVec2 offset = {tan_complex.
mTime * tan_constant_size,
909 static_cast<float>(tan_complex.
mValue) * -1.0f * tan_constant_size};
910 ImVec2 tan_point = {circlePoint.x + offset.x, circlePoint.y + offset.y};
913 bool tan_point_hovered =
false;
919 if((
mState.
mAction->template isAction<sequenceguiactions::None>() ||
920 mState.
mAction->template isAction<sequenceguiactions::HoveringCurve>() ||
921 mState.
mAction->template isAction<sequenceguiactions::HoveringSegment>())
922 && ImGui::IsMouseHoveringRect
924 {tan_point.x - tan_bounds, tan_point.y - tan_bounds},
925 {tan_point.x + tan_bounds, tan_point.y + tan_bounds})
928 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::HoveringTanPoint>(track.
mID, tan_stream.str());
929 tan_point_hovered =
true;
935 if(action->mTanPointID == tan_stream.str())
937 if(ImGui::IsMouseHoveringRect(
938 {tan_point.x - tan_bounds, tan_point.y - tan_bounds},
939 {tan_point.x + tan_bounds, tan_point.y + tan_bounds}))
942 tan_point_hovered =
true;
945 if(ImGui::IsMouseDown(0))
947 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::DraggingTanPoint>(
953 }
else if(ImGui::IsMouseDown(1))
955 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::EditingTanPointPopup>(
961 (
float) tan_complex.mValue,
967 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
977 if(action->mSegmentID == segment.
mID &&
978 action->mControlPointIndex == controlPointIndex &&
979 action->mType == type &&
980 action->mCurveIndex == curveIndex)
982 tan_point_hovered =
true;
991 if(type == sequencecurveenums::ETanPointTypes::IN)
994 curve_segment.
mCurves[curveIndex]->mPoints[controlPointIndex].mInTan.mTime + delta_time;
995 new_value = curve_segment.mCurves[curveIndex]->mPoints[controlPointIndex].mInTan.mValue +
999 new_time = curve_segment.
mCurves[curveIndex]->mPoints[controlPointIndex].mOutTan.mTime +
1001 new_value = curve_segment.mCurves[curveIndex]->mPoints[controlPointIndex].mOutTan.mValue +
1005 action->mNewTime = new_time;
1006 action->mNewValue = new_value;
1023 template<
typename T>
1024 bool SequenceCurveTrackView::pasteClipboardSegments(
const std::string &trackId,
double time,
utility::ErrorState &errorState)
1030 std::vector<std::unique_ptr<rtti::Object>> read_objects;
1033 std::vector<T *> curve_segments = curve_segment_clipboard->
deserialize<T>(read_objects, errorState);
1037 nap::Logger::error(errorState.
toString());
1041 assert(curve_segments.size() > 0);
1044 std::sort(curve_segments.begin(), curve_segments.end(), [](T *a, T *b)
1046 return a->mStartTime < b->mStartTime;
1050 if(curve_segments.size() > 0)
1052 curve_segments[0]->mStartTime = 0.0;
1054 for(
int i = 1; i < curve_segments.size(); i++)
1056 curve_segments[i]->mStartTime = curve_segments[i - 1]->mStartTime + curve_segments[i - 1]->mDuration;
1060 for(
auto curve_segment: curve_segments)
1063 auto *base_controller = getEditor().getControllerWithTrackID(trackId);
1066 assert(base_controller !=
nullptr);
1069 assert(base_controller->get_type().template is_derived_from<SequenceControllerCurve>());
1073 const auto *new_segment = curve_controller->
insertSegment(trackId, time + curve_segment->mStartTime);
1076 curve_controller->changeSegmentLabel(trackId, new_segment->mID, curve_segment->mLabel);
1079 curve_controller->segmentDurationChange(trackId, new_segment->mID, curve_segment->mDuration);
1082 updateSegmentsInClipboard(trackId);
1085 for(
int c = 0; c < curve_segment->mCurves.size(); c++)
1087 for(
int i = 1; i < curve_segment->mCurves[c]->mPoints.size() - 1; i++)
1089 curve_controller->insertCurvePoint(trackId, new_segment->mID, curve_segment->mCurves[c]->mPoints[i].mPos.mTime, c);
1092 curve_controller->changeCurveType(trackId, new_segment->mID, curve_segment->mCurveTypes[c], c);
1097 for(
int c = 0; c < curve_segment->mCurves.size(); c++)
1099 for(
int i = 0; i < curve_segment->mCurves[c]->mPoints.size(); i++)
1101 curve_controller->changeCurvePoint(trackId, new_segment->mID, i, c,
1102 curve_segment->mCurves[c]->mPoints[i].mPos.mTime,
1103 curve_segment->mCurves[c]->mPoints[i].mPos.mValue);
1105 curve_controller->changeTanPoint(trackId, new_segment->mID, i, c, sequencecurveenums::IN,
1106 curve_segment->mCurves[c]->mPoints[i].mInTan.mTime,
1107 curve_segment->mCurves[c]->mPoints[i].mInTan.mValue);
1112 curve_controller->updateCurveSegments(trackId);
1115 updateSegmentsInClipboard(trackId);
1123 template<
typename T>
1124 void SequenceCurveTrackView::pasteClipboardSegmentInto(
const std::string& trackId,
const std::string& segmentId)
1130 assert(curve_segment_clipboard->getObjectCount() == 1);
1133 std::vector<std::unique_ptr<rtti::Object>> read_objects;
1134 std::vector<T *> curve_segments;
1138 curve_segments = curve_segment_clipboard->deserialize<T>(read_objects, errorState);
1142 T *curve_segment = curve_segments[0];
1144 assert(curve_segment !=
nullptr);
1150 const auto *target_segment = curve_controller.
getSegment(trackId, segmentId);
1153 assert(target_segment->get_type().template is_derived_from<T>());
1154 const T *target_segment_upcast =
static_cast<const T *
>(target_segment);
1157 for(
size_t c = 0; c < target_segment_upcast->mCurves.size(); c++)
1159 for(
size_t p = 1; p < target_segment_upcast->mCurves[c]->mPoints.size() - 1; p++)
1161 curve_controller.deleteCurvePoint(trackId, segmentId, p, c);
1166 curve_controller.segmentDurationChange(trackId, target_segment_upcast->mID, curve_segment->mDuration);
1169 for(
int c = 0; c < curve_segment->mCurves.size(); c++)
1171 for(
int i = 1; i < curve_segment->mCurves[c]->mPoints.size() - 1; i++)
1173 curve_controller.insertCurvePoint(trackId, target_segment_upcast->mID, curve_segment->mCurves[c]->mPoints[i].mPos.mTime, c);
1176 curve_controller.changeCurveType(trackId, target_segment_upcast->mID, curve_segment->mCurveTypes[c], c);
1181 for(
int c = 0; c < curve_segment->mCurves.size(); c++)
1183 for(
int i = 0; i < curve_segment->mCurves[c]->mPoints.size(); i++)
1185 curve_controller.changeCurvePoint(trackId, target_segment_upcast->mID, i, c,
1186 curve_segment->mCurves[c]->mPoints[i].mPos.mTime,
1187 curve_segment->mCurves[c]->mPoints[i].mPos.mValue);
1189 curve_controller.changeTanPoint(trackId, target_segment_upcast->mID, i, c, sequencecurveenums::IN,
1190 curve_segment->mCurves[c]->mPoints[i].mInTan.mTime,
1191 curve_segment->mCurves[c]->mPoints[i].mInTan.mValue);
1196 curve_controller.updateCurveSegments(trackId);
1199 updateSegmentsInClipboard(trackId);
1202 nap::Logger::error(errorState.
toString());
1207 template<
typename T>
1208 void SequenceCurveTrackView::handleChangeMinMaxCurve()
1210 auto *action = mState.mAction->template getDerived<sequenceguiactions::ChangeMinMaxCurve<T>>();
1211 auto &controller = getEditor().template getController<SequenceControllerCurve>();
1212 controller.template changeMinMaxCurveTrack<T>(action->mTrackID, action->mNewMin, action->mNewMax);
1214 mState.mDirty =
true;
1215 mState.mAction = sequenceguiactions::createAction<sequenceguiactions::None>();