Update of Particle Editor to standardize it up and utilize inspectors rather than adhoc guis

This commit is contained in:
JeffR 2025-12-21 16:39:19 -06:00
parent 1f5a4267ac
commit 12ebebff46
31 changed files with 5091 additions and 6095 deletions

View file

@ -0,0 +1,86 @@
$guiContent = new GuiTabPageCtrl() {
position = "2 50";
extent = "361 615";
horizSizing = "width";
vertSizing = "height";
profile = "GuiDefaultProfile";
tooltipProfile = "GuiToolTipProfile";
fitBook = "1";
new GuiControl() {
extent = "342 26";
horizSizing = "width";
profile = "GuiDefaultProfile";
tooltipProfile = "GuiToolTipProfile";
isContainer = "1";
class = "QuickEditDropDownTextEditCtrl";
new GuiButtonCtrl() {
Text = "";
maxLength = "255";
position = "4 4";
extent = "268 18";
horizSizing = "width";
profile = "ToolsGuiButtonProfile";
command = "ParticleEditorGui.openList($ThisControl.getParent().getParent());";
tooltipProfile = "GuiToolTipProfile";
isContainer = "0";
internalName = "PopupMenu";
};
new GuiBitmapButtonCtrl() {
BitmapAsset = "ToolsModule:new_n_image";
position = "276 5";
extent = "17 17";
horizSizing = "left";
profile = "ToolsGuiDefaultProfile";
command = "";
tooltipProfile = "GuiToolTipProfile";
ToolTip = "Create New";
internalName = "CreateNewBtn";
};
new GuiBitmapButtonCtrl() {
BitmapAsset = "ToolsModule:save_icon_n_image";
position = "292 5";
extent = "17 17";
horizSizing = "left";
profile = "ToolsGuiDefaultProfile";
command = "";
tooltipProfile = "GuiToolTipProfile";
ToolTip = "Save Current";
internalName = "SaveCurrentBtn";
};
new GuiBitmapButtonCtrl() {
BitmapAsset = "ToolsModule:delete_n_image";
position = "309 5";
extent = "17 17";
horizSizing = "left";
profile = "ToolsGuiDefaultProfile";
command = "";
tooltipProfile = "GuiToolTipProfile";
ToolTip = "Delete Current";
internalName = "DeleteCurrentBtn";
};
};
new GuiScrollCtrl() {
hScrollBar = "alwaysOff";
vScrollBar = "dynamic";
position = "0 30";
extent = "356 586";
minExtent = "8 8";
horizSizing = "width";
vertSizing = "height";
profile = "ToolsGuiScrollProfile";
tooltipProfile = "GuiToolTipProfile";
new GuiInspector() {
class = "ParticleEditorInspector";
groupFilters = "-Internal -Editing -Object -Persistence -Dynamic Fields -Scripting -AFX -AFX Pooled Particles";
position = "1 1";
extent = "339 48";
horizSizing = "width";
profile = "GuiInspectorProfile";
tooltipProfile = "GuiToolTipProfile";
internalName = "inspector";
};
};
};

View file

@ -0,0 +1,83 @@
//-----------------------------------------------------------------------------
// Torque
// Copyright GarageGames, LLC 2011
//-----------------------------------------------------------------------------
$PE_guielement_pos_single_container = "0 0";
$PE_guielement_ext_single_container = "184 20";
$PE_guielement_pos_name = "1 0";
$PE_guielement_ext_name = "70 18";
$PE_guielement_pos_slider = "74 2";
$PE_guielement_ext_slider = "58 12";
$PE_guielement_pos_value = "138 0";
$PE_guielement_ext_value = "36 18";
$PE_guielement_pos_textedit = "74 0";
$PE_guielement_ext_textedit = "100 18";
$PE_guielement_ext_checkbox_name = "156 18";
$PE_guielement_pos_checkbox = "161 0";
$PE_guielement_ext_checkbox = "15 18";
$PE_guielement_pos_colorpicker = "158 0";
$PE_guielement_ext_colorpicker = "18 18";
//--- OBJECT WRITE BEGIN ---
$guiContent = new GuiControl(ParticleEditorGui) {
extent = "1280 720";
profile = "GuiNonModalDefaultProfile";
tooltipProfile = "GuiToolTipProfile";
isContainer = "1";
canSaveDynamicFields = "0";
new GuiWindowCollapseCtrl(PE_Window) {
Text = ":: Particle Editor - Emitters";
canMove = "0";
canClose = "0";
canMinimize = "0";
canMaximize = "0";
canCollapse = "0";
edgeSnap = "0";
position = "920 39";
extent = "360 1345";
minExtent = "300 140";
horizSizing = "windowRelative";
vertSizing = "windowRelative";
profile = "ToolsGuiWindowProfile";
tooltipProfile = "GuiToolTipProfile";
new GuiTabBookCtrl(PE_TabBook) {
tabMargin = "0";
tabHeight = "20";
selectedPage = "0";
docking = "Client";
margin = "3 2 3 3";
position = "9 29";
extent = "342 1306";
horizSizing = "width";
vertSizing = "height";
profile = "ToolsGuiTabBookProfile";
tooltipProfile = "GuiToolTipProfile";
internalName = "EditorTabBook";
};
new GuiBitmapButtonCtrl() {
BitmapAsset = "ToolsModule:play_btn_n_image";
position = "318 25";
extent = "18 18";
horizSizing = "left";
profile = "ToolsGuiButtonProfile";
command = "ParticleEditor.updateEmitterNode();";
tooltipProfile = "ToolsGuiToolTipProfile";
ToolTip = "Play Particle Effect from Start";
};
new GuiBitmapButtonCtrl() {
BitmapAsset = "ToolsModule:camera_image";
position = "338 26";
extent = "16 16";
horizSizing = "left";
profile = "ToolsGuiButtonProfile";
command = "ParticleEditor.resetEmitterNode();";
tooltipProfile = "ToolsGuiToolTipProfile";
ToolTip = "Drops Particle Effect in front of the Camera";
};
};
};
//--- OBJECT WRITE END ---

View file

@ -0,0 +1,197 @@
//--- OBJECT WRITE BEGIN ---
$guiContent = new GuiControl(ParticleEditorCreatePrompt) {
position = "0 0";
extent = "1024 768";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "bottom";
profile = "ToolsGuiDefaultProfile";
visible = "1";
active = "1";
tooltipProfile = "ToolsGuiToolTipProfile";
hovertime = "1000";
isContainer = "1";
canSave = "1";
canSaveDynamicFields = "1";
fixedAspectRatio = "0";
new GuiWindowCtrl() {
text = "Create New Datablock";
resizeWidth = "0";
resizeHeight = "0";
canMove = "0";
canClose = "1";
canMinimize = "0";
canMaximize = "0";
canCollapse = "0";
closeCommand = "canvas.popDialog(ParticleEditorCreatePrompt);";
edgeSnap = "0";
margin = "0 0 0 0";
padding = "0 0 0 0";
anchorTop = "1";
anchorBottom = "0";
anchorLeft = "1";
anchorRight = "0";
position = "758 420";
extent = "400 167";
minExtent = "8 2";
horizSizing = "center";
vertSizing = "center";
profile = "ToolsGuiWindowProfile";
visible = "1";
active = "1";
tooltipProfile = "ToolsGuiToolTipProfile";
hovertime = "1000";
isContainer = "1";
internalName = "promptWindow";
canSave = "1";
canSaveDynamicFields = "0";
new GuiTextCtrl() {
text = "Your new object must have a name";
maxLength = "1024";
margin = "0 0 0 0";
padding = "0 0 0 0";
anchorTop = "1";
anchorBottom = "0";
anchorLeft = "1";
anchorRight = "0";
position = "7 26";
extent = "250 15";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "bottom";
profile = "ToolsGuiTextProfile";
visible = "1";
active = "1";
tooltipProfile = "ToolsGuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
canSave = "1";
canSaveDynamicFields = "0";
internalName = "namePromptText";
};
new GuiTextEditCtrl() {
historySize = "0";
tabComplete = "0";
sinkAllKeyEvents = "0";
password = "0";
passwordMask = "*";
placeholderText = "Name";
maxLength = "1024";
margin = "0 0 0 0";
padding = "0 0 0 0";
anchorTop = "1";
anchorBottom = "0";
anchorLeft = "1";
anchorRight = "0";
position = "7 45";
extent = "294 18";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "bottom";
profile = "ToolsGuiTextEditProfile";
visible = "1";
active = "1";
tooltipProfile = "ToolsGuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
internalName = "nameText";
canSave = "1";
canSaveDynamicFields = "0";
};
new GuiButtonCtrl() {
text = "Create";
groupNum = "-1";
buttonType = "PushButton";
useMouseEvents = "0";
position = "111 137";
extent = "122 22";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "bottom";
profile = "ToolsGuiButtonProfile";
visible = "1";
active = "1";
accelerator = "return";
tooltipProfile = "ToolsGuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
canSave = "1";
canSaveDynamicFields = "0";
internalName = "createBtn";
};
new GuiButtonCtrl() {
text = "Cancel";
groupNum = "-1";
buttonType = "PushButton";
useMouseEvents = "0";
position = "239 137";
extent = "63 22";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "bottom";
profile = "ToolsGuiButtonProfile";
visible = "1";
active = "1";
command = "canvas.popDialog(ParticleEditorCreatePrompt);";
accelerator = "escape";
tooltipProfile = "ToolsGuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
canSave = "1";
canSaveDynamicFields = "0";
};
new GuiTextCtrl() {
text = "Inherit values from";
maxLength = "1024";
margin = "0 0 0 0";
padding = "0 0 0 0";
anchorTop = "1";
anchorBottom = "0";
anchorLeft = "1";
anchorRight = "0";
position = "7 66";
extent = "120 17";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "bottom";
profile = "ToolsGuiTextProfile";
visible = "1";
active = "1";
tooltipProfile = "ToolsGuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
canSave = "1";
canSaveDynamicFields = "0";
};
new GuiPopUpMenuCtrl() {
maxPopupHeight = "200";
sbUsesNAColor = "0";
reverseTextList = "0";
bitmapBounds = "16 16";
maxLength = "1024";
margin = "0 0 0 0";
padding = "0 0 0 0";
anchorTop = "1";
anchorBottom = "0";
anchorLeft = "1";
anchorRight = "0";
position = "7 87";
extent = "294 19";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "bottom";
profile = "ToolsGuiPopUpMenuProfile";
visible = "1";
active = "1";
tooltipProfile = "ToolsGuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
internalName = "CopySourceDropdown";
canSave = "1";
canSaveDynamicFields = "0";
};
};
};
//--- OBJECT WRITE END ---

View file

@ -0,0 +1,33 @@
function ParticleEditorCreatePrompt::show(%this, %name, %typeFilter, %callback)
{
Canvas.pushDialog(%this);
%this-->promptWindow.text = "Create New " @ %name;
%this-->namePromptText.text = "Your new " @ %name @ " must have a name";
%this-->nameText.placeholderText = "new" @ %name;
%this-->createBtn.command = %callback;
// Need to prompt for a name.
%this-->nameText.setText("");
%this-->nameText.selectAllText();
// Populate the copy source dropdown.
%list = %this-->CopySourceDropdown;
%list.clear();
%list.add( "", 0 );
%set = DataBlockSet;
%count = %set.getCount();
for( %i = 0; %i < %count; %i ++ )
{
%datablock = %set.getObject( %i );
%datablockClass = %datablock.getClassName();
if( !isMemberOfClass( %datablockClass, %typeFilter ) )
continue;
%list.add( %datablock.getName(), %i + 1 );
}
}

View file

@ -0,0 +1,326 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
// Open the particle editor to spawn a test emitter in front of the player.
// Edit the sliders, check boxes, and text fields and see the results in
// realtime. Switch between emitters and particles with the buttons in the
// top left corner. When in particle mode, the only particles available will
// be those assigned to the current emitter to avoid confusion. In the top
// right corner, there is a button marked "Drop Emitter", which will spawn the
// test emitter in front of the player again, and a button marked "Restart
// Emitter", which will play the particle animation again.
//=============================================================================================
// ParticleEditor.
//=============================================================================================
//---------------------------------------------------------------------------------------------
function ParticleEditor::initEditor( %this )
{
echo( "Initializing ParticleEmitterData and ParticleData DataBlocks..." );
PE_TabBook.clear();
for(%i=0; %i < PE_ParticleDataTypes.count(); %i++)
{
%groupName = PE_ParticleDataTypes.getKey(%i);
%typesList = getField(PE_ParticleDataTypes.getValue(%i), 0);
%editorName = getField(PE_ParticleDataTypes.getValue(%i), 1);
if(exec("./PETabTemplate.gui"))
{
echo("MADE A NEW TAB PAGE: " @ $guiContent);
$guiContent.text = %groupName;
$guiContent.typesList = %typesList;
$guiContent.setName(%editorName);
$guiContent.saver = new PersistenceManager( "PE_" @ %groupName @ "Saver" );
$guiContent.unlistedSet = new SimSet( "PE_Unlisted" @ %groupName );
$guiContent-->CreateNewBtn.tooltip = "Create New " @ %groupName;
$guiContent-->CreateNewBtn.command = %editorName @ ".showNewDialog();";
$guiContent-->SaveCurrentBtn.tooltip = "Save Current " @ %groupName;
$guiContent-->SaveCurrentBtn.command = %editorName @ ".save" @ %groupName @ "();";
$guiContent-->DeleteCurrentBtn.tooltip = "Delete Current " @ %groupName;
$guiContent-->DeleteCurrentBtn.command = %editorName @ ".showDeleteDialog();";
PE_TabBook.add($guiContent);
if($guiContent.isMethod("init"))
$guiContent.init();
}
else
{
error("Something went wrong when trying to generatea a ParticleEditor tab for type: " @ %groupName);
}
}
PE_Window-->EditorTabBook.selectPage( 0 );
}
function ParticleEditorGui::openList( %this, %editorCtrl )
{
// This function creates the list of all particles and particle emitters
%listCount = 0;
%listSet = new SimSet(){ internalName = %editorCtrl.text; };
foreach( %obj in DatablockGroup )
{
%typesListCount = getWordCount(%editorCtrl.typesList);
for(%i=0; %i < %typesListCount; %i++)
{
%type = getWord(%editorCtrl.typesList, %i);
if( %obj.isMemberOfClass( %type ) )
{
// Filter out emitters on the PE_UnlistedEmitters list.
%unlistedFound = false;
foreach( %unlisted in %editorCtrl.unlistedSet ){
if( %unlisted.getId() == %obj.getId() )
{
%unlistedFound = true;
break;
}
}
if( %unlistedFound )
continue;
// To prevent our default emitters from getting changed,
// prevent them from populating the list. Default emitters
// should only be used as a template for creating new ones.
if ( %obj.getName() $= "DefaultEmitter")
continue;
if(%typesListCount > 1)
{
%typeSet = %listSet.findObjectByInternalName(%type);
if(!isObject(%typeSet))
{
%typeSet = new SimSet(){ internalName = %type; };
%listSet.add(%typeSet);
}
%typeSet.add(%obj);
}
else
{
%listSet.add(%obj);
}
%listCount++;
}
}
}
ContextedDropdownListGui.show(%listSet, "Select", "" @ %editorCtrl @ ".selectObject", %this-->PopupMenu);
if(%this-->PopupMenu.getText() !$= "")
{
%obj = %this-->PopupMenu.getText().getId();
ContextedDropdownListGui.seekItemObject(%obj);
}
//ContextedDropdownListGui-->tree.sort(0, true);
//Go through and mark any items that are indicated as dirty
for(%i=0; %i < %editorCtrl.saver.getDirtyObjectCount(); %i++)
{
%dirtyObj = %editorCtrl.saver.getDirtyObject(%i);
%itemId = ContextedDropdownListGui-->tree.findItemByObjectId(%dirtyObj.getId());
if(%itemId != -1) //can happen if it was previously marked as unlisted or somehow removed
{
ContextedDropdownListGui-->tree.markItem(%itemId, true);
}
}
}
//---------------------------------------------------------------------------------------------
function ParticleEditor::resetEmitterNode( %this )
{
%tform = ServerConnection.getControlObject().getEyeTransform();
%vec = VectorNormalize( ServerConnection.getControlObject().getForwardVector() );
%vec = VectorScale( %vec, 4 );
%tform = setWord( %tform, 0, getWord( %tform, 0 ) + getWord( %vec, 0 ) );
%tform = setWord( %tform, 1, getWord( %tform, 1 ) + getWord( %vec, 1 ) );
%tform = setWord( %tform, 2, getWord( %tform, 2 ) + getWord( %vec, 2 ) );
%this.selectedEditor.resetVizNode(%tform);
}
//---------------------------------------------------------------------------------------------
function ParticleEditor::updateEmitterNode( %this )
{
%this.selectedEditor.updateVizNode();
}
//------------------------------------------------------------------------------
function ParticleEditor::open(%this, %datablock)
{
//TODO:
//Check if we're dirty and if so, prompt about saving the change first
for(%i=0; %i < PE_ParticleDataTypes.count(); %i++)
{
%groupName = PE_ParticleDataTypes.getKey(%i);
%typesList = getField(PE_ParticleDataTypes.getValue(%i), 0);
%editorName = getField(PE_ParticleDataTypes.getValue(%i), 1);
%typesListCount = getWordCount(%typesList);
for(%t=0; %t < %typesListCount; %t++)
{
%type = getWord(%typesList, %t);
if( %datablock.isMemberOfClass( %type ) )
{
PE_TabBook.selectPage(%i);
%editorName.selectObject(%datablock);
return true;
}
}
}
return false;
}
//=============================================================================================
// PE_TabBook.
//=============================================================================================
//---------------------------------------------------------------------------------------------
function PE_TabBook::onTabSelected( %this, %text, %idx )
{
if(isObject(ParticleEditor.selectedEditor))
ParticleEditor.selectedEditor.closeEditorTab();
%tab = %this.getObject(%idx);
%tab.openEditorTab();
ParticleEditor.selectedEditor = %tab;
}
//------------------------------------------------------------------------------
// PE Window
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
function ParticleEditor::maxSize(%this, %window)
{
// Resize the windows to the max height
// and force these to the right side if set
if(EditorSettings.value( "WorldEditor/forceSidebarToSide" ) == 1 && %this.resizing == true)
{
// prevent onResize after a resize
%this.resizing = false;
%offset = -1; // tweak the vertical offset so that it aligns neatly
%top = EditorGuiToolbar.extent.y + %offset;
%bottom = %top + 59;
%maxHeight = Canvas.extent.y - %top - %bottom;
// --- Fixed window (top) ------------------------------------------------
// put it back if it moved
%window.position.x = Canvas.extent.x - %window.extent.x;
%window.position.y = %top;
// don't go beyond the canvas
%window.extent.y = %maxHeight + 42;
%position = %window.position.x SPC %window.position.y;
%extent = %window.extent.x SPC %window.extent.y;
%window.resize(%position.x, %position.y, %extent.x, %extent.y);
// --- AssetBrowser window ----------------------------------------------
if(isObject(AssetBrowserWindow))
{
// Only resize the AssetBrowser if it's docked
if(AssetBrowserWindow.docked == true)
{
// The width is relative to the sidepanel
%browserWidth = Canvas.extent.x - %extent.x;
%browserHeight = AssetBrowserWindow.extent.y;
%browserPosY = Canvas.extent.y - AssetBrowserWindow.extent.y - 33;
AssetBrowserWindow.resize(0, %browserPosY, %browserWidth, %browserHeight);
}
}
// --- Windowed Console --------------------------------------------------
if(isObject(windowConsoleControl))
{
// Only resize the AssetBrowser if it's docked
if(windowConsoleControl.docked == true)
{
// The width is relative to the sidepanel
%consoleWidth = Canvas.extent.x - %extent.x;
%consoleHeight = windowConsoleControl.extent.y;
%consolePosY = Canvas.extent.y - windowConsoleControl.extent.y - 33;
windowConsoleControl.resize(0, %consolePosY, %consoleWidth, %consoleHeight);
}
}
}
}
function PE_Window::onMouseDragged(%this)
{
%parent = ParticleEditor;
if(%parent.resizing == false)
{
%parent.resizing = true;
%parent.maxSize(%this);
}
}
function ParticleEditor::onResize(%this, %newPosition, %newExtent)
{
// Window to focus on (mostly the fluid window)
%window = PE_Window;
if(%this.resizing == false)
{
// Only resize once
%this.resizing = true;
%this.maxSize(%window);
}
FieldInfoControl.position = 5 SPC EWInspectorWindow.extent.y - 40;
}
//------------------------------------------------------------------------------
function ParticleEditorInspector::onInspectorFieldModified(%this, %object, %fieldName, %arrayIndex, %oldValue, %newValue)
{
if(%oldValue $= %newValue)
return;
ParticleEditor.selectedEditor.onInspectorFieldModified(%object, %fieldName, %arrayIndex, %oldValue, %newValue);
ParticleEditor.selectedEditor.setDirty(true);
}