def closeProject(save=None,clear=None): """Close the current project, saving it or not. Parameters: - `save`: None, True or False. Determines whether the project should be saved prior to closing it. If None, it will be asked from the user. Note that this parameter is only used for named Projects. Temporary Projects are never saved implicitely. - `clear`: None, True or False. """ if pf.PF.filename is not None: if save is None: save = draw.ack("Save the current project before closing it?") pf.message("Closing project %s (save=%s)" % (pf.PF.filename,save)) if save: saveProject() if pf.PF: listProject() if clear is None: clear = draw.ask("What shall I do with the existing globals?",["Delete","Keep"]) == "Delete" if clear: pf.PF.clear() pf.PF.filename = None pf.GUI.setcurproj('None') updateSettings({ 'curproj':pf.PF.filename, },save=True)
def updateSettings(res,save=None): """Update the current settings (store) with the values in res. res is a dictionary with configuration values. The current settings will be update with the values in res. If res contains a key 'Save changes' and its value is True, the preferences will also be saved to the user's preference file. Else, the user will be asked whether he wants to save the changes. """ pf.debug("Accepted settings:",res) if save is None: save = res.get('Save changes',None) if save is None: save = draw.ack("Save the current changes to your configuration file?") # Do not use 'pf.cfg.update(res)' here! # It will not work with our Config class! for k in res: if k.startswith('_'): # skip temporary variables continue if pf.cfg[k] != res[k]: pf.cfg[k] = res[k] if save and pf.prefcfg[k] != pf.cfg[k]: pf.prefcfg[k] = pf.cfg[k] if pf.GUI: if k in _activate_settings: _activate_settings[k]() pf.debug("New settings:",pf.cfg) pf.debug("New preferences:",pf.prefcfg)
def askConfigPreferences(items, prefix=None, store=None): """Ask preferences stored in config variables. Items in list should only be keys. store is usually a dictionary, but can be any class that allow the setdefault method for lookup while setting the default, and the store[key]=val syntax for setting the value. If a prefix is given, actual keys will be 'prefix/key'. The current values are retrieved from the store, and the type returned will be in accordance. If no store is specified, the global config GD.cfg is used. """ if not store: store = GD.cfg if prefix: items = ["%s/%s" % (prefix, i) for i in items] itemlist = [[i, store.setdefault(i, "")] for i in items] res, accept = widgets.InputDialog(itemlist, "Config Dialog", GD.gui).getResult() if accept: GD.debug(res) if draw.ack("Update the settings?"): # This does not work for our Config class! # store.update(res) # Therefore, set individually for k, v in res.items(): store[k] = v ## for i,r in zip(itemlist,res): ## GD.debug("IN : %s\nOUT: %s" % (i,r)) ## if type(i[1]) == str: ## store[r[0]] = r[1] ## else: ## store[r[0]] = eval(r[1]) GD.debug(GD.cfg) return accept
def openScript(fn=None,exist=True,create=False): """Open a pyFormex script and set it as the current script. If no filename is specified, a file selection dialog is started to select an existing script, or allow to create a new file if exist is False. If the file exists and is a pyFormex script, it is set ready to execute. If create is True, a default pyFormex script template will be written to the file, overwriting the contents if the file existed. Then, the script is loaded into the editor. We encourage the use of createScript() to create new scripts and leave openScript() to open existing scripts. """ if fn is None: cur = GD.cfg.get('curfile',GD.cfg.get('workdir','.')) typ = "pyFormex scripts (*.py)" fn = widgets.FileSelection(cur,typ,exist=exist).getFilename() if fn: if create: if not exist and os.path.exists(fn) and not draw.ack("The file %s already exists.\n Are you sure you want to overwrite it?" % fn): return None template = GD.cfg['scripttemplate'] if (os.path.exists(template)): shutil.copyfile(template,fn) GD.cfg['workdir'] = os.path.dirname(fn) GD.GUI.setcurfile(fn) GD.GUI.history.add(fn) if create: editScript(fn) return fn
def recordSession(stop=0): """Record the current pyFormex session.""" global _recording_pid from guimain import hasDRI print("RECORDING with dri=%s" % pf.options.dri) ok = utils.checkExternal('recordmydesktop') if not ok: return if hasDRI(): if not draw.ack("Recording the session while using DRI may fail to correctly capture the OpenGL canvas. We recommend starting pyformex with the --nodri option to do session recording (at the expense of a slower execution). If you click YES I will nevertheless go ahead with recording."): return fn = draw.askFilename(pf.cfg['workdir'],"Theora video files (*.ogv)",exist=False) if not fn: return print("Recording your session to file %s" % fn) x,y,w,h = pf.GUI.XGeometry() cmd = "recordmydesktop -x %s -y %s --width %s --height %s --no-frame -o %s" % (x,y,w,h,fn) print(cmd) pid = utils.spawn(cmd) print("Recording pid = %s" % pid) _recording_pid = pid
def recordSession(stop=0): """Record the current pyFormex session.""" global _recording_pid from guimain import hasDRI print("RECORDING with dri=%s" % pf.options.dri) ok = utils.checkExternal('recordmydesktop') if not ok: return if hasDRI(): if not draw.ack( "Recording the session while using DRI may fail to correctly capture the OpenGL canvas. We recommend starting pyformex with the --nodri option to do session recording (at the expense of a slower execution). If you click YES I will nevertheless go ahead with recording." ): return fn = draw.askFilename(pf.cfg['workdir'], "Theora video files (*.ogv)", exist=False) if not fn: return print("Recording your session to file %s" % fn) x, y, w, h = pf.GUI.XGeometry() cmd = "recordmydesktop -x %s -y %s --width %s --height %s --no-frame -o %s" % ( x, y, w, h, fn) print(cmd) pid = utils.spawn(cmd) print("Recording pid = %s" % pid) _recording_pid = pid
def closeProject(save=None, clear=None): """Close the current project, saving it or not. Parameters: - `save`: None, True or False. Determines whether the project should be saved prior to closing it. If None, it will be asked from the user. Note that this parameter is only used for named Projects. Temporary Projects are never saved implicitely. - `clear`: None, True or False. """ if pf.PF.filename is not None: if save is None: save = draw.ack("Save the current project before closing it?") pf.message("Closing project %s (save=%s)" % (pf.PF.filename, save)) if save: saveProject() if pf.PF: listProject() if clear is None: clear = draw.ask( "What shall I do with the existing globals?", ["Delete", "Keep"]) == "Delete" if clear: pf.PF.clear() pf.PF.filename = None pf.GUI.setcurproj('None') updateSettings({ 'curproj': pf.PF.filename, }, save=True)
def updateSettings(res,save=None): """Update the current settings (store) with the values in res. res is a dictionary with configuration values. The current settings will be updated with the values in res. If res contains a key '_save_', or a `save` argument is supplied, and its value is True, the preferences will also be saved to the user's preference file. Else, the user will be asked whether he wants to save the changes. """ pf.debug("\nACCEPTED SETTINGS\n%s"% res,pf.DEBUG.CONFIG) if save is None: save = res.get('_save_',None) if save is None: save = draw.ack("Save the current changes to your configuration file?") # Do not use 'pf.cfg.update(res)' here! # It will not work with our Config class! # a set to uniquely register updatefunctions todo = set([]) for k in res: if k.startswith('_'): # skip temporary variables continue changed = False # first try to set in prefs, as these will cascade to cfg if save and pf.prefcfg[k] != res[k]: pf.prefcfg[k] = res[k] changed = True # if not saved, set in cfg print("Setting %s = %s" % (k,res[k])) if pf.cfg[k] != res[k]: pf.cfg[k] = res[k] changed = True if changed and pf.GUI: # register the corresponding update function if k in _activate_settings: todo.add(_activate_settings[k]) # We test for pf.GUI in case we want to call updateSettings before # the GUI is created if pf.GUI: for f in todo: f() pf.debug("\nNEW SETTINGS\n%s"%pf.cfg,pf.DEBUG.CONFIG) pf.debug("\nNEW PREFERENCES\n%s"%pf.prefcfg,pf.DEBUG.CONFIG)
def updateSettings(res, save=None): """Update the current settings (store) with the values in res. res is a dictionary with configuration values. The current settings will be updated with the values in res. If res contains a key '_save_', or a `save` argument is supplied, and its value is True, the preferences will also be saved to the user's preference file. Else, the user will be asked whether he wants to save the changes. """ pf.debug("\nACCEPTED SETTINGS\n%s" % res, pf.DEBUG.CONFIG) if save is None: save = res.get('_save_', None) if save is None: save = draw.ack("Save the current changes to your configuration file?") # Do not use 'pf.cfg.update(res)' here! # It will not work with our Config class! # a set to uniquely register updatefunctions todo = set([]) for k in res: if k.startswith('_'): # skip temporary variables continue changed = False # first try to set in prefs, as these will cascade to cfg if save and pf.prefcfg[k] != res[k]: pf.prefcfg[k] = res[k] changed = True # if not saved, set in cfg print("Setting %s = %s" % (k, res[k])) if pf.cfg[k] != res[k]: pf.cfg[k] = res[k] changed = True if changed and pf.GUI: # register the corresponding update function if k in _activate_settings: todo.add(_activate_settings[k]) # We test for pf.GUI in case we want to call updateSettings before # the GUI is created if pf.GUI: for f in todo: f() pf.debug("\nNEW SETTINGS\n%s" % pf.cfg, pf.DEBUG.CONFIG) pf.debug("\nNEW PREFERENCES\n%s" % pf.prefcfg, pf.DEBUG.CONFIG)
def updateSettings(res,store): """Update the current settings (store) with the values in res. store and res are both dictionaries This asks the users to confirm that he wants to update the settings. """ GD.debug(res) if res.get('Save changes',None) or draw.ack("Save the changes to your configuration file?\n\nCurrently, the changes will be rejected if you do not save them!\n"): # Do not use 'store.update(res)' here! # It will not work with our Config class! for k,v in res.items(): store[k] = v GD.debug(store) return True return False
def updateSettings(res,store): """Update the current settings (store) with the values in res. store and res are both dictionaries This asks the users to confirm that he wants to update the settings. """ GD.debug(res) if draw.ack("Update the settings?"): # The following does not work for our Config class! # store.update(res) # Therefore, set individually for k,v in res.items(): store[k] = v GD.debug(store) return True return False
def exportWebGL(): """Export the current scene to WebGL""" from plugins.webgl import WebGL types = [ utils.fileDescription('html') ] fn = draw.askNewFilename(pf.cfg['workdir'],types) if fn: pf.message("Exporting current scene to %s" % fn) pf.GUI.setBusy() fn = os.path.basename(fn) name = utils.projectName(fn) W = WebGL(name) W.addScene() fn = W.export(title="%s WebGL model"%name,createdby=50) pf.GUI.setBusy(False) if draw.ack("Show the scene in your browser?"): fn = os.path.join(os.getcwd(),fn) print(fn) from gui.helpMenu import help help('file:%s' % fn)
def exportWebGL(): """Export the current scene to WebGL""" from plugins.webgl import WebGL types = [utils.fileDescription('html')] fn = draw.askNewFilename(pf.cfg['workdir'], types) if fn: pf.message("Exporting current scene to %s" % fn) pf.GUI.setBusy() fn = os.path.basename(fn) name = utils.projectName(fn) W = WebGL(name) W.addScene() fn = W.export(title="%s WebGL model" % name, createdby=50) pf.GUI.setBusy(False) if draw.ack("Show the scene in your browser?"): fn = os.path.join(os.getcwd(), fn) print(fn) from gui.helpMenu import help help('file:%s' % fn)
def openScript(fn=None, exist=True, create=False): """Open a pyFormex script and set it as the current script. If no filename is specified, a file selection dialog is started to select an existing script, or allow to create a new file if exist is False. If the file exists and is a pyFormex script, it is set ready to execute. If create is True, a default pyFormex script template will be written to the file, overwriting the contents if the file existed. Then, the script is loaded into the editor. We encourage the use of createScript() to create new scripts and leave openScript() to open existing scripts. """ if fn is None: cur = pf.cfg['curfile'] if cur is None: cur = pf.cfg['workdir'] if cur is None: cur = '.' typ = utils.fileDescription('pyformex') fn = widgets.FileSelection(cur, typ, exist=exist).getFilename() if fn: if create: if not exist and os.path.exists(fn) and not draw.ack( "The file %s already exists.\n Are you sure you want to overwrite it?" % fn): return None template = pf.cfg['scripttemplate'] if (os.path.exists(template)): shutil.copyfile(template, fn) updateSettings({'workdir': os.path.dirname(fn)}, save=True) pf.GUI.setcurfile(fn) pf.GUI.scripthistory.add(fn) if create: draw.editFile(fn) return fn
def createProject(create=True,compression=0,addGlobals=None): """Open a file selection dialog and let the user select a project. The default will let the user create new project files as well as open existing ones. Use create=False or the convenience function openProject to only accept existing project files. If a compression level (1..9) is given, the contents will be compressed, resulting in much smaller project files at the cost of Only one pyFormex project can be open at any time. The open project owns all the global data created and exported by any script. If addGlobals is None, the user is asked whether the current globals should be added to the project. Set True or False to force or reject the adding without asking. """ global the_project # ask filename from user if the_project is None: cur = GD.cfg.get('workdir','.') else: options = ['Cancel','Close without saving','Save and Close'] ans = draw.ask("Another project is still open. Shall I close it first?", options) if ans == 'Cancel': return if ans == options[2]: the_project.save() cur = the_project.filename typ = [ 'pyFormex projects (*.pyf)', 'All files (*)' ] res = widgets.ProjectSelection(cur,typ,exist=not create).getResult() if res is None: # user canceled return fn = res.fn if not fn.endswith('.pyf'): fn += '.pyf' legacy = res.leg compression = res.cpr print fn,legacy,compression if create and os.path.exists(fn): res = draw.ask("The project file '%s' already exists\nShall I delete the contents or add to it?" % fn,['Delete','Add','Cancel']) if res == 'Cancel': return if res == 'Add': create = False GD.message("Opening project %s" % fn) if GD.PF: GD.message("Exported symbols: %s" % GD.PF.keys()) if addGlobals is None: res = draw.ask("pyFormex already contains exported symbols.\nShall I delete them or add them to your project?",['Delete','Add','Cancel']) if res == 'Cancel': # ESCAPE FROM CREATING THE PROJECT return addGlobals = res == 'Add' # OK, we have all data, now create/open the project GD.cfg['workdir'] = os.path.dirname(fn) GD.GUI.setBusy() try: sig = GD.Version[:GD.Version.rfind('-')] the_project = project.Project(fn,create=create,signature=sig,compression=compression,legacy=legacy) if GD.PF and addGlobals: the_project.update(GD.PF) GD.PF = the_project GD.GUI.setcurproj(fn) GD.message("Project contents: %s" % the_project.keys()) if hasattr(the_project,'autofile') and draw.ack("The project has an autofile attribute: %s\nShall I execute this script?" % the_project.autofile): processArgs([the_project.autofile]) finally: GD.GUI.setBusy(False)
def createProject(create=True,compression=0,addGlobals=None,makeDefault=True): """Open a file selection dialog and let the user select a project. The default will let the user create new project files as well as open existing ones. Use create=False or the convenience function openProject to only accept existing project files. If a compression level (1..9) is given, the contents will be compressed, resulting in much smaller project files at the cost of Only one pyFormex project can be open at any time. The open project owns all the global data created and exported by any script. If makeDefault is True, an already open project will be closed and the opened project becomes the current project. If makeDefault is False, the project data are imported into GD.PF and the current project does not change. This means that if a project was open, the imported data will be added to it. If addGlobals is None, the user is asked whether the current globals should be added to the project. Set True or False to force or reject the adding without asking. """ global the_project # ask filename from user if the_project is None: cur = GD.cfg.get('workdir','.') else: if makeDefault: options = ['Cancel','Close without saving','Save and Close'] ans = draw.ask("Another project is still open. Shall I close it first?", options) if ans == 'Cancel': return if ans == options[2]: the_project.save() cur = the_project.filename typ = utils.fileDescription(['pyf','all']) res = widgets.ProjectSelection(cur,typ,exist=not create).getResult() if res is None: # user canceled return fn = res.fn if not fn.endswith('.pyf'): fn += '.pyf' legacy = res.leg ignoresig = res.sig compression = res.cpr #print(fn,legacy,compression) if create and os.path.exists(fn): res = draw.ask("The project file '%s' already exists\nShall I delete the contents or add to it?" % fn,['Delete','Add','Cancel']) if res == 'Cancel': return if res == 'Add': create = False GD.message("Opening project %s" % fn) if GD.PF: GD.message("Exported symbols: %s" % GD.PF.keys()) if addGlobals is None: res = draw.ask("pyFormex already contains exported symbols.\nShall I delete them or add them to your project?",['Delete','Add','Cancel']) if res == 'Cancel': # ESCAPE FROM CREATING THE PROJECT return addGlobals = res == 'Add' # OK, we have all data, now create/open the project updateSettings({'workdir':os.path.dirname(fn)},save=True) sig = GD.Version[:GD.Version.rfind('-')] if ignoresig: sig = '' proj = _open_project(fn,create,sig,compression,legacy) GD.message("Project contents: %s" % proj.keys()) if hasattr(proj,'_autoscript_'): _ignore = "Ignore it!" _show = "Show it" _edit = "Load it in the editor" _exec = "Execute it" res = draw.ask("There is an autoscript stored inside the project.\nIf you received this project file from an untrusted source, you should probably not execute it.",[_ignore,_show,_edit,_exec]) if res == _show: res = draw.showText(proj._autoscript_)#,actions=[_ignore,_edit,_show]) return if res == _exec: draw.playScript(proj._autoscript_) elif res == _edit: fn = "_autoscript_.py" draw.checkWorkdir() f = file(fn,'w') f.write(proj._autoscript_) f.close() openScript(fn) editScript(fn) if hasattr(proj,'autofile') and draw.ack("The project has an autofile attribute: %s\nShall I execute this script?" % proj.autofile): processArgs([proj.autofile]) if makeDefault: the_project = proj if GD.PF and addGlobals: the_project.update(GD.PF) GD.PF = the_project GD.GUI.setcurproj(fn) else: # Just import the data into current project GD.PF.update(proj) GD.message("Exported symbols: %s" % GD.PF.keys())
def setProject(proj): """Make the specified project the current project. proj is an open project. If a filename, the project file is opened. .. note: The remainder is obsolete The user is asked for a Project file name and the access modalities. Depending on the results of the dialog: - either an new project is create or an old is opened, - the old data may be discarded, added to the current pyFormex globals, or replace them - the opened Project may become the current Project, or its data are just imported in the current Project. The default will let the user create new project files as well as open existing ones. Use create=False or the convenience function openProject to only accept existing project files. If a compression level (1..9) is given, the contents will be compressed, resulting in much smaller project files at the cost of Only one pyFormex project can be open at any time. The open project owns all the global data created and exported by any script. If makeDefault is True, an already open project will be closed and the opened project becomes the current project. If makeDefault is False, the project data are imported into pf.PF and the current project does not change. This means that if a project was open, the imported data will be added to it. If addGlobals is None, the user is asked whether the current globals should be added to the project. Set True or False to force or reject the adding without asking. """ pf.message("Setting current project to %s" % proj.filename) pf.message("Project contents: %s" % utils.sortedKeys(proj)) keep = {} if pf.PF: pf.message("Current pyFormex globals: %s" % utils.sortedKeys(pf.PF)) _delete = "Delete" _add = "Keep non existing" _overwrite = "Keep all (overwrite project)" res = draw.ask("What shall I do with the current pyFormex globals?",[_delete,_add,_overwrite]) if res == _add: keep = utils.removeDict(pf.PF,proj) elif res == _overwrite: keep = pf.PF pf.PF = proj if keep: pf.PF.update(keep) if pf.PF.filename: updateSettings({ 'curproj':pf.PF.filename, 'workdir':os.path.dirname(pf.PF.filename), },save=True) pf.GUI.setcurproj(pf.PF.filename) if hasattr(proj,'_autoscript_'): _ignore = "Ignore it!" _show = "Show it" _edit = "Load it in the editor" _exec = "Execute it" res = draw.ask("There is an autoscript stored inside the project.\nIf you received this project file from an untrusted source, you should probably not execute it.",[_ignore,_show,_edit,_exec]) if res == _show: res = draw.showText(proj._autoscript_)#,actions=[_ignore,_edit,_show]) return if res == _exec: draw.playScript(proj._autoscript_) elif res == _edit: fn = "_autoscript_.py" draw.checkWorkdir() f = open(fn,'w') f.write(proj._autoscript_) f.close() openScript(fn) editApp(fn) if hasattr(proj,'autofile') and draw.ack("The project has an autofile attribute: %s\nShall I execute this script?" % proj.autofile): draw.processArgs([proj.autofile]) listProject()
def setProject(proj): """Make the specified project the current project. proj is an open project. If a filename, the project file is opened. .. note: The remainder is obsolete The user is asked for a Project file name and the access modalities. Depending on the results of the dialog: - either an new project is create or an old is opened, - the old data may be discarded, added to the current pyFormex globals, or replace them - the opened Project may become the current Project, or its data are just imported in the current Project. The default will let the user create new project files as well as open existing ones. Use create=False or the convenience function openProject to only accept existing project files. If a compression level (1..9) is given, the contents will be compressed, resulting in much smaller project files at the cost of Only one pyFormex project can be open at any time. The open project owns all the global data created and exported by any script. If makeDefault is True, an already open project will be closed and the opened project becomes the current project. If makeDefault is False, the project data are imported into pf.PF and the current project does not change. This means that if a project was open, the imported data will be added to it. If addGlobals is None, the user is asked whether the current globals should be added to the project. Set True or False to force or reject the adding without asking. """ pf.message("Setting current project to %s" % proj.filename) pf.message("Project contents: %s" % utils.sortedKeys(proj)) keep = {} if pf.PF: pf.message("Current pyFormex globals: %s" % utils.sortedKeys(pf.PF)) _delete = "Delete" _add = "Keep non existing" _overwrite = "Keep all (overwrite project)" res = draw.ask("What shall I do with the current pyFormex globals?", [_delete, _add, _overwrite]) if res == _add: keep = utils.removeDict(pf.PF, proj) elif res == _overwrite: keep = pf.PF pf.PF = proj if keep: pf.PF.update(keep) if pf.PF.filename: updateSettings( { 'curproj': pf.PF.filename, 'workdir': os.path.dirname(pf.PF.filename), }, save=True) pf.GUI.setcurproj(pf.PF.filename) if hasattr(proj, '_autoscript_'): _ignore = "Ignore it!" _show = "Show it" _edit = "Load it in the editor" _exec = "Execute it" res = draw.ask( "There is an autoscript stored inside the project.\nIf you received this project file from an untrusted source, you should probably not execute it.", [_ignore, _show, _edit, _exec]) if res == _show: res = draw.showText( proj._autoscript_) #,actions=[_ignore,_edit,_show]) return if res == _exec: draw.playScript(proj._autoscript_) elif res == _edit: fn = "_autoscript_.py" draw.checkWorkdir() f = open(fn, 'w') f.write(proj._autoscript_) f.close() openScript(fn) editApp(fn) if hasattr(proj, 'autofile') and draw.ack( "The project has an autofile attribute: %s\nShall I execute this script?" % proj.autofile): draw.processArgs([proj.autofile]) listProject()