Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions integration/houdini/Conduct.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"hpath" : "$HFS/packages/Conduct"
}
23 changes: 23 additions & 0 deletions integration/houdini/MainMenuCommon.xml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: is it possible to set this up as two menu items, where each one hides itself by some expression when it shouldn't be available, instead of as one menu item which switches between two states?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or not necessarily hidden, but im pretty sure there is a way for menu items to be disabled/grayed out based on an expression, which would be preferable i think - it might be more intuitive for me to try and implement it this way in blender too...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was definitely the easiest solution instead of having two entries that hide.
But greying out should be easy, assuming there is a native way to grey them out, which Im really confident about.

Copy link
Collaborator Author

@Devostated Devostated Dec 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: I have no idea how to do that.
The only menu item I found that has such feature was the redo/undo function.
It uses following for that:

      <menuStripDynamic id="undo_strip">
        <value>undo.menu</value>
      </menuStripDynamic>

No idea where undo.menu is coming from.

Another Menu had , but I didn't manage to get it working, it always told me that it's an unknown command.

While writing this I found following:
"It is not currently possible to dynamically enable and disable user-defined menus/items."
https://www.sidefx.com/docs/houdini/basics/config_menus.html#menu-items

I'm not sure if that is just the top level item in the menu bar or also it's scriptItems

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could still split that into two <scriptItems> and use an <expression> to en-/disable them accordingly, if you would prefer that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah thats a shame... I think splitting them in to two menus will be less prone to bugs. I can see a scenario where the two expressions for controlling the text and the logic for the single menu become out of sync and lead to unexpected behaviour

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know, it's not much stored. Department, Asset, Shot and if it's imported. Could also just do a check if department exists. Usually try to avoid working with strings as much as possible, that's why I didn't like the idea of hardcoding the conduct node path.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>

<mainMenu>
<menuBar>

<subMenu id="conduct_menu">
<label>Conduct</label>
<scriptItem id="conduct">
<labelExpression><![CDATA["Select Project" if not getattr(hou.session, "projectImported", False) else "Load Asset(s)"]]></labelExpression>
<insertAtIndex>0</insertAtIndex>
<scriptCode><![CDATA[
if not getattr(hou.session, "projectImported", False):
import ConductPlugin.select_project as select_project
select_project.create_setup()
else:
import ConductPlugin.load_asset as load_asset
load_asset.load()
]]>
</scriptCode>
</scriptItem>
</subMenu>
</menuBar>
</mainMenu>
3 changes: 3 additions & 0 deletions integration/houdini/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Installation
Place the `Conduct.json` in `Houdini <version_name>/packages`
Either adjust it's path or place the `MainMenuCommon.xml` file and `scripts` folder into `Houdini <version_name>/packages/Conduct`
Binary file added integration/houdini/otls/LAGMACHINE.Conduct.hdalc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you unpack this hda to text format?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an issue with the limited commercial version:
Cannot convert non-commercial HDAs

I still get an output. Here is the download.
LAGMACHINE.Conduct.zip

Repacking says:
Error collapsing library from: LAGMACHINE.Conduct

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fucking proprietary software... looking at the contents of the zip file you provided, I think the node was still successfully unpacked. I can see your OnCreated, OnDeleted scripts and the parms:

LAGMACHINE.Conduct/LAGMACHINE_8_8Object_1Conduct/OnCreated

hou.hscript("ophide Object LAGMACHINE::Conduct")
node = kwargs['node']
try:
  node.setName("Conduct")
except:
  hou.ui.displayMessage("A Conduct node already exists.", severity=hou.severityType.Message)

Houdini should be able to load the hda directly from unpacked state, so converting back to packed format shouldn't be necessary. Could you see if you can load without converting? if so I think we can go ahead with this

Binary file not shown.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def load():
print("Hello, World!")
46 changes: 46 additions & 0 deletions integration/houdini/scripts/python/ConductPlugin/select_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import hou
from . import utils
import os


def create_setup():
path = utils.select_project()
if path == "":
return {'FINISHED'}
path = hou.expandString(path)

if hou.licenseCategory() != hou.licenseCategoryType.Commercial:
fileExtension = ".hiplc" if hou.licenseCategory(
) == hou.licenseCategoryType.Indie else ".hipnc"
else:
fileExtension = ".hip"

conduct = utils.get_conduct_object(path)

result = conduct.setup(fileExtension)
if result['result'] != 'ok':
return {'FINISHED'}

data_node = utils.get_conduct_data_node()

pSelectedParm: hou.Parm = data_node.parm("project_selected")
pSelectedParm.set(True)

projectParm: hou.Parm = data_node.parm("project")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think we need to store this, and if we did it would only be a valid path for the person who initially did this. If i opened the project on a machine where the project is stored elsewhere, it wouldn't be accurate anymore

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree on the project path.
The pSelected is a check to hide the Select Project button in the Conduct node. I could try taking a different approach, but not sure how worth that it would be.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe could just check if the the current file is saved, if you feel like it also could check that its saved to a valid project location - doing so would have some extra io calls so im not sure if there would be a performance impact.

Generally I would prefer to avoid hidden parms like this where possible, it can be prone to adding weird behaviour

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion is setUserData() probably the best approach, as you mentioned in the original issue.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe, for me I prefer to store as little information as possible, and to derive this kind of state from elsewhere - the way I see it the more state you are storing, the more chances there are to end up in weird invalid states

projectParm.set(path)

dialog_data = result['data']

deptParm: hou.Parm = data_node.parm("department")
deptParm.set(dialog_data['department'])

assetParm: hou.Parm = data_node.parm("asset")
assetParm.set(dialog_data['asset'])

shot = dialog_data['shot']
if shot is not None:
shotParm: hou.Parm = data_node.parm("shot")
shotParm.set(shot)

setattr(hou.session, "projectImported", True)
hou.hipFile.save(file_name=os.path.join(dialog_data['path']))
38 changes: 38 additions & 0 deletions integration/houdini/scripts/python/ConductPlugin/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import hou
from . import conduct


# Not sure about the efficiency
def get_conduct_data_node() -> hou.Node:
all_nodes = hou.node("/obj").allNodes()
data_node = None
for node in all_nodes:
if node.type().name() == "LAGMACHINE::Conduct" and node.name() == "Conduct":
data_node = node
break

if data_node is None:
data_node: hou.Node = hou.node(
"/obj").createNode("LAGMACHINE::Conduct")
data_node.setName("Conduct")
data_node.setPosition((0, 0))

return data_node


def get_conduct_object(manifest_path=None) -> conduct.Conduct:
if manifest_path != None:
return conduct.get_from_manifest_path(manifest_path, "houdini")
else:
return conduct.find_from_current_path(hou.hipFile.path(), "houdini")


def select_project():
file_path = hou.ui.selectFile(
start_directory=hou.hipFile.path(),
title="Select a project",
pattern="*.yml,*.yaml",
chooser_mode=hou.fileChooserMode.Read
)

return file_path
Loading