Drag-Drop Material as String


#1

I was checking out this thread about a way to simulate drag-and-droping materials outside of the Material Editor:
http://forums.cgsociety.org/showthread.php?f=98&t=685803&highlight=drag+drop

and in it PiXeL_MoNKeY suggested a way of doing it using the LoneRobot method since max stores materials as unique strings. In the end MarcoBrunetta came up with a different solution, but I was curious if what PiXeL_MoNKeY wrote can be done since his version would allow dropping into the material editor and not just objects in the scene.

My question is how do I find out this “unique string” for a material for example in a material library somewhere?

I tried just loading a Temp Material Library and getting its first material, but max gave an error saying that it couldn’t convert the material to a “type: System.Object”

try (destroyDialog ::DragDropOps) catch()
rollout DragDropOps "LoneRobot Drag Drop" width:136 height:150
(
	dotNetControl btndragdrop "label" pos:[5,5] width:125 height:139 
	on DragDropOps open do
	(
		btndragdrop.allowdrop = true
		btndragdrop.text = "Hooray! A Drag/Drop Enabled Label!!! 

To drop a Texturemap, just pass the map path string in the dataobject instead of a max file path. This will also work if draging a map to the material editor"
		btndragdrop.borderstyle = (dotNetClass "System.Windows.Forms.BorderStyle").fixedsingle	
		btndragdrop.backcolor = (dotnetclass "System.Drawing.Color").orangered	
		btndragdrop.forecolor = (dotnetclass "System.Drawing.Color").yellow
	)
	on btndragdrop mousemove sender args do
	(
		if (sender.clientrectangle.contains args.x args.y) then setSysCur #arrow
		else setSysCur #move
	)
	on btndragdrop mouseup sender args do
	(
		if (sender.clientrectangle.contains args.x args.y) then (print "asd")
		else
		(			
			theIniFile = getdir #maxData  + "3dsmax.ini" 
			theKeys = getIniSetting theIniFile "FileList"
			
			
-- 			filenameString = "D:\Object.max" -- max object
-- 			filenameString = "D:\Texture.jpg" -- texture
			filenameString = "?????????" -- material
-- 			matLib = loadTempMaterialLibrary "D:\MatLib.mat"
-- 			filenameString = matLib[1]
			
			dropfile = dotnetobject "System.String[]" 1
			dropfile.setvalue filenameString 0			
			DataObj = dotnetobject "DataObject" ((dotnetclass "DataFormats").filedrop) dropfile
			sender.dodragdrop Dataobj ((dotnetclass "DragDropEffects").Copy)
		)
	)
)
createdialog DragDropOps style:#(#style_toolwindow, #style_sysmenu)

#2

where from do you want to drag and where on do you want to drop a material?


#3

Well, in the example I posted you drag from the label with the text on it. And I want to be able to drag to an scene object, material editor slot, VrayBlendMtl slot, etc. Any place where max allows materials to be dropped.


#4

they are all three different tricks. a universal solution i know is the using of hook procedures.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx

but it’s too advanced for this topic


#5

So you are saying it can’t be done without super-advanced tricks and that what PiXeL_MoNKeY wrote was wrong? :confused:

In the code I posted, if the variable filenameString is a file path for an image or max file somewhere on the hard drive, the dragging functionality seems to work universally. I don’t know enough about how max handles things behind the scene, but I assumed if would be possible since I can’t imagine the material and maps in the Material/Map browser not having some unique ID that max uses when handling the drag-drop action within it.


#6

material name might not be unique. at least you can’t know it for sure. so you have use anything else. the anim handle is probably the best thing.


#7

I see. Can you give me an example of what string you used so that you got drag-drop to work only on objects in the scene? I’m curious what I did wrong.


#8

here is how i would do it easiest way:

try(destroydialog dialog) catch()
rollout dialog "Simple Mats" width:300
(
	dotnetcontrol lv "ListView" width:296 height:200 pos:[2,2]
	
	fn fillLv =
	(
		items = for mat in meditmaterials collect
		(
			item = dotnetobject "ListViewItem" mat.name 
			item.tag = dotnetmxsvalue mat
			item
		)
		lv.items.addrange items
	)
	fn initLv = 
	(
		lv.View = lv.View.Details
		lv.MultiSelect = off
		lv.AllowDrop = on
		lv.Columns.add "Materials" 280
			
		fillLv()
	)
	
	local drag_item
	local effect = dotNetclass "System.Windows.Forms.DragDropEffects"
	
	fn isDraggable item = item != undefined and iskindof item.tag dotnetmxsvalue and iskindof item.tag.value Material 
	on lv ItemDrag s arg do 
	(	
		local item = arg.item
		if (isDraggable item) then
		(
			drag_item = item
			lv.DoDragDrop drag_item effect.move
		)
		else drag_item = undefined
	)
	on lv QueryContinueDrag s arg do
	(
		if (arg.Action == arg.Action.Drop) and (isDraggable drag_item) do
		(
			mpos = mouse.pos
			nodes = boxPickNode (box2 (mpos.x-2) (mpos.y-2) 4 4) crossing:on
			if nodes.count > 0 do undo "Apply Material" on
			(
				nodes.material = mat = drag_item.tag.value
				format ">> nodes: % %
" nodes mat
			)
		)
		if (arg.Action != arg.Action.Continue) do drag_item = undefined
	)
	on dialog open do
	(
		initLv()
	)
)
createdialog dialog

it’s not perfect but it gives you an idea


Drag\Drop image and get the filename
#9

I have a similar question: Can you ‘trick’ the drag-drop function from the material editor into thinking a rollout is a scene object that can be dropped onto and then passing the drop info to it?


#10

do you want to drag from mat editor and drop onto some ui control?

material drag-drop in implemented by system and material developer. it’s a black box. i don’t think we can capture that something is dragging at the moment.


#11

Additionally, if you wanted to use the 3ds Max Drag&Drop cursors, you could use something like the following code:

(
 	struct DragDropCursors
 	(
 		PRIVATE
 		
 		DRAG_NO_CURSOR,
 		DRAG_OK_CURSOR,
 		cursor = dotnetClass "System.Windows.Forms.Cursor",
 		
 		on create do
 		(
 			DRAG_NO_CURSOR = (dotnetClass "ManagedServices.AppSDK+MaxCustomCursors").DRAG_NO_CURSOR
 			DRAG_OK_CURSOR = (dotnetClass "ManagedServices.AppSDK+MaxCustomCursors").DRAG_OK_CURSOR
 			GetMaxCursor = (dotnetclass "ManagedServices.AppSDK").GetMaxCustomCursor
 			
 			DRAG_NO_CURSOR = dotnetobject "System.Windows.Forms.Cursor" (dotnetobject "System.IntPtr" (GetMaxCursor DRAG_NO_CURSOR))
 			DRAG_OK_CURSOR = dotnetobject "System.Windows.Forms.Cursor" (dotnetobject "System.IntPtr" (GetMaxCursor DRAG_OK_CURSOR))
 		),
 		
 		PUBLIC
 		
 		fn SetCursor val =
 		(
 			case val of
 			(
 				1: cursor.Current = DRAG_OK_CURSOR
 				2: cursor.Current = DRAG_NO_CURSOR
 			)
 		)
 	)
 
 	cursor = DragDropCursors()
 	cursor.SetCursor 2
 )

#12

very nice! i didn’t know about it