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 =
static_cast<const SequenceTrackSegmentDuration*
>(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;
143 if(action->mTakeSnapshot)
145 action->mTakeSnapshot =
false;
150 action->mValue[curveIndex] * (action->mMaximum[curveIndex] - action->mMinimum[curveIndex]) +
151 action->mMinimum[curveIndex];
152 if(ImGui::InputFloat(
"value", &value))
154 float translated_value = (value - action->mMinimum[curveIndex]) /
155 (action->mMaximum[curveIndex] - action->mMinimum[curveIndex]);
170 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
172 ImGui::CloseCurrentPopup();
179 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
188 const ImVec2& trackTopLeft,
189 const float previousSegmentX,
190 const float segmentWidth,
191 const float segmentX,
192 ImDrawList* drawList)
197 bool needs_drawing = ImGui::IsRectVisible({trackTopLeft.x + previousSegmentX, trackTopLeft.y}, {
198 trackTopLeft.x + previousSegmentX + segmentWidth, trackTopLeft.y + track_height});
205 const long point_num = (int) (points_per_pixel * segmentWidth);
206 std::vector<std::vector<ImVec2>> curves;
207 for(
int v = 0; v < segment.mCurves.size(); v++)
209 std::vector<ImVec2> curve;
212 auto start_x = math::max<float>(trackTopLeft.x, 0);
218 for(; i <= point_num; i++)
220 float p = (float) i / (
float) point_num;
221 float x = trackTopLeft.x + previousSegmentX + segmentWidth * p;
224 float value = 1.0f - segment.mCurves[v]->evaluate(p);
229 trackTopLeft.y + value * track_height
231 curve.emplace_back(point);
242 curves.emplace_back(std::move(curve));
244 mCurveCache.emplace(segment.mID, std::move(curves));
248 int selected_curve = -1;
254 && ImGui::IsMouseHoveringRect(
255 {trackTopLeft.x + segmentX - segmentWidth, trackTopLeft.y},
256 {trackTopLeft.x + segmentX, trackTopLeft.y + track_height}))
259 ImVec2 mouse_pos = ImGui::GetMousePos();
261 ((mouse_pos.x - (trackTopLeft.x + segmentX - segmentWidth)) /
mState.
mStepSize) / segment.mDuration;
262 float y_in_segment = 1.0f - ((mouse_pos.y - trackTopLeft.y) / track_height);
264 for(
int i = 0; i < segment.mCurves.size(); i++)
267 float y_in_curve = segment.mCurves[i]->evaluate(x_in_segment);
270 const float maxDist = 0.1f;
271 if(std::abs(y_in_curve - y_in_segment) < maxDist)
273 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::HoveringCurve>(
278 if(ImGui::IsMouseClicked(1))
280 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::InsertingCurvePoint>(
289 if(selected_curve == -1)
291 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
296 segment, x_in_segment,
305 if(action->mSegmentID == segment.mID)
307 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
315 for(
int i = 0; i < segment.mCurves.size(); i++)
319 float thickness = selected_curve == i ? 3.0f : 1.0f;
321 drawList->AddPolyline
339 const ImVec2& trackTopLeft,
340 float previousSegmentX,
343 ImDrawList* drawList,
350 bool draw_selection_background =
false;
354 draw_selection_background = action->
mSegmentID == segment.
mID;
358 draw_selection_background = action->
mSegmentID == segment.
mID;
362 draw_selection_background = action->
mSegmentID == segment.
mID;
366 draw_selection_background = action->
mSegmentID == segment.
mID;
370 draw_selection_background = action->
mSegmentID == segment.
mID;
377 drawList->AddRectFilled(
378 { trackTopLeft.x + segmentX - segmentWidth, trackTopLeft.y },
380 ImGui::ColorConvertFloat4ToU32(curve_segment.mColor));
382 if(draw_selection_background)
384 drawList->AddRectFilled(
385 {trackTopLeft.x + segmentX - segmentWidth, trackTopLeft.y},
386 {trackTopLeft.x + segmentX, trackTopLeft.y + track_height},
387 ImGui::ColorConvertFloat4ToU32(ImVec4(1, 1, 1, 0.25f)));
401 drawList->AddRectFilled
403 {trackTopLeft.x + segmentX - segmentWidth, trackTopLeft.y},
404 {trackTopLeft.x + segmentX, trackTopLeft.y + track_height},
405 ImGui::ColorConvertFloat4ToU32(red)
423 drawControlPoints<T>(
442 sequencecurveenums::ESegmentValueTypes::BEGIN,
453 sequencecurveenums::ESegmentValueTypes::END,
463 T min = curve_track.mMinimum;
464 T max = curve_track.mMaximum;
467 ImGui::PushID(track.
mID.c_str());
469 float drag_float_x = ImGui::GetCursorPosX() + (40.0f *
mState.
mScale);
470 ImGui::SetCursorPos({ImGui::GetCursorPosX() + offset, ImGui::GetCursorPosY() + offset});
473 ImGui::PushID(
"min");
474 ImGui::SetCursorPosX(drag_float_x);
475 if(inputFloat<T>(min, 3))
477 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::ChangeMinMaxCurve<T>>(track.
mID, min, max);
480 ImGui::PopItemWidth();
481 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offset);
484 ImGui::PushID(
"max");
485 ImGui::SetCursorPosX(drag_float_x);
486 if(inputFloat<T>(max, 3))
488 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::ChangeMinMaxCurve<T>>(track.
mID, min, max);
491 ImGui::PopItemWidth();
500 const ImVec2& trackTopLeft,
501 const float segmentX,
502 const float segmentWidth,
504 ImDrawList* drawList)
534 for(
int v = 0; v < segment.mCurves.size(); v++)
537 ImVec2 segment_value_pos =
541 (
float) segment.mCurves[v]->mPoints[0].mPos.mValue :
542 (
float) segment.mCurves[v]->mPoints[
543 segment.mCurves[v]->mPoints.size() - 1].mPos.mValue) /
547 bool hovered =
false;
556 ImGui::IsMouseHoveringRect(
563 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::HoveringSegmentValue>(
569 if(ImGui::IsMouseDown(0))
571 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::DraggingSegmentValue>(
576 get_value_map[RTTI_OF(T)](segment, v, segmentType));
577 }
else if(ImGui::IsMouseDown(1))
582 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::EditingSegmentCurveValue<T>>(
587 (segmentType == sequencecurveenums::ESegmentValueTypes::BEGIN)
588 ? curve_segment.getStartValue() : curve_segment.getEndValue(),
589 curve_track.mMinimum,
590 curve_track.mMaximum);
606 if(action->mType == segmentType &&
607 action->mSegmentID == segment.mID &&
608 action->mCurveIndex == v)
610 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
627 if(action->mSegmentID == segment.mID)
629 if(action->mType == segmentType && action->mCurveIndex == v)
641 float value = get_value_map[RTTI_OF(T)](segment, v, segmentType) + drag_amount;
643 action->mNewValue = value;
662 const ImVec2& trackTopLeft,
663 const float segmentX,
664 const float segmentWidth,
665 ImDrawList* drawList)
672 if(track.
mSegments[0]->mID == segment.mID)
674 for(
int v = 0; v < segment.mCurves.size(); v++)
676 const auto &curve_point = segment.mCurves[v]->mPoints[0];
677 std::ostringstream string_stream;
678 string_stream << segment.mID <<
"_point_" << 0 <<
"_curve_" << v;
680 ImVec2 circle_point =
681 {(trackTopLeft.x + segmentX - segmentWidth) + segmentWidth * curve_point.mPos.mTime,
682 trackTopLeft.y + track_height * (1.0f - (
float) curve_point.mPos.mValue)};
689 segment, string_stream,
690 segmentWidth, curve_point, circle_point,
693 sequencecurveenums::ETanPointTypes::IN,
698 segment, string_stream,
699 segmentWidth, curve_point, circle_point,
702 sequencecurveenums::ETanPointTypes::OUT,
710 for(
int v = 0; v < segment.mCurves.size(); v++)
712 for(
int i = 1; i < segment.mCurves[v]->mPoints.size() - 1; i++)
715 const auto &curve_point = segment.mCurves[v]->mPoints[i];
716 std::ostringstream string_stream;
717 string_stream << segment.mID <<
"_point_" << i <<
"_curve_" << v;
718 std::string point_id = string_stream.str();
721 ImVec2 circle_point =
722 {(trackTopLeft.x + segmentX - segmentWidth) + segmentWidth * curve_point.mPos.mTime,
723 trackTopLeft.y + track_height * (1.0f - (
float) curve_point.mPos.mValue)};
726 bool hovered =
false;
733 && ImGui::IsMouseHoveringRect({circle_point.x - offset, circle_point.y - offset},
734 {circle_point.x + offset, circle_point.y + offset}))
743 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::HoveringControlPoint>(
752 segment, curve_point.mPos.mTime,
753 curve_point.mPos.mTime * segment.mDuration + segment.mStartTime,
757 if(ImGui::IsMouseDown(0))
759 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::DraggingControlPoint>(
764 curve_point.mPos.mTime,
765 curve_point.mPos.mValue);
768 else if(ImGui::IsMouseClicked(1))
770 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::CurvePointActionPopup<T>>(
775 curve_point.mPos.mValue,
776 curve_point.mPos.mTime,
786 if(action->mControlPointIndex == i && track.
mID == action->mTrackID &&
787 segment.mID == action->mSegmentID && v == action->mCurveIndex)
789 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
801 if(action->mSegmentID == segment.mID)
803 if(action->mControlPointIndex == i && action->mCurveIndex == v)
812 segment, curve_point.mPos.mTime,
813 curve_point.mPos.mTime * segment.mDuration + segment.mStartTime,
816 action->mNewValue += value_adjust;
817 action->mNewTime += time_adjust;
824 drawList->AddCircleFilled
835 segment, string_stream,
836 segmentWidth, curve_point, circle_point,
839 sequencecurveenums::ETanPointTypes::IN,
844 segment, string_stream,
845 segmentWidth, curve_point, circle_point,
848 sequencecurveenums::ETanPointTypes::OUT,
854 for(
int v = 0; v < segment.mCurves.size(); v++)
858 const int control_point_index = segment.mCurves[v]->mPoints.size() - 1;
859 const auto &curve_point = segment.mCurves[v]->mPoints[control_point_index];
861 std::ostringstream string_stream;
862 string_stream << segment.mID <<
"_point_" << control_point_index <<
"_curve_" << v;
863 std::string point_id = string_stream.str();
865 ImVec2 circle_point =
866 {(trackTopLeft.x + segmentX - segmentWidth) + segmentWidth * curve_point.mPos.mTime,
867 trackTopLeft.y + track_height * (1.0f - (
float) curve_point.mPos.mValue)};
873 segment, string_stream,
874 segmentWidth, curve_point, circle_point, control_point_index,
876 sequencecurveenums::ETanPointTypes::IN,
881 segment, string_stream,
882 segmentWidth, curve_point, circle_point, control_point_index,
884 sequencecurveenums::ETanPointTypes::OUT,
890 ImGui::SetCursorPosY(ImGui::GetCursorPosY() - track_height);
898 std::ostringstream& stringStream,
899 const float segmentWidth,
901 const ImVec2& circlePoint,
902 const int controlPointIndex,
903 const int curveIndex,
905 ImDrawList* drawList)
912 std::ostringstream tan_stream;
913 tan_stream << stringStream.str() << ((type == sequencecurveenums::ETanPointTypes::IN) ?
"inTan" :
"outTan");
921 ImVec2 offset = {tan_complex.
mTime * tan_constant_size,
922 static_cast<float>(tan_complex.
mValue) * -1.0f * tan_constant_size};
923 ImVec2 tan_point = {circlePoint.x + offset.x, circlePoint.y + offset.y};
926 bool tan_point_hovered =
false;
932 if((
mState.
mAction->template isAction<sequenceguiactions::None>() ||
933 mState.
mAction->template isAction<sequenceguiactions::HoveringCurve>() ||
934 mState.
mAction->template isAction<sequenceguiactions::HoveringSegment>())
935 && ImGui::IsMouseHoveringRect
937 {tan_point.x - tan_bounds, tan_point.y - tan_bounds},
938 {tan_point.x + tan_bounds, tan_point.y + tan_bounds})
941 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::HoveringTanPoint>(track.
mID, tan_stream.str());
942 tan_point_hovered =
true;
948 if(action->mTanPointID == tan_stream.str())
950 if(ImGui::IsMouseHoveringRect(
951 {tan_point.x - tan_bounds, tan_point.y - tan_bounds},
952 {tan_point.x + tan_bounds, tan_point.y + tan_bounds}))
955 tan_point_hovered =
true;
958 if(ImGui::IsMouseDown(0))
960 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::DraggingTanPoint>(
966 }
else if(ImGui::IsMouseDown(1))
968 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::EditingTanPointPopup>(
974 (
float) tan_complex.mValue,
980 mState.
mAction = sequenceguiactions::createAction<sequenceguiactions::None>();
990 if(action->mSegmentID == segment.
mID &&
991 action->mControlPointIndex == controlPointIndex &&
992 action->mType == type &&
993 action->mCurveIndex == curveIndex)
995 tan_point_hovered =
true;
1004 if(type == sequencecurveenums::ETanPointTypes::IN)
1007 curve_segment.
mCurves[curveIndex]->mPoints[controlPointIndex].mInTan.mTime + delta_time;
1008 new_value = curve_segment.mCurves[curveIndex]->mPoints[controlPointIndex].mInTan.mValue +
1012 new_time = curve_segment.
mCurves[curveIndex]->mPoints[controlPointIndex].mOutTan.mTime +
1014 new_value = curve_segment.mCurves[curveIndex]->mPoints[controlPointIndex].mOutTan.mValue +
1018 action->mNewTime = new_time;
1019 action->mNewValue = new_value;
1036 template<
typename T>
1037 bool SequenceCurveTrackView::pasteClipboardSegments(
const std::string &trackId,
double time,
utility::ErrorState &errorState)
1043 std::vector<std::unique_ptr<rtti::Object>> read_objects;
1046 std::vector<T *> curve_segments = curve_segment_clipboard->
deserialize<T>(read_objects, errorState);
1050 nap::Logger::error(errorState.
toString());
1054 assert(curve_segments.size() > 0);
1057 std::sort(curve_segments.begin(), curve_segments.end(), [](T *a, T *b)
1059 return a->mStartTime < b->mStartTime;
1063 if(curve_segments.size() > 0)
1065 curve_segments[0]->mStartTime = 0.0;
1067 for(
int i = 1; i < curve_segments.size(); i++)
1069 curve_segments[i]->mStartTime = curve_segments[i - 1]->mStartTime + curve_segments[i - 1]->mDuration;
1073 for(
auto curve_segment: curve_segments)
1076 auto *base_controller = getEditor().getControllerWithTrackID(trackId);
1079 assert(base_controller !=
nullptr);
1082 assert(base_controller->get_type().template is_derived_from<SequenceControllerCurve>());
1086 const auto *new_segment = curve_controller->
insertSegment(trackId, time + curve_segment->mStartTime);
1089 curve_controller->changeSegmentLabel(trackId, new_segment->mID, curve_segment->mLabel);
1092 curve_controller->segmentDurationChange(trackId, new_segment->mID, curve_segment->mDuration,
true);
1095 updateSegmentsInClipboard(trackId);
1098 for(
int c = 0; c < curve_segment->mCurves.size(); c++)
1100 for(
int i = 1; i < curve_segment->mCurves[c]->mPoints.size() - 1; i++)
1102 curve_controller->insertCurvePoint(trackId, new_segment->mID, curve_segment->mCurves[c]->mPoints[i].mPos.mTime, c);
1105 curve_controller->changeCurveType(trackId, new_segment->mID, curve_segment->mCurveTypes[c], c);
1110 for(
int c = 0; c < curve_segment->mCurves.size(); c++)
1112 for(
int i = 0; i < curve_segment->mCurves[c]->mPoints.size(); i++)
1114 curve_controller->changeCurvePoint(trackId, new_segment->mID, i, c,
1115 curve_segment->mCurves[c]->mPoints[i].mPos.mTime,
1116 curve_segment->mCurves[c]->mPoints[i].mPos.mValue);
1118 curve_controller->changeTanPoint(trackId, new_segment->mID, i, c, sequencecurveenums::IN,
1119 curve_segment->mCurves[c]->mPoints[i].mInTan.mTime,
1120 curve_segment->mCurves[c]->mPoints[i].mInTan.mValue);
1125 curve_controller->updateCurveSegments(trackId);
1128 updateSegmentsInClipboard(trackId);
1136 template<
typename T>
1137 void SequenceCurveTrackView::pasteClipboardSegmentInto(
const std::string& trackId,
const std::string& segmentId)
1143 assert(curve_segment_clipboard->getObjectCount() == 1);
1146 std::vector<std::unique_ptr<rtti::Object>> read_objects;
1147 std::vector<T *> curve_segments;
1151 curve_segments = curve_segment_clipboard->deserialize<T>(read_objects, errorState);
1155 T *curve_segment = curve_segments[0];
1157 assert(curve_segment !=
nullptr);
1163 const auto *target_segment = curve_controller.
getSegment(trackId, segmentId);
1166 assert(target_segment->get_type().template is_derived_from<T>());
1167 const T *target_segment_upcast =
static_cast<const T *
>(target_segment);
1170 for(
size_t c = 0; c < target_segment_upcast->mCurves.size(); c++)
1172 for(
size_t p = 1; p < target_segment_upcast->mCurves[c]->mPoints.size() - 1; p++)
1174 curve_controller.deleteCurvePoint(trackId, segmentId, p, c);
1179 curve_controller.segmentDurationChange(trackId, target_segment_upcast->mID, curve_segment->mDuration,
true);
1182 for(
int c = 0; c < curve_segment->mCurves.size(); c++)
1184 for(
int i = 1; i < curve_segment->mCurves[c]->mPoints.size() - 1; i++)
1186 curve_controller.insertCurvePoint(trackId, target_segment_upcast->mID, curve_segment->mCurves[c]->mPoints[i].mPos.mTime, c);
1189 curve_controller.changeCurveType(trackId, target_segment_upcast->mID, curve_segment->mCurveTypes[c], c);
1194 for(
int c = 0; c < curve_segment->mCurves.size(); c++)
1196 for(
int i = 0; i < curve_segment->mCurves[c]->mPoints.size(); i++)
1198 curve_controller.changeCurvePoint(trackId, target_segment_upcast->mID, i, c,
1199 curve_segment->mCurves[c]->mPoints[i].mPos.mTime,
1200 curve_segment->mCurves[c]->mPoints[i].mPos.mValue);
1202 curve_controller.changeTanPoint(trackId, target_segment_upcast->mID, i, c, sequencecurveenums::IN,
1203 curve_segment->mCurves[c]->mPoints[i].mInTan.mTime,
1204 curve_segment->mCurves[c]->mPoints[i].mInTan.mValue);
1209 curve_controller.updateCurveSegments(trackId);
1212 updateSegmentsInClipboard(trackId);
1215 nap::Logger::error(errorState.
toString());
1220 template<
typename T>
1221 void SequenceCurveTrackView::handleChangeMinMaxCurve()
1224 auto *action = mState.mAction->template getDerived<sequenceguiactions::ChangeMinMaxCurve<T>>();
1227 getEditor().takeSnapshot(action->get_type());
1230 auto &controller = getEditor().template getController<SequenceControllerCurve>();
1231 controller.template changeMinMaxCurveTrack<T>(action->mTrackID, action->mNewMin, action->mNewMax);
1234 mState.mDirty =
true;
1237 mState.mAction = sequenceguiactions::createAction<sequenceguiactions::None>();