Download CommonLua/Ged/XTemplates/AnimMetadataEditorTimeline.lua from sirnii/myspace: direct link, hf CLI and curl.
- Browser
- Download file 26.4 kB
-
https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/Ged/XTemplates/AnimMetadataEditorTimeline.lua
- Command line
-
hf download hf://spaces/sirnii/myspace/CommonLua/Ged/XTemplates/AnimMetadataEditorTimeline.lua
-
curl -L -o AnimMetadataEditorTimeline.lua https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/Ged/XTemplates/AnimMetadataEditorTimeline.lua
26.4 kB
| -- ========== GENERATED BY XTemplate Editor (Alt-F3) DO NOT EDIT MANUALLY! ========== | |
| PlaceObj('XTemplate', { | |
| __is_kind_of = "XDialog", | |
| group = "Common", | |
| id = "AnimMetadataEditorTimeline", | |
| recreate_after_save = true, | |
| save_in = "Ged", | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XDialog", | |
| 'Id', "idAnimMetadataEditorTimeline", | |
| 'Padding', box(0, 50, 0, 40), | |
| 'Dock', "box", | |
| 'HAlign', "center", | |
| 'VAlign', "bottom", | |
| 'MinWidth', 1000, | |
| 'MinHeight', 130, | |
| 'LayoutMethod', "HList", | |
| 'UseClipBox', false, | |
| 'HandleMouse', true, | |
| }, { | |
| PlaceObj('XTemplateWindow', { | |
| 'VAlign', "bottom", | |
| 'LayoutMethod', "HList", | |
| }, { | |
| PlaceObj('XTemplateWindow', { | |
| 'Margins', box(0, 0, 5, 0), | |
| 'VAlign', "center", | |
| 'LayoutMethod', "VList", | |
| }, { | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XText", | |
| 'Id', "idAnimationName", | |
| 'Margins', box(0, 0, 0, 5), | |
| 'TextStyle', "AnimMetadataEditorTimeline", | |
| 'TextHAlign', "center", | |
| }), | |
| PlaceObj('XTemplateWindow', { | |
| 'HAlign', "center", | |
| 'LayoutMethod', "HList", | |
| }, { | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XTextButton", | |
| 'Id', "idPlay", | |
| 'Margins', box(0, 0, 5, 0), | |
| 'HAlign', "left", | |
| 'VAlign', "center", | |
| 'MaxWidth', 30, | |
| 'MaxHeight', 30, | |
| 'OnPress', function (self, gamepad) | |
| GedOpAnimMetadataEditorPlay(self, GetAnimationMomentsEditorObject()) | |
| end, | |
| 'Image', "CommonAssets/UI/Ged/play", | |
| }), | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XTextButton", | |
| 'Id', "idStop", | |
| 'Margins', box(0, 0, 5, 0), | |
| 'HAlign', "left", | |
| 'VAlign', "center", | |
| 'MaxWidth', 30, | |
| 'MaxHeight', 30, | |
| 'GridX', 2, | |
| 'LayoutMethod', "None", | |
| 'OnPress', function (self, gamepad) | |
| GedOpAnimMetadataEditorStop(self, GetAnimationMomentsEditorObject()) | |
| end, | |
| 'Image', "CommonAssets/UI/Ged/pause", | |
| }), | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XToggleButton", | |
| 'Id', "idLoop", | |
| 'Margins', box(0, 0, 5, 0), | |
| 'HAlign', "left", | |
| 'VAlign', "center", | |
| 'MaxWidth', 30, | |
| 'MaxHeight', 30, | |
| 'GridX', 3, | |
| 'LayoutMethod', "None", | |
| 'OnPress', function (self, gamepad) | |
| GedOpAnimationMomentsEditorToggleLoop(self, GetAnimationMomentsEditorObject()) | |
| end, | |
| 'Image', "CommonAssets/UI/Ged/undo", | |
| }), | |
| }), | |
| }), | |
| PlaceObj('XTemplateWindow', { | |
| 'Id', "idTimeline", | |
| 'IdNode', true, | |
| 'Margins', box(5, 0, 5, 0), | |
| 'HAlign', "left", | |
| 'VAlign', "center", | |
| 'MinWidth', 1000, | |
| 'MinHeight', 60, | |
| 'MaxHeight', 60, | |
| 'GridX', 4, | |
| 'LayoutMethod', "None", | |
| 'BorderColor', RGBA(0, 255, 246, 255), | |
| 'Background', RGBA(0, 0, 0, 255), | |
| 'HandleMouse', true, | |
| }, { | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "DrawContent(self)", | |
| 'func', function (self) | |
| local obj = GetAnimationMomentsEditorObject() | |
| if not IsValid(obj) or not IsValidEntity(obj:GetEntity()) then return end | |
| -- draw current time | |
| local dragging = AnimMetadataEditorTimelineSelectedControl and AnimMetadataEditorTimelineSelectedControl.dragging | |
| local frame = obj:GetFrame() | |
| if dragging then | |
| local time = AnimMetadataEditorTimelineSelectedControl.moment.Time | |
| frame = obj:GetModifiedTime(time) | |
| else | |
| self:DrawLine(frame, RGB(0, 255, 0)) | |
| end | |
| local dlg = self.parent.parent | |
| local button_text = string.format("+New moment (%s)", FormatTimeline(frame, 3)) | |
| dlg:UpdateControl(frame, button_text, dlg:ResolveId("idMoment-NewMoment"), "above timeline") | |
| local enabled = dlg:GetEnabledMomentTypes() | |
| local moment_controls = dlg:GetMomentControls() | |
| table.sort(moment_controls, function(a, b) return a.moment.Time < b.moment.Time end) | |
| for index, control in ipairs(moment_controls) do | |
| local moment = control.moment | |
| if enabled[moment.Type] then | |
| local time, text = dlg:GetMomentTime(moment) | |
| self:DrawLine(time, RGB(255, 0, 0)) | |
| dlg:UpdateControl(time, text, control, index % 2 == 1) | |
| end | |
| end | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "OnMouseButtonDown(self, pos, button)", | |
| 'func', function (self, pos, button) | |
| if button ~= "L" then return end | |
| AnimMetadataEditorTimelineDragging = true | |
| self:UpdateFrame(pos) | |
| return "break" | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "OnMouseButtonUp(self, pos, button)", | |
| 'func', function (self, pos, button) | |
| if button ~= "L" then return end | |
| if not AnimMetadataEditorTimelineDragging then return end | |
| self:UpdateFrame(pos) | |
| AnimMetadataEditorTimelineDragging = false | |
| self.parent.parent:CreateNewMomentControl() | |
| local timeline = GetDialog("AnimMetadataEditorTimeline") | |
| if timeline then | |
| timeline:DeselectMoment() | |
| end | |
| return "break" | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "OnMousePos(self, pos)", | |
| 'func', function (self, pos) | |
| if not AnimMetadataEditorTimelineDragging then return end | |
| DeleteThread(AnimMetadataEditorTimelineDragging) | |
| AnimMetadataEditorTimelineDragging = CreateMapRealTimeThread(function() | |
| self:DrawContent() | |
| self:UpdateFrame(pos, "delayed moments binding") | |
| end) | |
| return "break" | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "UpdateFrame(self, pos, delayed_moments_binding)", | |
| 'func', function (self, pos, delayed_moments_binding) | |
| local frame = self:GetFrame(pos) | |
| if frame then | |
| local obj = GetAnimationMomentsEditorObject() | |
| obj:SetFrame(frame, delayed_moments_binding) | |
| GedObjectModified(obj) | |
| end | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "MoveFrame(self, time)", | |
| 'func', function (self, time) | |
| local obj = GetAnimationMomentsEditorObject() | |
| if AnimMetadataEditorTimelineSelectedControl then | |
| local moment = AnimMetadataEditorTimelineSelectedControl.moment | |
| obj:SetFrame(obj:GetModifiedTime(moment.Time)) | |
| local duration = obj:GetAbsoluteTime(obj.anim_duration) | |
| moment.Time = Clamp(obj:GetAbsoluteTime(obj.Frame) + time, 0, duration - 1) | |
| obj:SetFrame(obj:GetModifiedTime(moment.Time)) | |
| else | |
| obj:SetFrame(obj:GetAbsoluteTime(obj.Frame) + time) | |
| end | |
| GedObjectModified(obj) | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "DrawLine(self, frame, color)", | |
| 'func', function (self, frame, color) | |
| local obj = GetAnimationMomentsEditorObject() | |
| if not obj then return end | |
| local duration = Max(obj.anim_duration, 1) | |
| local b = self.box | |
| local width = b:sizex() | |
| local column = b:minx() + width * frame / duration | |
| UIL.DrawLine(point(column, b:miny()), point(column, b:maxy()), color) | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "GetFrame(self, pos)", | |
| 'func', function (self, pos) | |
| local obj = GetAnimationMomentsEditorObject() | |
| if not obj then return end | |
| local duration = obj.anim_duration | |
| if duration <= 0 then return end | |
| local control = AnimMetadataEditorTimelineSelectedControl | |
| local box = self.box | |
| local width = box:sizex() | |
| local column = pos:x() - box:minx() | |
| if not (control and control.dragging) then | |
| column = Clamp(column, 0, width) | |
| end | |
| return MulDivTrunc(duration, column, width) | |
| end, | |
| }), | |
| }), | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XText", | |
| 'Id', "idDuration", | |
| 'Margins', box(5, 0, 5, 0), | |
| 'HAlign', "left", | |
| 'VAlign', "center", | |
| 'MinWidth', 50, | |
| 'MaxHeight', 30, | |
| 'GridX', 5, | |
| 'LayoutMethod', "None", | |
| 'TextStyle', "AnimMetadataEditorTimeline", | |
| 'Text', "Duration", | |
| 'TextVAlign', "center", | |
| }), | |
| }), | |
| PlaceObj('XTemplateWindow', { | |
| 'GridX', 6, | |
| 'GridStretchX', false, | |
| 'GridStretchY', false, | |
| 'LayoutMethod', "VList", | |
| 'LayoutVSpacing', 5, | |
| }, { | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XText", | |
| 'HAlign', "center", | |
| 'MinWidth', 50, | |
| 'MaxHeight', 20, | |
| 'LayoutMethod', "None", | |
| 'HandleKeyboard', false, | |
| 'HandleMouse', false, | |
| 'TextStyle', "AnimMetadataEditorTimeline", | |
| 'Text', "Preview Speed", | |
| 'TextHAlign', "center", | |
| 'TextVAlign', "center", | |
| }), | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XToggleButton", | |
| 'Id', "idSpeed100", | |
| 'BorderWidth', 1, | |
| 'HAlign', "center", | |
| 'MinWidth', 50, | |
| 'Background', RGBA(134, 134, 134, 255), | |
| 'OnPress', function (self, gamepad) | |
| GedOpAnimationMomentsEditorToggleSpeed(self, 100) | |
| self:SetToggled(true) | |
| self:ResolveId("idSpeed50"):SetToggled(false) | |
| self:ResolveId("idSpeed20"):SetToggled(false) | |
| self:ResolveId("idSpeed10"):SetToggled(false) | |
| end, | |
| 'RolloverBackground', RGBA(178, 178, 178, 255), | |
| 'PressedBackground', RGBA(172, 172, 172, 255), | |
| 'Text', "100%", | |
| 'Toggled', true, | |
| 'ToggledBackground', RGBA(204, 204, 204, 255), | |
| }), | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XToggleButton", | |
| 'Id', "idSpeed50", | |
| 'BorderWidth', 1, | |
| 'HAlign', "center", | |
| 'MinWidth', 50, | |
| 'Background', RGBA(134, 134, 134, 255), | |
| 'OnPress', function (self, gamepad) | |
| GedOpAnimationMomentsEditorToggleSpeed(self, 50) | |
| self:SetToggled(true) | |
| self:ResolveId("idSpeed100"):SetToggled(false) | |
| self:ResolveId("idSpeed20"):SetToggled(false) | |
| self:ResolveId("idSpeed10"):SetToggled(false) | |
| end, | |
| 'RolloverBackground', RGBA(178, 178, 178, 255), | |
| 'PressedBackground', RGBA(172, 172, 172, 255), | |
| 'Text', "50%", | |
| 'ToggledBackground', RGBA(204, 204, 204, 255), | |
| }), | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XToggleButton", | |
| 'Id', "idSpeed20", | |
| 'BorderWidth', 1, | |
| 'HAlign', "center", | |
| 'MinWidth', 50, | |
| 'Background', RGBA(134, 134, 134, 255), | |
| 'OnPress', function (self, gamepad) | |
| GedOpAnimationMomentsEditorToggleSpeed(self, 20) | |
| self:SetToggled(true) | |
| self:ResolveId("idSpeed100"):SetToggled(false) | |
| self:ResolveId("idSpeed50"):SetToggled(false) | |
| self:ResolveId("idSpeed10"):SetToggled(false) | |
| end, | |
| 'RolloverBackground', RGBA(178, 178, 178, 255), | |
| 'PressedBackground', RGBA(172, 172, 172, 255), | |
| 'Text', "20%", | |
| 'ToggledBackground', RGBA(204, 204, 204, 255), | |
| }), | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XToggleButton", | |
| 'Id', "idSpeed10", | |
| 'BorderWidth', 1, | |
| 'HAlign', "center", | |
| 'MinWidth', 50, | |
| 'Background', RGBA(134, 134, 134, 255), | |
| 'OnPress', function (self, gamepad) | |
| GedOpAnimationMomentsEditorToggleSpeed(self, 10) | |
| self:SetToggled(true) | |
| self:ResolveId("idSpeed100"):SetToggled(false) | |
| self:ResolveId("idSpeed50"):SetToggled(false) | |
| self:ResolveId("idSpeed20"):SetToggled(false) | |
| end, | |
| 'RolloverBackground', RGBA(178, 178, 178, 255), | |
| 'PressedBackground', RGBA(172, 172, 172, 255), | |
| 'Text', "10%", | |
| 'ToggledBackground', RGBA(204, 204, 204, 255), | |
| }), | |
| }), | |
| PlaceObj('XTemplateWindow', { | |
| 'Id', "idFilters", | |
| 'Margins', box(10, 0, 10, 0), | |
| 'BorderWidth', 1, | |
| 'Padding', box(5, 2, 5, 2), | |
| 'GridX', 6, | |
| 'GridStretchX', false, | |
| 'GridStretchY', false, | |
| 'LayoutMethod', "VList", | |
| 'LayoutVSpacing', 5, | |
| 'Background', RGBA(128, 128, 128, 255), | |
| }, { | |
| PlaceObj('XTemplateWindow', { | |
| '__class', "XText", | |
| 'HAlign', "center", | |
| 'MinWidth', 50, | |
| 'MaxHeight', 20, | |
| 'LayoutMethod', "None", | |
| 'HandleKeyboard', false, | |
| 'HandleMouse', false, | |
| 'TextStyle', "AnimMetadataEditorTimeline", | |
| 'Text', "Moments Filter", | |
| 'TextHAlign', "center", | |
| 'TextVAlign', "center", | |
| }), | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "CreateNewMomentControl(self)", | |
| 'func', function (self) | |
| local obj = GetAnimationMomentsEditorObject() | |
| local id = "idMoment-NewMoment" | |
| local control = rawget(self, id) | |
| if not control then | |
| control = XTextButton:new({Id = id}, self) | |
| self:InitControl(control) | |
| control.OnMouseButtonDown = function(this, pos, button) | |
| if button == "L" then | |
| CreateRealTimeThread(function() | |
| local time = obj:GetProperty("Frame") | |
| local moments = ActionMomentNamesCombo() | |
| local moment = WaitListChoice(terminal.desktop, moments, "Select Moment Type", | |
| 1, nil, "free_input") | |
| if moment then | |
| self:OnNewMoment(moment, time) | |
| end | |
| end) | |
| return "break" | |
| end | |
| end | |
| end | |
| self:UpdateControl(obj.Frame, "+New Moment", control, "above timeline") | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "DeleteNewMomentControl(self)", | |
| 'func', function (self) | |
| local control = self:ResolveId("idMoment-NewMoment") | |
| if control then | |
| control:delete() | |
| end | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "CreateMomentControls(self, ...)", | |
| 'func', function (self, ...) | |
| local obj = GetAnimationMomentsEditorObject() | |
| if not obj then return end | |
| for i = #self, 1, -1 do | |
| local control = self[i] | |
| if string.match(control.Id, "^idMoment-") then | |
| control:delete() | |
| end | |
| end | |
| -- current current time control | |
| local control = XText:new({Id = "idMoment-CurrentMoment"}, self) | |
| control:SetTextStyle(self.idDuration:GetTextStyle()) | |
| control:SetDock("ignore") | |
| self:UpdateControl(obj.Frame, FormatTimeline(obj.Frame), control, "above timeline") | |
| if obj.anim_speed == 0 then | |
| self:CreateNewMomentControl() | |
| end | |
| -- create moment controls | |
| local visible_types = self:GetEnabledMomentTypes() | |
| local moment_types = {} | |
| local moments = obj:GetAnimMoments() | |
| table.sortby_field(moments, "Time") | |
| for index, moment in ipairs(moments) do | |
| moment_types[moment.Type] = true | |
| local visible = visible_types[moment.Type] | |
| if visible == nil or visible == true then | |
| local control = XTextButton:new({Id = "idMoment", moment = moment, offset = 0, dragging = false, update_thread = false}, self) | |
| self:InitControl(control) | |
| local time, text = self:GetMomentTime(moment) | |
| self:UpdateControl(time, text, control, index % 2 == 1) | |
| control.OnMouseButtonDown = function(this, pos, button) | |
| if button == "L" then | |
| self:DeselectMoment() | |
| AnimMetadataEditorTimelineSelectedControl = this | |
| this:SetBackground(RGBA(38, 146, 227, 255)) | |
| local frame = self.idTimeline:GetFrame(pos) | |
| local time = obj:GetAbsoluteTime(frame) | |
| AnimMetadataEditorTimelineSelectedControl.offset = time - this.moment.Time | |
| AnimMetadataEditorTimelineSelectedControl.dragging = true | |
| this.moment.AnimRevision = obj.AnimRevision | |
| self:DeleteNewMomentControl() | |
| return "break" | |
| elseif button == "R" then | |
| CreateRealTimeThread(function() | |
| if terminal.IsKeyPressed(const.vkControl) then | |
| local actors = ActorFXClassCombo() | |
| table.remove_value(actors, "any") | |
| local actor = WaitListChoice(terminal.desktop, actors, "Select Actor", | |
| 1, nil, "free_input") | |
| if actor then | |
| moment.Actor = actor | |
| end | |
| else | |
| local actions = ActionFXClassCombo() | |
| table.remove_value(actions, "any") | |
| local fx = WaitListChoice(terminal.desktop, actions, "Select FX", | |
| 1, nil, "free_input") | |
| if fx then | |
| moment.FX = fx | |
| end | |
| end | |
| end) | |
| return "break" | |
| end | |
| end | |
| control.OnMouseButtonUp = function(this, pos, button) | |
| if button ~= "L" then return end | |
| if not AnimMetadataEditorTimelineSelectedControl then return end | |
| DeleteThread(AnimMetadataEditorTimelineSelectedControl.update_thread) | |
| local dragging = AnimMetadataEditorTimelineSelectedControl | |
| local moment = dragging.moment | |
| local frame = self.idTimeline:GetFrame(pos) | |
| local time = obj:GetAbsoluteTime(frame) | |
| local duration = obj:GetAbsoluteTime(obj.anim_duration) | |
| moment.Time = Clamp(time - dragging.offset, 0, duration - 1) | |
| table.sortby_field(moments, "Time") | |
| dragging.update_thread = false | |
| dragging.dragging = false | |
| AnimationMomentsEditorBindObjects(obj) | |
| self:CreateNewMomentControl() | |
| obj:SetFrame(obj:GetModifiedTime(moment.Time)) -- NOTE: green line should be underneath moment red line(invisible) | |
| return "break" | |
| end | |
| control.OnMousePos = function(this, pos) | |
| if not AnimMetadataEditorTimelineSelectedControl then return end | |
| if not AnimMetadataEditorTimelineSelectedControl.dragging then return end | |
| local dragging = AnimMetadataEditorTimelineSelectedControl | |
| local moment = dragging.moment | |
| local frame = self.idTimeline:GetFrame(pos) | |
| local time = obj:GetAbsoluteTime(frame) | |
| local duration = obj:GetAbsoluteTime(obj.anim_duration) | |
| moment.Time = Clamp(time - dragging.offset, 0, duration - 1) | |
| if not dragging.update_thread then | |
| dragging.update_thread = CreateRealTimeThread(function() | |
| obj:SetFrame(obj:GetModifiedTime(moment.Time), "delayed moments binding") | |
| table.sortby_field(moments, "Time") | |
| dragging.update_thread = false | |
| end) | |
| end | |
| return "break" | |
| end | |
| control.OnMouseButtonDoubleClick = function(this, pos, button) | |
| if button ~= "L" then return end | |
| this.moment.AnimRevision = obj.AnimRevision | |
| obj:SetFrame(obj:GetModifiedTime(self:GetMomentTime(this.moment))) | |
| return "break" | |
| end | |
| end | |
| end | |
| -- add check buttons for hiding/showing different moment types | |
| local parent = self:ResolveId("idFilters") | |
| for i = #parent, 1, -1 do | |
| local control = parent[i] | |
| if IsKindOf(control, "XCheckButton") then | |
| control:delete() | |
| end | |
| end | |
| parent:SetVisible(next(moment_types)) | |
| for _, moment_type in ipairs(table.keys2(moment_types, "sorted")) do | |
| local check = XCheckButton:new({ moment_type = moment_type }, parent) | |
| check:SetCheck(true) | |
| if visible_types[moment_type] ~= nil then | |
| check:SetCheck(visible_types[moment_type]) | |
| end | |
| check:SetText(moment_type) | |
| check.OnChange = function(check, value) | |
| self:CreateMomentControls() | |
| --[[for i = #self, 1, -1 do | |
| local control = self[i] | |
| if control.moment and control.moment.Type == check.moment_type then | |
| control:SetVisible(value) | |
| end | |
| end ]] | |
| end | |
| end | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "GetMomentControls(self)", | |
| 'func', function (self) | |
| -- draw moments | |
| local moment_controls = {} | |
| for _, control in ipairs(self) do | |
| if control.Id == "idMoment" then | |
| table.insert(moment_controls, control) | |
| end | |
| end | |
| return moment_controls | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "GetEnabledMomentTypes(self)", | |
| 'func', function (self) | |
| local enabled = {} | |
| for _, control in ipairs(self:ResolveId("idFilters")) do | |
| if control.moment_type then | |
| enabled[control.moment_type] = control:GetCheck() | |
| end | |
| end | |
| return enabled | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "InitControl(self, control)", | |
| 'func', function (self, control) | |
| control:SetTextStyle(self.idDuration:GetTextStyle()) | |
| control:SetDock("ignore") | |
| control:SetBackground(RGBA(128, 128, 128, 255)) | |
| control:SetRolloverBackground(RGBA(192, 192, 192, 255)) | |
| control:SetImage("CommonAssets/UI/round-frame-20.tga") | |
| control:SetImageScale(point(500, 500)) | |
| control:SetFrameBox(box(9, 9, 9, 9)) | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "UpdateControl(self, time, text, control, above_timeline)", | |
| 'func', function (self, time, text, control, above_timeline) | |
| if not control then return end | |
| local tw, th = control:Measure(1000000, 1000000) | |
| local b = self.idTimeline.box | |
| local width = b:sizex() | |
| local duration = GetAnimationMomentsEditorObject().anim_duration | |
| local column = b:minx() + width * time / Max(1, duration) | |
| local y = above_timeline and b:miny() - 5 - th or b:maxy() + 5 | |
| if control.Id == "idMoment-NewMoment" then | |
| y = y - control.box:sizey() - 5 | |
| end | |
| control:SetBox(column - tw / 2, y, tw, th) | |
| local l, u, r, b = control.Padding:xyxy() | |
| local x1, y1, x2, y2 = control.box:xyxy() | |
| control:SetBox(x1 - l, y1 - u, x2 - x1 + l + r, y2 - y1 + u + b) | |
| control:SetText(text) | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "DeleteMoment(self,moment)", | |
| 'func', function (self,moment) | |
| local obj = GetAnimationMomentsEditorObject() | |
| local moments = obj:GetAnimMoments() | |
| table.remove_entry(moments, moment) | |
| self:CreateMomentControls() | |
| AnimationMomentsEditorBindObjects(obj) | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "DeselectMoment(self)", | |
| 'func', function (self) | |
| if AnimMetadataEditorTimelineSelectedControl then | |
| AnimMetadataEditorTimelineSelectedControl:SetBackground(RGBA(128, 128, 128, 255)) | |
| AnimMetadataEditorTimelineSelectedControl = false | |
| end | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "SelectMoment(self, control)", | |
| 'func', function (self, control) | |
| AnimMetadataEditorTimelineSelectedControl = control | |
| control:SetBackground(RGBA(38, 146, 227, 255)) | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "OnNewMoment(self, moment, time)", | |
| 'func', function (self, moment, time) | |
| local obj = GetAnimationMomentsEditorObject() | |
| local entity, anim, anim_preset = GetOrCreateAnimMetadata(obj) | |
| local ent_speed = GetStateSpeedModifier(entity, GetStateIdx(anim)) | |
| local absolute_time = MulDivTrunc(time, ent_speed, const.AnimSpeedScale) | |
| local new_moment = AnimMoment:new{ | |
| Type = moment, | |
| Time = absolute_time, | |
| AnimRevision = obj.AnimRevision, | |
| parent = anim_preset | |
| } | |
| anim_preset.Moments = anim_preset.Moments or {} | |
| table.insert_sorted(anim_preset.Moments, new_moment, "Time") | |
| UpdateParentTable(new_moment, anim_preset) | |
| AnimationMomentsEditorBindObjects(obj) | |
| self:CreateMomentControls() | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "GetMomentTime(self, moment)", | |
| 'func', function (self, moment) | |
| local obj = GetAnimationMomentsEditorObject() | |
| local time = obj:GetModifiedTime(moment.Time) | |
| local text = string.format("%s %s", moment.Type, FormatTimeline(time)) | |
| return time, text | |
| end, | |
| }), | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "OnMouseButtonDown(self, pos, button)", | |
| 'func', function (self, pos, button) | |
| local timeline = GetDialog("AnimMetadataEditorTimeline") | |
| if not timeline then return "continue" end | |
| local moment_controls = timeline:GetMomentControls() | |
| for _, control in ipairs(moment_controls) do | |
| if pos:InBox(control.box) then | |
| return control:OnMouseButtonDown(pos, button) | |
| end | |
| end | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "OnMousePos(self, pos)", | |
| 'func', function (self, pos) | |
| if AnimMetadataEditorTimelineDragging then | |
| local timeline = GetDialog("AnimMetadataEditorTimeline") | |
| if not timeline then return "continue" end | |
| return timeline.idTimeline:OnMousePos(pos) | |
| elseif AnimMetadataEditorTimelineSelectedControl then | |
| return AnimMetadataEditorTimelineSelectedControl:OnMousePos(pos) | |
| end | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "OnMouseButtonUp(self, pos, button)", | |
| 'func', function (self, pos, button) | |
| if AnimMetadataEditorTimelineSelectedControl and AnimMetadataEditorTimelineSelectedControl.dragging then | |
| return AnimMetadataEditorTimelineSelectedControl:OnMouseButtonUp(pos, button) | |
| end | |
| if AnimMetadataEditorTimelineDragging then | |
| local timeline = GetDialog("AnimMetadataEditorTimeline") | |
| if not timeline then return "continue" end | |
| return timeline.idTimeline:OnMouseButtonUp(pos, button) | |
| end | |
| end, | |
| }), | |
| PlaceObj('XTemplateFunc', { | |
| 'name', "OnShortcut(self, shortcut, source, ...)", | |
| 'func', function (self, shortcut, source, ...) | |
| if not AnimationMomentsEditor then return end | |
| local timeline = GetDialog("AnimMetadataEditorTimeline") | |
| if not timeline then return "continue" end | |
| if AnimMetadataEditorTimelineSelectedControl then | |
| if shortcut == "Delete" then | |
| timeline:DeleteMoment(AnimMetadataEditorTimelineSelectedControl.moment) | |
| AnimMetadataEditorTimelineSelectedControl = false | |
| return "break" | |
| elseif shortcut == "Escape" then | |
| timeline:DeselectMoment() | |
| return "break" | |
| end | |
| end | |
| if shortcut == "Left" then | |
| local obj = GetAnimationMomentsEditorObject() | |
| if obj.anim_speed == 0 then | |
| local time = terminal.IsKeyPressed(const.vkControl) and 100 or 1 | |
| timeline.idTimeline:MoveFrame(-time) | |
| end | |
| return "break" | |
| elseif shortcut == "Right" then | |
| local obj = GetAnimationMomentsEditorObject() | |
| if obj.anim_speed == 0 then | |
| local time = terminal.IsKeyPressed(const.vkControl) and 100 or 1 | |
| timeline.idTimeline:MoveFrame(time) | |
| end | |
| return "break" | |
| elseif shortcut == "Up" or shortcut == "Down" then | |
| local obj = GetAnimationMomentsEditorObject() | |
| local frame = obj:GetFrame() | |
| local moment_controls = timeline:GetMomentControls() | |
| if shortcut == "Up" then | |
| for _, control in ipairs(moment_controls) do | |
| local moment_frame = control.moment.Time | |
| local time = obj:GetAbsoluteTime(moment_frame) | |
| if time > frame then | |
| obj:SetFrame(obj:GetModifiedTime(moment_frame)) | |
| timeline:SelectMoment(control) | |
| break | |
| end | |
| end | |
| else | |
| for i = #moment_controls, 1, -1 do | |
| local control = moment_controls[i] | |
| local moment_frame = control.moment.Time | |
| local time = obj:GetAbsoluteTime(moment_frame) | |
| if time < frame then | |
| obj:SetFrame(obj:GetModifiedTime(moment_frame)) | |
| timeline:SelectMoment(control) | |
| break | |
| end | |
| end | |
| end | |
| return "break" | |
| end | |
| if shortcut == "Space" and not AnimMetadataEditorTimelineDragging then | |
| local obj = GetAnimationMomentsEditorObject() | |
| if obj.anim_speed == 0 then | |
| GedOpAnimMetadataEditorPlay(self, GetAnimationMomentsEditorObject()) | |
| else | |
| GedOpAnimMetadataEditorStop(self, GetAnimationMomentsEditorObject()) | |
| end | |
| return "break" | |
| end | |
| end, | |
| }), | |
| }) | |