[Closed] Automatically Add Custom Attribute?
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
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