Livery Editor – Layer Edit
Manages the full edit lifecycle for a single decal layer - transform (translate, rotate, scale, skew), material properties, and gamepad/controller hold-repeat input.
Manages the full edit lifecycle for a single decal layer - transform (translate, rotate, scale, skew), material properties, and gamepad/controller hold-repeat input.
Overview
ui_liveryEditor_layerEdit handles adding new decals and editing existing ones. It maintains an editState object that tracks whether the user is adding or modifying, stores the original layer for cancel/restore, and provides incremental transform operations with configurable step units. It also implements a hold-repeat system for controller input.
Extension path: lua/ge/extensions/ui/liveryEditor/layerEdit.lua
Exports (M)
| Function | Signature | Description |
|---|---|---|
setup | () | Resets the edit state. |
editNewDecal | (params) | Begins adding a new decal with params.texturePath. |
editExistingLayer | (layerUid, replaceOnSave) | Begins editing an existing layer. If replaceOnSave, the layer is hidden and cursor shown. |
setCursorProperties | (layer) | Copies all layer properties (position, texture, color, scale, rotation, mirror) to the cursor. |
translateLayer | (steps_x, steps_y) → {x, y} | Moves the cursor position by step increments. |
setPosition | (x, y) | Sets cursor position absolutely. |
scaleLayer | (steps_x, steps_y) → {x, y} | Adjusts scale by step increments. |
setScale | (x, y, lock) | Sets scale absolutely. If lock is true, aspect ratio is locked. |
skewLayer | (x, y) → {x, y} | Adjusts skew by step increments. |
setSkew | (x, y) | Sets skew absolutely. |
rotateLayer | (steps, counterClockwise) → degrees | Rotates by step increments. Returns new degree value. |
setRotation | (degrees) | Sets rotation absolutely in degrees. |
setLayerMaterials | (properties) | Sets color, metallic, and roughness. Values 0–100 from UI are scaled to 0–1. |
saveChanges | () | Commits edits - stamps a new decal if position changed. |
cancelChanges | () | Restores original layer properties and exits edit mode. |
requestReposition | () | Enters reposition mode (shows cursor, hides layer). |
applyReposition | () | Stamps repositioned decal and updates the layer. |
cancelReposition | () | Cancels reposition, restores layer visibility. |
stampDecal | () | Stamps cursor as decal (mouse projection mode). |
requestStateData | () | Sends current editState to the UI. |
requestLayerMaterials | () | Sends color/metallic/roughness to the UI. |
requestTransform | () | Enables transform action maps and shows cursor. |
endTransform | () | Disables transform action maps and hides cursor. |
showCursorOrLayer | (show) | Shows/hides the cursor or layer depending on edit mode. |
requestInitialLayerData | () | Sends full transform data (position, scale, skew, rotation, materials) to the UI. |
resetEditState | () | Clears edit state to defaults. |
toggleUseMouseOrCursor | () → {isUseMouse} | Toggles between mouse and cursor projection. |
Controller Hold-Repeat
| Function | Signature | Description |
|---|---|---|
holdTranslate | (axis, value) | Starts/stops held translation on x or y axis. |
holdTranslateScalar | (axis, value) | Scalar axis translation with threshold. |
holdRotate | (direction, value) | Starts/stops held rotation. |
holdScale | (axis, value) | Starts/stops held scaling. |
holdSkew | (axis, value) | Starts/stops held skewing. |
holdPrecise | (enable) | Toggles precise mode (smaller increments). |
setIsRotationPrecise | (value) | Sets whether rotation uses precise stepping. |
setAllowRotationAction | (value) | Sets whether rotation input actions are allowed. |
holdTranslateAction | () | Executes pending hold-translate on update tick. |
holdRotateAction | () | Executes pending hold-rotate on update tick. |
holdScaleAction | () | Executes pending hold-scale on update tick. |
holdSkewAction | () | Executes pending hold-skew on update tick. |
Data Fields
| Field | Description |
|---|---|
M.isPositionChanged | false - tracks whether position was modified during edit. |
M.allowRotationAction | true - whether rotation actions are permitted. |
M.isRotationPrecise | false - whether rotation uses precise stepping. |
M.holdAction | nil - current hold-repeat action function. |
M.holdValue | nil - current hold-repeat value. |
M.holdAxis | nil - current hold-repeat axis. |
M.holdTime | 0 - accumulated hold time for repeat threshold. |
M.precise | false - whether precise mode is active for hold-repeat. |
M.showCursor | function - reference to the internal showCursor function. |
Internals
Step Units
TRANSLATE_STEP_UNIT = 0.001
ROTATE_STEP_UNIT = 0.01
SCALE_STEP_UNIT = 0.01
SKEW_STEP_UNIT = 0.01Edit State
M.editState = {
layerUid = nil, -- UID of the layer being edited
layerType = nil, -- api.layerTypes value
isAdd = nil, -- true = adding new, false = editing existing
layer = nil, -- deep copy of original layer (for cancel)
replaceOnSave = nil, -- if true, stamps a new decal on save
isStampReapplying = nil,
useMouseRealValue = nil
}onUpdate(dtReal, dtSim, dtRaw)
The onUpdate tick checks if a hold action is active. After a 0.5s delay, it repeats the action every frame, providing smooth continuous transform via controller sticks.
How It Works
editExistingLayer(uid, true)- stores original layer, switches camera, shows cursor- User adjusts position/scale/rotation via UI controls or controller
saveChanges()- stamps a new decal at the cursor position, replaces the original- Or
cancelChanges()- restores the deep copy of the original layer
Additional Exports
The following exports are available but not yet documented in detail:
M.applyRepositionM.cancelChangesM.cancelRepositionM.editExistingLayerM.editNewDecalM.endTransformM.holdPreciseM.holdRotateM.holdRotateActionM.holdScaleM.holdScaleActionM.holdSkewM.holdSkewActionM.holdTranslateM.holdTranslateActionM.holdTranslateScalarM.onUpdateM.requestInitialLayerDataM.requestLayerMaterialsM.requestRepositionM.requestStateDataM.requestTransformM.resetEditStateM.rotateLayerM.saveChangesM.scaleLayerM.setAllowRotationActionM.setCursorPropertiesM.setIsRotationPreciseM.setLayerMaterialsM.setPositionM.setRotationM.setScaleM.setSkewM.setupM.showCursorOrLayerM.skewLayerM.stampDecalM.toggleUseMouseOrCursorM.translateLayer