myspace / CommonLua /Editor /XEditor /XEditorPlacementHelper.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
9.21 kB
----- XEditorPlacementHelper
--
-- Each placement helper defines a sub-mode of the default XSelectObjectsTool.
-- Leaf children of XEditorPlacementHelper define shortcust, icons, and rollover
-- descriptions, and are auto-displayed as buttons in the editor statusbar.
--
-- Placement helpers define the editor's behavior when objects are dragged upon
-- or after initial placement. Editor gizmos are also implemented as placement helpers.
--
-- The base class is abstract and only defines methods/members that need to be present.
DefineClass.XEditorPlacementHelper = {
__parents = { "InitDone" },
operation_started = false,
local_cs = false,
snap = false,
HasLocalCSSetting = false,
HasSnapSetting = false,
InXPlaceObjectTool = false,
InXSelectObjectsTool = false,
AllowRotationAfterPlacement = false,
UsesCodeRenderables = false,
Title = "None",
Description = false,
ActionSortKey = "0",
ActionIcon = "CommonAssets/UI/Editor/Tools/VertexNudge.tga", -- proxy icon for testing
ActionShortcut = "",
ActionShortcut2 = "",
}
function XEditorPlacementHelper:GetDescription()
end
function XEditorPlacementHelper:CheckStartOperation(mouse_pos)
-- return true if clicking on this position should start object movement
end
function XEditorPlacementHelper:StartOperation(mouse_pos, objects)
-- initialize and start the movement operation here; you can assume CheckStartOperation was called and returned true
self.operation_started = true
end
function XEditorPlacementHelper:PerformOperation(mouse_pos, objects)
-- perform object movement here
end
function XEditorPlacementHelper:EndOperation(objects)
-- called when the movement operation ends
self.operation_started = false
end
----- XEditorGizmo, base class for editor gizmos
DefineClass.XEditorGizmo = {
__parents = { "XEditorPlacementHelper", "Mesh" },
InXSelectObjectsTool = true,
UsesCodeRenderables = true,
thickness = 75,
opacity = 110,
scale = 85,
sensitivity = 100,
update_thread = false,
}
function XEditorGizmo:GetProperties()
return empty_table -- prevent properties of the Mesh class from appearing in the tool settings
end
function XEditorGizmo:Init()
self.update_thread = CreateRealTimeThread(function()
while IsValid(self) do
self.thickness = XEditorSettings:GetGizmoThickness()
self.opacity = XEditorSettings:GetGizmoOpacity()
self.scale = XEditorSettings:GetGizmoScale()
self.sensitivity = XEditorSettings:GetGizmoSensitivity()
self:Render()
WaitNextFrame()
end
end)
end
function XEditorGizmo:Done()
DeleteThread(self.update_thread)
end
function XEditorGizmo:Render()
end
----- XObjectPlacementHelper - sample implementation / base class, a helper that moves selected/placed objects
DefineClass.XObjectPlacementHelper = {
__parents = { "XEditorPlacementHelper" },
InXPlaceObjectTool = true,
InXSelectObjectsTool = true,
init_drag_position = false,
init_move_positions = false,
init_orientations = false,
}
function XObjectPlacementHelper:CheckStartOperation(mouse_pos)
local obj = GetObjectAtCursor()
return obj and editor.IsSelected(obj) -- start operation when we drag an already selected object
end
function XObjectPlacementHelper:StartOperation(mouse_pos, objects)
SuspendPassEditsForEditOp(objects)
self:StartMoveObjects(mouse_pos, objects)
self.operation_started = true
end
function XObjectPlacementHelper:PerformOperation(mouse_pos, objects)
self:MoveObjects(mouse_pos, objects)
end
function XObjectPlacementHelper:EndOperation(objects)
self.init_drag_position = false
self.init_move_positions = false
self.init_orientations = false
self.operation_started = false
ResumePassEditsForEditOp()
end
function XObjectPlacementHelper:StartMoveObjects(mouse_pos, objects)
self.init_drag_position = GetTerrainCursor()
self.init_move_positions = {}
self.init_orientations = {}
for i, o in ipairs(objects) do
self.init_move_positions[i] = o:GetPos()
self.init_orientations[i] = { o:GetOrientation() }
end
end
function XObjectPlacementHelper:MoveObjects(mouse_pos, objects) -- override in your child class (this is a sample implementation)
local vMove = (GetTerrainCursor() - self.init_drag_position):SetZ(0)
for i, obj in ipairs(objects) do
obj:SetPos(self.init_move_positions[i] + vMove)
end
Msg("EditorCallback", "EditorCallbackMove", objects)
end
----- XEditorPlacementHelperHost
local helper_classes
function helpers_button_list(tool_class)
if not helper_classes then
helper_classes = ClassLeafDescendantsList("XEditorPlacementHelper")
table.sort(helper_classes, function(a, b) return g_Classes[a].ActionSortKey < g_Classes[b].ActionSortKey end)
end
local buttons = {}
for _, class_name in ipairs(helper_classes) do
local class = g_Classes[class_name]
if class.Title ~= "None" and class["In" .. tool_class] then
table.insert(buttons, {
toggle = true,
func = function(self, root, prop_id, ged, param) self:SetHelperClass(param) end,
is_toggled = function(self) return self:GetHelperClass() == class_name end,
name = class_name,
param = class_name,
icon = class.ActionIcon,
icon_scale = 100,
rollover = class.Title .. (class.Description and ("\n\n" .. table.concat(class.Description, "\n\n")) or ""),
-- not part of the button definition - used by the tools the helpers are present it
shortcut = class.ActionShortcut,
shortcut2 = class.ActionShortcut2,
})
end
end
return buttons
end
DefineClass.XEditorPlacementHelperHost = {
__parents = { "InitDone", "XEditorToolSettings" },
helper_class = false, -- define the default helper in your tool
placement_helper = false,
prop_cache = false,
props_from_helper = false,
}
function XEditorPlacementHelperHost:Init()
self.placement_helper = g_Classes[self.helper_class]:new()
end
function XEditorPlacementHelperHost:Done()
self.placement_helper:delete()
end
function XEditorPlacementHelperHost:GetToolTitle()
return self.placement_helper.Title or self.ToolTitle
end
function XEditorPlacementHelperHost:GetProperties()
if not self.prop_cache then
-- append the placement helper properties after ours
local props = {}
for _, prop_meta in ipairs(InitDone.GetProperties(self)) do
props[#props + 1] = table.copy(prop_meta)
end
self.props_from_helper = {}
for _, prop_meta in ipairs(self.placement_helper and self.placement_helper:GetProperties()) do
self.props_from_helper[prop_meta.id] = true
props[#props + 1] = table.copy(prop_meta)
end
self.prop_cache = props
end
return self.prop_cache
end
function XEditorPlacementHelperHost:GetProperty(prop)
if self.props_from_helper and self.props_from_helper[prop] then
return self.placement_helper:GetProperty(prop)
end
return PropertyObject.GetProperty(self, prop)
end
function XEditorPlacementHelperHost:SetProperty(prop, value)
if self.props_from_helper and self.props_from_helper[prop] then
self.placement_helper:SetProperty(prop, value)
return
end
PropertyObject.SetProperty(self, prop, value)
end
function XEditorPlacementHelperHost:GetHelperClass()
return self.helper_class
end
function XEditorPlacementHelperHost:SetHelperClass(class_name, properties)
self.prop_cache = nil
self.props_from_helper = nil
self.helper_class = class_name
if not IsKindOf(self.placement_helper, class_name) then
self.placement_helper:delete()
self.placement_helper = g_Classes[class_name]:new(properties)
end
local statusbar = GetDialog("XEditorStatusbar")
if statusbar then
statusbar:ActionsUpdated()
end
self:UpdatePlacementHelper()
ObjModified(self)
Msg("EditorToolChanged", GetDialog("XEditor").Mode, self.helper_class)
end
function XEditorPlacementHelperHost:UpdatePlacementHelper()
end
function XEditorPlacementHelperHost:OnShortcut(shortcut, source, ...)
local buttons = helpers_button_list(self.class)
local button = table.find_value(buttons, "shortcut", shortcut) or table.find_value(buttons, "shortcut2", shortcut)
if button then
if self.placement_helper.operation_started then
self.desktop:SetMouseCapture() -- stop current operation if one is in progress
end
self:SetHelperClass(button.name)
return "break"
end
if self.placement_helper:HasMember("OnShortcut") then
return self.placement_helper:OnShortcut(shortcut, source, ...)
end
end
function XEditorPlacementHelperHost:OnMouseButtonDown(pt, button)
if button == "L" then
local ret = self.placement_helper:CheckStartOperation(pt, "btn_pressed")
if ret == "break" then
return "break"
elseif ret then
SuspendPassEditsForEditOp()
self.placement_helper:StartOperation(pt, editor.GetSel())
self.desktop:SetMouseCapture(self)
return "break"
end
end
end
function XEditorPlacementHelperHost:OnMousePos(pt)
if self.placement_helper.operation_started then
self.placement_helper:PerformOperation(pt, editor.GetSel())
return "break"
end
end
function XEditorPlacementHelperHost:OnMouseButtonUp(pt, button)
if self.placement_helper.operation_started then
self.desktop:SetMouseCapture()
return "break"
end
end
function XEditorPlacementHelperHost:OnCaptureLost()
if self.placement_helper.operation_started then
self.placement_helper:EndOperation(editor.GetSel())
ResumePassEditsForEditOp()
end
end