|
local max_curve_points = 8 |
|
|
|
DefineClass.XCurveEditor = { |
|
__parents = { "XControl", "XActionsHost" }, |
|
|
|
properties = { |
|
{ category = "General", id = "ControlPoints", editor = "number", default = 4, min = 2, max = max_curve_points, }, |
|
{ category = "General", id = "MaxX", editor = "number", default = 1000, min = 1 }, |
|
{ category = "General", id = "MinX", editor = "number", default = 0, min = 1 }, |
|
{ category = "General", id = "MaxY", editor = "number", default = 1000, min = 1 }, |
|
{ category = "General", id = "MinY", editor = "number", default = 0 }, |
|
{ category = "General", id = "DisplayScaleX", editor = "number", default = 1000, min = 1, help = "Used for displaying numbers around the graph" }, |
|
{ category = "General", id = "DisplayScaleY", editor = "number", default = 1000, min = 1, help = "Used for displaying numbers around the graph"}, |
|
{ category = "General", id = "SnapX", editor = "number", default = 1, min = 1 }, |
|
{ category = "General", id = "SnapY", editor = "number", default = 1, min = 1 }, |
|
{ category = "General", id = "FixedX", editor = "bool", default = false }, |
|
{ category = "General", id = "PushPointsOnMove", editor = "bool", default = true, }, |
|
{ category = "General", id = "CurveColor", editor = "color", default = RGB(0,0,0), }, |
|
{ category = "General", id = "ControlPointMaxDist", editor = "number", default = 25, }, |
|
{ category = "General", id = "ControlPointColor", editor = "color", default = RGB(80, 80, 80), }, |
|
{ category = "General", id = "ControlPointCaptureColor", editor = "color", default = RGB(0,0,0), }, |
|
{ category = "General", id = "ControlPointHoverColor", editor = "color", default = RGB(130, 130, 130), }, |
|
{ category = "General", id = "GridUnitX", editor = "number", default = 100, }, |
|
{ category = "General", id = "GridUnitY", editor = "number", default = 100, }, |
|
{ category = "General", id = "GridColor", editor = "color", default = RGB(180, 180, 180), }, |
|
{ category = "General", id = "Smooth", editor = "bool", default = true, }, |
|
{ category = "General", id = "ReadOnly", editor = "bool", default = false, }, |
|
{ category = "General", id = "MinMaxRangeMode", editor = "bool", defalt = false, help = "Stores the /Min/ Value in point.z" }, |
|
}, |
|
|
|
OnCurveChanged = false, |
|
point_handles = false, |
|
capture_handle = false, |
|
hover_handle = false, |
|
points = false, |
|
scale_texts = false, |
|
font_id = false, |
|
|
|
text_space_required = false, |
|
MinMaxRangeMode = false, |
|
} |
|
|
|
|
|
for i = 1, max_curve_points do |
|
local xname = "x" .. i |
|
local yname = "y" .. i |
|
table.insert(XCurveEditor.properties, { |
|
category = "General", id = xname, editor = "number", min = 0, default = 0, |
|
max = function(obj) return obj.MaxX end, slider = true, |
|
no_edit = function(obj) return i > obj.ControlPoints end, |
|
}) |
|
table.insert(XCurveEditor.properties, { |
|
category = "General", id = yname, editor = "number", min = 0, default = 0, |
|
max = function(obj) return obj.MaxY end, slider = true, |
|
no_edit = function(obj) return i > obj.ControlPoints end, |
|
}) |
|
XCurveEditor["Get" .. xname] = function(obj) return obj.points[i]:x() end |
|
XCurveEditor["Get" .. yname] = function(obj) return obj.points[i]:y() end |
|
XCurveEditor["Set" .. xname] = function(obj, value) obj:MovePoint(i, obj.points[i]:SetX(value)) end |
|
XCurveEditor["Set" .. yname] = function(obj, value) obj:MovePoint(i, obj.points[i]:SetY(value)) end |
|
end |
|
|
|
function XCurveEditor:GeneratePointUIElements() |
|
self.point_handles = {} |
|
for idx, pt in pairs(self.points) do |
|
local main_handle = XCurveEditorHandle:new({ |
|
point_idx = idx, |
|
curve_editor = self, |
|
}) |
|
|
|
table.insert(self.point_handles, main_handle) |
|
|
|
if self.MinMaxRangeMode then |
|
local handle = XCurveEditorMinHandle:new({ |
|
point_idx = idx, |
|
curve_editor = self, |
|
parent = main_handle, |
|
}) |
|
|
|
table.insert(self.point_handles, handle) |
|
handle = XCurveEditorMaxHandle:new({ |
|
point_idx = idx, |
|
curve_editor = self, |
|
parent = main_handle, |
|
}) |
|
|
|
table.insert(self.point_handles, handle) |
|
end |
|
end |
|
end |
|
|
|
function XCurveEditor:GetRange() |
|
return point(self.MaxX - self.MinX, self.MaxY - self.MinY, self.MaxY - self.MinY) |
|
end |
|
|
|
function XCurveEditor:GetRangeMin() |
|
return point(self.MinX, self.MinY, self.MinY) |
|
end |
|
|
|
function XCurveEditor:GetRangeMax() |
|
return point(self.MaxX, self.MaxY, self.MaxY) |
|
end |
|
|
|
function XCurveEditor:Init() |
|
self.points = { } |
|
local max_points = self.ControlPoints - 1 |
|
local range = self:GetRange() |
|
assert(range:x() > 0 and range:y() > 0) |
|
for i = 0, max_points do |
|
local y = i * range:y() / max_points |
|
table.insert(self.points, point(i * range:x() / max_points, y, y)) |
|
end |
|
self:GeneratePointUIElements() |
|
|
|
end |
|
|
|
function XCurveEditor:GetControlPointSize() |
|
return point(ScaleXY(self.scale, 10, 10)) |
|
end |
|
|
|
function XCurveEditor:GetGraphBox() |
|
local control_size = self:GetControlPointSize() |
|
local topleft_padding = control_size / 2 |
|
local bottomright_padding = control_size / 2 |
|
|
|
local text_space_required = self.text_space_required |
|
if text_space_required then |
|
bottomright_padding = point(Max(text_space_required:x(), bottomright_padding:x()), Max(text_space_required:y(), bottomright_padding:y())) |
|
end |
|
return box(self.content_box:min() + topleft_padding, self.content_box:max() - bottomright_padding) |
|
end |
|
|
|
function XCurveEditor:TransformPoint(pos) |
|
local draw_box = self:GetGraphBox() |
|
local ranges = self:GetRange() |
|
local base = point(draw_box:minx(), draw_box:maxy()) |
|
|
|
pos = pos - self:GetRangeMin() |
|
pos = point(pos:x(), -pos:y()) |
|
return base + MulDivRoundPoint(draw_box:size(), pos, ranges) |
|
end |
|
|
|
local function FitScaleTexts(min_value, max_value, display_scale, size_getter, available_space, min_space_between) |
|
local begin_text = FormatNumberProp(min_value, display_scale, 2) |
|
local end_text = FormatNumberProp(max_value, display_scale, 2) |
|
local text_list = {} |
|
local secondary_axis_length = 0 |
|
|
|
local function subdivide(left_value, right_value, left_pos, right_pos) |
|
left_pos = left_pos + min_space_between |
|
right_pos = right_pos - min_space_between |
|
local diff = right_pos - left_pos |
|
if diff <= 10 then |
|
return |
|
end |
|
local target_value = (left_value + right_value) / 2 |
|
local text = FormatNumberProp(target_value, display_scale, 2) |
|
local size, secondary_len = size_getter(text) |
|
if size > diff then |
|
return |
|
end |
|
secondary_axis_length = Max(secondary_axis_length, secondary_len) |
|
table.insert(text_list, text) |
|
local mid = left_pos + diff / 2 |
|
table.insert(text_list, mid - size / 2) |
|
|
|
subdivide(left_value, target_value, left_pos, mid - size / 2) |
|
subdivide(target_value, right_value, mid + size / 2, right_pos) |
|
end |
|
local begin_text_size, secondary_len1 = size_getter(begin_text) |
|
local end_text_size, secondary_len2 = size_getter(end_text) |
|
secondary_axis_length = Max(secondary_axis_length, Max(secondary_len1, secondary_len2)) |
|
|
|
table.insert(text_list, begin_text) |
|
table.insert(text_list, 0) |
|
subdivide(min_value, max_value, 0, available_space) |
|
table.insert(text_list, end_text) |
|
table.insert(text_list, available_space - end_text_size) |
|
|
|
return text_list, secondary_axis_length |
|
end |
|
|
|
function XCurveEditor:Layout(x, y, width, height) |
|
local ret = XWindow.Layout(self, x, y, width, height) |
|
self:GenerateTexts() |
|
return ret |
|
end |
|
|
|
function XCurveEditor:GenerateTexts() |
|
self.font_id = TextStyles.GedDefault:GetFontIdHeightBaseline(self.scale:y()) |
|
self.text_space_required = point(0, 0) |
|
|
|
local _, font_height = UIL.MeasureText("AQj", self.font_id) |
|
local vertical_texts, min_width = FitScaleTexts(self.MinY, self.MaxY, self.DisplayScaleY, function(str) |
|
local width, height = UIL.MeasureText(str, self.font_id) |
|
return height, width |
|
end, self.content_box:sizey() - font_height, 10) |
|
local horizontal_texts = FitScaleTexts(0, self.MaxX, self.DisplayScaleX, function(str) |
|
local width, height = UIL.MeasureText(str, self.font_id) |
|
return width, height |
|
end, self.content_box:sizex() - min_width, 10) |
|
|
|
self.text_space_required = point(min_width, font_height) |
|
local graph_box = self:GetGraphBox() |
|
local content_box_min = self.content_box:min() |
|
|
|
self.scale_texts = {} |
|
for i = 2, #vertical_texts, 2 do |
|
local start_pos = point(graph_box:maxx(), graph_box:maxy() - vertical_texts[i] - font_height) - content_box_min |
|
vertical_texts[i] = sizebox(start_pos, point(UIL.MeasureText(vertical_texts[i - 1], self.font_id))) |
|
end |
|
for i = 2, #horizontal_texts, 2 do |
|
local start_pos = point(graph_box:minx() + horizontal_texts[i], graph_box:maxy()) - content_box_min |
|
horizontal_texts[i] = sizebox(start_pos, point(UIL.MeasureText(horizontal_texts[i - 1], self.font_id))) |
|
end |
|
|
|
table.iappend(vertical_texts, horizontal_texts) |
|
self.scale_texts = vertical_texts |
|
end |
|
|
|
|
|
local function min_point(a, b) |
|
return point(Min(a:x(), b:x()), Min(a:y(), b:y()), Min(a:z(), b:z())) |
|
end |
|
local function max_point(a, b) |
|
return point(Max(a:x(), b:x()), Max(a:y(), b:y()), Max(a:z(), b:z())) |
|
end |
|
function XCurveEditor:MovePoint(index, pos) |
|
local z = pos:z() |
|
assert(z and type(z) == "number") |
|
local points = self.points |
|
assert(index >= 1 and index <= self.ControlPoints and index <= #points) |
|
|
|
local old_pos = points[index] |
|
local min_pos = self:GetRangeMin() |
|
local max_pos = self:GetRangeMax() |
|
|
|
if self.FixedX or index == 1 or index == #points then |
|
min_pos = min_pos:SetX(old_pos:x()) |
|
max_pos = max_pos:SetX(old_pos:x()) |
|
end |
|
|
|
if not self.PushPointsOnMove then |
|
if index > 1 then |
|
min_pos = max_point(min_pos, points[index - 1]) |
|
end |
|
if index < #point then |
|
max_pos = min_point(max_pos, points[index + 1]) |
|
end |
|
end |
|
|
|
pos = point((pos:x() + self.SnapX / 2) / self.SnapX * self.SnapX, |
|
(pos:y() + self.SnapY / 2) / self.SnapY * self.SnapY, |
|
(pos:z() + self.SnapY / 2) / self.SnapY * self.SnapY) |
|
|
|
pos = min_point(max_point(pos, min_pos), max_pos) |
|
points[index] = pos |
|
|
|
if self.PushPointsOnMove and not self.FixedX then |
|
for i = 1, index - 1 do |
|
if points[i]:x() > pos:x() then |
|
points[i] = points[i]:SetX(pos:x()) |
|
end |
|
end |
|
for i = index + 1, #points do |
|
if points[i]:x() < pos:x() then |
|
points[i] = points[i]:SetX(pos:x()) |
|
end |
|
end |
|
end |
|
|
|
if self.OnCurveChanged and old_pos ~= pos then |
|
self.OnCurveChanged(self) |
|
self:Invalidate() |
|
end |
|
|
|
return pos |
|
end |
|
|
|
|
|
function XCurveEditor:OnMouseButtonDown(pt, button) |
|
if button == "L" then |
|
self.capture_handle = self.hover_handle |
|
self:SetFocus() |
|
self.desktop:SetMouseCapture(self) |
|
self:OnMousePos(pt) |
|
return "break" |
|
end |
|
end |
|
|
|
function XCurveEditor:OnSetRollover(rollover) |
|
XControl.OnSetRollover(self, rollover) |
|
if not rollover then |
|
self.hover_handle = false |
|
self:Invalidate() |
|
end |
|
end |
|
|
|
function XCurveEditor:OnMouseButtonUp(pt, button) |
|
if button == "L" then |
|
self.capture_handle = false |
|
self:OnMousePos(pt) |
|
self.desktop:SetMouseCapture() |
|
self:Invalidate() |
|
return "break" |
|
end |
|
end |
|
|
|
function XCurveEditor:GetHoveredHandle(pt) |
|
local handles = self.point_handles |
|
local best_handle = -1 |
|
local best_dist = 999999 |
|
for i, handle in ipairs(handles) do |
|
local dist = handle:HoverScore(self:TransformPoint(handle:GetPos()), pt) |
|
if dist < best_dist then |
|
best_handle = handle |
|
best_dist = dist |
|
end |
|
end |
|
|
|
local max_dist = ScaleXY(self.scale, self.ControlPointMaxDist) |
|
if best_dist < max_dist * max_dist then |
|
return best_handle |
|
end |
|
return false |
|
end |
|
|
|
function XCurveEditor:OnMousePos(pt) |
|
local old_hover = self.hover_handle |
|
self.hover_handle = self:GetHoveredHandle(pt) |
|
if old_hover ~= self.hover_handle then |
|
self:Invalidate() |
|
end |
|
if self.desktop:GetMouseCapture() ~= self then |
|
self.capture_handle = false |
|
return "break" |
|
end |
|
if not self.capture_handle then |
|
return "break" |
|
end |
|
if self.ReadOnly then |
|
return "break" |
|
end |
|
local content_box = self:GetGraphBox() |
|
local pos = self:GetRangeMin() + MulDivRoundPoint(point(pt:x() - content_box:minx(), content_box:maxy() - pt:y()), self:GetRange(), content_box:size()) |
|
self.capture_handle:SetPos(pos) |
|
return "break" |
|
end |
|
|
|
local function RoundUp(x, alignment) |
|
if x % alignment == 0 then return x end |
|
return (x / alignment) * alignment + alignment |
|
end |
|
|
|
function XCurveEditor:DrawGrid() |
|
local range = self:GetRange() |
|
local max_values = self:GetRangeMax() |
|
local min_values = self:GetRangeMin() |
|
|
|
if self.GridUnitX > 0 then |
|
for x = RoundUp(min_values:x(), self.GridUnitX), max_values:x(), self.GridUnitX do |
|
UIL.DrawLine(self:TransformPoint(point(x, min_values:y())), self:TransformPoint(point(x, max_values:y())), self.GridColor) |
|
end |
|
end |
|
if self.GridUnitY > 0 then |
|
for y = RoundUp(min_values:y(), self.GridUnitY), max_values:y(), self.GridUnitY do |
|
UIL.DrawLine(self:TransformPoint(point(min_values:x(), y)), self:TransformPoint(point(max_values:x(), y)), self.GridColor) |
|
end |
|
end |
|
end |
|
|
|
function XCurveEditor:DrawControlPoints() |
|
local graph_box = self:GetGraphBox() |
|
local base = point(graph_box:minx(), graph_box:maxy()) |
|
local points = self.points |
|
local size = self:GetControlPointSize() / 2 |
|
|
|
for idx = 1, #self.point_handles do |
|
local handle = self.point_handles[idx] |
|
local color = self.ControlPointColor |
|
if handle:IsCaptured() then |
|
color = self.ControlPointCaptureColor |
|
elseif handle:IsHovered() then |
|
color = self.ControlPointHoverColor |
|
end |
|
|
|
local pixel_pos = self:TransformPoint(handle:GetPos(true)) |
|
handle:Draw(graph_box, base, size, color, pixel_pos) |
|
end |
|
end |
|
|
|
function XCurveEditor:DrawGraphBackground(graph_box, points) |
|
|
|
end |
|
|
|
function XCurveEditor:DrawScaleTexts() |
|
|
|
if self.capture_handle then |
|
local pos = self.capture_handle:GetPos() |
|
local graph_box = self:GetGraphBox() |
|
|
|
local x_pos_text = FormatNumberProp(pos:x(), self.DisplayScaleX, 2) |
|
local x_pos_text_size = point(UIL.MeasureText(x_pos_text, self.font_id)) |
|
local y_pos_text = FormatNumberProp(pos:y(), self.DisplayScaleY, 2) |
|
local y_pos_text_size = point(UIL.MeasureText(y_pos_text, self.font_id)) |
|
local pixel_pos = self:TransformPoint(pos) |
|
|
|
local draw_text_x = Min(Max(pixel_pos:x() - x_pos_text_size:x() / 2, 0), graph_box:maxx() - x_pos_text_size:x()) |
|
UIL.StretchText(x_pos_text, sizebox(point(draw_text_x, graph_box:maxy()), x_pos_text_size), self.font_id, self.CurveColor) |
|
local draw_text_y = Min(Max(pixel_pos:y() - x_pos_text_size:y() / 2, 0), graph_box:maxy() - x_pos_text_size:y()) |
|
UIL.StretchText(y_pos_text, sizebox(point(graph_box:maxx(), draw_text_y), y_pos_text_size), self.font_id, self.CurveColor) |
|
return |
|
end |
|
|
|
local content_box_min = self.content_box:min() |
|
|
|
local texts = self.scale_texts |
|
if not texts then |
|
self:GenerateTexts() |
|
texts = self.scale_texts |
|
end |
|
if texts then |
|
local StretchText = UIL.StretchText |
|
for i = 1, #texts, 2 do |
|
StretchText(texts[i], Offset(texts[i + 1], content_box_min), self.font_id, self.CurveColor) |
|
end |
|
end |
|
end |
|
|
|
local function DrawCurveWithPoints(smooth, points, color) |
|
if smooth then |
|
local step = 3 |
|
local last_pt = points[1] |
|
for i = 1, #points - 1 do |
|
local left_pt_prev = points[i - 1] or points[i] |
|
local left_pt = points[i] |
|
local right_pt = points[i + 1] |
|
local diff_x = right_pt:x() - left_pt:x() |
|
local right_pt_next = points[i + 2] or points[i + 1] |
|
for x = left_pt:x() + step, right_pt:x(), step do |
|
|
|
local pt = CatmullRomSpline(left_pt_prev, left_pt, right_pt, right_pt_next, MulDivRound(x - left_pt:x(), 1000, diff_x ), 1000) |
|
pt = pt:SetX(x) |
|
UIL.DrawLine(last_pt, pt, color) |
|
last_pt = pt |
|
end |
|
end |
|
else |
|
local last_pt = points[1] |
|
for i = 2, #points do |
|
local pt = points[i] |
|
UIL.DrawLine(last_pt, pt, color) |
|
last_pt = pt |
|
end |
|
end |
|
end |
|
function XCurveEditor:DrawCurve() |
|
assert(self.points[1]:z()) |
|
local graph = self:GetGraphBox() |
|
local points = {} |
|
for key, value in ipairs(self.points) do |
|
points[key] = self:TransformPoint(value) |
|
end |
|
DrawCurveWithPoints(self.Smooth, points, self.CurveColor) |
|
if self.MinMaxRangeMode then |
|
points = {} |
|
for key, value in ipairs(self.points) do |
|
points[key] = self:TransformPoint(point(value:x(), value:z())) |
|
end |
|
DrawCurveWithPoints(self.Smooth, points, self.CurveColor) |
|
end |
|
|
|
UIL.DrawLine(point(graph:maxx(), graph:miny()), graph:max(), self.CurveColor) |
|
UIL.DrawLine(point(graph:minx(), graph:maxy()), graph:max(), self.CurveColor) |
|
end |
|
|
|
function XCurveEditor:DrawContent() |
|
local graph_box = self:GetGraphBox() |
|
self:DrawGraphBackground(graph_box, self.points) |
|
self:DrawGrid() |
|
self:DrawCurve() |
|
self:DrawControlPoints() |
|
|
|
self:DrawScaleTexts() |
|
end |
|
|
|
function XCurveEditor:ValidatePoints() |
|
for i = 1, #self.points do |
|
local pt = self.points[i] |
|
self.points[i] = max_point(min_point(pt, self:GetRangeMax()), self:GetRangeMin()) |
|
end |
|
self.points[1] = self.points[1]:SetX(self.MinX) |
|
self.points[#self.points] = self.points[#self.points]:SetX(self.MaxX) |
|
end |
|
|
|
|
|
|
|
|
|
DefineClass.XCurveEditorHandle = { |
|
__parents = {"PropertyObject"}, |
|
|
|
type = false, |
|
point_idx = false, |
|
curve_editor = false, |
|
box = false, |
|
parent = false, |
|
} |
|
|
|
function XCurveEditorHandle:SetPos(pt) |
|
local old_pt = self.curve_editor.points[self.point_idx] |
|
local height = (old_pt:z() - old_pt:y()) / 2 |
|
local new_point = point(pt:x(), pt:y() - height, pt:y() + height) |
|
|
|
self.curve_editor:MovePoint(self.point_idx, new_point) |
|
return self:GetPos("refetch") |
|
end |
|
|
|
function XCurveEditorHandle:GetPos(refetch) |
|
local pt = self.curve_editor.points[self.point_idx] |
|
return point(pt:x(), (pt:y() + pt:z()) / 2) |
|
end |
|
|
|
function XCurveEditorHandle:GetBox() |
|
local old_pt = self.curve_editor.points[self.point_idx] |
|
if self.curve_editor.MinMaxRangeMode then |
|
local height = (old_pt:z() - old_pt:y()) |
|
local height_in_pixels = MulDivRound(height, self.curve_editor:GetGraphBox():sizey(), self.curve_editor:GetRange():y()) |
|
local half_control_point_width = self.curve_editor:GetControlPointSize():x() / 4 |
|
local pixel_pos = self.curve_editor:TransformPoint(old_pt) |
|
self.box = box(point(pixel_pos:x() - half_control_point_width, pixel_pos:y() - height_in_pixels), |
|
point(pixel_pos:x() + half_control_point_width, pixel_pos:y())) |
|
else |
|
local half_control_point_width = self.curve_editor:GetControlPointSize():x() / 2 |
|
local pixel_pos = self.curve_editor:TransformPoint(old_pt) |
|
self.box = box(point(pixel_pos:x() - half_control_point_width, pixel_pos:y() - half_control_point_width), |
|
point(pixel_pos:x() + half_control_point_width, pixel_pos:y() + half_control_point_width)) |
|
end |
|
return self.box |
|
end |
|
|
|
function XCurveEditorHandle:HoverScore(self_pt, mouse_pt) |
|
if terminal.IsKeyPressed(const.vkShift) then |
|
return 1000000 |
|
end |
|
|
|
local is = self:GetBox():Intersect(box(mouse_pt - point(10, 10), mouse_pt + point(10, 10))) |
|
if is ~= const.irOutside then |
|
return 0 |
|
end |
|
|
|
return mouse_pt:Dist2(self_pt) |
|
end |
|
|
|
function XCurveEditorHandle:Draw(graph_box, base, size, color, pixel_pos) |
|
UIL.DrawSolidRect(self:GetBox(), color) |
|
end |
|
|
|
DefineClass.XCurveEditorMinHandle = { |
|
__parents = {"XCurveEditorHandle"}, |
|
} |
|
|
|
function XCurveEditorMinHandle:SetPos(pt) |
|
local old_pt = self.curve_editor.points[self.point_idx] |
|
local new_pt = point(pt:x(), Min(pt:y(), old_pt:z()), old_pt:z()) |
|
|
|
self.curve_editor:MovePoint(self.point_idx, new_pt) |
|
return self:GetPos("refetch") |
|
end |
|
|
|
function XCurveEditorHandle:IsCaptured() |
|
local capture = self.curve_editor.capture_handle |
|
local current = self |
|
while current do |
|
if capture == current then return true end |
|
current = current.parent |
|
end |
|
return false |
|
end |
|
|
|
function XCurveEditorHandle:IsHovered() |
|
local capture = self.curve_editor.hover_handle |
|
local current = self |
|
while current do |
|
if capture == current then return true end |
|
current = current.parent |
|
end |
|
return false |
|
end |
|
|
|
function XCurveEditorMinHandle:GetPos(refetch) |
|
local pt = self.curve_editor.points[self.point_idx] |
|
return point(pt:x(), pt:y()) |
|
end |
|
|
|
|
|
function XCurveEditorMinHandle:HoverScore(self_pt, mouse_pt) |
|
return mouse_pt:Dist2(self_pt) |
|
end |
|
|
|
function XCurveEditorMinHandle:Draw(graph_box, base, size, color, pixel_pos) |
|
UIL.DrawSolidRect(box(pixel_pos - size, pixel_pos + size), color) |
|
end |
|
|
|
|
|
DefineClass.XCurveEditorMaxHandle = { |
|
__parents = {"XCurveEditorHandle"}, |
|
} |
|
|
|
function XCurveEditorMaxHandle:SetPos(pt) |
|
local old_pt = self.curve_editor.points[self.point_idx] |
|
local new_pt = point(pt:x(), old_pt:y(), Max(pt:y(), old_pt:y())) |
|
|
|
self.curve_editor:MovePoint(self.point_idx, new_pt) |
|
return self:GetPos("refetch") |
|
end |
|
|
|
function XCurveEditorMaxHandle:GetPos(refetch) |
|
local pt = self.curve_editor.points[self.point_idx] |
|
return point(pt:x(), pt:z()) |
|
end |
|
|
|
|
|
function XCurveEditorMaxHandle:HoverScore(self_pt, mouse_pt) |
|
return mouse_pt:Dist2(self_pt) |
|
end |
|
|
|
function XCurveEditorMaxHandle:Draw(graph_box, base, size, color, pixel_pos) |
|
UIL.DrawSolidRect(box(pixel_pos - size, pixel_pos + size), color) |
|
end |
|
|
|
|
|
DefineClass.TestPicker = { |
|
__parents = {"PropertyObject"}, |
|
properties = { |
|
{id = "test1", editor = "packedcurve", default = PackCurveParams(point(0, 127000), point(40000, 0), point(80000, 255000), point(255000, 0)),} |
|
} |
|
} |
|
|