Commit 47d176d4 authored by eric pellegrini's avatar eric pellegrini
Browse files

Reintroduced and refactored some plugins

parent 7b12be21
......@@ -25,57 +25,47 @@
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
'''
Created on Mar 27, 2015
Created on Apr 14, 2015
@author: pellegrini
'''
import time
import wx
class UserDefinable(dict):
'''
Base class for user definable objects. User definable objects are objects used in MDANSE for
storing information that can be reused later when setting up jobs (e.g. k-vectors defintion,
atom selection ...). A user definable object is a dictionary with a predefined set of keys that
depends on the user definable object. Object serialization is the underlying mechanism used to
save those objets and is done using cPickle module.
'''
def __init__(self, target):
'''
The constructor
'''
class UserDefinitionsPanel(wx.Panel):
def __init__(self, parent, *args, **kwargs):
self._target = target
wx.Panel.__init__(self, parent, wx.ID_ANY, *args, **kwargs)
self._creationTime = time.ctime()
self._parent = parent
self._definition = {}
@property
def target(self):
sb = wx.StaticBox(self, wx.ID_ANY)
actionsSizer = wx.StaticBoxSizer(sb, wx.HORIZONTAL)
self._cancelButton = wx.Button(self, wx.ID_ANY, label="Cancel")
self._udName = wx.TextCtrl(self, wx.ID_ANY, style = wx.TE_PROCESS_ENTER)
self._saveButton = wx.Button(self, wx.ID_ANY, label="Save")
return self._target
@property
def creationTime(self):
actionsSizer.Add(self._cancelButton, 0, wx.ALL, 5)
actionsSizer.Add(self._udName, 1, wx.ALL|wx.EXPAND, 5)
actionsSizer.Add(self._saveButton, 0, wx.ALL, 5)
return self._creationTime
@property
def definition(self):
self.SetSizer(actionsSizer)
return self._definition
self.Layout()
self.Bind(wx.EVT_BUTTON, self.on_close, self._cancelButton)
self.Bind(wx.EVT_BUTTON, self.on_save, self._saveButton)
def __str__(self):
'''
Return the informal representation of a user definable object
'''
def get_selection_name(self):
if not self._definition:
return "Not yet defined"
return self._udName.GetValue()
def on_close(self, event):
info = ["Created on: %s\n" % self._creationTime] + ["%s:\n%s\n" % (k,v) for k,v in self._definition.iteritems()]
self._parent.Parent.on_close()
def on_save(self, event):
return "".join(info)
\ No newline at end of file
self._parent.Parent.on_save()
\ No newline at end of file
......@@ -25,7 +25,7 @@
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
'''
Created on Apr 10, 2015
Created on Apr 14, 2015
@author: pellegrini
'''
......
......@@ -25,7 +25,7 @@
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
'''
Created on Apr 10, 2015
Created on Apr 14, 2015
@author: pellegrini
'''
......
#MDANSE : Molecular Dynamics Analysis for Neutron Scattering Experiments
#------------------------------------------------------------------------------------------
#Copyright (C)
#2015- Eric C. Pellegrini Institut Laue-Langevin
#BP 156
#6, rue Jules Horowitz
#38042 Grenoble Cedex 9
#France
#pellegrini[at]ill.fr
#goret[at]ill.fr
#aoun[at]ill.fr
#
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU Lesser General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#Lesser General Public License for more details.
#
#You should have received a copy of the GNU Lesser General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
'''
Created on Apr 14, 2015
@author: pellegrini
'''
import wx
import wx.aui as wxaui
from MDANSE.Externals.pubsub import pub as Publisher
from MDANSE.App.GUI.Icons import ICONS
from MDANSE.App.GUI.Framework.Plugins.ComponentPlugin import ComponentPlugin
class AnimationPlugin(ComponentPlugin):
type = "animation"
label = "Animation"
ancestor = "molecular_viewer"
def __init__(self, parent, *args, **kwargs):
ComponentPlugin.__init__(self, parent, size=(-1,50), *args, **kwargs)
def build_panel(self):
panel = wx.Panel(self, wx.ID_ANY, size=self.GetSize())
controlSizer = wx.BoxSizer(wx.HORIZONTAL)
firstButton = wx.BitmapButton(panel, wx.ID_ANY, ICONS["first",32,32])
self.playPause = wx.BitmapButton(panel, wx.ID_ANY, ICONS["play",32,32])
lastButton = wx.BitmapButton(panel, wx.ID_ANY, ICONS["last",32,32])
self.frameSlider = wx.Slider(panel,id=wx.ID_ANY, value=0, minValue=0, maxValue=1, style=wx.SL_HORIZONTAL)
self.frameEntry = wx.TextCtrl(panel,id=wx.ID_ANY,value="0", size=(60,20), style= wx.SL_HORIZONTAL|wx.TE_PROCESS_ENTER)
speedBitmap = wx.StaticBitmap(panel,-1, ICONS["clock",42,42])
self.speedSlider = wx.Slider(panel,id=wx.ID_ANY,value=0,minValue=0,maxValue=1,style=wx.SL_HORIZONTAL)
self.speedSlider.SetRange(0,self._parent.max_laps)
speed = self._parent.max_laps - self._parent.timer_interval
self.speedSlider.SetValue(speed)
self.speedEntry = wx.TextCtrl(panel,id=wx.ID_ANY,value=str(speed), size=(60,20), style= wx.SL_HORIZONTAL|wx.TE_PROCESS_ENTER)
controlSizer.Add(firstButton, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL,5)
controlSizer.Add(self.playPause, 0, wx.ALIGN_CENTER_VERTICAL)
controlSizer.Add(lastButton, 0, wx.ALIGN_CENTER_VERTICAL)
controlSizer.Add((5, -1), 0, wx.ALIGN_RIGHT)
controlSizer.Add(self.frameSlider, 3, wx.ALIGN_CENTER_VERTICAL)
controlSizer.Add(self.frameEntry, 0, wx.ALIGN_CENTER_VERTICAL)
controlSizer.Add((5, -1), 0, wx.ALIGN_RIGHT)
controlSizer.Add(speedBitmap, 0 , wx.ALIGN_CENTER_VERTICAL)
controlSizer.Add((5, -1), 0, wx.ALIGN_RIGHT)
controlSizer.Add(self.speedSlider, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL)
controlSizer.Add(self.speedEntry, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL,5)
panel.SetSizer(controlSizer)
controlSizer.Fit(panel)
panel.Layout()
self._mgr.AddPane(panel, wxaui.AuiPaneInfo().Center().Dock().CaptionVisible(False).CloseButton(False).MinSize(self.GetSize()))
self._mgr.Update()
self.Bind(wx.EVT_SCROLL, self.on_frame_sliding, self.frameSlider)
self.Bind(wx.EVT_TEXT_ENTER, self.on_set_frame, self.frameEntry)
self.Bind(wx.EVT_SLIDER, self.on_change_frame_rate, self.speedSlider)
self.Bind(wx.EVT_TEXT_ENTER, self.on_set_speed, self.speedEntry)
self.Bind(wx.EVT_BUTTON, self.on_start_stop_animation, self.playPause)
self.Bind(wx.EVT_BUTTON, self.on_goto_first_frame, firstButton)
self.Bind(wx.EVT_BUTTON, self.on_goto_last_frame, lastButton)
Publisher.subscribe(self.on_update_animation_icon, ('Animation'))
Publisher.subscribe(self.on_set_up_frame_slider, ('Load trajectory'))
Publisher.subscribe(self.on_timer, ('On timer'))
def plug(self):
self._parent._mgr.GetPane(self).LeftDockable(False).RightDockable(False).Dock().Bottom().CloseButton(True)
self._parent._mgr.Update()
Publisher.sendMessage(('Load trajectory'), message = self.parent)
def on_change_frame_rate(self, event=None):
laps = self.speedSlider.GetValue()
self._parent.change_frame_rate(laps)
self.speedEntry.SetValue(str(self.speedSlider.GetValue()))
def on_frame_sliding(self, event=None):
frame = self.frameSlider.GetValue()
self._parent.set_frame(frame)
frame = self._parent.current_frame
self.frameEntry.SetValue(str(frame))
self.frameSlider.SetValue(frame)
def on_goto_first_frame(self, event=None):
self._parent.goto_first_frame()
self.frameEntry.SetValue(str(0))
self.frameSlider.SetValue(0)
def on_goto_last_frame(self, event=None):
self._parent.goto_last_frame()
self.frameEntry.SetValue(str(self._parent.n_frames-1))
self.frameSlider.SetValue(self._parent.n_frames-1)
def on_set_speed(self, event=None):
self.speedSlider.SetValue(int(self.speedEntry.GetValue()))
self._parent.change_frame_rate()
def on_timer(self, message):
mv = message
if not self.has_parent(mv):
return
frame = mv.current_frame
self.frameEntry.SetValue(str(frame))
self.frameSlider.SetValue(int(frame))
def on_set_frame(self, event=None):
frame = int(self.frameEntry.GetValue())
self._parent.set_configuration(frame)
self.frameSlider.SetValue(frame)
def on_start_stop_animation(self, event=None):
self._parent.start_stop_animation()
def on_update_animation_icon(self, message):
mv = message
if not self.has_parent(mv):
return
if mv.animation_loop:
self.playPause.SetBitmapLabel(ICONS["pause",32,32])
else:
self.playPause.SetBitmapLabel(ICONS["play",32,32])
def on_set_up_frame_slider(self, message):
mv = message
if not self.has_parent(mv):
return
self.frameSlider.SetRange(0,self._parent.n_frames-1)
\ No newline at end of file
#MDANSE : Molecular Dynamics Analysis for Neutron Scattering Experiments
#------------------------------------------------------------------------------------------
#Copyright (C)
#2015- Eric C. Pellegrini Institut Laue-Langevin
#BP 156
#6, rue Jules Horowitz
#38042 Grenoble Cedex 9
#France
#pellegrini[at]ill.fr
#goret[at]ill.fr
#aoun[at]ill.fr
#
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU Lesser General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#Lesser General Public License for more details.
#
#You should have received a copy of the GNU Lesser General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
'''
Created on Apr 14, 2015
@author: pellegrini
'''
import collections
import os
import wx
import wx.aui as wxaui
from MDANSE import LOGGER, REGISTRY, UD_STORE
from MDANSE.Core.Error import Error
from MDANSE.Externals.pubsub import pub
from MDANSE.Framework.AtomSelectionParser import AtomSelectionParser, AtomSelectionParserError
from MDANSE.App.GUI.Framework.Plugins.Plugin import ComponentPlugin
from MDANSE.App.GUI.ComboWidgets.UserDefinitionsPanel import UserDefinitionsPanel
from MDANSE.MolecularDynamics.Trajectory import sorted_atoms
class AtomSelectionPluginError(Error):
pass
class Query(object):
def __init__(self):
self._list = []
self._parser = None
def get_expression(self):
s = []
for v in self._list:
if isinstance(v, list):
keyword,arguments = v
arguments = ",".join([str(val) for val in arguments])
s.append("%s %s" % (keyword,arguments))
else:
s.append(v)
return "".join(s)
@property
def list(self):
return self._list
@property
def parser(self):
return self._parser
def add_operator(self, operator):
if operator == "(":
if self._list:
if self._list[-1] == ")" or isinstance(self._list[-1], list):
return
self._list.append("(")
elif operator == ")":
if self._list:
if self._list[-1] == ")" or isinstance(self._list[-1], list):
if self._list.count(")") < self._list.count("("):
self._list.append(")")
elif operator == "not":
if self._list[-1] == ")":
return
self._list.append(" not ")
elif operator in ["and","or"]:
if self._list:
if self._list[-1] == ")" or isinstance(self._list[-1], list):
self._list.append(" %s " % operator)
def add_query(self, query):
if not self._list:
if query is not None:
self._list.append(query)
else:
keyword, values = query
if isinstance(self._list[-1], list):
if self._list[-1][0] == keyword:
if values:
self._list[-1] = query
else:
del self._list[-1]
else:
self._list.extend([' or ', query])
elif isinstance(self._list[-1], basestring):
if self._list[-1] in [' and ',' or ','(',' not ']:
self._list.append(query)
def clear(self):
self._list = []
def is_empty(self):
return len(self._list) == 0
def parse(self):
if self._parser is None:
return []
try:
selection = self._parser(self.get_expression(),True)
except AtomSelectionParserError:
selection = ("",[])
return selection
def pop(self):
return self._list.pop()
def set_parser(self, parser):
self._parser = parser
class AtomSelectionPlugin(ComponentPlugin):
type = "atom_selection"
label = "Atom selection"
ancestor = "molecular_viewer"
def __init__(self, parent, *args, **kwargs):
self._query = Query()
self._selectors = {}
self._expression = None
self._selection = None
self._selectionParser = None
ComponentPlugin.__init__(self, parent, size = (500,450), *args, **kwargs)
def build_panel(self):
self._mainPanel = wx.Panel(self, wx.ID_ANY, size=self.GetSize())
self._notebook = wxaui.AuiNotebook(self._mainPanel, wx.ID_ANY, style=wxaui.AUI_NB_DEFAULT_STYLE^wxaui.AUI_NB_TAB_MOVE)
settingsPanel = wx.Panel(self._mainPanel,wx.ID_ANY)
self.keywordsRadioButton = wx.RadioButton(settingsPanel, wx.ID_ANY, label = "Keywords")
self.keywordsRadioButton.SetValue(True)
self.pythonScriptRadioButton = wx.RadioButton(settingsPanel, wx.ID_ANY, label = "Python script")
self.mouseClickRadioButton = wx.RadioButton(settingsPanel, wx.ID_ANY, label = "Mouse click")
self.boxWidgetRadioButton = wx.RadioButton(settingsPanel, wx.ID_ANY, label = "Box widget")
# Build the widgets used to build a selection from selection strings and operators
self._queryPanel = wx.Panel(settingsPanel)
self.filterTree = wx.TreeCtrl(self._queryPanel, 1, wx.DefaultPosition, style=wx.TR_HIDE_ROOT|wx.TR_HAS_BUTTONS)
root = self.filterTree.AddRoot("filters")
filters = self.filterTree.AppendItem(root, "Filter by")
selectors = REGISTRY["selector"].values()
self.__filters = collections.OrderedDict()
for selector in selectors:
if selector.section is not None:
if self.__filters.has_key(selector.section):
self.__filters[selector.section].append(selector.type)
else:
self.__filters[selector.section] = [selector.type]
for section, subsections in sorted(self.__filters.items()):
section_node = self.filterTree.AppendItem(filters, section)
for subsection in sorted(subsections):
self.filterTree.AppendItem(section_node,subsection)
self.values = wx.ListBox(self._queryPanel, wx.ID_ANY, style = wx.LB_MULTIPLE|wx.LB_NEEDED_SB)
leftBraceLinker = wx.Button(self._queryPanel, wx.ID_ANY, label = "(")
rightBraceLinker = wx.Button(self._queryPanel, wx.ID_ANY, label = ")")
andLinker = wx.Button(self._queryPanel, wx.ID_ANY, label = "and")
orLinker = wx.Button(self._queryPanel, wx.ID_ANY, label = "or")
notLinker = wx.Button(self._queryPanel, wx.ID_ANY, label = "not")
self._pythonScript = wx.Button(settingsPanel,wx.ID_ANY,label="Browse")
self._pythonScript.Disable()
self._selectionSummary = wx.TextCtrl(self._mainPanel,wx.ID_ANY,style=wx.TE_LINEWRAP|wx.TE_MULTILINE|wx.TE_READONLY)
self._notebook.AddPage(settingsPanel, "settings")
self._notebook.AddPage(self._selectionSummary, "selection")
selectionExpressionStaticBox = wx.StaticBox(self._mainPanel, wx.ID_ANY, label = "Selection")
# The widgets related to the selection being performed
self.selectionTextCtrl = wx.TextCtrl(self._mainPanel, wx.ID_ANY, style = wx.TE_READONLY)
clearButton = wx.Button(self._mainPanel, wx.ID_ANY, label="Clear")
undoButton = wx.Button(self._mainPanel, wx.ID_ANY, label="Undo")
# The panel related to user definition control
self._udPanel = UserDefinitionsPanel(self._mainPanel)
selectionStringSizer = wx.BoxSizer(wx.VERTICAL)
keywordsValuesSizer = wx.BoxSizer(wx.HORIZONTAL)
keywordsValuesSizer.Add(self.filterTree, 1, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT|wx.EXPAND, 2)
keywordsValuesSizer.Add(self.values, 3, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT|wx.EXPAND, 2)
linkersSizer = wx.BoxSizer(wx.HORIZONTAL)
linkersSizer.Add(leftBraceLinker, 1, flag=wx.ALL|wx.EXPAND)
linkersSizer.Add(rightBraceLinker, 1, flag=wx.ALL|wx.EXPAND)
linkersSizer.Add(andLinker, 1, flag=wx.ALL|wx.EXPAND)
linkersSizer.Add(orLinker, 1, flag=wx.ALL|wx.EXPAND)
linkersSizer.Add(notLinker, 1, flag=wx.ALL|wx.EXPAND)
selectionStringSizer.Add(keywordsValuesSizer,1,wx.ALL|wx.EXPAND,5)
selectionStringSizer.Add(linkersSizer,0,wx.ALL|wx.EXPAND,5)
self._queryPanel.SetSizer(selectionStringSizer)
selectionSizer = wx.GridBagSizer(5,5)
selectionSizer.AddGrowableCol(1)
selectionSizer.AddGrowableRow(1)
selectionSizer.Add(self.keywordsRadioButton,pos=(0,0),span=(1,2))
selectionSizer.Add((20,-1),pos=(1,0),flag=wx.EXPAND)
selectionSizer.Add(self._queryPanel,pos=(1,1),flag=wx.EXPAND)
selectionSizer.Add(self.pythonScriptRadioButton,pos=(2,0),span=(1,2))
selectionSizer.Add((20,-1),pos=(3,0),flag=wx.EXPAND)
selectionSizer.Add(self._pythonScript,pos=(3,1))
selectionSizer.Add(self.mouseClickRadioButton,pos=(4,0),span=(1,2))
selectionSizer.Add(self.boxWidgetRadioButton,pos=(5,0),span=(1,2))
settingsPanel.SetSizer(selectionSizer)
selectionExpressionStaticBoxSizer = wx.StaticBoxSizer(selectionExpressionStaticBox, wx.HORIZONTAL)
self._selectionExpressionSizer = wx.GridBagSizer(5,5)
self._selectionExpressionSizer.AddGrowableCol(0)
self._selectionExpressionSizer.Add(self.selectionTextCtrl, pos=(0,0), span=(1,2),flag=wx.ALL|wx.EXPAND)
self._selectionExpressionSizer.Add(clearButton, pos=(0,2), flag=wx.ALL)
self._selectionExpressionSizer.Add(undoButton, pos=(0,3), flag=wx.ALL)
selectionExpressionStaticBoxSizer.Add(self._selectionExpressionSizer,1,wx.ALL|wx.EXPAND,5)