Set highlighted range in Maya's Time Slider - maya

It is easy to get the highligted range in the time slider using:
import maya.cmds as cmds
import maya.mel as mel
aTimeSlider = mel.eval('$tmpVar=$gPlayBackSlider')
timeRange = cmds.timeControl(aTimeSlider, q=True, rangeArray=True)
Likewise the Qt widget can be accessed with
from maya import mel
from maya import OpenMayaUI as omui
try:
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from PySide2 import __version__
from shiboken2 import wrapInstance
except ImportError:
from PySide.QtCore import *
from PySide.QtGui import *
from PySide import __version__
from shiboken import wrapInstance
widgetStr = mel.eval( 'string $tempString = $gPlayBackSlider' )
ptr = omui.MQtUtil.findControl( widgetStr )
timeSliderWidget = wrapInstance(long(ptr), QWidget)
However, setting the highlighted range programmatically of the time slider seems nearly impossible. Is there really no way?
I was thinking that there may be a way to modify the Qt widget, but I'm lost on this one.
EDIT:
It is the highlighted range I'm trying to set programmatically.

This seems to be the same question as this question.
I posted a hacky workaround there as an answer.
Posting it here too for completeness sake:
Here's the biggest hacky workaround there is. Using Qt Mouse press, move and release events to mimic the mouse behavior on the time slider widget to have it select.
In code I'm temporarily changing the time slider range to maximize the screen space for the frames I want to click on.
from maya import mel
from maya import OpenMayaUI as omui
from shiboken2 import wrapInstance
from PySide2 import QtCore, QtGui, QtWidgets
def select_time_slider_range(start, end):
app = QtWidgets.QApplication.instance()
widgetStr = mel.eval('$gPlayBackSlider=$gPlayBackSlider')
ptr = omui.MQtUtil.findControl(widgetStr)
slider = wrapInstance(long(ptr), QtWidgets.QWidget)
slider_width = slider.size().width()
slider_height = slider.size().height()
# Store time slider settings
min_time = cmds.playbackOptions(query=True, minTime=True)
max_time = cmds.playbackOptions(query=True, maxTime=True)
animation_start_time = cmds.playbackOptions(query=True, animationStartTime=True)
animation_end_time = cmds.playbackOptions(query=True, animationEndTime=True)
t = cmds.currentTime(query=True)
# Set the time slider to the range we want so we have
# perfect precision to click at the start and end of the
# time slider.
cmds.playbackOptions(minTime=start)
cmds.playbackOptions(maxTime=end)
a_pos = QtCore.QPoint(0, slider_height / 2.0)
b_pos = QtCore.QPoint(slider_width, slider_height / 2.0)
# Trigger some mouse events on the Time Control
# Somehow we need to have some move events around
# it so the UI correctly understands it stopped
# clicking, etc.
event = QtGui.QMouseEvent(QtCore.QEvent.MouseMove,
a_pos,
QtCore.Qt.MouseButton.LeftButton,
QtCore.Qt.MouseButton.LeftButton,
QtCore.Qt.NoModifier)
app.sendEvent(slider, event)
event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress,
a_pos,
QtCore.Qt.MouseButton.LeftButton,
QtCore.Qt.MouseButton.LeftButton,
QtCore.Qt.ShiftModifier)
app.sendEvent(slider, event)
event = QtGui.QMouseEvent(QtCore.QEvent.MouseMove,
b_pos,
QtCore.Qt.MouseButton.LeftButton,
QtCore.Qt.MouseButton.LeftButton,
QtCore.Qt.ShiftModifier)
app.sendEvent(slider, event)
event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonRelease,
b_pos,
QtCore.Qt.MouseButton.LeftButton,
QtCore.Qt.MouseButton.LeftButton,
QtCore.Qt.ShiftModifier)
app.sendEvent(slider, event)
event = QtGui.QMouseEvent(QtCore.QEvent.MouseMove,
b_pos,
QtCore.Qt.MouseButton.LeftButton,
QtCore.Qt.MouseButton.LeftButton,
QtCore.Qt.NoModifier)
app.sendEvent(slider, event)
app.processEvents()
# Reset time slider settings
cmds.playbackOptions(minTime=min_time)
cmds.playbackOptions(maxTime=max_time)
cmds.playbackOptions(animationStartTime=animation_start_time)
cmds.playbackOptions(animationEndTime=animation_end_time)
cmds.currentTime(t)
select_time_slider_range(-200, 500000)

Related

pyqgis plugin change QDialog to QMainWindow

I have a plugin window is QDialog, but I want to add QMenubar or QStatusBar
I have tried to find a way to convert QDialog to QMainWindow, but there is no result,
So I try to add QMenubar in QDialog again and everything works fine
Until the position of the object I added to the layout screen ran to the upper left corner.
I am not a native English speaker
def run(self):
"""Run method that performs all the real work"""
# Create the dialog with elements (after translation) and keep reference
# Only create GUI ONCE in callback, so that it will only load when the plugin is started
if self.first_start == True:
self.first_start = False
#建立menuBar的父節點物件
file_menu = QMenu("File")
#建立一個
open_action = QAction("Open",file_menu)
open_action.setShortcut('Alt+F4')
#把剛才建立的open action 加入file 節點
file_menu.addAction(open_action)
#建立一個menubar物件
menubar = QMenuBar(self.dlg)
#將父節點加入menubar
menubar.addMenu(file_menu)
#將self.dlg的menubar設定為menubar物件
self.dlg.setMenuBar(menubar)
# show the dialog
self.dlg.show()
# Run the dialog event loop
result = self.dlg.exec_()
# See if OK was pressed
if result:
# Do something useful here - delete the line containing pass and
# substitute with your code.
pass

Maya Python Mash - How can I add a selection set using Maya Mash API (in python)

Adding the cmds.connectAttr at the end does connect the selection set in Maya in the UI, but that's all it does. It acts as it its not registering.
import maya.cmds as cmds
import MASH.api as mapi
sel = cmds.ls(sl=1, l=1, fl=1)
new_set = cmds.sets(sel, n="custom_set")
obj_name = sel[0].split(".")[0]
shape = cmds.listRelatives(obj_name, s=True, f=1)
print(shape)
shape = "pCylinderShape1" #distribute mesh
cmds.select("|pCylinder2") #main mesh MASH
#create a new MASH network
mashNetwork = mapi.Network()
mashNetwork.createNetwork(name="Custom_placement", geometry="Repro")
shape = "pCylinderShape1"
mashNetwork.meshDistribute(shape, 4)
cmds.connectAttr(new_set+".message", mashNetwork.distribute+".selectionSetMessage")
Closest answer I found was here but I am not a programmer to know what that means.
If anyone can help, I'd much appreciate it.
After a lot of investigation I did manage to find the answer from the provided link.
The code I wrote was only the first part of the solution.
hasMASHFlag = cmds.objExists('%s.mashOutFilter' % (new_set))
if not hasMASHFlag:
cmds.addAttr( new_set, longName='mashOutFilter', attributeType='bool' )
cmds.setAttr( '%s.arrangement' % (mashNetwork.distribute), 4 )
cmds.setAttr( '%s.meshType' % (mashNetwork.distribute), 7 )
Note sure is needed but I noticed when you connect a selection set by default it has an extra attribute called mashOutFilter.
The part that is needed is the .meshType that makes it work.

Change cursor on widget mouseover (PyGObject)

I've been trying to change the cursor on Gtk.ScrolledWindow() (it has an image widget in it) mouseover:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GdkPixbuf
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title = "Test")
self.maximize()
grid = Gtk.Grid()
self.add(grid)
scrolled = Gtk.ScrolledWindow()
scrolled.set_hexpand(True)
scrolled.set_vexpand(True)
scrolled.connect("motion-notify-event", self.mousemove)
grid.add(scrolled)
pixbuf = GdkPixbuf.Pixbuf.new_from_file("anyimage.jpg")
image = Gtk.Image.new_from_pixbuf(pixbuf)
scrolled.add(image)
def mousemove(self, widget, event):
print("Mouseover triggered")
circle = Gdk.Cursor(Gdk.CursorType.CIRCLE)
widget.get_window().set_cursor(circle)
win = MainWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
The event is triggered but instead of a circle the cursor is displayed as an arrow with a "disabled" symbol as its subscript.
Am I missing something here?
I was wrong, it's not a bug. It's entirely up to the cursor theme in use. I was recommended to stick to cursors listed by name here:
https://developer.gnome.org/gdk3/3.24/gdk3-Cursors.html#gdk-cursor-new-from-name
Those correspond to CSS and are most likely to be available across cursor themes.

refresh the textScrollList in maya with Python

I have an array with lights , everytime I create a light it stores is my array.
I have a textScrollList that displays all lights in my Array.
When I add lights , it doesn't refersh the textScrollList.
Can someone tell me how I can do this , so everytime I make a light it display it in the textScrollList. Or with a refresh button.
Thanks !
Code I have now :
import maya.cmds as cmds
lights=[]
myWindow = cmds.window(title='My Lights', wh=(200,400),sizeable =False )
cmds.columnLayout()
cmds.showWindow(myWindow)
LightsButton = cmds.button(label='Make Lights', command = "makeLights()", width =200,height = 25,align='center')
def makeLights():
lights.append(cmds.shadingNode('aiAreaLight', asLight=True))
LightSelector = cmds.textScrollList( numberOfRows=8, allowMultiSelection=True,append=(lights), showIndexedItem=4, selectCommand = 'selectInTextList()' )
You can add a function that will refresh the list with the lights. This can be called after you create a new light so it adds to the list. You can also add a refresh button to call this same function in case you add/delete lights in the scene, and it will update properly.
You don't need to add the lights to a list and keep track of it. Instead you can use cmds.ls() to collect all the lights in the scene. Unless you really do need the list for some reason, it's easy to edit the example below to use it:
import maya.cmds as cmds
# Clear the listview and display the current lights in the scene.
def refreshList():
# Clear all items in list.
cmds.textScrollList(lightSelector, e=True, removeAll=True)
# Collect all lights in the scene.
allLights = cmds.ls(type='aiAreaLight')
# Add lights to the listview.
for obj in allLights:
cmds.textScrollList(lightSelector, e=True, append=obj)
# Create a new light and add it to the listview.
def makeLights():
lights.append(cmds.shadingNode('aiAreaLight', asLight=True))
refreshList()
def selectInTextList():
# Collect a list of selected items.
# 'or []' converts it to a list when nothing is selected to prevent errors.
selectedItems = cmds.textScrollList(lightSelector, q=True, selectItem=True) or []
# Use a list comprehension to remove all lights that no longer exist in the scene.
newSelection = [obj for obj in selectedItems if cmds.objExists(obj)]
cmds.select(newSelection)
# Create window.
myWindow = cmds.window(title='My Lights', wh=(200,400), sizeable=False)
cmds.columnLayout()
cmds.showWindow(myWindow)
# Create interface items.
addButton = cmds.button(label='Make Lights', command='makeLights()', width=200, height=25, align='center')
lightSelector = cmds.textScrollList(numberOfRows=8, allowMultiSelection=True, append=cmds.ls(type='aiAreaLight'), showIndexedItem=4, selectCommand='selectInTextList()')
refreshButton = cmds.button(label='Refresh list', command='refreshList()', width=200, height=25, align='center')
Hope that helps.

Pixel vs Percentige at Mobile env

Im currently building fps-like game for android environment.
I had notice that if I make object with use of pixel low resolution devices can play game so easy than hight resolution phones.
If I use percentage for building objects this time bigger devices gain advantage. Such as Tablets have great size than phones and they can shot my object easly.
I want my objects exact same size on every device is it possible?
More specificly I use python-kivy is it possible to define object as cm/ft or etc.
You can make a relative_size and relative_position method. And make them relative to the windows width or height.
You get the size of the window from the Window class.
Remember only to make the objects size (w,h) relative to only one of width or height. Or your objects will be warped.
from kivy.uix.widget import Widget
from kivy.graphics import Canvas,InstructionGroup,Color,Ellipse
from kivy.core.window import Window
from kivy.app import App
class MyCanvas(Widget):
def __init__(self,**kwargs):
super(MyCanvas,self).__init__(**kwargs)
#Window.size = (200,100)
self.size = Window.size
self.orientation = "vertical"
self.ball = InstructionGroup()
self.ball_size = self.relative_size(10,10)
self.color = Color(0, 1, 1)
self.ellipse = Ellipse(size=self.ball_size,pos=self.relative_position(100,50,self.ball_size))
self.ball.add(self.color)
self.ball.add(self.ellipse)
self.canvas.add(self.ball)
def relative_position(self,x,y,obj_size=(0,0)): # pass obj_size if you want the position to be the center of the object11
x = ( self.width / 100.0 ) * x - obj_size[0]/2.0
y = ( self.height / 100.0 ) * y - obj_size[1]/2-.0
return (x,y)
def relative_size(self,w,h):
return (self.width/float(w),self.width/float(h)) # only make it relative to your width or heigh
# or your object will be warped
class MyApp(App):
def build(self):
return MyCanvas()
if __name__ == "__main__":
MyApp().run()
The relative_position method here will now be a percantage. So you pass from 0-100 in both directions. If you want something else, change the 100s in tht method.
Try to uncomment the #Window.size = (200,100) and play with the window size, and see how it works.
You could also make an event if your application changes size, like if your phone changes orientation.
As I did not make that, this will only work for the size the application started with.

Resources