Files
gtav-src/tools_ng/wildwest/script/3dsMax/General_tools/RSL_CollisionOps2Attribute.ms
T
2025-09-29 00:52:08 +02:00

1293 lines
56 KiB
Plaintext
Executable File

---------------------------------------------------------------------------------------------------------------------------------------
-- RSL_CollisionOps2Attribute
-- By Paul Truss
-- Senior Technical Artist
-- Rockstar Games London
-- 12/01/2011
--
-- Modified for Rockstar North by Neil Gregory
-- 07/2011
--
-- Structure containing functions and UI used by RSL_CollisionOps2 in create mode
---------------------------------------------------------------------------------------------------------------------------------------
-- main struct
struct RSL_CollisionOps2Attribute
(
---------------------------------------------------------------------------------------------------------------------------------------
-- Struct variables
---------------------------------------------------------------------------------------------------------------------------------------
INIfile = (RsConfigGetWildWestDir() + "etc/config/general/collisionOps2.ini"),
textureDirectory = (RsConfigGetWildWestDir() +"etc/config/general/collision_textures/"),
rsNorthAttFile = (RsConfigGetToolsDir() +"dcc/current/max2011/plugcfg/rsnorth.att"),
materialsDatFile = (RsConfigGetCommonDir() + "/data/materials/materials.dat"),
proceduralDatFile = (RsConfigGetCommonDir() + "/data/materials/procedural.dat"),
-- there are two surface type arrays depending on weather the object has rexbound materials or not and two arrays for each
-- because we remove "temp" surface types. The full arrays are used to get the chosen surface type, the reduced arrays
-- are used for the surface type dialogs
fullAttSurfaceTypeArray = #(),
fullMaterialsDatSurfaceTypeArray = #(),
attSurfaceTypeArray = #(),
matDatSurfaceTypeArray = #(),
-- rebound and attribute specific arrays
proceduralArray = #(),
pieceTypeArray = #(),
-- standard attribute indices
idxColType = getAttrIndex "Gta Collision" "Coll Type",
idxStairs = getAttrIndex "Gta Collision" "Stairs",
idxNoClimb = getAttrIndex "Gta Collision" "Non Climable",
idxSee = getAttrIndex "Gta Collision" "See Through",
idxNoCamera = getAttrIndex "Gta Collision" "Non Camera Collidable",
idxShoot = getAttrIndex "Gta Collision" "Shoot Through",
idxWet = getAttrIndex "Gta Collision" "Wet",
idxPath = getAttrIndex "Gta Collision" "Path",
idxPiece = getAttrIndex "Gta Collision" "Piece Type",
idxDay = getAttrIndex "Gta Collision" "Day Brightness",
idxNight = getAttrIndex "Gta Collision" "Night Brightness",
idxAudio = getAttrIndex "Gta Collision" "Audio Material",
idxRoomID = getAttrIndex "Gta Collision" "Room ID",
--idxLeeds = getAttrIndex "Gta Collision" "Edited by Leeds",
idxBVH = getAttrIndex "Gta Collision" "BVH Bound",
idxProcTint = getAttrIndex "Gta Collision" "Use Procedural Tint",
idxClothColl = getAttrIndex "Gta Collision" "Is Cloth Collision",
---------------------------------------------------------------------------------------------------------------------------------------
-- UI variables
---------------------------------------------------------------------------------------------------------------------------------------
toolTip = dotNetObject "ToolTip",
colourDialog = dotNetObject "ColorDialog",
copiedColour,
lastType,
lastColour,
mousePoint,
surfaceTypeForm,palletteList,surfaceTypeOkButton,surfaceTypeCancelButton,
typeControlMenu,editColour,copyColour,pasteColour,selectFaces,
pieceTypeForm,pieceTypeListview,pieceTypeOkButton,pieceTypeCancelButton,
proceduralTypeForm,proceduralTypeListview,proceduralTypeOkButton,proceduralTypeCancelButton,
miloRoomForm,miloRoomListview,miloRoomOkButton,miloRoomCancelButton,
---------------------------------------------------------------------------------------------------------------------------------------
--
-- FUNCTIONS
--
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
-- filterTemp() Removes any "temp*" surface types from the two surface type arrays
---------------------------------------------------------------------------------------------------------------------------------------
fn filterTemp =
(
local tempArray = attSurfaceTypeArray
attSurfaceTypeArray = #()
for entry in tempArray do
(
if not (matchPattern entry.type pattern:"temp*") then
(
append attSurfaceTypeArray entry
)
)
tempArray = matDatSurfaceTypeArray
matDatSurfaceTypeArray = #()
for entry in tempArray do
(
if not (matchPattern entry.type pattern:"temp*") then
(
append matDatSurfaceTypeArray entry
)
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- readAttFile() Reads the rsnorth.att and assigns all surface types to the att surface type arrays
---------------------------------------------------------------------------------------------------------------------------------------
fn readAttFile =
(
local dataStream = openFile rsNorthAttFile
fullAttSurfaceTypeArray = #()
attSurfaceTypeArray = #()
if dataStream != undefined then
(
skipToString dataStream "startui \"Gta Collision\" #editing \"Gta Collision\""
skipToString dataStream "list 7 \""
local line = (readDelimitedString dataStream "\"")
pieceTypeArray = filterString line ","
skipToString dataStream "tlist 367 \""
line = toUpper (readDelimitedString dataStream "\"")
attSurfaceTypeArray = filterString line ","
sort attSurfaceTypeArray
fullAttSurfaceTypeArray = deepCopy attSurfaceTypeArray
for i = 1 to attSurfaceTypeArray.count do
(
attSurfaceTypeArray[i] = (dataPair type:attSurfaceTypeArray[i] index:i)
)
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- readMaterialsDatFile() Reads the materials.dat and assigns all surface types to the materials dat surface type arrays
---------------------------------------------------------------------------------------------------------------------------------------
fn readMaterialsDatFile =
(
local dataStream = openFile materialsDatFile
fullMaterialsDatSurfaceTypeArray = #()
matDatSurfaceTypeArray = #()
if dataStream != undefined then
(
readLine dataStream
while not (eof dataStream) do
(
local line = readLine dataStream
if line != "" and line[1] != "#" and line[1] != "\t" then
(
local filtered = filterString line "\t"
if filtered.count > 0 then
(
append matDatSurfaceTypeArray (toUpper filtered[1])
)
)
)
sort matDatSurfaceTypeArray
fullMaterialsDatSurfaceTypeArray = deepCopy matDatSurfaceTypeArray
for i = 1 to matDatSurfaceTypeArray.count do
(
matDatSurfaceTypeArray[i] = (dataPair type:matDatSurfaceTypeArray[i] index:i)
)
-- set the last type so that we can set the surface type button
lastType = getINISetting INIFile "settings" "lastType"
if lastType == "" then lastType = matDatSurfaceTypeArray[1].type
)
else
(
print "materials dat failed to load."
)
close dataStream
),
---------------------------------------------------------------------------------------------------------------------------------------
-- readPoceduralDatFile() Reads the procedural.dat and assigns all procedural types to the proceduralArray
---------------------------------------------------------------------------------------------------------------------------------------
fn readPoceduralDatFile =
(
local dataStream = openFile proceduralDatFile
proceduralArray = #()
if dataStream != undefined then
(
skipToString dataStream "PROCOBJ_DATA_START"
while not (eof dataStream) do
(
local line = readLine dataStream
-- make sure we ignore the lines we don't need
if line != "" and line[1] != "#" and line[1] != "\t" and line != "PLANT_DATA_START" and line != "PLANT_DATA_END" and line != "PROCOBJ_DATA_END" then
(
local filtered = filterString line " \t"
-- make sure we ignore any lines with only tabs in them
if filtered.count > 0 then
(
appendIfUnique proceduralArray filtered[1]
)
)
)
sort proceduralArray
insertItem "NONE" proceduralArray 1
)
else
(
print "procedural dat failed to load."
)
close dataStream
),
---------------------------------------------------------------------------------------------------------------------------------------
-- getColours() Gets the colours set in the INI file for each surface type control in the palletteFlow
---------------------------------------------------------------------------------------------------------------------------------------
fn getColours =
(
for i = 0 to palletteFlow.controls.count - 1 do
(
local control = palletteFlow.controls.item[i]
local colour = getINISetting INIFile "surfaceColours" control.name
-- if a colour setting exists we can set the back colour for the control
if colour != "" then
(
local colourValue = readExpr (colour as stringStream)
control.backColor = RS_dotNetClass.colourClass.fromARGB colourValue.r colourValue.g colourValue.b
-- check to see if the back colour is not too similar to the fore colour
local backColTotal = colourValue.r + colourValue.g + colourValue.b
local foreColTotal = control.foreColor.r + control.foreColor.g + control.foreColor.b
-- they are too similar so we set the fore colour to either black or white
if (abs (backColTotal - foreColTotal)) < 128 then
(
if control.foreColor == RS_dotNetClass.colourClass.White then
(
control.foreColor = RS_dotNetClass.colourClass.Black
)
else
(
control.foreColor = RS_dotNetClass.colourClass.White
)
)
)
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- makeTexture() Creates a texture for the parsed name with the parsed colour. The texture has the parsed name printed
-- in the middle. If updateFile is true, we re-create the texture regardless of weather it exists or not.
---------------------------------------------------------------------------------------------------------------------------------------
fn makeTexture name colour updateFile:false =
(
-- attempt to make the directory if it does not already exist
makeDir textureDirectory
local file = textureDirectory + name + ".bmp"
if not (doesFileExist file) or updateFile then
(
-- delete the file if it exists
deleteFile file
-- if the colour is set to transparent, it's not be set so we make sure it's silver
if colour == RS_dotNetClass.colourClass.Transparent then
(
colour = RS_dotNetClass.colourClass.Silver
)
local bitmapImage = dotNetObject RS_dotNetClass.bitmapClass 256 256
local graphics = (dotNetClass "System.Drawing.Graphics").FromImage bitmapImage
local backBrush = dotNetObject RS_dotNetClass.solidBushClass colour
local font = dotNetObject "System.Drawing.Font" "Trebuchet MS" ((256 / 100) * 6) RS_dotNetPreset.f_Bold
local fontColour = RS_dotNetClass.brushesClass.White
-- check to see if the back colour is not too similar to the fore colour
local fontColTotal = fontColour.Color.r + fontColour.Color.g + fontColour.Color.b
local colourTotal = colour.r + colour.g + colour.b
-- they are too similar so we set the font colour to black
if (abs (fontColTotal - colourTotal)) < 128 then
(
fontColour = RS_dotNetClass.brushesClass.Black
)
local size = graphics.MeasureString name font
local x = 128.0 - (size.width * 0.5)
local y = 128.0 - (size.height * 0.5)
-- fill the bitmap with the colur and write the name string to the bitmap
graphics.FillRectangle backBrush (dotNetObject RS_dotNetClass.rectangleClass 0 0 256 256)
graphics.DrawString name font fontColour x y
bitmapImage.save file (RS_dotNetClass.imageFormatClass.bmp)
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- appendSurfaceTypeData()
---------------------------------------------------------------------------------------------------------------------------------------
mapped fn appendSurfaceTypeData data array =
(
local found = false
for entry in array do
(
if (matchPattern entry.type pattern:data.type) then
(
found = true
)
)
if not found then
(
append array data
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- generateTextures() Generates the display textures if needed
---------------------------------------------------------------------------------------------------------------------------------------
fn generateTextures =
(
local tempArray = deepCopy attSurfaceTypeArray
appendSurfaceTypeData matDatSurfaceTypeArray tempArray
progressStart "Creating Display Textures..."
for i = 1 to tempArray.count do
(
local entry = tempArray[i]
local colour = RS_dotNetClass.colourClass.Transparent
local colourString = getINISetting INIFile "surfaceColours" entry.type
if colourString != "" then
(
local colourValue = readExpr (colourString as stringStream)
colour = RS_dotNetClass.colourClass.fromARGB colourValue.r colourValue.g colourValue.b
)
makeTexture entry.type colour
progressUpdate (i as float / tempArray.count * 100.0)
)
progressEnd()
),
---------------------------------------------------------------------------------------------------------------------------------------
-- showDisplayMaterial() Sets the diffuse textures in the currentMesh material to displayed
---------------------------------------------------------------------------------------------------------------------------------------
fn showDisplayMaterial =
(
local material = ::RSL_CollisionOps.currentMesh.material
case (classOf material) of
(
Standardmaterial:
(
-- un-display and then display to ensure they update
showTextureMap material material.diffuseMap false
showTextureMap material material.diffuseMap true
)
Multimaterial:
(
for subMaterial in material.materialList where (classOf subMaterial) == Standardmaterial do
(
-- un-display and then display to ensure they update
showTextureMap subMaterial subMaterial.diffuseMap false
showTextureMap subMaterial subMaterial.diffuseMap true
)
)
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- setColour() Sets colour for the parsed name in the INI file to the parsed colour
---------------------------------------------------------------------------------------------------------------------------------------
fn setColour name colour =
(
setINISetting INIFile "surfaceColours" name ((color colour.r colour.g colour.b) as string)
-- re-make the texture because we've changed the colour
makeTexture name colour updateFile:true
-- if we're in edit mode force the texture to be displayed so that it updates
if ::RSL_CollisionOps.currentTool.name == "editTableLayout" then
(
showDisplayMaterial()
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- addSurfaceTypeItem() Adds each parsed surfaceType to the parsed listView if it matches the parsed searchText
---------------------------------------------------------------------------------------------------------------------------------------
mapped fn addSurfaceTypeItem surfaceType listView searchText =
(
local okToContinue = true
-- if the searchText has some text, we check that the surfaceType matches
if searchText.count > 0 then
(
okToContinue = (matchPattern surfaceType.type pattern:("*" + searchText + "*"))
)
if okToContinue then
(
local newItem = dotNetObject "ListViewItem" surfaceType.type
newItem.selected = surfaceType.type == lastType
if newItem.selected then
(
newItem.EnsureVisible()
)
-- get the colour for the surfaceType if it exists in the INI file
local colour = getINISetting INIFile "surfaceColours" surfaceType.type
if colour != "" then
(
local colourValue = readExpr (colour as stringStream)
newItem.backColor = RS_dotNetClass.colourClass.fromARGB colourValue.r colourValue.g colourValue.b
-- check to see if the back colour is not too similar to the fore colour
local backColTotal = colourValue.r + colourValue.g + colourValue.b
local foreColTotal = newItem.foreColor.r + newItem.foreColor.g + newItem.foreColor.b
-- they are too similar so we set the fore colour to either black or white
if (abs (backColTotal - foreColTotal)) < 128 then
(
if newItem.foreColor == RS_dotNetClass.colourClass.White then
(
newItem.foreColor = RS_dotNetClass.colourClass.Black
)
else
(
newItem.foreColor = RS_dotNetClass.colourClass.White
)
)
)
listView.items.add newItem
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- addTypeItem() Adds each parsed type to the parsed listView.
---------------------------------------------------------------------------------------------------------------------------------------
mapped fn addTypeItem type listView =
(
local newItem = dotNetObject "ListViewItem" type
listView.items.add newItem
),
---------------------------------------------------------------------------------------------------------------------------------------
-- addTypeItem() Adds each parsed object to the miloRoomListview.
---------------------------------------------------------------------------------------------------------------------------------------
mapped fn addMiloRoomItem object =
(
-- make sure we only add GtaMloRoom class objects
if (classOf object) == GtaMloRoom then
(
local newItem = dotNetObject "ListViewItem" object.name
-- assign the object to the tag because we will use it when the user chooses the listViewItem from the dialog
newItem.tag = dotNetMXSValue object
miloRoomListview.items.add newItem
)
),
---------------------------------------------------------------------------------------------------------------------------------------
--
-- UI FUNCTIONS
--
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchOkButtonClick() Dispatches OkButtonClick() Called when the user presses any one of the dialog ok buttons
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchOkButtonClick s e =
(
::RSL_CollisionOps.attribute.OkButtonClick s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- OkButtonClick() Depending on which dialog ok button was pressed, sets the relevant items up based on the choosen item
-- in the dialog
---------------------------------------------------------------------------------------------------------------------------------------
fn OkButtonClick s e =
(
case s.name of
(
"surfaceTypeOkButton":
(
case ::RSL_CollisionOps.currentTool.name of
(
"createTableLayout":
(
::RSL_CollisionOps.createUI.surfaceTypeButton.text = lastType
::RSL_CollisionOps.createUI.surfaceTypeButton.backColor = lastColour
)
"selectDisplayTableLayout":
(
::RSL_CollisionOps.selectDisplayUI.surfaceTypeButton.text = lastType
::RSL_CollisionOps.selectDisplayUI.surfaceTypeButton.backColor = lastColour
)
)
surfaceTypeForm.close()
)
"pieceTypeOkButton":
(
if pieceTypeListview.selectedItems.count == 1 then
(
case ::RSL_CollisionOps.currentTool.name of
(
"createTableLayout":
(
::RSL_CollisionOps.createUI.pieceTypeButton.text = pieceTypeListview.selectedItems.item[0].text
)
"editTableLayout":
(
::RSL_CollisionOps.editUI.pieceTypeButton.text = pieceTypeListview.selectedItems.item[0].text
)
"selectDisplayTableLayout":
(
::RSL_CollisionOps.selectDisplayUI.pieceTypeButton.text = pieceTypeListview.selectedItems.item[0].text
)
)
pieceTypeForm.close()
)
else
(
messageBox "Nothing selected. You must pick one or cancel." title:"Error..."
)
)
"proceduralTypeOkButton":
(
if proceduralTypeListview.selectedItems.count == 1 then
(
case ::RSL_CollisionOps.currentTool.name of
(
"createTableLayout":
(
::RSL_CollisionOps.createUI.proceduralTypeButton.text = proceduralTypeListview.selectedItems.item[0].text
)
"editTableLayout":
(
::RSL_CollisionOps.editUI.proceduralTypeButton.text = proceduralTypeListview.selectedItems.item[0].text
)
"selectDisplayTableLayout":
(
::RSL_CollisionOps.selectDisplayUI.proceduralTypeButton.text = proceduralTypeListview.selectedItems.item[0].text
)
)
proceduralTypeForm.close()
)
else
(
messageBox "Nothing selected. You must pick one or cancel." title:"Error..."
)
)
"miloRoomOkButton":
(
if miloRoomListview.selectedItems.count == 1 then
(
local selected = miloRoomListview.selectedItems.item[0]
local name = "None"
if selected.tag != undefined then
(
name = selected.tag.value.name
)
if ::RSL_CollisionOps.currentTool.name == "createTableLayout" then
(
::RSL_CollisionOps.createUI.miloRoomButton.text = name
::RSL_CollisionOps.createUI.miloRoomButton.tag = selected.tag
)
else
(
::RSL_CollisionOps.editUI.miloRoomButton.text = name
::RSL_CollisionOps.editUI.miloRoomButton.tag = selected.tag
)
miloRoomForm.close()
)
else
(
messageBox "Nothing selected. You must pick one or cancel." title:"Error..."
)
)
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchCancelButtonClick() Dispatches CancelButtonClick() Called when the user presses any one of the dialog cancel buttons
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchCancelButtonClick s e =
(
::RSL_CollisionOps.attribute.CancelButtonClick s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- CancelButtonClick() Depending on which dialog cancel button was pressed, closes the relevant dialog
---------------------------------------------------------------------------------------------------------------------------------------
fn CancelButtonClick s e =
(
case s.name of
(
"surfaceTypeCancelButton":
(
surfaceTypeForm.close()
)
"pieceTypeCancelButton":
(
pieceTypeForm.close()
)
"proceduralTypeCancelButton":
(
proceduralTypeForm.close()
)
"miloRoomCancelButton":
(
miloRoomForm.close()
)
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchMiloRoomFormClosing() Dispatches miloRoomFormClosing() Called when the milo room dialog is closed
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchMiloRoomFormClosing s e =
(
::RSL_CollisionOps.attribute.miloRoomFormClosing s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- miloRoomFormClosing() Enables the main form
---------------------------------------------------------------------------------------------------------------------------------------
fn miloRoomFormClosing s e =
(
::RSL_CollisionOps.CollisionForm.enabled = true
),
---------------------------------------------------------------------------------------------------------------------------------------
-- miloRoomDialog() Creates the milo room dialog
---------------------------------------------------------------------------------------------------------------------------------------
fn miloRoomDialog =
(
-- dissable the main form whilst the milo room dialog is open
RSL_CollisionOps.CollisionForm.enabled = false
--In this case, we're going to use a standard form rather than the custom maxForm written for max. this is because I want to change the
-- form back colour which you can't do if you use the custom maxForm. For this to work, we need to set the parent of the form to be Max.
-- USING THIS TYPE OF FORM MEANS WE NEED TO DISSABLE ACCELERATORS WHEN WE FOCUS ON A CONTROL THAT TAKES
-- KEY PRESSES SUCH AS SPINNERS AND TEXT BOXES
--Get the max handle pointer.
local maxHandlePointer=(Windows.GetMAXHWND())
--Convert the HWND handle of Max to a dotNet system pointer
local sysPointer = DotNetObject "System.IntPtr" maxHandlePointer
--Create a dotNet wrapper containing the maxHWND
local maxHwnd = DotNetObject "MaxCustomControls.Win32HandleWrapper" sysPointer
miloRoomForm = RS_dotNetUI.Form "miloRoomForm" text:"Procedural Types" size:[216,512] min:[216,128] borderStyle:RS_dotNetPreset.FB_SizableToolWindow
miloRoomForm.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").CenterScreen
dotnet.addEventHandler miloRoomForm "FormClosing" dispatchMiloRoomFormClosing
miloRoomListview = RS_dotNetUI.listView "attributeListView" dockStyle:RS_dotNetPreset.DS_Fill
miloRoomListview.HeaderStyle = (dotNetClass "System.Windows.Forms.ColumnHeaderStyle").None
miloRoomListview.columns.add "Milo Rooms"
miloRoomListview.items.Add (dotNetObject "ListViewItem" "None")
miloRoomOkButton = RS_dotNetUI.Button "miloRoomOkButton" text:("OK") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2)
dotnet.addEventHandler miloRoomOkButton "click" dispatchOkButtonClick
miloRoomCancelButton = RS_dotNetUI.Button "miloRoomCancelButton" text:("Cancel") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2)
dotnet.addEventHandler miloRoomCancelButton "click" dispatchCancelButtonClick
miloRoomLayout = RS_dotNetUI.tableLayout "miloRoomLayout" text:"miloRoomLayout" collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \
rows:#((dataPair type:"Percent" value:50),(dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill
miloRoomLayout.controls.add miloRoomListview 0 0
miloRoomLayout.controls.add miloRoomOkButton 0 1
miloRoomLayout.controls.add miloRoomCancelButton 1 1
miloRoomLayout.SetColumnSpan miloRoomListview 2
miloRoomForm.controls.add miloRoomLayout
addMiloRoomItem helpers
miloRoomListview.AutoResizeColumns (dotNetClass "ColumnHeaderAutoResizeStyle").HeaderSize
miloRoomForm.show maxHwnd
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchProceduralFormClosing() Dispatches proceduralFormClosing() Called when the procedural dialog is closed
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchProceduralFormClosing s e =
(
::RSL_CollisionOps.attribute.proceduralFormClosing s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- proceduralFormClosing() Enables the main form
---------------------------------------------------------------------------------------------------------------------------------------
fn proceduralFormClosing s e =
(
::RSL_CollisionOps.CollisionForm.enabled = true
),
---------------------------------------------------------------------------------------------------------------------------------------
-- proceduralFormClosing() Creates the procedural dialog
---------------------------------------------------------------------------------------------------------------------------------------
fn proceduralTypeDialog =
(
-- dissable the main form whilst the procedural dialog is open
RSL_CollisionOps.CollisionForm.enabled = false
--In this case, we're going to use a standard form rather than the custom maxForm written for max. this is because I want to change the
-- form back colour which you can't do if you use the custom maxForm. For this to work, we need to set the parent of the form to be Max.
-- USING THIS TYPE OF FORM MEANS WE NEED TO DISSABLE ACCELERATORS WHEN WE FOCUS ON A CONTROL THAT TAKES
-- KEY PRESSES SUCH AS SPINNERS AND TEXT BOXES
--Get the max handle pointer.
local maxHandlePointer=(Windows.GetMAXHWND())
--Convert the HWND handle of Max to a dotNet system pointer
local sysPointer = DotNetObject "System.IntPtr" maxHandlePointer
--Create a dotNet wrapper containing the maxHWND
local maxHwnd = DotNetObject "MaxCustomControls.Win32HandleWrapper" sysPointer
proceduralTypeForm = RS_dotNetUI.Form "proceduralTypeForm" text:"Procedural Types" size:[216,512] min:[216,128] borderStyle:RS_dotNetPreset.FB_SizableToolWindow
proceduralTypeForm.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").CenterScreen
dotnet.addEventHandler proceduralTypeForm "FormClosing" dispatchProceduralFormClosing
proceduralTypeListview = RS_dotNetUI.listView "attributeListView" dockStyle:RS_dotNetPreset.DS_Fill
proceduralTypeListview.HeaderStyle = (dotNetClass "System.Windows.Forms.ColumnHeaderStyle").None
proceduralTypeListview.columns.add "type"
proceduralTypeOkButton = RS_dotNetUI.Button "proceduralTypeOkButton" text:("OK") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2)
dotnet.addEventHandler proceduralTypeOkButton "click" dispatchOkButtonClick
proceduralTypeCancelButton = RS_dotNetUI.Button "proceduralTypeCancelButton" text:("Cancel") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2)
dotnet.addEventHandler proceduralTypeCancelButton "click" dispatchCancelButtonClick
proceduralTypeLayout = RS_dotNetUI.tableLayout "proceduralTypeLayout" text:"proceduralTypeLayout" collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \
rows:#((dataPair type:"Percent" value:50),(dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill
proceduralTypeLayout.controls.add proceduralTypeListview 0 0
proceduralTypeLayout.controls.add proceduralTypeOkButton 0 1
proceduralTypeLayout.controls.add proceduralTypeCancelButton 1 1
proceduralTypeLayout.SetColumnSpan proceduralTypeListview 2
proceduralTypeForm.controls.add proceduralTypeLayout
addTypeItem proceduralArray proceduralTypeListview
proceduralTypeListview.AutoResizeColumns (dotNetClass "ColumnHeaderAutoResizeStyle").HeaderSize
proceduralTypeForm.show maxHwnd
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchPieceFormClosing() Dispatches pieceFormClosing() Called when the piece type dialog is closed
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchPieceFormClosing s e =
(
::RSL_CollisionOps.attribute.pieceFormClosing s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- pieceFormClosing() Enables the main form
---------------------------------------------------------------------------------------------------------------------------------------
fn pieceFormClosing s e =
(
::RSL_CollisionOps.CollisionForm.enabled = true
),
---------------------------------------------------------------------------------------------------------------------------------------
-- pieceFormClosing() Creates the piece type dialog
---------------------------------------------------------------------------------------------------------------------------------------
fn pieceTypeDialog =
(
-- dissable the main form whilst the piece type dialog is open
RSL_CollisionOps.CollisionForm.enabled = false
--In this case, we're going to use a standard form rather than the custom maxForm written for max. this is because I want to change the
-- form back colour which you can't do if you use the custom maxForm. For this to work, we need to set the parent of the form to be Max.
-- USING THIS TYPE OF FORM MEANS WE NEED TO DISSABLE ACCELERATORS WHEN WE FOCUS ON A CONTROL THAT TAKES
-- KEY PRESSES SUCH AS SPINNERS AND TEXT BOXES
--Get the max handle pointer.
local maxHandlePointer=(Windows.GetMAXHWND())
--Convert the HWND handle of Max to a dotNet system pointer
local sysPointer = DotNetObject "System.IntPtr" maxHandlePointer
--Create a dotNet wrapper containing the maxHWND
local maxHwnd = DotNetObject "MaxCustomControls.Win32HandleWrapper" sysPointer
pieceTypeForm = RS_dotNetUI.Form "pieceTypeForm" text:"Piece Types" size:[216,512] min:[216,128] borderStyle:RS_dotNetPreset.FB_SizableToolWindow
pieceTypeForm.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").CenterScreen
dotnet.addEventHandler pieceTypeForm "FormClosing" dispatchPieceFormClosing
pieceTypeListview = RS_dotNetUI.listView "attributeListView" dockStyle:RS_dotNetPreset.DS_Fill
pieceTypeListview.HeaderStyle = (dotNetClass "System.Windows.Forms.ColumnHeaderStyle").None
pieceTypeListview.columns.add "type"
pieceTypeOkButton = RS_dotNetUI.Button "pieceTypeOkButton" text:("OK") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2)
dotnet.addEventHandler pieceTypeOkButton "click" dispatchOkButtonClick
pieceTypeCancelButton = RS_dotNetUI.Button "pieceTypeCancelButton" text:("Cancel") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2)
dotnet.addEventHandler pieceTypeCancelButton "click" dispatchCancelButtonClick
pieceTypeLayout = RS_dotNetUI.tableLayout "pieceTypeLayout" text:"pieceTypeLayout" collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \
rows:#((dataPair type:"Percent" value:50),(dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill
pieceTypeLayout.controls.add pieceTypeListview 0 0
pieceTypeLayout.controls.add pieceTypeOkButton 0 1
pieceTypeLayout.controls.add pieceTypeCancelButton 1 1
pieceTypeLayout.SetColumnSpan pieceTypeListview 2
pieceTypeForm.controls.add pieceTypeLayout
addTypeItem pieceTypeArray pieceTypeListview
pieceTypeListview.AutoResizeColumns (dotNetClass "ColumnHeaderAutoResizeStyle").HeaderSize
pieceTypeForm.show maxHwnd
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchSurfaceFormClosing() Dispatches surfaceFormClosing() Called when the surface type dialog is closed
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchSurfaceFormClosing s e =
(
::RSL_CollisionOps.attribute.surfaceFormClosing s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- surfaceFormClosing() Enables the main form
---------------------------------------------------------------------------------------------------------------------------------------
fn surfaceFormClosing s e =
(
::RSL_CollisionOps.CollisionForm.enabled = true
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchEditColourClick() Dispatches editColourClick() Called when the editColour menu item is clicked
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchEditColourClick s e =
(
::RSL_CollisionOps.attribute.editColourClick s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- editColourClick() Displays the colour dialog and sets the new colour
---------------------------------------------------------------------------------------------------------------------------------------
fn editColourClick s e =
(
-- get the listView the menu item is assigned to
local listView = s.Owner.SourceControl
-- get the list view item that was right clicked
local source = listView.GetItemAt mousePoint.x mousePoint.y
if source != undefined then
(
-- set the colour dialog colour to the back colour of the right clicked list view item
colourDialog.Color = source.backColor
-- if the user presses the ok button in the colour dialog, we can set the colour
if (colourDialog.ShowDialog()) == (dotNetClass "DialogResult").ok then
(
source.backColor = colourDialog.Color
-- check to see if the fore colour and back colour are too similar
local backColTotal = source.backColor.r + source.backColor.g + source.backColor.b
local foreColTotal = source.foreColor.r + source.foreColor.g + source.foreColor.b
-- they are so we set the fore colour to either white or black
if (abs (backColTotal - foreColTotal)) < 128 then
(
if source.foreColor == RS_dotNetClass.colourClass.White then
(
source.foreColor = RS_dotNetClass.colourClass.Black
)
else
(
source.foreColor = RS_dotNetClass.colourClass.White
)
)
-- save the colour to the INI file and update the texture
setColour source.text source.backColor
)
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchCopyPasteColourClick() Dispatches copyPasteColourClick() Called when either the copyColour or pasteColour menu
-- items are clicked
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchCopyPasteColourClick s e =
(
::RSL_CollisionOps.attribute.copyPasteColourClick s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- copyPasteColourClick() Depending on which menu item was clicked, copies the right clicked list view item's colour or pastes
-- an alread copied colour onto the right clicked list view item
---------------------------------------------------------------------------------------------------------------------------------------
fn copyPasteColourClick s e =
(
-- get the listView the menu item is assigned to
local listView = s.Owner.SourceControl
-- get the list view item that was right clicked
local source = listView.GetItemAt mousePoint.x mousePoint.y
if source != undefined then
(
case s.name of
(
"copyColour":
(
-- set the copiedColour struct variable to the back colour of the right clicked list view item
-- and enable the pasteColour menu item
copiedColour = source.backColor
pasteColour.enabled = true
)
"pasteColour":
(
if copiedColour != undefined then
(
-- set the bacl colour of the right clicked list view item to the copiedColour
source.backColor = copiedColour
-- check to see if the fore colour and back colour are too similar
local backColTotal = copiedColour.r + copiedColour.g + copiedColour.b
local foreColTotal = source.foreColor.r + source.foreColor.g + source.foreColor.b
-- they are so we set the fore colour to either white or black
if (abs (backColTotal - foreColTotal)) < 128 then
(
if source.foreColor == RS_dotNetClass.colourClass.White then
(
source.foreColor = RS_dotNetClass.colourClass.Black
)
else
(
source.foreColor = RS_dotNetClass.colourClass.White
)
)
-- save the colour to the INI file and update the texture
setColour source.text source.backColor
)
)
)
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchSelectFacesClick() Dispatches selectFacesClick() Called when the selectFaces copyColour menu item is clicked
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchSelectFacesClick s e =
(
::RSL_CollisionOps.attribute.selectFacesClick s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- selectFacesClick() Selects any faces in the currentMesh if they are set to the surface type of the right clicked list
-- view item. THIS IS ONLY AVAILABLE IN EDIT MODE
---------------------------------------------------------------------------------------------------------------------------------------
fn selectFacesClick s e =
(
-- get the list view
local listView = s.Tag.Value
-- get the right clicked list view item
local source = listView.GetItemAt mousePoint.x mousePoint.y
-- get all the surface values for the currentMesh. Uses SimpleFaceData
local surfaceArray = ::RSL_CollisionOps.editUI.surfaceChannel.getValues()
local faceArray = #()
if ::RSL_CollisionOps.currentTool.name == "editTableLayout" then
(
-- check to see if the control key is being held down. If so, we add the currently selected faces to faceArray
-- so that we will grow the selection rather than replace it
local control = dotNetClass "system.windows.forms.control"
if control.modifierKeys == control.modifierKeys.Control then
(
faceArray = for f in ::RSL_CollisionOps.currentMesh.selectedFaces collect f.index
)
)
-- loop through all the surface types on the object and append any face indices for face that have the surface type
for i = 1 to surfaceArray.count do
(
local surfaceType = fullMaterialsDatSurfaceTypeArray[surfaceArray[i]]
if surfaceType == source.text then
(
appendIfUnique faceArray i
)
)
-- make sure we're in modify mode and face mode, then select the faces
setCommandPanelTaskMode #modify
subObjectLevel = 4
::RSL_CollisionOps.currentMesh.selectedFaces = #()
::RSL_CollisionOps.currentMesh.selectedFaces = faceArray
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchRightClickOpening() Dispatches rightClickOpening() Called when the user right clicks a list view item in the surface
-- type pallette
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchRightClickOpening s e =
(
::RSL_CollisionOps.attribute.rightClickOpening s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- rightClickOpening() Sets the mousePoint struct variable to the mouse position and the enabled state of the selectFaces
-- menu item
---------------------------------------------------------------------------------------------------------------------------------------
fn rightClickOpening s e =
(
local listView = s.SourceControl
mousePoint = listView.PointToClient (listView.Cursor.Position)
selectFaces.enabled = ::RSL_CollisionOps.currentType == #rexbound
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchPalletteListClick() Dispatches PalletteListClick() Called when the user clicks a list view item in the surface
-- type pallette
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchPalletteListClick s e =
(
::RSL_CollisionOps.attribute.PalletteListClick s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- PalletteListClick() Sets the mousePoint struct variable to the mouse position, the lastType stuct variable to the text
-- of the selected list view item and the lastColour struct variable to the back colour of the selected list view item
---------------------------------------------------------------------------------------------------------------------------------------
fn PalletteListClick s e =
(
mousePoint = s.PointToClient (s.Cursor.Position)
if s.selectedItems.count == 1 then
(
lastType = s.selectedItems.item[0].text
lastColour = s.selectedItems.item[0].backColor
setINISetting INIFile "settings" "lastType" lastType
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchPalletteListDoubleClick() Dispatches palletteListDoubleClick() Called when the user double clicks a list view item
-- in the surface type pallette
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchPalletteListDoubleClick s e =
(
::RSL_CollisionOps.attribute.palletteListDoubleClick s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- palletteListDoubleClick() If we're in Create mode, sets the lastType stuct variable to the text of the selected list view
-- item and the lastColour struct variable to the back colour of the selected list view item and then closes the surface type dialog.
-- If we're in Edit mode, runs the selectFacesClick function.
---------------------------------------------------------------------------------------------------------------------------------------
fn palletteListDoubleClick s e =
(
if s.selectedItems.count == 1 then
(
if ::RSL_CollisionOps.currentTool.name == "editTableLayout" and ::RSL_CollisionOps.currentType == #rebound then
(
selectFacesClick selectFaces ""
)
else
(
lastType = s.selectedItems.item[0].text
lastColour = s.selectedItems.item[0].backColor
setINISetting INIFile "settings" "lastType" lastType
OkButtonClick surfaceTypeOkButton ""
)
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- dispatchPalletteListResize() Dispatches palletteListResize() Called when the user resizes the surface type dialog or pallette
---------------------------------------------------------------------------------------------------------------------------------------
fn dispatchPalletteListResize s e =
(
::RSL_CollisionOps.attribute.palletteListResize s e
),
---------------------------------------------------------------------------------------------------------------------------------------
-- palletteListResize() Resizes the list view column
---------------------------------------------------------------------------------------------------------------------------------------
fn palletteListResize s e =
(
if palletteList.columns.count > 0 then
(
palletteList.columns.Item[0].width = (::RSL_CollisionOps.CollisionForm.width - 42)
)
),
---------------------------------------------------------------------------------------------------------------------------------------
-- surfaceTypePallette() Creates the surface type pallette for the Edit mode. The parsed type variable controls which
-- surface type array we use to populate the pallette. The parsed searchText variable is used the filter the surface types.
-- Returns the list view.
---------------------------------------------------------------------------------------------------------------------------------------
fn surfaceTypePallette type searchText =
(
editColour = RS_dotNetUI.ToolStripMenuItem "editColour" text:"Edit Colour"
dotnet.addEventHandler editColour "Click" dispatchEditColourClick
copyColour = RS_dotNetUI.ToolStripMenuItem "copyColour" text:"Copy Colour"
dotnet.addEventHandler copyColour "Click" dispatchCopyPasteColourClick
pasteColour = RS_dotNetUI.ToolStripMenuItem "pasteColour" text:"Paste Colour"
pasteColour.enabled = false
dotnet.addEventHandler pasteColour "Click" dispatchCopyPasteColourClick
selectFaces = RS_dotNetUI.ToolStripMenuItem "selectFaces" text:"Select Faces"
selectFaces.enabled = (type == #rexBound)
dotnet.addEventHandler selectFaces "Click" dispatchSelectFacesClick
typeControlMenu = RS_dotNetUI.ContextMenuStrip "typeControlMenu" items:#(selectFaces,RS_dotNetUI.separator(),editColour,RS_dotNetUI.separator(),copyColour,pasteColour)
dotnet.addEventHandler typeControlMenu "Opening" dispatchRightClickOpening
colourDialog.FullOpen = true
palletteList = RS_dotNetUI.listView "palletteList" dockStyle:RS_dotNetPreset.DS_Fill
palletteList.view = (dotNetClass "System.Windows.Forms.View").Details
palletteList.HeaderStyle = (dotNetClass "System.Windows.Forms.ColumnHeaderStyle").None
palletteList.Sorting = (dotNetClass "System.Windows.Forms.SortOrder").None
palletteList.HideSelection = false
palletteList.scrollable = true
palletteList.fullRowSelect = true
palletteList.ContextMenuStrip = typeControlMenu
palletteList.backColor = RS_dotNetPreset.controlColour_Medium
dotnet.addEventHandler palletteList "SelectedIndexChanged" dispatchPalletteListClick
dotnet.addEventHandler palletteList "MouseDoubleClick" dispatchPalletteListDoubleClick
dotNet.addEventHandler palletteList "Resize" dispatchPalletteListResize
-- Depending on the parsed type, we populate the pallette from the correct surface type array
if type == #primitive then
(
addSurfaceTypeItem attSurfaceTypeArray palletteList searchText
)
else
(
addSurfaceTypeItem matDatSurfaceTypeArray palletteList searchText
)
selectFaces.tag = dotNetMXSValue palletteList
palletteList.Columns.Add "SurfaceType" (::RSL_CollisionOps.CollisionForm.width - 42)
palletteList
),
---------------------------------------------------------------------------------------------------------------------------------------
-- surfaceTypeDialog() Creates the surface type dialog use in Create mode. The parsed type variable controls which
-- surface type array we use to populate the pallette.
---------------------------------------------------------------------------------------------------------------------------------------
fn surfaceTypeDialog type =
(
RSL_CollisionOps.CollisionForm.enabled = false
--In this case, we're going to use a standard form rather than the custom maxForm written for max. this is because I want to change the
-- form back colour which you can't do if you use the custom maxForm. For this to work, we need to set the parent of the form to be Max.
-- USING THIS TYPE OF FORM MEANS WE NEED TO DISSABLE ACCELERATORS WHEN WE FOCUS ON A CONTROL THAT TAKES
-- KEY PRESSES SUCH AS SPINNERS AND TEXT BOXES
--Get the max handle pointer.
local maxHandlePointer=(Windows.GetMAXHWND())
--Convert the HWND handle of Max to a dotNet system pointer
local sysPointer = DotNetObject "System.IntPtr" maxHandlePointer
--Create a dotNet wrapper containing the maxHWND
local maxHwnd = DotNetObject "MaxCustomControls.Win32HandleWrapper" sysPointer
surfaceTypeForm = RS_dotNetUI.Form "surfaceTypeForm" text:"Surface Types" size:[216,512] min:[216,128] borderStyle:RS_dotNetPreset.FB_SizableToolWindow
surfaceTypeForm.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").CenterScreen
dotnet.addEventHandler surfaceTypeForm "FormClosing" dispatchSurfaceFormClosing
editColour = RS_dotNetUI.ToolStripMenuItem "editColour" text:"Edit Colour"
dotnet.addEventHandler editColour "Click" dispatchEditColourClick
copyColour = RS_dotNetUI.ToolStripMenuItem "copyColour" text:"Copy Colour"
dotnet.addEventHandler copyColour "Click" dispatchCopyPasteColourClick
pasteColour = RS_dotNetUI.ToolStripMenuItem "pasteColour" text:"Paste Colour"
pasteColour.enabled = false
dotnet.addEventHandler pasteColour "Click" dispatchCopyPasteColourClick
typeControlMenu = RS_dotNetUI.ContextMenuStrip "typeControlMenu" items:#(editColour,RS_dotNetUI.separator(),copyColour,pasteColour)
colourDialog.FullOpen = true
palletteList = RS_dotNetUI.listView "palletteList" dockStyle:RS_dotNetPreset.DS_Fill
palletteList.view = (dotNetClass "System.Windows.Forms.View").Details
palletteList.HeaderStyle = (dotNetClass "System.Windows.Forms.ColumnHeaderStyle").None
palletteList.Sorting = (dotNetClass "System.Windows.Forms.SortOrder").None
palletteList.HideSelection = false
palletteList.scrollable = true
palletteList.fullRowSelect = true
palletteList.ContextMenuStrip = typeControlMenu
palletteList.backColor = RS_dotNetPreset.controlColour_Medium
dotnet.addEventHandler palletteList "SelectedIndexChanged" dispatchPalletteListClick
dotnet.addEventHandler palletteList "MouseDoubleClick" dispatchPalletteListDoubleClick
dotNet.addEventHandler palletteList "Resize" dispatchPalletteListResize
-- Depending on the parsed type, we populate the pallette from the correct surface type array
if type == #primitive then
(
addSurfaceTypeItem attSurfaceTypeArray palletteList ""
)
else
(
addSurfaceTypeItem matDatSurfaceTypeArray palletteList ""
)
palletteList.Columns.Add "SurfaceType" (::RSL_CollisionOps.CollisionForm.width - 42)
surfaceTypeOkButton = RS_dotNetUI.Button "surfaceTypeOkButton" text:("OK") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2)
dotnet.addEventHandler surfaceTypeOkButton "click" dispatchOkButtonClick
surfaceTypeCancelButton = RS_dotNetUI.Button "surfaceTypeCancelButton" text:("Cancel") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2)
dotnet.addEventHandler surfaceTypeCancelButton "click" dispatchCancelButtonClick
surfaceTypeLayout = RS_dotNetUI.tableLayout "surfaceTypeLayout" text:"surfaceTypeLayout" collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \
rows:#((dataPair type:"Percent" value:50),(dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill
surfaceTypeLayout.controls.add palletteList 0 0
surfaceTypeLayout.controls.add surfaceTypeOkButton 0 1
surfaceTypeLayout.controls.add surfaceTypeCancelButton 1 1
surfaceTypeLayout.SetColumnSpan palletteList 2
surfaceTypeForm.controls.add surfaceTypeLayout
surfaceTypeForm.show maxHwnd
)
)