How to implement MObject picker in Maya - c#

I have a plugin running inside Maya that needs to perform an 'eye dropper' test against objects in the scene. My Plugin is running as a hosted WPF control, so I have a C# button event callback that wants to operate in a modal fashion until the hit is performed or escape is pressed. This was really easy to do in 3D Studio Max, but I cannot find out how to do this in Maya.
Any advice?

I do miss that in 3dsMax, but as far as I know, no, there's no built-in functionality to do that.
Most tools in Maya work already having a selection before execution so then the tool can use cmds.ls(sl=True) to capture the selection and preform your validation.
What you can do is mimic an object picker by using a selection callback. There's cmds.scriptJob, but it's more efficient to use OpenMaya's callbacks. Here's an example that uses a class to store the callback's id and auto-manages it:
import maya.cmds as cmds
import maya.OpenMaya as OpenMaya
class ObjectPicker():
_id = None # Store callback's id here.
def __init__(self):
# When this class is created, add the callback.
OpenMaya.MGlobal.displayWarning("Please pick an object")
ObjectPicker.add_callback()
#staticmethod
def on_selection_changed(*args):
# This gets triggered from the callback when the user changes the selection.
# Auto-remove the callaback afterwards.
print "Selection:", cmds.ls(sl=True)
ObjectPicker.remove_callback()
#staticmethod
def add_callback():
# First remove any existing callback, then store the id in this class.
ObjectPicker.remove_callback()
ObjectPicker._id = OpenMaya.MEventMessage.addEventCallback("SelectionChanged", ObjectPicker.on_selection_changed)
#staticmethod
def remove_callback():
# Remove the callback so it stops triggering the function.
if ObjectPicker._id is not None:
OpenMaya.MEventMessage.removeCallback(ObjectPicker._id)
ObjectPicker._id = None
# After calling this, pick a new object then it will print it in the Script Editor.
picker = ObjectPicker()
After creating an new instance of the class with picker = ObjectPicker(), a warning will pop-up to the user to pick an object. After the selection changes, it triggers the callback which prints the selection to the Script Editor then removes its own callback.
I think this might work, but Maya isn't 3dsMax, and at the end of the day it might be best to not force one software to work like another. So I'd consider to just stick with what everyone is already used to, and that is to work with the user's current selection.
Edit:
Sorry just noticed c++ tag, but the same concept should apply.
Edit #2:
I just learned about the command cmds.scriptCtx, so a picker does exist! I think it's an older command as it seems to only support MEL and the implementation doesn't feel that great. If you want to learn more then check out my answer to another question.

Related

Can JavaScript inserted into a Script string be called as normal by a WebBrowser object?

I may not be asking that question correctly but I have a WebBrowser that has pretty verbose script inside it.
I'm using some string manipulation to insert my own JavaScript string into it (just a simple window.external.(); line), hoping that it will call it, but so far, it hasn't.
Like so:
string script = <WebBrowserObject>.Document.GetElementsByTagName("script")[3].InnerText;
script = script.Insert(script.IndexOf(<Line to place function call after>) + <length of that line>, <string variable holding my function call>);
<WebBrowserObject>.Document.GetElementsByTagName("script")[3].InnerText = script;
There's a JavaScript function that fires repeatedly that I need to be in sync with a form display that shows a countdown timer.
And I have also:
<WebBrowserObject>.ObjectForScripting = this;
There hasn't been a JavaScript error shown, and I've been able to tie in a JavaScript like response by adding the window.external.(); line to an input buttons onclick attribute and seen results. Right now the only thing the function is supposed to do is write a line to the output window to make sure it works.
Is this method the correct method to achieve this desired result? Does anyone have a better way?
As far as I know, once the contents of a script tag have been run, you can't run it again (you might be able to reset it's flag regarding if the contents have run or not but I'm sure if that exists, that's a browser specific thing) . What I think you need to do is to add a new script tag with the code you want inside of it. If the WebBrowser control's interface is anything like you'd do in javascript when interfacing with the DOM, you can create a script element, add your text to the element, and then attach it somewhere to the DOM (like the head) an then it should run.
In pure javascript, it'd be something like.
var head1 = document.getElementsByTagName('head')[0]
var script1 = document.createElement('script');
script1.innerText = "alert('hey');"; //javascript to run.
head1.appendChild(script1)
Of course, when you're done, you probably ought to h1111.removeChild(script111) just to keep the DOM from accumulating scripts.... I don't know if there's anything special about when it's safe to remove the script tag in certain browsers... you might get away with removing it immediately (I just seem to have some vague and maybe incorrect recollection about reading some case where it is advisable to wait a little bit).

Window[] function in javascript Dev Express

I'm writing a Dashboard Application in C#, using DevExpress components. I am trying to dynamically create a circular gauge, and update the gauges value using a callback function. In the DevExpress sample here:
http://demos.devexpress.com/ASPxGaugesDemos/Gauges/CircularGauge.aspx
They show how to update a gauge that has already been added to the form at design time. One of the calls in their sample has var gague = window[gaugeName]
When I make the call to this function the value comes back undefiend:
function PerformCallbackCore(gaugeName) {
var gauge = window[gaugeName];
m_isDirty = gauge.InCallback();
if (!m_isDirty)
gauge.PerformCallback();
}
Does anyone possibly know why I cannot retrieve the gauge value?
Thanks - Larry
It is due to bad code in the gauge demo. Yes, I use (and pay for) DX; I can say that.
The code uses setTimeout with a string (enough ick here!) and passes in the "name" of window property assigned to the control with ClientInstanceName (the code won't work if the name used and this don't match up). The demo code is further confusing/ugly by having a different "proxy" function for Gauge1 ... GaugeN.
Now, I suspect that the ClientInstanceName wasn't used or the correct name wasn't passed somewhere, so window[aPropertyName] evaluates to undefined, however ..
.. a better way to write it would be to use/pass the object directly instead of relying on the artificial "client name" / window property. See
ASPxClientGaugeControl (and follow links to the appropriate handler) and consider this:
<ClientSideEvents EndCallback="onEndGaugeCallback" />
With a single unified callback (and distinct lack of "client names" and useless proxy methods):
function onEndGaugeCallback (s, e) {
// "s" is for Sender; it evaluates to the appropriate [Gauge] control
// or rename it to "gauge" or whatever :-)
}
Happy coding!

Overriding a Dotnet Treeview Shortcuts/Hotkeys

I'm actually working on a .Net Treeview-based Interface in 3D Studio Max, therefore coding with maxscript and C#. I've been desperately looking for a way to override the default behavior of a keyboard action, namely selecting the next node starting by the character type in.
For instance, I'd like to call a custom function when pressing the letter "F" and nothing more. By now, it actually run the function but also selects the next node starting with an F. Would anyone know how to prevent this last behavior ?
Thanks a lot.
Have you tried setting the Handled-Property (see HERE) or the SuppressKeyPress-Property (see HERE) of the KeyEventArgs to true?

List-based publish subscribe pattern in c# (Wordpress hooks / filters)

I come from a PHP background and have used Wordpress quite a lot, I love how their plugin architecture works and the ability to hook events to event names. One of the best parts I like about it is being able to *add_filter()* to any database value just before it gets shown to the end user. My question is multi-part on how to replicate the whole plugin architecture in a C#.NET environment?
Part 1:
To create plug-ins I have researched the MEF framework would probably be the best (Managed Extensibility Framework -http://mef.codeplex.com/). This is designed specifically to take the grunt work out by giving you the ability to monitor directories for new plug-ins, tracking dependencies and other normal things. MEF ships with .NET 3.5+
Part 2
Hooking events? I can't seem to find much information about replicating a global channel based event system. From what I have upto yet I need a publish/subscribe pattern (which isn't that hard to make as you just create some concrete objects and give them events). The hard part is giving each event a 'channel' name and for all the events in the whole system to be part of a global collection (Mediator pattern).
To replicate: (http://codex.wordpress.org/Function_Reference/add_filter)
Example 1
// Add's my button to the end of the content
add_filter('the_content', 'my_plugin_button');
function my_plugin_button( $content ) {
// Add's my button to the end of the content
return $content . "<a href='#'>My button</a>";
}
OR
Example 2
// Add a new admin menu item by hooking in
add_action('admin_menu', 'my_plugin_menu');
function my_plugin_menu() {
add_options_page('My Plugin Options', 'My Plugin', 'manage_options', 'my-unique-identifier', 'my_plugin_options');
}
I hope your all with me upto yet? I have managed to replicate the functionality I need in Javascript and even jQuery has their .on() event function... same thing but channel or list based...
My 2 examples:
http://jsfiddle.net/AaronLayton/U3ucS/53/
http://jsfiddle.net/AaronLayton/eyNre/33/
Can anyone point me in the correct direction or is this the totaly wrong approach for c#?
I think NServiceBus can help you a lot with these issues. Udi Dahan which is the author of NServiceBus has also written a lot of articles about Domain Event pattern, which is a publish/subscribe mechanism.
Know it's been a long time since you posted this and you probably built something already. However I have been thinking about something like this myself. There are 2 options - really forget WordPress and try and build something much cleaner - it's a mess at the bottom of WordPress' code :D
Or this:
function the_content()
{
var result = get_the_content();
// do other stuff...if you want to.
execute_filters(ref result);
execute_actions(ref result);
return result;
}
function execute_filters(ref string result, string action_name)
{
var filters = get_pre_filters(action_name);
filters.ForEach(filter =>
{
/// somehow call the method name in filter. PHP is generally global. C# namespaced,
/// so you would need to think about that.
}
}
function execute_actions(ref string result, string action_name)
{
/// and so on....
}
When building something to mimic WordPress, you need to remember many of the issues of WordPress' plugin architecture (in my personal opinion)... It seems to want to run every plugin near enough on every page even if that page has nothing to do with that plugin. I onced installed a plugin that added 60 database queries to each page call, and it wasn't used.
Try and think smart about it when you are building it. Try and add a way to only have the plugins that are going to get used on the page/post of your new setup to be run e.g. in your database have a "Plugins" field on the post/page object with a list of plugins allowed to run on that page. That way you won't need to check all the plugins each time to see if it wants to run.
Anyways. Hope you got something working.

How to create IDLE -like functionality to WinForms application

I'd like to add "IDLE-like functionality" to C# WinForms application, but I don't quite have an idea how to do that and couldn't find anything useful with Google.
So basically I want interactive command line interface, where user could enter some Python code and execute it (not just expressions, should be possible to define new functions).
So, where to start? Are there any good tutorials or samples available?
If my memory serves me correctly there's a chapter on embedding Python in the book Python in a Nutshell. Perhaps you can find some useful information there, but since the book is not Windows specific, you may have to adapt it yourself.
I would setyp my WinForm like this: add 2 textboxes.
1: for output. Set the multiline property of the first to true, and make it read only.
2: for input. Use KeyUp Or KeyPress Event for e.g. the return key and use the text to do what you want: add command to output textbox, launch code against the engine and capture output of interpreter
This link (http://groups.google.com/group/ironpy/browse_thread/thread/5e61a944c7c94d4b/0cbf29ec0f5fbb64?pli=1) might give some answers about launching commands agains a python engine.
IronRuby comes with a command line interpreter. Doesn't IronPython also have one? If so, the source code would be a good start :)
Oh, and if it doesn't, be sure to look at the IronRuby interpreter, because both languages are based on the DLR and are therefore similar enough to learn from both.
Thru IronPython mailing list I found IronTextBox2, which is good example how things are done. It needs a little tweaking, to get it running, but otherwise is good solution.
Here go my most generic solution:
Point cursorPoint;
int minutesIdle=0;
private bool isIdle(int minutes)
{
return minutesIdle >= minutes;
}
private void idleTimer_Tick(object sender, EventArgs e)
{
if (Cursor.Position != cursorPoint)
{
// The mouse moved since last check
minutesIdle = 0;
}
else
{
// Mouse still stoped
minutesIdle++;
}
// Save current position
cursorPoint = Cursor.Position;
}
You can setup a timer running on 60000 interval. By this way you will just know how many minutes the user don't move the mice. You can also call "isIdle" on the Tick event itself to check on each interval.

Categories

Resources