Main.py
1    from __future__ import print_function, absolute_import
2    
3    import json
4    import os
5    import sys
6    import wx
7    
8    THISFILE = os.path.abspath(sys.argv[0])
9    THISPATH = os.path.dirname(THISFILE)
10   if THISPATH not in sys.path:
11       sys.path.append(THISPATH)
12   
13   if sys.version_info.major > 2:
14       # Python 3 (Poser 12 and above)
15       basestring = str
16   else:
17       # Python 2 (Poser 11 and below)
18       if not os.path.exists(os.path.join(THISPATH, "__init__.py")):
19           # this file must exist to be able to make includes
20           with open(os.path.join(THISPATH, "__init__.py"), "w"):
21               pass
22   
23   try:
24       import poser
25   except ImportError:
26       import POSER_FAKE as poser
27   
28   try:
29       from .im_export import do_import, do_export
30   except ValueError:
31       from im_export import do_import, do_export
32   
33   try:
34       from . import menu as Menu
35       from .ConfigDialog import Dialog as CfgDialog
36       from .CombineMorphDialog import Dialog as CombineDialog
37   except ValueError:
38       import menu as Menu
39       from ConfigDialog import Dialog as CfgDialog
40       from CombineMorphDialog import Dialog as CombineDialog
41   
42   aui = poser.WxAuiManager()
43   python_pane = [p for p in aui.GetAllPanes() if "python" in p.name.lower()]
44   if python_pane and not python_pane[0].IsShown():
45       poser.ProcessCommand(1509)
46   
47   SCENE = poser.Scene()
48   Menu.TITLE = "OBJ Im-/Export"
49   Menu.TEMPDIR = poser.TempLocation()
50   
51   
52   # Global configuration
53   IMEX_CONFIG = globals().setdefault("IMEX_CONFIG", dict()) or dict()
54   IMEX_CONFIG["THISPATH"] = os.path.dirname(sys.argv[0])
55   
56   
57   def PopUpMessage(text, bg=(0xf0, 0xf0, 0xf0), fg=(0x10, 0x10, 0x10), closeafter=3):
58       root = wx.GetTopLevelWindows()[0]
59       dialog = wx.Frame(root, id=wx.ID_ANY, title="IM-Export Notification",
60                         style=wx.CAPTION | wx.STAY_ON_TOP)
61       dialog.SetForegroundColour(fg)
62       dialog.SetBackgroundColour(bg)
63       sz = wx.BoxSizer(wx.HORIZONTAL)
64       txt = wx.StaticText(dialog, label=text)
65       sz.Add(txt, 1, wx.ALL | wx.EXPAND, border=15)
66       sz.Layout()
67       dialog.SetSizer(sz)
68   
69       w, h = sz.ComputeFittingWindowSize(dialog)
70       dialog.SetSize((w, h))
71   
72       pos_x, pos_y = root.GetPosition()
73       size = root.GetSize()
74       center_x = size[0] / 2.0
75       center_y = size[1] / 2.0
76       dialog.SetPosition((pos_x + center_x - w / 2, pos_y + center_y - h / 2))
77       dialog.Show()
78   
79       if closeafter:
80           wx.CallLater(closeafter * 1000, dialog.Destroy)
81   
82       return dialog
83   
84   
85 def load_config(): 86 global IMEX_CONFIG 87 if os.path.isfile(os.path.join(THISPATH, "imex.config")): 88 with open(os.path.join(THISPATH, "imex.config")) as fh: 89 IMEX_CONFIG = json.load(fh) 90 91
92 def save_config(): 93 global IMEX_CONFIG 94 try: 95 with open(os.path.join(THISPATH, "imex.config"), "w") as fh: 96 json.dump(IMEX_CONFIG, fh, indent=4) 97 except Exception as err: 98 with wx.MessageDialog(None, message="Can't write config to path '%s'" % THISPATH, 99 caption="IM-/EXPORT Save Config", 100 style=wx.ICON_ERROR) as dlg: 101 dlg.ShowModal() 102 103 104 load_config() 105 106
107 def get_filename_in(): 108 in_name = IMEX_CONFIG.get("in_fname") 109 if not in_name: 110 with wx.FileDialog(None, "IM-/EXPORT: File to Import", 111 wildcard="OBJ files (*.obj)|*.obj", 112 defaultDir=IMEX_CONFIG.get("last_path") or THISPATH, 113 style=wx.FD_DEFAULT_STYLE | wx.FD_OPEN) as dlg: 114 if dlg.ShowModal() != wx.ID_CANCEL: 115 in_name = IMEX_CONFIG["in_fname"] = dlg.GetPath() 116 IMEX_CONFIG["last_path"] = os.path.dirname(in_name) 117 save_config() 118 119 return in_name 120 121
122 def get_filename_out(): 123 out_name = IMEX_CONFIG.get("out_fname") 124 if not out_name: 125 with wx.FileDialog(None, "IM-/EXPORT: Filename to export to", 126 wildcard="OBJ files (*.obj)|*.obj", 127 defaultDir=IMEX_CONFIG.get("last_path") or THISPATH, 128 style=wx.FD_DEFAULT_STYLE | wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as dlg: 129 if dlg.ShowModal() != wx.ID_CANCEL: 130 out_name = IMEX_CONFIG["out_fname"] = dlg.GetPath() 131 IMEX_CONFIG["last_path"] = os.path.dirname(out_name) 132 save_config() 133 134 return out_name 135 136
137 def get_morphname(default=None): 138 morphname = IMEX_CONFIG.get("morphname") 139 if morphname is None or not morphname: 140 with wx.TextEntryDialog(None, message="Morphname to use:", 141 caption="OBJECT IM-EXPORT") as dlg: 142 dlg.SetValue(default or "NewMorph") 143 if dlg.ShowModal() != wx.ID_CANCEL: 144 morphname = IMEX_CONFIG["morphname"] = dlg.GetValue() 145 save_config() 146 147 return morphname 148 149
150 def get_scale(default=1): 151 scale = IMEX_CONFIG.get("scale") 152 if scale is None: 153 with wx.NumberEntryDialog(None, message="Scale (hint: Blender=10, C4D=1000):", 154 value=default or 1, min=1, max=5000, prompt=">>>", 155 caption="OBJECT IM-EXPORT") as dlg: 156 if dlg.ShowModal() != wx.ID_CANCEL: 157 scale = IMEX_CONFIG["scale"] = dlg.GetValue() 158 save_config() 159 160 return scale 161 162
163 class ImExMenu(Menu.MenuClass): 164 def setup(self): 165 self.screen_name = "OBJ Im-/ExPorter" 166
167 def BUTTON_title(self, *args): 168 """ 169 :nr: 1 170 :title: <<[ OBJ Im-/Export ]>> 171 """ 172 # print("=" * 40) 173 # print("IM-/Export status:") 174 # print("\nConfig file:", os.path.join(THISPATH, "imex.config")) 175 # print("\nExport Path:", IMEX_CONFIG.get("out_fname", "")) 176 # print("Import Path:", IMEX_CONFIG.get("in_fname", "")) 177 # print("\nMorphname:", IMEX_CONFIG.get("morphname", "")) 178 # print("Scale:", IMEX_CONFIG.get("scale", "")) 179 # print("=" * 40) 180 181 with CfgDialog(IMEX_CONFIG) as dlg: 182 if dlg.ShowModal() != wx.ID_CANCEL: 183 save_config() 184
185 def BUTTON_Export(self, *args): 186 """ 187 :title: * Export Figure 188 """ 189 if not SCENE.CurrentFigure(): 190 PopUpMessage("No figure selected.") 191 return 192 193 out_file = get_filename_out() 194 if out_file is None or not os.path.isdir(os.path.dirname(out_file)): 195 with wx.MessageDialog(None, message="Export aborted.", 196 caption="OBJECT EXPORT", 197 style=wx.ICON_EXCLAMATION) as dlg: 198 dlg.ShowModal() 199 else: 200 with wx.BusyInfo("Exporting Figures Geometry"): 201 res = do_export(SCENE.CurrentFigure(), 202 filename=out_file or SCENE.CurrentFigure().Name() + ".obj", 203 scale=get_scale(), 204 use_groups=False, 205 use_mat=True) 206 if res: 207 PopUpMessage("Exported to '%s'" % out_file) 208
209 def BUTTON_Import(self, *args): 210 """ 211 :title: * Import Figure 212 """ 213 if not SCENE.CurrentFigure(): 214 PopUpMessage("No figure selected.") 215 return 216 217 # First make sure filenames and morphname is set. 218 if get_filename_in() and get_filename_out() and get_morphname(): 219 # Then start the import. 220 with wx.BusyInfo("Importing Morph to Figure"): 221 res = do_import(SCENE.CurrentFigure(), 222 new_filename=get_filename_in(), 223 old_filename=get_filename_out(), 224 morphname=get_morphname(), 225 scale=get_scale(), 226 ) 227 if res: 228 PopUpMessage("Imported to morph '%s'" % get_morphname()) 229 else: 230 with wx.MessageDialog(None, message="Import Aborted.", 231 caption="OBJECT IMPORT", 232 style=wx.ICON_EXCLAMATION) as dlg: 233 dlg.ShowModal() 234
235 def BUTTON_4_blank1(self, *args): 236 """:title: ---""" 237
238 def BUTTON_5_MergeMorphs(self, *args): 239 """ 240 :title: Merge Morphs to One... 241 """ 242 if SCENE.CurrentFigure(): 243 with CombineDialog(figure=SCENE.CurrentFigure(), 244 config=IMEX_CONFIG, 245 new_morphname=IMEX_CONFIG.get("morphname", "MORPH") + "_NEW") as dlg: 246 dlg.ShowModal() 247 save_config() 248
249 def BUTTON_10_back(self, *args): 250 """ 251 :title: <<< Back <<< 252 """ 253 254 # THISFILE is used to insert this script into the 255 # standard Button Menu if this is the first page of ower script. 256 self.back(THISFILE) 257 258 Menu.activate(ImExMenu) 259