Ok, here is a version that runs on Poser12 and Poser13.
Even though I have avoided any Python3-specific instructions, I have not been able to instantiate the HyperTreeList control, something's making the original code crash on Poser11.
I could have used a simple list but the fact that it's hierarchically presented is one of the key point.
The window may remain opened, and pushed on a side of the screen. Each time the selection is done on another object and the window is once again activated, it is refreshed. Once the window is closed using its upper-right cross, it maintains its position and size for the next time.
Furthermore, that are probably a few useless instructions but consider that it's a small part (260 lines) among a rather bigger Python script (more than 3130 lines)
try:
import poser
except ImportError:
import _POSER_FAKE as poser
import wx
import wx.lib.agw.hypertreelist as HTL
import os
import os.path
import configparser
HTL_ITEM_NORMAL=0
HTL_ITEM_CHECKBOX=1
HTL_ITEM_RADIO=2
class CypMaterialsList(wx.Frame):
# ---------- Dialog part
def __init__(self, dlg_name):
self.parent = poser.WxAuiManager().GetManagedWindow().GetParent()
self.title_font = wx.Font(9, wx.DECORATIVE, wx.NORMAL, wx.BOLD)
self.dlg_name = dlg_name
self.load_config()
self.load_environment()
wx.Frame.__init__(
self,
self.parent,
title=self.get_dialog_title(),
pos=(self.dlg_x, self.dlg_y),
size=(self.dlg_w, self.dlg_h),
style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_TOOL_WINDOW|wx.FRAME_FLOAT_ON_PARENT|wx.FRAME_NO_TASKBAR|wx.FRAME_DRAWER,
name=dlg_name
)
self.Bind(wx.EVT_CLOSE, self.on_close)
self.Bind(wx.EVT_ACTIVATE, self.on_activate)
self.Bind(wx.EVT_SIZING, self.on_sizing)
self.HTL_mat_panel = wx.Panel(self)
self.create_materiels_list()
self.Show()
def create_materiels_list(self):
htl_width = self.dlg_w-500
self.mats_tree_list = HTL.HyperTreeList(
self.HTL_mat_panel,
pos=(5,5),
size=(htl_width, self.dlg_h-45),
agwStyle=wx.TR_DEFAULT_STYLE
)
self.mats_tree_list.AddColumn("Materials")
self.mats_tree_list.AddColumn("Gamma")
self.mats_tree_list.AddColumn("Filtering")
self.mats_tree_root = self.mats_tree_list.AddRoot("Root")
self.mats_tree_root.Expand()
self.tree_root_materials = self.mats_tree_list.AppendItem(self.mats_tree_root, "Object", ct_type=HTL_ITEM_NORMAL)
self.tree_root_materials.Expand()
self.mats_tree_list.SetColumnWidth(0, int(self.dlg_w*0.70))
self.HTL_Prepare_materials_list()
sizer = wx.BoxSizer()
sizer.Add(self.mats_tree_list, 1, wx.ALL | wx.EXPAND, 5)
self.HTL_mat_panel.SetSizer(sizer)
# ---------- HyperTreeList mamagenemt
def _deep_scan_for_bitmaps(self, from_node=None):
if not from_node: return {}
current_list = {}
detected = {}
if from_node.Type() == 'image_map':
sni = from_node.InputByInternalName('Image_Source')
file_name = sni.Value()
texture = sni.Texture()
gamma = 2.2 if texture.UseSceneGamma() else texture.Gamma()
filtering_i = int(from_node.InputByInternalName('Filtering').Value())
filtering = "Filtering: " + { 1:'none', 2:'fast', 3:'quality', 4:'crisp'}.get(filtering_i, 'unknown')
detected = {file_name: (str(gamma), filtering)}
elif from_node.Type() == 'ccl_ImageTexture':
sni = from_node.InputByInternalName('Image')
file_name = sni.Value()
texture = sni.Texture()
gamma = 2.2 if texture.UseSceneGamma() else texture.Gamma()
detected = {file_name: (str(gamma), "-")}
if not detected:
for sni in from_node.Inputs():
in_node = sni.InNode()
if in_node:
detected = self._deep_scan_for_bitmaps(from_node=in_node)
if detected:
current_list.update(detected)
else:
current_list.update(detected)
return current_list
def OnCompareItems(self, item1, item2):
a = item1.Name()
b = item2.Name()
return (a > b) - (a < b) # equivalent to old cmp function
def HTL_mat_scan_4_bitmaps(self, material, place):
tree = material.ShaderTree()
root_node = tree.RendererRootNode(self.scene.CurrentRenderEngine())
full_list = self._deep_scan_for_bitmaps(from_node=root_node)
check = False
for file_name, values in dict(sorted(full_list.items())).items():
gamma, filtering = values #full_list[file_name]
check = True
img_info = self.mats_tree_list.AppendItem(place, file_name)
img_info.SetText(1, gamma)
img_info.SetText(2, filtering)
return check
def HTL_mats_scan(self, place, item):
if not item.IsProp() and not item.IsBodyPart(): return
sorted_materials = [
material
for material in item.Materials()
]
from functools import cmp_to_key
sorted_materials.sort(key=cmp_to_key(self.OnCompareItems))
for material in sorted_materials:
this = self.mats_tree_list.AppendItem(place, material.Name())
if not self.HTL_mat_scan_4_bitmaps(material, this):
this.Hide(True)
else:
this.Expand()
def HTL_Prepare_materials_list(self):
self.tree_root_materials.DeleteChildren(self.mats_tree_list.GetMainWindow())
title = "Object"
if self.figure:
if self.figure.IsFigure():
actor = self.figure.RootActor()
title = "Figure: {}".format(self.figure.Name())
else:
actor = self.figure
title = "{}: {}".format(title, actor.Name())
self.HTL_mats_scan(self.tree_root_materials, actor)
self.tree_root_materials.SetText(0, title)
# ---------- Events management
def on_close(self, event=None):
try:
if self.IsIconized(): self.Iconize(False)
if self.IsMaximized(): self.Maximize(False)
if not self.IsIconized():
self.save_config()
except: pass
self.Destroy()
def on_sizing(self, event=None):
# if event:
# new_w, new_h = event.GetSize()
# for ctrl, rel_pos in self.moving_controls.items():
# ctrl.Move(new_w-1-rel_pos[0], new_h-1-rel_pos[1])
event.ResumePropagation(wx.EVENT_PROPAGATE_MAX)
def on_activate(self, event=None):
if not event: return
if event.GetActive():
self.load_environment()
self.SetTitle(self.get_dialog_title())
# ---------- Hypertreelists Management
check = getattr(self, 'mats_tree_root', None)
if check:
self.HTL_Prepare_materials_list()
# ---------- Gen Tools
def get_render_engine(self):
try:
return {
4: " - Superfly",
1: " - Firefly",
3: " - Sketch",
0: " - Preview"
}.get(self.scene.CurrentRenderEngine(), "")
except:
return ''
def load_config(self, def_x=100, def_y=200, def_w=750, def_h=300):
'''
Load the dialog's position from the configuration file, if any
'''
self.section_name = "Materials List"
self.configFile = os.path.join(poser.PrefsLocation(), "Cyp" + os.extsep + "cfg")
self.config = configparser.RawConfigParser()
self.config.read(self.configFile)
if not self.config.has_section(self.section_name): self.config.add_section(self.section_name)
try: self.dlg_x = self.config.getint(self.section_name, "x")
except: self.dlg_x = def_x
try: self.dlg_y = self.config.getint(self.section_name, "y")
except: self.dlg_y = def_y
try: self.dlg_w = self.config.getint(self.section_name, "w")
except: self.dlg_w = def_w
try: self.dlg_h = self.config.getint(self.section_name, "h")
except: self.dlg_h = def_h
def save_config(self):
r = self.GetScreenRect()
self.config.set(self.section_name, "x", r.left)
self.config.set(self.section_name, "y", r.top)
self.config.set(self.section_name, "w", r.width)
self.config.set(self.section_name, "h", r.height)
self.config.write(open(self.configFile, "w"))
def load_environment(self):
'''
Load all values for the dialog,
'''
self.scene = poser.Scene()
try:
figure = self.scene.CurrentActor()
if figure.IsBodyPart():
figure = self.scene.CurrentFigure()
except:
figure = None
self.figure = figure
def get_dialog_title(self):
title = "List of materials {}".format(self.get_render_engine())
if self.figure:
title = "{}: {}".format(title, self.figure.Name())
return title
dlg_name = "Cyp's Materials List"
# Kill any stalled previous instances
[w.Destroy() for w in poser.WxAuiManager().GetManagedWindow().GetParent().Children if w.GetName()==dlg_name]
CypMaterialsList(dlg_name)