Notifications
Clear all

[Closed] Mouse input window

Haha how could the animators complain wial they are having Seizures.

Omg this is really a psycho UI. Gotta add this into my April fools sabotage script

That last one is pretty cool Paul,
you can add a function that checks wich user is working with it
and if this user is on your black list you can turn the psycho function on.

now here is something I was working on before I found this thread…

try (destroyDialog joyStick) catch ()
 
 rollout joyStick "JoyStick"
 (
 -- Local Variable Declerations
 ------------------------------------------
 
 	local upColor = black
 	local downColor = yellow
 	local dim = 200
 	local joyDim = 10
 	local activateJS = false
 	local joyBitmap = bitmap joyDim joyDim color:upColor
 	local joyBitmapMask = bitmap joyDim joyDim color:black
 	local mouseLBState = false
 	local mouseOffset = [0,0]
 	local spinnerSize = 60
 	local joyStickPos = [dim / 2,dim / 2]
 	local signState = false
 
 -- User Interface
 ------------------------------------------
 
 	-- Build the static Cross
 	groupBox gb1 "" pos:[0, - 6] width:(dim/2) height:(dim/2 + 6)
 	groupBox gb2 "" pos:[(dim/2), - 6] width:(dim/2) height:(dim/2 + 6)
 	groupBox gb3 "" pos:[0,(dim/2) - 6] width:(dim/2) height:(dim/2 + 6)
 	groupBox gb4 "" pos:[(dim/2),(dim/2) - 6] width:(dim/2) height:(dim/2 + 6)
 	
 	-- Adds the Values to the Cross
 	label lbA "1" pos:[dim / 2 - 9,2]
 	label lbB "-1" pos:[dim / 2 - 12,dim - 15]
 	label lbC "-1" pos:[2,dim / 2 - 16]
 	label lbD "1" pos:[dim - 10,dim / 2 - 16]
 	label lbSignature "" pos:[5,5]
 
 	
 	-- Build the dynamic Cross
 	groupBox gbVer "" pos:[0,(dim - joyDim)/ 2] width:(dim * 3) height:(dim * 3)
 	groupBox gbHor "" pos:[dim / 2 ,-10] width:(dim * 3) height:(dim * 3)
 	
 	-- X and Y spinners
 	spinner spX "X:" pos:[10,dim + 4] width:spinnerSize scale:0.001 range:[-1,1,0]
 	spinner spY "Y:" pos:[dim - spinnerSize - 5,dim + 4] width:spinnerSize scale:0.001 range:[-1,1,0]
 	
 	-- The JoyStick
 	checkButton cbJoy "" width:joyDim height:joyDim pos:[(dim - joyDim)/2,(dim - joyDim)/2] 
 		images:#(joyBitmap,joyBitmapMask,1,1,2,1,1) highlightColor:downColor
 	
 -- Functions
 ------------------------------------------
 	
 	fn posToVal posX posY =
 	(
 		[2 * posX / dim - 1 , 1 - 2 * posY / dim]
 	)
 	
 	fn ValToPos valX valY = 
 	(
 		[dim * (valX + 1) / 2 , (1 - valY) * dim / 2]
 	)
 	
 	fn controlTarget pos =
 	(
 		if selection.count == 1 do (
 			$.pos.x = pos.x * 100
 			$.pos.y = pos.y * 100
 		)
 	)
 	
 	fn updateJS mPos =
 	(
 		if mPos.y > dim do mPos.y = dim
 		if activateJS then (
 			joyStickPos = mPos
 			gbVer.pos.y = mPos.y - joyDim/2
 			gbHor.pos.x = mPos.x
 			local newPos = posToVal mPos.x mPos.y
 			spX.value = newPos.x
 			spY.value = newPos.y
 			spX.pos *= 1
 			spY.pos *= 1
 			cbJoy.pos = joyStickPos - [joyDim/2,joyDim/2]
 			controlTarget newPos
 		) else (
 			if mouseLBState then SetDialogPos joyStick (mouse.screenPos - mouseOffset)
 		)
 	)
 	
 	fn updateSpinner axis valX valY =
 	(
 		if axis < 3 do joyStickPos.x = (ValToPos valX valY).x
 		if axis > 1 do joyStickPos.y = (ValToPos valX valY).y
 		gbVer.pos.y = joyStickPos.y - joyDim/2
 		gbHor.pos.x = joyStickPos.x
 		spX.pos.y = spY.pos.y = dim + 4
 		spY.pos.x = dim - 18
 		cbJoy.pos = joyStickPos - [joyDim/2,joyDim/2]
 		controlTarget (posToVal joyStickPos.x joyStickPos.y)
 	)
 	
 	fn reSizeDialog pos =
 	(
 		dim = (pos.x + pos.y - 24) / 2
 		joyStick.width = dim
 		joyStick.height = dim + 24
 		
 		gb1.width = gb2.width = gb3.width = gb4.width = dim/2
 		gb1.height = gb2.height = gb3.height = gb4.height = dim/2 + 6
 		gb2.pos = [(dim/2), - 6]
 		gb3.pos = [0,(dim/2) - 6]
 		gb4.pos = [(dim/2),(dim/2) - 6]
 		
 		lbA.pos = [dim / 2 - 9,2]
 		lbB.pos = [dim / 2 - 12,dim - 15]
 		lbC.pos = [2,dim / 2 - 16]
 		lbD.pos = [dim - 10,dim / 2 - 16]
 		
 		gbVer.width = gbVer.height = gbHor.width = gbHor.height = (dim * 3)
 		
 		updateSpinner 2 spX.value spY.value
 	)
 	
 	fn signature state =
 	(
 		if keyboard.altPressed and keyboard.controlPressed do signState = not signState
 		lbSignature.caption = if signState then "Matan Halberstadt" else ""
 		lbSignature.pos = [5,5]
 	)
 	
 	fn openDialog =
 	(
 		createDialog joyStick width:dim height:(dim + 24) style:#(#style_sunkenedge, #style_resizing) 
 		SetDialogPos joyStick (mouse.screenPos - [dim/2,dim/2])
 	)
 	
 	fn init =
 	(
 		
 	)
 
 	fn done =
 	(
 		gc light:true
 	)
 
 -- Event Handlers
 ------------------------------------------
 
 	on cbJoy changed state do (
 		activateJS = state
 		signature state
 	)
 	on joyStick mouseMove pos do updateJS pos
 	on joyStick rbuttonup pos do destroyDialog joyStick
 	on joyStick lbuttondown pos do (
 		mouseLBState = true
 		mouseOffset = pos
 	)
 	on joyStick lbuttonup pos do mouseLBState = false
 	on spX changed val do updateSpinner 1 val 0
 	on spY changed val do updateSpinner 3 0 val
 	on joyStick resized pos do reSizeDialog pos
 	on joyStick open do init()
 	on joyStick close do done()
 
 ) -- end of rollout
 
 joyStick.openDialog()

I couldn’t resist and wrote a DotNet version real quick. It seems to mess up garbage collection once in a while but I’m too lazy to figure out why right now

Martijn

I’ve been meaning to get back to this for a while now

    I've finally re-written the c# control to sit inside a max rollout
    you can grab the .dll from my site
     
   [ http://www.designimage.co.uk/Max/files/MouseControl/windowsControl.dll ]( http://www.designimage.co.uk/Max/files/MouseControl/windowsControl.dll) 

put the dll in your scripts directory

  The sample code shows various methods to use the control.

Set the control size as you would normally using the width and height properties
Use the SetRange function to set the range of values you want the control to output.

double click the control to zero (function controlled by the maxscript)
right click to cancel. (function built into the dot net control)

note that when you do right click to cancel the control sends out another PosEvent with the original postion.


        assemblyFileName = ((getdir #scripts) as string + "/WindowsControl.dll")
        dotnet.LoadAssembly assemblyFileName 
        rollout TestRoll "test"
        (
        
        	dotNetControl dnMouseWindow  "WindowsControl.MouseWindow"  width:200 height:200 align:#left
        	local oldpos = [0,0]
        
        	on dnMouseWindow PosEvent a b  do format "pos: %, %
" b.x b.y
        	on dnMousewindow DoubleClick do dnMousewindow.SetPos 0 0
        	on dnMousewindow mouseDown do 
        	(
        		oldPos.x  = (dnMousewindow.getPos()).x
        		oldpos.y = (dnMousewindow.getPos()).y
        	)
        	on TestRoll open do
        	(
        		
        		dnMousewindow.SetRange -100 -100 100 100 -- bottom left x y topright x y : default 0,0 1,1
        		--top right will always have higher values than bottom left 
        		--If values are the wrong way round the SetRange function swaps them rather than throwing and error.
        		dnMousewindow.SetPos 0 0  -- set the cross position after setting the range values.
        		-- if SetPos is out of range the value is clamped.
        	)
        )
        
        if 	TestWindow != undefined then CloseRolloutFloater TestWindow
        TestWindow = NewRolloutFloater "" 400 300
        
        AddRollout TestRoll TestWindow
        

for those that are interested here’s the c# code


   using System;
   using System.Collections;
   using System.ComponentModel;
   using System.Drawing;
   using System.Data;
   using System.Windows.Forms;
   
   namespace WindowsControl
   {
   	/// <summary>
   	/// Summary description for UserControl1.
   	/// </summary>
   	public delegate void PosEventHandler(object sender,PosEventArgs e);
   	public class MouseWindow : System.Windows.Forms.UserControl
   	{
   		/// <summary>
   		/// Required designer variable.
   		/// </summary>
   		private RangeLimit xRange = new RangeLimit();
   		private RangeLimit yRange = new RangeLimit();
   		private System.ComponentModel.Container components = null;
   		private System.Windows.Forms.Label LblCross;
   		private Point crossOffset = new Point(0,0);
   		private Point oldCrossPostion = new Point(0,0);
   		private FloatPoint pos = new FloatPoint(0,0);
   		private bool mouseCancel = false;
   		public int xWinOffset = -13;
   		public int yWinOffset = -16;
   		private void SetOldCrossPostion()
   		{
   			this.oldCrossPostion = this.LblCross.Location;
   		}
   		public void SetRange(float xMin,float yMin,float xMax,float yMax)
   		{
   			xRange.set(xMin, xMax);
   			yRange.set(yMin, yMax);
   		}
   		public void SetPos(float x, float y)
   		{
   			pos.x = xRange.clamp(x);
   			pos.y = yRange.clamp(y);
   			Point P = new Point(0,0);
   			P.X = xRange.ScaleToWindow(pos.x,this.Size.Width)+ xWinOffset;
   			P.Y = this.Size.Height - yRange.ScaleToWindow(pos.y,this.Size.Height)+ yWinOffset;
   			this.LblCross.Location = P;
   			this.SetOldCrossPostion();
   		}
   		public FloatPoint GetPos()
   		{
   			setPosFromWindow();
   			return pos;
   		}
   		private void CalcCrossOffset()
   		{
   			crossOffset.X = this.PointToClient(Control.MousePosition).X - this.LblCross.Location.X;
   			crossOffset.Y = this.PointToClient(Control.MousePosition).Y - this.LblCross.Location.Y;
   		}
   		private void setPosFromWindow()
   		{
   			pos.x = xRange.ScaleFromWindow(this.LblCross.Location.X - xWinOffset,this.Size.Width);
   			pos.y = yRange.ScaleFromWindow(this.Size.Height - (this.LblCross.Location.Y - yWinOffset),this.Size.Height);
   		}
   		private void MoveCross()
   		{
   			Point P = this.PointToClient(Control.MousePosition);
   			P.X -= crossOffset.X;
   			P.Y -= crossOffset.Y;
   			P.X = RangeLimit.clamp(P.X,xWinOffset,this.Size.Width + xWinOffset);
   			P.Y = RangeLimit.clamp(P.Y,yWinOffset,this.Size.Height + yWinOffset);
   			this.LblCross.Location = P;
   			this.setPosFromWindow();
   		}
   		
   		public event PosEventHandler PosEvent;
   
   		public PosEventArgs GetPosEventArgs()
   		{
   			//return new PosEventArgs(pos[index],index);
   			return new PosEventArgs(this.pos,1);
   		}
   		protected virtual void OnPosEvent(PosEventArgs e) 
   		{
   			if (PosEvent != null)
   				PosEvent(this, e);
   		}
   		private void setPos(object sender, System.Windows.Forms.MouseEventArgs e)
   		{
   			if ((e.Button == MouseButtons.Left) && !mouseCancel)
   			{
   				MoveCross();		
   				OnPosEvent(GetPosEventArgs());
   			}
   
   		}
   
   		private void SetOffset(object sender, System.Windows.Forms.MouseEventArgs e)
   		{
   			if ((e.Button == MouseButtons.Right) && (e.Button == MouseButtons.Right))
   			{
   				this.LblCross.Location = this.oldCrossPostion;
   				this.setPosFromWindow();
   				mouseCancel = true;
   				OnPosEvent(GetPosEventArgs());
   			}
   			if (e.Button == MouseButtons.Left)
   			{
   				mouseCancel = false;
   				this.SetOldCrossPostion();
   				CalcCrossOffset();
   			}
   		}
   		public MouseWindow()
   		{
   			// This call is required by the Windows.Forms Form Designer.
   			InitializeComponent();
   			// TODO: Add any initialization after the InitComponent call
   		}
   
   		/// <summary>
   		/// Clean up any resources being used.
   		/// </summary>
   		protected override void Dispose( bool disposing )
   		{
   			if( disposing )
   			{
   				if( components != null )
   					components.Dispose();
   			}
   			base.Dispose( disposing );
   		}
   
   		#region Component Designer generated code
   		/// <summary>
   		/// Required method for Designer support - do not modify 
   		/// the contents of this method with the code editor.
   		/// </summary>
   		private void InitializeComponent()
   		{
   			this.LblCross = new System.Windows.Forms.Label();
   			this.SuspendLayout();
   			// 
   			// LblCross
   			// 
   			this.LblCross.Font = new System.Drawing.Font("Microsoft Sans Serif", 20.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
   			this.LblCross.Location = new System.Drawing.Point(96, 96);
   			this.LblCross.Name = "LblCross";
   			this.LblCross.Size = new System.Drawing.Size(30, 30);
   			this.LblCross.TabIndex = 0;
   			this.LblCross.Text = "+";
   			this.LblCross.MouseMove += new System.Windows.Forms.MouseEventHandler(this.setPos);
   			this.LblCross.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SetOffset);
   			// 
   			// MouseWindow
   			// 
   			this.Controls.Add(this.LblCross);
   			this.Name = "MouseWindow";
   			this.Size = new System.Drawing.Size(200, 200);
   			this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.setPos);
   			this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SetOffset);
   			this.ResumeLayout(false);
   
   		}
   		#endregion
   	}
   	public class PosEventArgs : EventArgs
   	{
   		public float x = 0;
   		public float y = 0;
   		public int index = 0;
   
   		public PosEventArgs(FloatPoint p,int i)
   		{
   			x = p.x;
   			y = p.y;
   			index = i;
   		}
   	}
   
   	public class FloatPoint
   	{
   		public float x = 0;
   		public float y = 0;
   		public FloatPoint(){}
   		public FloatPoint(float x , float y)
   		{
   			set (x , y);
   		}
   		public FloatPoint (System.Drawing.Point p)
   		{
   			set (p);
   		}
   
   		public void set (float x , float y)
   		{
   			this.x = x;
   			this.y = y;
   		}
   		public void set (System.Drawing.Point p)
   		{
   			set (p.X,p.Y ); //implicit type conversion
   		}
   	}
   
   	public class RangeLimit
   	{
   		public float outputMin = 0;
   		public float outputMax = 1;
   		public int ScaleToWindow(float i,int scale)
   		{
   			float f = (i - outputMin)/(outputMax - outputMin);
   			return (int)(f * scale);
   		}
   		public float ScaleFromWindow(int i,int scale)
   		{
   			float s = (float)i/(float) scale;
   			return (float)((outputMax - outputMin) * s ) + outputMin;
   		}
   		public void set(float min,float max)
   		{
   			if (max > min )
   			{
   				this.outputMin = min;
   				this.outputMax = max;
   			}
   			else
   			{
   				this.outputMin = max;
   				this.outputMax = min;
   			}
   		}
   		public RangeLimit(){}
   		public RangeLimit(float max)
   		{
   			this.set(0,max);
   		}
   		public RangeLimit(float min , float max)
   		{
   			this.set(min,max);
   		}
   		public static int clamp(int i,int min,int max)
   		{
   			if (i < min){i = min;}
   			else
   			{
   				if(i>(max)){i = max;}
   			}
   			return i;
   		}
   		public static float clamp(float i,float min,float max)
   		{
   			if (i < min){i = min;}
   			else
   			{
   				if(i>(max)){i = max;}
   			}
   			return i;
   		}
   		public float clamp(float i)
   		{
   			if (i < this.outputMin){i = this.outputMin;}
   			else
   			{
   				if(i>(this.outputMax)){i = this.outputMax;}
   			}
   			return i;
   		}
   	}
   }
   
   
   
 PEN

I haven’t tried yet but why are you running it out of the script directory instead of plugins?

 PEN

Nice work, do we have drawing options for the target and back ground?

1 Reply
(@kenzor)
Joined: 11 months ago

Posts: 0

the background inherits from System.Windows.Forms.Usercontrol which has a whole bunch of properties to play with… ie.
.BackgroundImage : <System.Drawing.Image>
.BackColor : <System.Drawing.Color>

the target is just a text label … System.Windows.Forms.Label.
currently its a private object so there’s no access from Maxscript

I could make the target public… but it would then be possible to break the control…

or I could make a bunch of get and set functions for the properties you need…
what would be useful?

What I’d really like to do is link the mouseWindow x y position properties directly to two controllers .
In the same way you use the controller property of a spinner.

… though i doubt it possible in c# …


The .dll can go anywhere. I guess I felt that the plugins directory should be reserved for actual max plugins rather than dotnet controls.

1 Reply
(@lonerobot)
Joined: 11 months ago

Posts: 0

nice one ken, I’d been thinking about this for a while too, and Had come up with this stumbling block also. I think this could be done with a timechange callback. You can link this to update the properties of a dotnet object. I have managed to do this with a dotnet custom slider object i have written.

what id like to do is make a composite slider object for a morpher that adds min/max buttons in dotnet. but i cant get the trackbar scroll event in the control to be exposed to the base usercontrol scroll event. Any thoughts?

 PEN

I didn’t get it to work from the plugins folder either. I didn’t load the dll as it is not a max dll.

Could we have an image maybe for the target or at least a selection of different choices. With the one that I use now I have a circle with target lines.

I’ve made some changes to allow for customization

Theres a zip file on my site with all the new files including the C# source “UserControl1.cs”

Zip File

I’ve added some new functions to edit the target labels properties.

.SetTargetImage <filePath> – returns true if successful
.SetTargetSize x y
.SetTargetBackgroundColor a r g b
.SetTargetBackgroundColor r g b

There’s also a new property .TargetCenter a “system.drawing.point”. It’s automatically set to half the label size, when you set a new target image or size.

Note that because the default target label displays a ‘+’ sign the default TargetCenter is actually slightly below center (15,14) because of the font.

I’ve also made the target label a public object so you access it properties directly if you wish.

The new test code shows some of these methods


 rollout TestRoll "test"
 (
 	local scriptDir = ((getdir #scripts) as string)
 	local test = dotnet.LoadAssembly (scriptDir + "/CsharpClasses/WindowsControl.dll")
 	dotNetControl dnMouseWindow  "WindowsControl.MouseWindow"  width:200 height:200 align:#center
 	
 	local oldpos = [0,0]
 
 	on dnMouseWindow PosEvent a b  do format "pos: %, %
" b.x b.y
 	on dnMousewindow DoubleClick do dnMousewindow.SetPos 0 0
 	on dnMousewindow mouseDown do 
 	(
 		oldPos.x  = (dnMousewindow.getPos()).x
 		oldpos.y = (dnMousewindow.getPos()).y
 	)
 	on TestRoll open do
 	(
 		
 		dnMousewindow.SetRange -100 -100 100 100 -- bottom left x y topright x y : default 0,0 1,1
 		--top right will always have higher values than bottom left 
 		--If values are the wrong way round the SetRange function swaps them rather than throwing and error.
 		dnMousewindow.SetTargetImage (scriptDir + "/target.jpg")
 		dnMousewindow.SetTargetSize 16 16
 		dnMousewindow.SetPos 0 0  -- set the cross position after setting the range values. and target size
 		-- if SetPos is out of range the value is clamped.
 		--to access the target label properties use dnMousewindow.Target
 	)
 )
 
 if 	TestWindow != undefined then CloseRolloutFloater TestWindow
 TestWindow = NewRolloutFloater "" 400 300
 
 AddRollout TestRoll TestWindow
 
Page 3 / 10