Index: simview/perspectives/simulation/ShapeParameters.py
===================================================================
--- simview/perspectives/simulation/ShapeParameters.py	(revision cb78690f4ebb9fc671a343665015e7ba652ac655)
+++ simview/perspectives/simulation/ShapeParameters.py	(revision 6ef7ac5a1ebae5f5bb799ce6af74adf54c7053b7)
@@ -14,8 +14,9 @@
 import SimCanvas
 
-
 (CreateShapeEvent, EVT_ADD_SHAPE) = wx.lib.newevent.NewEvent()
 (EditShapeEvent, EVT_EDIT_SHAPE)  = wx.lib.newevent.NewEvent()
-(DelShapeEvent, EVT_DEL_SHAPE)  = wx.lib.newevent.NewEvent()
+(DelShapeEvent, EVT_DEL_SHAPE)    = wx.lib.newevent.NewEvent()
+(QRangeEvent, EVT_Q_RANGE)        = wx.lib.newevent.NewEvent() 
+(PtDensityEvent, EVT_PT_DENSITY)  = wx.lib.newevent.NewEvent() 
 
 class ShapeParameterPanel(wx.Panel):
@@ -24,5 +25,5 @@
     CENTER_PANE = True
     
-    def __init__(self, parent, *args, **kwargs):
+    def __init__(self, parent, q_min=0.001, q_max=0.5, q_npts=10, pt_density=0.1, *args, **kwargs):
         wx.Panel.__init__(self, parent, *args, **kwargs)
         
@@ -62,5 +63,5 @@
             
         self.model_combo = wx.ComboBox(self, -1, value=value_list[0], choices=value_list, style=wx.CB_READONLY)
-        self.model_combo.SetToolTip(wx.ToolTip("select a geometric shape from the drop-down list"))
+        self.model_combo.SetToolTip(wx.ToolTip("Select a geometric shape from the drop-down list"))
         
         ny+=1
@@ -78,6 +79,8 @@
         self.bck.Add(point_density_text, (ny,0), flag = wx.LEFT|wx.ALIGN_CENTER_VERTICAL, border = 15)
         self.point_density_ctrl = wx.TextCtrl(self, -1, size=(40,20), style=wx.TE_PROCESS_ENTER)
-        self.point_density_ctrl.Bind(wx.EVT_TEXT_ENTER, self._on_parameter_changed)
-        self.point_density_ctrl.Bind(wx.EVT_KILL_FOCUS, self._on_parameter_changed)
+        self.point_density_ctrl.SetValue(str(pt_density))
+        self.point_density_ctrl.SetToolTip(wx.ToolTip("Enter the number of real-space points per Angstrom cube"))
+        self.point_density_ctrl.Bind(wx.EVT_TEXT_ENTER, self._on_density_changed)
+        self.point_density_ctrl.Bind(wx.EVT_KILL_FOCUS, self._on_density_changed)
         self.bck.Add(self.point_density_ctrl, (ny,1), flag = wx.LEFT|wx.ALIGN_CENTER_VERTICAL, border = 15)
         
@@ -87,6 +90,8 @@
         self.bck.Add(q_min_text, (ny,0), flag = wx.LEFT|wx.ALIGN_CENTER_VERTICAL, border = 15)
         self.q_min_ctrl = wx.TextCtrl(self, -1, size=(40,20), style=wx.TE_PROCESS_ENTER)
-        self.q_min_ctrl.Bind(wx.EVT_TEXT_ENTER, self._on_parameter_changed)
-        self.q_min_ctrl.Bind(wx.EVT_KILL_FOCUS, self._on_parameter_changed)
+        self.q_min_ctrl.SetValue(str(q_min))
+        self.q_min_ctrl.SetToolTip(wx.ToolTip("Enter the minimum Q value to be simulated"))
+        self.q_min_ctrl.Bind(wx.EVT_TEXT_ENTER, self._on_q_range_changed)
+        self.q_min_ctrl.Bind(wx.EVT_KILL_FOCUS, self._on_q_range_changed)
         self.bck.Add(self.q_min_ctrl, (ny,1), flag = wx.LEFT|wx.ALIGN_CENTER_VERTICAL, border = 15)
         
@@ -94,7 +99,18 @@
         self.bck.Add(q_max_text, (ny,2), flag = wx.LEFT|wx.ALIGN_CENTER_VERTICAL, border = 15)
         self.q_max_ctrl = wx.TextCtrl(self, -1, size=(40,20), style=wx.TE_PROCESS_ENTER)
-        self.q_max_ctrl.Bind(wx.EVT_TEXT_ENTER, self._on_parameter_changed)
-        self.q_max_ctrl.Bind(wx.EVT_KILL_FOCUS, self._on_parameter_changed)
+        self.q_max_ctrl.SetValue(str(q_max))
+        self.q_min_ctrl.SetToolTip(wx.ToolTip("Enter the maximum Q value to be simulated"))
+        self.q_max_ctrl.Bind(wx.EVT_TEXT_ENTER, self._on_q_range_changed)
+        self.q_max_ctrl.Bind(wx.EVT_KILL_FOCUS, self._on_q_range_changed)
         self.bck.Add(self.q_max_ctrl, (ny,3), flag = wx.LEFT|wx.ALIGN_CENTER_VERTICAL, border = 15)
+        
+        q_npts_text = wx.StaticText(self, -1, "No. of Q pts", style=wx.ALIGN_LEFT)
+        self.bck.Add(q_npts_text, (ny,4), flag = wx.LEFT|wx.ALIGN_CENTER_VERTICAL, border = 15)
+        self.q_npts_ctrl = wx.TextCtrl(self, -1, size=(40,20), style=wx.TE_PROCESS_ENTER)
+        self.q_npts_ctrl.SetValue(str(q_npts))
+        self.q_min_ctrl.SetToolTip(wx.ToolTip("Enter the number of Q points to be simulated"))
+        self.q_npts_ctrl.Bind(wx.EVT_TEXT_ENTER, self._on_q_range_changed)
+        self.q_npts_ctrl.Bind(wx.EVT_KILL_FOCUS, self._on_q_range_changed)
+        self.bck.Add(self.q_npts_ctrl, (ny,5), flag = wx.LEFT|wx.ALIGN_CENTER_VERTICAL, border = 15)
         
         # Shape List
@@ -132,21 +148,25 @@
         self.editShape(shape)    
 
-    def _on_parameter_changed(self, event):
+    def _on_density_changed(self, event):
         """
             Process event that might mean a change of the simulation point density
         """
-        event_obj = event.GetEventObject()
-        if event_obj.IsModified():
-            event_obj.SetModified(False)
-            self._simulation_update()
-            
-    def _simulation_update(self):
-        """
-            Process an update of the simulation parameters
-        """
-        #TODO: create an event to pass the parameters to the simulation plug-in for processing
-        print "TODO: Simulation update"
-        pass
-        
+        npts  = self._readCtrlFloat(self.point_density_ctrl)
+        if npts is not None:
+            event = PtDensityEvent(npts=npts)
+            wx.PostEvent(self.parent, event)
+            
+    def _on_q_range_changed(self, event):
+        """
+            Process event that might mean a change in Q range
+            @param event: EVT_Q_RANGE event
+        """
+        q_min = self._readCtrlFloat(self.q_min_ctrl)
+        q_max = self._readCtrlFloat(self.q_max_ctrl)
+        npts  = self._readCtrlInt(self.q_npts_ctrl)
+        if q_min is not None or q_max is not None or npts is not None:
+            event = QRangeEvent(q_min=q_min, q_max=q_max, npts=npts)
+            wx.PostEvent(self.parent, event)
+            
     def _onEditShape(self, evt):
         """
@@ -295,5 +315,13 @@
 
     def _readCtrlFloat(self, ctrl):
+        """
+            Parses a TextCtrl for a float value.
+            Returns None is the value hasn't changed or the value is not a float.
+            The control background turns pink if the value is not a float.
+            
+            @param ctrl: TextCtrl object
+        """
         if ctrl.IsModified():
+            ctrl.SetModified(False)
             str_value = ctrl.GetValue().lstrip().rstrip()
             try:
@@ -303,4 +331,26 @@
                 ctrl.Refresh()
                 return flt_value
+            except:
+                ctrl.SetBackgroundColour("pink")
+                ctrl.Refresh()
+        return None
+
+    def _readCtrlInt(self, ctrl):
+        """
+            Parses a TextCtrl for a float value.
+            Returns None is the value hasn't changed or the value is not a float.
+            The control background turns pink if the value is not a float.
+            
+            @param ctrl: TextCtrl object
+        """
+        if ctrl.IsModified():
+            ctrl.SetModified(False)
+            str_value = ctrl.GetValue().lstrip().rstrip()
+            try:
+                int_value = int(str_value)
+                ctrl.SetBackgroundColour(
+                        wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
+                ctrl.Refresh()
+                return int_value
             except:
                 ctrl.SetBackgroundColour("pink")
Index: simview/perspectives/simulation/requirements.txt
===================================================================
--- simview/perspectives/simulation/requirements.txt	(revision eaeb13e6f126a4f9e4dc056eec68e9caab6ad776)
+++ simview/perspectives/simulation/requirements.txt	(revision 6ef7ac5a1ebae5f5bb799ce6af74adf54c7053b7)
@@ -1,6 +1,6 @@
 UI requirements
-- Allow user to modify q range from main panel
+- Allow user to modify q range from main panel [DONE]
 - Move list of shapes from top menu to central simulation panel
-- Popup P(r) plot and update for each simulation
+- Popup P(r) plot and update for each simulation [DONE]
 - Allow user to choose whether he wants the simulation to be run automatically with each parameter change
   or whether he wants to hit 'simulate' himself when he's done.
Index: simview/perspectives/simulation/simulation.py
===================================================================
--- simview/perspectives/simulation/simulation.py	(revision cb78690f4ebb9fc671a343665015e7ba652ac655)
+++ simview/perspectives/simulation/simulation.py	(revision 6ef7ac5a1ebae5f5bb799ce6af74adf54c7053b7)
@@ -71,4 +71,6 @@
 ## Default number of q point for simulation output
 DEFAULT_Q_NPTS = 10
+## Default number of real-space points per Angstrom cube
+DEFAULT_PT_DENSITY = 0.1
    
 class Plugin:
@@ -105,9 +107,14 @@
 
         # Central simulation panel
-        self.paramPanel = ShapeParameters.ShapeParameterPanel(self.parent, style=wx.RAISED_BORDER)
+        self.paramPanel = ShapeParameters.ShapeParameterPanel(self.parent, 
+                                                              q_min = self.q_min,
+                                                              q_max = self.q_max,
+                                                              q_npts = self.q_npts,
+                                                              pt_density = DEFAULT_PT_DENSITY,
+                                                              style=wx.RAISED_BORDER)
         
         # Simulation
         self.volCanvas = VolumeCanvas.VolumeCanvas()
-        self.volCanvas.setParam('lores_density', 0.1)
+        self.volCanvas.setParam('lores_density', DEFAULT_PT_DENSITY)
         self.adapter = ShapeAdapter.ShapeVisitor()
         self._data_1D = None
@@ -128,4 +135,6 @@
         self.parent.Bind(ShapeParameters.EVT_ADD_SHAPE, self._onAddShape)
         self.parent.Bind(ShapeParameters.EVT_DEL_SHAPE, self._onDelShape)
+        self.parent.Bind(ShapeParameters.EVT_Q_RANGE, self._on_q_range_changed)
+        self.parent.Bind(ShapeParameters.EVT_PT_DENSITY, self._on_pt_density_changed)
 
         return [self.plotPanel, self.paramPanel]
@@ -166,4 +175,32 @@
         # Refresh the 3D viewer
         self._refresh_3D_viewer()   
+        
+    def _on_q_range_changed(self, evt):
+        """
+            Modify the Q range of the simulation output
+        """
+        if evt.q_min is not None:
+            self.q_min = evt.q_min
+        if evt.q_max is not None:
+            self.q_max = evt.q_max
+        if evt.npts is not None:
+            self.q_npts = evt.npts
+        
+        # Q-values for plotting simulated I(Q)
+        step = (self.q_max-self.q_min)/(self.q_npts-1)
+        self.x = numpy.arange(self.q_min, self.q_max+step*0.01, step)    
+         
+        # Compute the simulated I(Q)
+        self._simulate_Iq()
+        
+    def _on_pt_density_changed(self, evt):
+        """
+            Modify the Q range of the simulation output
+        """
+        if evt.npts is not None:
+            self.volCanvas.setParam('lores_density', evt.npts)
+         
+        # Compute the simulated I(Q)
+        self._simulate_Iq()
         
     def _simulate_Iq(self):
@@ -212,9 +249,20 @@
         # Create the plotting event to pop up the I(Q) plot.
         new_plot = Data1D(x=self.x, y=output, dy=error)
-        new_plot.name = "Simulation"
+        new_plot.name = "I(Q) Simulation"
         new_plot.group_id = "simulation_output"
         new_plot.xaxis("\\rm{Q}", 'A^{-1}')
         new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
-        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Simulation output"))
+        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Simulation I(Q)"))
+        
+        # Create the plotting event to pop up the P(r) plot.
+        r, pr = self.volCanvas.getPrData()
+        new_plot = Data1D(x=r, y=pr, dy=[0]*len(r))
+        new_plot.name = "P(r) Simulation"
+        new_plot.group_id = "simulated_pr"
+        new_plot.xaxis("\\rm{r}", 'A')
+        new_plot.yaxis("\\rm{P(r)} ","cm^{-3}") 
+        
+        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Simulated P(r)"))        
+        
         
         # Notify the user of the simlation time and update the basic
@@ -235,19 +283,7 @@
     def populate_menu(self, id, owner):
         """
-            -- TEMPORARY --
             Create a menu for the plug-in
-            
-            #TODO: remove this method once:
-                1- P(r) is plotted with the I(q) simulation result
-        """
-        # Shapes
-        shapes = wx.Menu()
- 
-        #TODO: Save P(r) should be replaced by plotting P(r) for each simulation
-        id = wx.NewId()
-        shapes.Append(id, '&Save P(r) output')
-        wx.EVT_MENU(self.parent, id, self._onSavePr)
-
-        return [(id+1, shapes, "Save P(r)")]  
+        """
+        return []  
     
     def _change_point_density(self, point_density):
@@ -257,19 +293,4 @@
         """
         self.volCanvas.setParam('lores_density', point_density)
-    
-    def _onSavePr(self, evt):
-        """
-            Save the current P(r) output to a file
-            TODO: refactor this away once P(r) is plotted
-        """      
-        path = None
-        dlg = wx.FileDialog(None, "Choose a file", self._default_save_location, "", "*.txt", wx.SAVE)
-        if dlg.ShowModal() == wx.ID_OK:
-            path = dlg.GetPath()
-            self._default_save_location = os.path.dirname(path)
-        dlg.Destroy()
-        
-        if not path == None:
-            self.volCanvas.write_pr(path)    
     
     def help(self, evt):
