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;
}
}
}
I haven’t tried yet but why are you running it out of the script directory instead of plugins?
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.
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?
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”
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