Notifications
Clear all

[Closed] Automatically Add Custom Attribute?

I like it … it’s a nice catch…

another option would be to subclass sme parameter editor window and check if CA is present at each repaint event

parameters paint event
(

local   source = ""
		source  = "using System;\n"
		source += "using System.Collections.Generic;\n"
		source += "using System.Text;\n"
		source += "using System.Runtime.InteropServices;\n"
		source += "using System.Windows.Forms;\n"
		source += "\n"
		source += "namespace WinAPI\n"
		source += "{\n"
		source += "		class MessageSnooper : NativeWindow\n"
		source += "		{\n"
		source += "		public class MsgEventArgs : EventArgs
							{
								public MsgEventArgs( Message message )
								{
									Message = message;
									Handled = false;
								}
								public readonly Message Message;
								public bool Handled = false;
							}
						
							public event EventHandler MessageEvent;
												
							
							protected override void WndProc( ref Message message )
							{
								if ( MessageEvent != null )
								{
									MsgEventArgs msg = new MsgEventArgs( message );
									MessageEvent( this, msg );
									
									if ( msg.Handled ) return;
								}

								base.WndProc( ref message );
							}
						}
					}
					"		

				
		csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
		compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
		compilerParams.ReferencedAssemblies.Add("System.dll");
		compilerParams.ReferencedAssemblies.Add("System.IO.dll");
		compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");		
		compilerParams.GenerateInMemory = on
		compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
		
		
		if (compilerResults.Errors.Count > 0 ) then
		(
			local errs = stringstream ""
			for i = 0 to (compilerResults.Errors.Count-1) do
			(
				local err = compilerResults.Errors.Item[i]
				format "Error:% Line:% Column:% %\n" err.ErrorNumber err.Line err.Column err.ErrorText to:errs
			)
			format "%\n" errs
			undefined
		)

		compilerResults.CompiledAssembly.CreateInstance "WinAPI.MessageSnooper"	

		global messagesnooper = dotnetobject "WinAPI.MessageSnooper"
		
)

try (destroydialog X ) catch ()
rollout X "SME Param Editor Subclassing" width:250
(	
	fn GetSMEParamEditorHWND = 
	(
		try
		(
			local max_hwnd          = windows.getMAXHWND()
			local sme_window_hwnd   = for w in windows.getChildrenHWND 0 where w[4] == "NodeJoeMainWindow" and w[6] == max_hwnd do exit with w[1]	
			local param_editor_hwnd = (windows.getChildHWND sme_window_hwnd "Material Parameter Editor")[1]
		
		)catch()
	)

	local param_editor_hwnd = GetSMEParamEditorHWND()
		
	checkbutton hook "Disabled" align:#center width:240
	
	fn OnMessageEvent msg =
	(		
		if msg.Message.Msg == 0x0085 do -- WM_NCPAINT
		(
			format "HWnd:%  LParam:% WParam:% Result:%\n" msg.Message.HWnd msg.Message.LParam msg.Message.WParam msg.Message.Result
			
			local item = SME.GetMtlInParamEditor()
			
			if item != undefined do
			(
				format ">> %\n" item
			)
		)		
	)		
	
	on x open do
	(	
		if not SME.IsOpen() do
		(
			SME.Open()
			param_editor_hwnd = GetSMEParamEditorHWND()

			setFocus X	
		)
		
		::messagesnooper.releaseHandle()
		dotNet.removeAllEventHandlers messagesnooper		
	)

	on hook changed state do
	(		
		if state and UIAccessor.IsWindow param_editor_hwnd then
		(			
			hook.Text = "Enabled"
			::messagesnooper.releaseHandle()
			dotNet.removeAllEventHandlers messagesnooper
			::messagesnooper.assignHandle (dotNetObject "System.IntPtr" param_editor_hwnd)
			dotnet.addEventHandler messagesnooper "MessageEvent" OnMessageEvent
			
		) else
		(			
			hook.checked = false
			hook.Text = "Disabled"
			::messagesnooper.releaseHandle()
			dotNet.removeAllEventHandlers messagesnooper
			
		)
		
	)

)
createDialog X

upd
actually it is better to catch WM_SETTEXT event sent to MtlName edit text control as it is fired less often and only when user changes node name or opens a texmap/mtl in parameters editor


(

local   source = ""
		source  = "using System;\n"
		source += "using System.Collections.Generic;\n"
		source += "using System.Text;\n"
		source += "using System.Runtime.InteropServices;\n"
		source += "using System.Windows.Forms;\n"
		source += "\n"
		source += "namespace WinAPI\n"
		source += "{\n"
		source += "		class MessageSnooper : NativeWindow\n"
		source += "		{\n"
		source += "		public class MsgEventArgs : EventArgs
							{
								public MsgEventArgs( Message message )
								{
									Message = message;
									Handled = false;
								}
								public readonly Message Message;
								public bool Handled = false;
							}
						
							public event EventHandler MessageEvent;
												
							
							protected override void WndProc( ref Message message )
							{
								if ( MessageEvent != null )
								{
									MsgEventArgs msg = new MsgEventArgs( message );
									MessageEvent( this, msg );
									
									if ( msg.Handled ) return;
								}

								base.WndProc( ref message );
							}
						}
					}
					"		

				
		csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
		compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
		compilerParams.ReferencedAssemblies.Add("System.dll");
		compilerParams.ReferencedAssemblies.Add("System.IO.dll");
		compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");		
		compilerParams.GenerateInMemory = on
		compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
		
		
		if (compilerResults.Errors.Count > 0 ) then
		(
			local errs = stringstream ""
			for i = 0 to (compilerResults.Errors.Count-1) do
			(
				local err = compilerResults.Errors.Item[i]
				format "Error:% Line:% Column:% %\n" err.ErrorNumber err.Line err.Column err.ErrorText to:errs
			)
			format "%\n" errs
			undefined
		)

		compilerResults.CompiledAssembly.CreateInstance "WinAPI.MessageSnooper"	

		global messagesnooper = dotnetobject "WinAPI.MessageSnooper"
		
)

try (destroydialog X ) catch ()
rollout X "SME Param Editor Subclassing" width:250
(	
	fn GetSMEParamEditorHWND = 
	(
		try
		(
			local max_hwnd          = windows.getMAXHWND()
			local sme_window_hwnd   = for w in windows.getChildrenHWND 0 where w[4] == "NodeJoeMainWindow" and w[6] == max_hwnd do exit with w[1]	
			local param_editor_hwnd = (windows.getChildHWND sme_window_hwnd "MtlName")[1]
			for w in windows.getChildrenHWND param_editor_hwnd where w[4] == "Edit" do exit with w[1]

		)catch()
	)

	local param_editor_hwnd = GetSMEParamEditorHWND()
		
	checkbutton hook "Disabled" align:#center width:240
	
	fn OnMessageEvent msg =
	(	
		if msg.Message.Msg == 0x000C do -- WM_SETTEXT
		(
			format "HWnd:%  LParam:% WParam:% Result:%\n" msg.Message.HWnd msg.Message.LParam msg.Message.WParam msg.Message.Result
			
			local item = SME.GetMtlInParamEditor()
			
			if item != undefined do
			(
				format ">> %\n" item
			)
		)		
	)		
	
	on x open do
	(	
		if not SME.IsOpen() do
		(
			SME.Open()
			param_editor_hwnd = GetSMEParamEditorHWND()

			setFocus X	
		)
		
		::messagesnooper.releaseHandle()
		dotNet.removeAllEventHandlers messagesnooper		
	)

	on hook changed state do
	(		
		if state and UIAccessor.IsWindow param_editor_hwnd then
		(			
			hook.Text = "Enabled"
			::messagesnooper.releaseHandle()
			dotNet.removeAllEventHandlers messagesnooper
			::messagesnooper.assignHandle (dotNetObject "System.IntPtr" param_editor_hwnd)
			dotnet.addEventHandler messagesnooper "MessageEvent" OnMessageEvent
			
		) else
		(			
			hook.checked = false
			hook.Text = "Disabled"
			::messagesnooper.releaseHandle()
			dotNet.removeAllEventHandlers messagesnooper
			
		)
		
	)

)
createDialog X

How about this (?):

global AdvBitmapAttr = attributes AdvBitmapAttr attribid:#(0x00de01, 0xde00de) 
(
	parameters params rollout:params
	(
	)
	rollout params "Advanced Attribute"
	(
	)
)

macroScript BitmapTextureCheck
	category:"Debug Ops"
	buttonText:"BMP CHECK"
	toolTip:"BitmapTexture Check"
	autoUndoEnabled:off
	silentErrors:off
(
	local need_add = off
	local enable_edit = on
	
	fn enabled = 
	(
		bb = getclassinstances BitmapTexture
		need_add = off
		for b in bb while not need_add where b.custattributes[#AdvBitmapAttr] == undefined do need_add = on 
		need_add
	)
	fn add_bitmap_ca = 
	(
		bb = getclassinstances BitmapTexture
		for b in bb where b.custattributes[#AdvBitmapAttr] == undefined do custattributes.add b AdvBitmapAttr
	)
	
	on isEnabled do (enabled())
	--on isChecked do (enabled() and enable_edit)
	on execute do if enabled() do 
	(
		undo "Add Bitmap Attribute" on add_bitmap_ca()
		updateToolbarButtons()
	)
)			

deleteAllChangeHandlers id:#bitmap_ca_check 
when geometry meditmaterials change id:#bitmap_ca_check do (updateToolbarButtons())
when geometry scenematerials change id:#bitmap_ca_check do (updateToolbarButtons())

when construct can be used for automatic update as well

bitmaptexture must be used in a scene or an edit material in this case

PS. of course all above can be combined in one Struct to minimize extra globals

So CAs assigned only manually?

It seems to ‘randomly’ call updateToolbarButtons from the first change handler when switching between materials in basic medit editor.

when geometry meditmaterials change id:#bitmap_ca_check do (format ">> 1\n"; updateToolbarButtons()) -- called multiple times when switching between basic mtl editor materials
when geometry scenematerials change id:#bitmap_ca_check do (format ">> 2\n"; updateToolbarButtons())
gif

something very weird happens on scene reset
lG10BRTQur

when you open/close material editor the system calls NOTIFY_MTL_REFADDED/NOTIFY_MTL_REFDELETED callbacks … once in the past it might have made sense, but now the need for it is completely incomprehensible

also you can see these callbacks every time you change the active slot of the material editor … (#added for selected and #deleted for deselected)

in this case, of course, no new references are creating and no old ones are deleting

Page 2 / 2