from ...command import CommandExit, Exit, Success, Failure, Command, Argument
from ...config import Setting
+from ...engine import CommandMessage
from ...interaction import Request, BooleanRequest, ReloadUserInterfaceConfig
-from ...ui import UserInterface, CommandMessage
+from ...ui import UserInterface
from .dialog.selection import Selection as SelectionDialog
from .dialog.save_file import select_save_file
from . import menu as menu
from . import navbar as navbar
from . import panel as panel
-from .panel.propertyeditor import prop_from_argument, prop_from_setting
+from .panel.propertyeditor import props_from_argument, props_from_setting
from . import statusbar as statusbar
self._setup_perspectives()
self._bind_events()
-
- self.execute_command(
- command=self._command_by_name('load playlist'),
- args={'input':'test/data/vclamp_picoforce/playlist'},
- )
return # TODO: cleanup
- self.playlists = self._c['playlist'].Playlists
self._displayed_plot = None
#load default list, if possible
self.do_loadlist(self.GetStringFromConfig('core', 'preferences', 'playlists'))
# size=(200, 250),
# style=wx.DIRCTRL_SHOW_FILTERS,
# filter=self.gui.config['folders-filters'],
-# defaultFilter=int(self.gui.config['folders-filter-index'])), 'left'), #HACK: config should convert
+# defaultFilter=self.gui.config['folders-filter-index']), 'left'),
(panel.PANELS['playlist'](
callbacks={
'delete_playlist':self._on_user_delete_playlist,
style=wx.WANTS_CHARS,
# WANTS_CHARS so the panel doesn't eat the Return key.
), 'center'),
-# ('assistant', wx.TextCtrl(
-# parent=self,
-# pos=wx.Point(0, 0),
-# size=wx.Size(150, 90),
-# style=wx.NO_BORDER|wx.TE_MULTILINE), 'right'),
(panel.PANELS['plot'](
callbacks={
+ '_set_status_text': self._on_plot_status_text,
},
parent=self,
style=wx.WANTS_CHARS|wx.NO_BORDER,
# ('results', panel.results.Results(self), 'bottom'),
]:
self._add_panel(p, style)
- #self._c['assistant'].SetEditable(False)
+ self.execute_command( # setup already loaded playlists
+ command=self._command_by_name('playlists'))
+ self.execute_command( # setup already loaded curve
+ command=self._command_by_name('get curve'))
def _add_panel(self, panel, style):
self._c[panel.name] = panel
def _on_close(self, *args):
self.log.info('closing GUI framework')
# apply changes
- self.gui.config['main height'] = str(self.GetSize().GetHeight())
- self.gui.config['main left'] = str(self.GetPosition()[0])
- self.gui.config['main top'] = str(self.GetPosition()[1])
- self.gui.config['main width'] = str(self.GetSize().GetWidth())
- # push changes back to Hooke.config?
+ self._set_config('main height', self.GetSize().GetHeight())
+ self._set_config('main left', self.GetPosition()[0])
+ self._set_config('main top', self.GetPosition()[1])
+ self._set_config('main width', self.GetSize().GetWidth())
self._c['manager'].UnInit()
del self._c['manager']
self.Destroy()
def _file_name(self, name):
"""Cleanup names according to configured preferences.
"""
- if self.gui.config['hide extensions'] == 'True': # HACK: config should decode
+ if self.gui.config['hide extensions'] == True:
name,ext = os.path.splitext(name)
return name
if args == None:
args = {}
if ('property editor' in self._c
- and self.gui.config['selected command'] == command):
- arg_names = [arg.name for arg in command.arguments]
+ and self.gui.config['selected command'] == command.name):
for name,value in self._c['property editor'].get_values().items():
- if name in arg_names:
- args[name] = value
- self.log.debug('executing %s with %s' % (command.name, args))
- self.inqueue.put(CommandMessage(command, args))
+ arg = self._c['property editor']._argument_from_label.get(
+ name, None)
+ if arg == None:
+ continue
+ elif arg.count == 1:
+ args[arg.name] = value
+ continue
+ # deal with counted arguments
+ if arg.name not in args:
+ args[arg.name] = {}
+ index = int(name[len(arg.name):])
+ args[arg.name][index] = value
+ for arg in command.arguments:
+ if arg.name not in args:
+ continue # undisplayed argument, e.g. 'driver' types.
+ count = arg.count
+ if hasattr(arg, '_display_count'): # support HACK in props_from_argument()
+ count = arg._display_count
+ if count != 1 and arg.name in args:
+ keys = sorted(args[arg.name].keys())
+ assert keys == range(count), keys
+ args[arg.name] = [args[arg.name][i]
+ for i in range(count)]
+ if arg.count == -1:
+ while (len(args[arg.name]) > 0
+ and args[arg.name][-1] == None):
+ args[arg.name].pop()
+ if len(args[arg.name]) == 0:
+ args[arg.name] = arg.default
+ cm = CommandMessage(command.name, args)
+ self.gui._submit_command(cm, self.inqueue)
+ return self._handle_response(command_message=cm)
+
+ def _handle_response(self, command_message):
results = []
while True:
msg = self.outqueue.get()
h.run(self, msg) # TODO: pause for response?
continue
pp = getattr(
- self, '_postprocess_%s' % command.name.replace(' ', '_'),
- self._postprocess_text)
- pp(command=command, args=args, results=results)
+ self, '_postprocess_%s' % command_message.command.replace(' ', '_'),
+ self._postprocess_text)
+ pp(command=command_message.command,
+ args=command_message.arguments,
+ results=results)
return results
def _handle_request(self, msg):
continue
self.inqueue.put(response)
+ def _set_config(self, option, value, section=None):
+ self.gui._set_config(section=section, option=option, value=value,
+ ui_to_command_queue=self.inqueue,
+ response_handler=self._handle_response)
# Command-specific postprocessing
self._c['output'].write(result.__class__.__name__+'\n')
self._c['output'].write(str(result).rstrip()+'\n')
+ def _postprocess_playlists(self, command, args={}, results=None):
+ """Update `self` to show the playlists.
+ """
+ if not isinstance(results[-1], Success):
+ self._postprocess_text(command, results=results)
+ return
+ assert len(results) == 2, results
+ playlists = results[0]
+ if 'playlist' in self._c:
+ for playlist in playlists:
+ if self._c['playlist'].is_playlist_loaded(playlist):
+ self._c['playlist'].update_playlist(playlist)
+ else:
+ self._c['playlist'].add_playlist(playlist)
+
+ def _postprocess_new_playlist(self, command, args={}, results=None):
+ """Update `self` to show the new playlist.
+ """
+ if not isinstance(results[-1], Success):
+ self._postprocess_text(command, results=results)
+ return
+ assert len(results) == 2, results
+ playlist = results[0]
+ if 'playlist' in self._c:
+ loaded = self._c['playlist'].is_playlist_loaded(playlist)
+ assert loaded == False, loaded
+ self._c['playlist'].add_playlist(playlist)
+
def _postprocess_load_playlist(self, command, args={}, results=None):
"""Update `self` to show the playlist.
"""
return
assert len(results) == 2, results
playlist = results[0]
- self._c['playlist']._c['tree'].add_playlist(playlist)
+ self._c['playlist'].add_playlist(playlist)
def _postprocess_get_playlist(self, command, args={}, results=[]):
if not isinstance(results[-1], Success):
return
assert len(results) == 2, results
playlist = results[0]
- self._c['playlist']._c['tree'].update_playlist(playlist)
+ if 'playlist' in self._c:
+ loaded = self._c['playlist'].is_playlist_loaded(playlist)
+ assert loaded == True, loaded
+ self._c['playlist'].update_playlist(playlist)
def _postprocess_get_curve(self, command, args={}, results=[]):
"""Update `self` to show the curve.
else:
raise NotImplementedError()
if 'note' in self._c:
- self._c['note'].set_text(curve.info['note'])
+ self._c['note'].set_text(curve.info.get('note', ''))
if 'playlist' in self._c:
- self._c['playlist']._c['tree'].set_selected_curve(
+ self._c['playlist'].set_selected_curve(
playlist, curve)
if 'plot' in self._c:
self._c['plot'].set_curve(curve, config=self.gui.config)
"""
pass
+ def _postprocess_glob_curves_to_playlist(
+ self, command, args={}, results=[]):
+ """Update `self` to show new curves.
+ """
+ if not isinstance(results[-1], Success):
+ self._postprocess_text(command, results=results)
+ return
+ if 'playlist' in self._c:
+ if args.get('playlist', None) != None:
+ playlist = args['playlist']
+ pname = playlist.name
+ loaded = self._c['playlist'].is_playlist_name_loaded(pname)
+ assert loaded == True, loaded
+ for curve in results[:-1]:
+ self._c['playlist']._add_curve(pname, curve)
+ else:
+ self.execute_command(
+ command=self._command_by_name('get playlist'))
+
def _postprocess_zero_block_surface_contact_point(
self, command, args={}, results=[]):
"""Update the curve, since the available columns may have changed.
def select_command(self, _class, method, command):
#self.select_plugin(plugin=command.plugin)
- if 'assistant' in self._c:
- self._c['assitant'].ChangeValue(command.help)
self._c['property editor'].clear()
+ self._c['property editor']._argument_from_label = {}
for argument in command.arguments:
if argument.name == 'help':
continue
else:
curves = results[0]
- p = prop_from_argument(
+ ret = props_from_argument(
argument, curves=curves, playlists=playlists)
- if p == None:
+ if ret == None:
continue # property intentionally not handled (yet)
- self._c['property editor'].append_property(p)
+ for label,p in ret:
+ self._c['property editor'].append_property(p)
+ self._c['property editor']._argument_from_label[label] = (
+ argument)
- self.gui.config['selected command'] = command # TODO: push to engine
+ self._set_config('selected command', command.name)
pass
def _on_delete_curve(self, _class, method, playlist, curve):
+ # TODO: execute_command 'remove curve from playlist'
os.remove(curve.path)
def _on_set_selected_playlist(self, _class, method, playlist):
+ # Plot panel interface
+
+ def _on_plot_status_text(self, _class, method, text):
+ if 'status bar' in self._c:
+ self._c['status bar'].set_plot_text(text)
+
+
+
# Navbar interface
def _next_curve(self, *args):
selected_perspective = self.gui.config['active perspective']
if not self._perspectives.has_key(selected_perspective):
- self.gui.config['active perspective'] = 'Default' # TODO: push to engine's Hooke
+ self._set_config('active perspective', 'Default')
self._restore_perspective(selected_perspective, force=True)
self._update_perspective_menu()
def _restore_perspective(self, name, force=False):
if name != self.gui.config['active perspective'] or force == True:
self.log.debug('restore perspective %s' % name)
- self.gui.config['active perspective'] = name # TODO: push to engine's Hooke
+ self._set_config('active perspective', name)
self._c['manager'].LoadPerspective(self._perspectives[name])
self._c['manager'].Update()
for pane in self._c['manager'].GetAllPanes():
style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
dialog.CenterOnScreen()
dialog.ShowModal()
+ if dialog.canceled == True:
+ return
names = [options[i] for i in dialog.selected]
dialog.Destroy()
self._delete_perspectives(
self.SetVendorName('')
self._setup_splash_screen()
- height = int(self.gui.config['main height']) # HACK: config should convert
- width = int(self.gui.config['main width'])
- top = int(self.gui.config['main top'])
- left = int(self.gui.config['main left'])
+ height = self.gui.config['main height']
+ width = self.gui.config['main width']
+ top = self.gui.config['main top']
+ left = self.gui.config['main left']
# Sometimes, the ini file gets confused and sets 'left' and
# 'top' to large negative numbers. Here we catch and fix
return True
def _setup_splash_screen(self):
- if self.gui.config['show splash screen'] == 'True': # HACK: config should decode
+ if self.gui.config['show splash screen'] == True:
path = self.gui.config['splash screen image']
if os.path.isfile(path):
- duration = int(self.gui.config['splash screen duration']) # HACK: config should decode types
+ duration = self.gui.config['splash screen duration']
wx.SplashScreen(
bitmap=wx.Image(path).ConvertToBitmap(),
splashStyle=wx.SPLASH_CENTRE_ON_SCREEN|wx.SPLASH_TIMEOUT,
Setting(section=self.setting_section, help=self.__doc__),
Setting(section=self.setting_section, option='icon image',
value=os.path.join('doc', 'img', 'microscope.ico'),
+ type='file',
help='Path to the hooke icon image.'),
Setting(section=self.setting_section, option='show splash screen',
- value=True,
+ value=True, type='bool',
help='Enable/disable the splash screen'),
Setting(section=self.setting_section, option='splash screen image',
value=os.path.join('doc', 'img', 'hooke.jpg'),
+ type='file',
help='Path to the Hooke splash screen image.'),
- Setting(section=self.setting_section, option='splash screen duration',
- value=1000,
+ Setting(section=self.setting_section,
+ option='splash screen duration',
+ value=1000, type='int',
help='Duration of the splash screen in milliseconds.'),
Setting(section=self.setting_section, option='perspective path',
value=os.path.join('resources', 'gui', 'perspective'),
value='.txt',
help='Extension for perspective files.'),
Setting(section=self.setting_section, option='hide extensions',
- value=False,
+ value=False, type='bool',
help='Hide file extensions when displaying names.'),
Setting(section=self.setting_section, option='plot legend',
- value=True,
+ value=True, type='bool',
help='Enable/disable the plot legend.'),
Setting(section=self.setting_section, option='plot SI format',
- value='True',
+ value='True', type='bool',
help='Enable/disable SI plot axes numbering.'),
Setting(section=self.setting_section, option='plot decimals',
- value=2,
+ value=2, type='int',
help='Number of decimal places to show if "plot SI format" is enabled.'),
Setting(section=self.setting_section, option='folders-workdir',
- value='.',
+ value='.', type='path',
help='This should probably go...'),
Setting(section=self.setting_section, option='folders-filters',
- value='.',
+ value='.', type='path',
help='This should probably go...'),
Setting(section=self.setting_section, option='active perspective',
value='Default',
help='Name of active perspective file (or "Default").'),
- Setting(section=self.setting_section, option='folders-filter-index',
- value='0',
+ Setting(section=self.setting_section,
+ option='folders-filter-index',
+ value=0, type='int',
help='This should probably go...'),
Setting(section=self.setting_section, option='main height',
- value=450,
+ value=450, type='int',
help='Height of main window in pixels.'),
Setting(section=self.setting_section, option='main width',
- value=800,
+ value=800, type='int',
help='Width of main window in pixels.'),
Setting(section=self.setting_section, option='main top',
- value=0,
+ value=0, type='int',
help='Pixels from screen top to top of main window.'),
Setting(section=self.setting_section, option='main left',
- value=0,
- help='Pixels from screen left to left of main window.'),
+ value=0, type='int',
+ help='Pixels from screen left to left of main window.'),
Setting(section=self.setting_section, option='selected command',
value='load playlist',
help='Name of the initially selected command.'),