29 from graphics.FBD_Objects import FBD_Block |
29 from graphics.FBD_Objects import FBD_Block |
30 from controls.LibraryPanel import LibraryPanel |
30 from controls.LibraryPanel import LibraryPanel |
31 from BlockPreviewDialog import BlockPreviewDialog |
31 from BlockPreviewDialog import BlockPreviewDialog |
32 |
32 |
33 #------------------------------------------------------------------------------- |
33 #------------------------------------------------------------------------------- |
34 # Create New Block Dialog |
34 # Set Block Parameters Dialog |
35 #------------------------------------------------------------------------------- |
35 #------------------------------------------------------------------------------- |
36 |
36 |
|
37 """ |
|
38 Class that implements a dialog for defining parameters of a FBD block graphic |
|
39 element |
|
40 """ |
|
41 |
37 class FBDBlockDialog(BlockPreviewDialog): |
42 class FBDBlockDialog(BlockPreviewDialog): |
38 |
43 |
39 def __init__(self, parent, controller, tagname): |
44 def __init__(self, parent, controller, tagname): |
|
45 """ |
|
46 Constructor |
|
47 @param parent: Parent wx.Window of dialog for modal |
|
48 @param controller: Reference to project controller |
|
49 @param tagname: Tagname of project POU edited |
|
50 """ |
40 BlockPreviewDialog.__init__(self, parent, controller, tagname, |
51 BlockPreviewDialog.__init__(self, parent, controller, tagname, |
41 size=wx.Size(600, 450), title=_('Block Properties')) |
52 size=wx.Size(600, 450), title=_('Block Properties')) |
42 |
53 |
|
54 # Create dialog main sizer |
43 main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=4, vgap=10) |
55 main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=4, vgap=10) |
44 main_sizer.AddGrowableCol(0) |
56 main_sizer.AddGrowableCol(0) |
45 main_sizer.AddGrowableRow(0) |
57 main_sizer.AddGrowableRow(0) |
46 |
58 |
|
59 # Create a sizer for dividing FBD block parameters in two columns |
47 column_sizer = wx.BoxSizer(wx.HORIZONTAL) |
60 column_sizer = wx.BoxSizer(wx.HORIZONTAL) |
48 main_sizer.AddSizer(column_sizer, border=20, |
61 main_sizer.AddSizer(column_sizer, border=20, |
49 flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) |
62 flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) |
50 |
63 |
|
64 # Create static box around library panel |
51 type_staticbox = wx.StaticBox(self, label=_('Type:')) |
65 type_staticbox = wx.StaticBox(self, label=_('Type:')) |
52 left_staticboxsizer = wx.StaticBoxSizer(type_staticbox, wx.VERTICAL) |
66 left_staticboxsizer = wx.StaticBoxSizer(type_staticbox, wx.VERTICAL) |
53 column_sizer.AddSizer(left_staticboxsizer, 1, border=5, |
67 column_sizer.AddSizer(left_staticboxsizer, 1, border=5, |
54 flag=wx.GROW|wx.RIGHT) |
68 flag=wx.GROW|wx.RIGHT) |
55 |
69 |
|
70 # Create Library panel and add it to static box |
56 self.LibraryPanel = LibraryPanel(self) |
71 self.LibraryPanel = LibraryPanel(self) |
|
72 # Set function to call when selection in Library panel changed |
57 setattr(self.LibraryPanel, "_OnTreeItemSelected", |
73 setattr(self.LibraryPanel, "_OnTreeItemSelected", |
58 self.OnLibraryTreeItemSelected) |
74 self.OnLibraryTreeItemSelected) |
59 left_staticboxsizer.AddWindow(self.LibraryPanel, 1, border=5, |
75 left_staticboxsizer.AddWindow(self.LibraryPanel, 1, border=5, |
60 flag=wx.GROW|wx.TOP) |
76 flag=wx.GROW|wx.TOP) |
61 |
77 |
|
78 # Create sizer for other block parameters and preview panle |
62 right_gridsizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=5) |
79 right_gridsizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=5) |
63 right_gridsizer.AddGrowableCol(0) |
80 right_gridsizer.AddGrowableCol(0) |
64 right_gridsizer.AddGrowableRow(2) |
81 right_gridsizer.AddGrowableRow(2) |
65 column_sizer.AddSizer(right_gridsizer, 1, border=5, |
82 column_sizer.AddSizer(right_gridsizer, 1, border=5, |
66 flag=wx.GROW|wx.LEFT) |
83 flag=wx.GROW|wx.LEFT) |
67 |
84 |
|
85 # Create sizer for other block parameters |
68 top_right_gridsizer = wx.FlexGridSizer(cols=2, hgap=0, rows=4, vgap=5) |
86 top_right_gridsizer = wx.FlexGridSizer(cols=2, hgap=0, rows=4, vgap=5) |
69 top_right_gridsizer.AddGrowableCol(1) |
87 top_right_gridsizer.AddGrowableCol(1) |
70 right_gridsizer.AddSizer(top_right_gridsizer, flag=wx.GROW) |
88 right_gridsizer.AddSizer(top_right_gridsizer, flag=wx.GROW) |
71 |
89 |
|
90 # Create label for block name |
72 name_label = wx.StaticText(self, label=_('Name:')) |
91 name_label = wx.StaticText(self, label=_('Name:')) |
73 top_right_gridsizer.AddWindow(name_label, |
92 top_right_gridsizer.AddWindow(name_label, |
74 flag=wx.ALIGN_CENTER_VERTICAL) |
93 flag=wx.ALIGN_CENTER_VERTICAL) |
75 |
94 |
|
95 # Create text control for defining block name |
76 self.BlockName = wx.TextCtrl(self) |
96 self.BlockName = wx.TextCtrl(self) |
77 self.Bind(wx.EVT_TEXT, self.OnNameChanged, self.BlockName) |
97 self.Bind(wx.EVT_TEXT, self.OnNameChanged, self.BlockName) |
78 top_right_gridsizer.AddWindow(self.BlockName, flag=wx.GROW) |
98 top_right_gridsizer.AddWindow(self.BlockName, flag=wx.GROW) |
79 |
99 |
|
100 # Create label for extended block input number |
80 inputs_label = wx.StaticText(self, label=_('Inputs:')) |
101 inputs_label = wx.StaticText(self, label=_('Inputs:')) |
81 top_right_gridsizer.AddWindow(inputs_label, |
102 top_right_gridsizer.AddWindow(inputs_label, |
82 flag=wx.ALIGN_CENTER_VERTICAL) |
103 flag=wx.ALIGN_CENTER_VERTICAL) |
83 |
104 |
|
105 # Create spin control for defining extended block input number |
84 self.Inputs = wx.SpinCtrl(self, min=2, max=20, |
106 self.Inputs = wx.SpinCtrl(self, min=2, max=20, |
85 style=wx.SP_ARROW_KEYS) |
107 style=wx.SP_ARROW_KEYS) |
86 self.Bind(wx.EVT_SPINCTRL, self.OnInputsChanged, self.Inputs) |
108 self.Bind(wx.EVT_SPINCTRL, self.OnInputsChanged, self.Inputs) |
87 top_right_gridsizer.AddWindow(self.Inputs, flag=wx.GROW) |
109 top_right_gridsizer.AddWindow(self.Inputs, flag=wx.GROW) |
88 |
110 |
89 execution_order_label = wx.StaticText(self, label=_('Execution Order:')) |
111 # Create label for block execution order |
|
112 execution_order_label = wx.StaticText(self, |
|
113 label=_('Execution Order:')) |
90 top_right_gridsizer.AddWindow(execution_order_label, |
114 top_right_gridsizer.AddWindow(execution_order_label, |
91 flag=wx.ALIGN_CENTER_VERTICAL) |
115 flag=wx.ALIGN_CENTER_VERTICAL) |
92 |
116 |
|
117 # Create spin control for defining block execution order |
93 self.ExecutionOrder = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS) |
118 self.ExecutionOrder = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS) |
94 self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged, self.ExecutionOrder) |
119 self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged, |
|
120 self.ExecutionOrder) |
95 top_right_gridsizer.AddWindow(self.ExecutionOrder, flag=wx.GROW) |
121 top_right_gridsizer.AddWindow(self.ExecutionOrder, flag=wx.GROW) |
96 |
122 |
97 execution_control_label = wx.StaticText(self, label=_('Execution Control:')) |
123 # Create label for block execution control |
|
124 execution_control_label = wx.StaticText(self, |
|
125 label=_('Execution Control:')) |
98 top_right_gridsizer.AddWindow(execution_control_label, |
126 top_right_gridsizer.AddWindow(execution_control_label, |
99 flag=wx.ALIGN_CENTER_VERTICAL) |
127 flag=wx.ALIGN_CENTER_VERTICAL) |
100 |
128 |
|
129 # Create check box to enable block execution control |
101 self.ExecutionControl = wx.CheckBox(self) |
130 self.ExecutionControl = wx.CheckBox(self) |
102 self.Bind(wx.EVT_CHECKBOX, self.OnExecutionOrderChanged, self.ExecutionControl) |
131 self.Bind(wx.EVT_CHECKBOX, self.OnExecutionOrderChanged, |
|
132 self.ExecutionControl) |
103 top_right_gridsizer.AddWindow(self.ExecutionControl, flag=wx.GROW) |
133 top_right_gridsizer.AddWindow(self.ExecutionControl, flag=wx.GROW) |
104 |
134 |
|
135 # Add preview panel and associated label to sizers |
105 right_gridsizer.AddWindow(self.PreviewLabel, flag=wx.GROW) |
136 right_gridsizer.AddWindow(self.PreviewLabel, flag=wx.GROW) |
106 right_gridsizer.AddWindow(self.Preview, flag=wx.GROW) |
137 right_gridsizer.AddWindow(self.Preview, flag=wx.GROW) |
107 |
138 |
108 main_sizer.AddSizer(self.ButtonSizer, border=20, |
139 main_sizer.AddSizer(self.ButtonSizer, border=20, |
109 flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) |
140 flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) |
110 |
141 |
111 self.SetSizer(main_sizer) |
142 self.SetSizer(main_sizer) |
112 |
143 |
|
144 self.ParamsControl = { |
|
145 "extension": self.Inputs, |
|
146 "executionOrder": self.ExecutionOrder, |
|
147 "executionControl": self.ExecutionControl |
|
148 } |
|
149 |
|
150 # Init controls value and sensibility |
113 self.BlockName.SetValue("") |
151 self.BlockName.SetValue("") |
114 self.BlockName.Enable(False) |
152 self.BlockName.Enable(False) |
115 self.Inputs.Enable(False) |
153 self.Inputs.Enable(False) |
|
154 |
|
155 # Variable containing last name typed |
116 self.CurrentBlockName = None |
156 self.CurrentBlockName = None |
117 |
157 |
|
158 # Refresh Library panel values |
118 self.LibraryPanel.SetBlockList(controller.GetBlockTypes(tagname)) |
159 self.LibraryPanel.SetBlockList(controller.GetBlockTypes(tagname)) |
119 self.LibraryPanel.SetFocus() |
160 self.LibraryPanel.SetFocus() |
120 |
161 |
121 def OnOK(self, event): |
162 def OnOK(self, event): |
|
163 """ |
|
164 Called when dialog OK button is pressed |
|
165 Test if parameters defined are valid |
|
166 @param event: wx.Event from OK button |
|
167 """ |
122 message = None |
168 message = None |
|
169 |
|
170 # Get block type selected |
123 selected = self.LibraryPanel.GetSelectedBlock() |
171 selected = self.LibraryPanel.GetSelectedBlock() |
|
172 |
|
173 # Get block type name and if block is a function block |
124 block_name = self.BlockName.GetValue() |
174 block_name = self.BlockName.GetValue() |
125 name_enabled = self.BlockName.IsEnabled() |
175 name_enabled = self.BlockName.IsEnabled() |
|
176 |
|
177 # Test that a type has been selected for block |
126 if selected is None: |
178 if selected is None: |
127 message = _("Form isn't complete. Valid block type must be selected!") |
179 message = _("Form isn't complete. Valid block type must be selected!") |
|
180 |
|
181 # Test, if block is a function block, that a name have been defined |
128 elif name_enabled and block_name == "": |
182 elif name_enabled and block_name == "": |
129 message = _("Form isn't complete. Name must be filled!") |
183 message = _("Form isn't complete. Name must be filled!") |
|
184 |
|
185 # Show error message if an error is detected |
130 if message is not None: |
186 if message is not None: |
131 self.ShowMessage(message) |
187 self.ShowMessage(message) |
|
188 |
|
189 # Test block name validity if necessary |
132 elif not name_enabled or self.TestBlockName(block_name): |
190 elif not name_enabled or self.TestBlockName(block_name): |
133 BlockPreviewDialog.OnOK(self, event) |
191 BlockPreviewDialog.OnOK(self, event) |
134 |
192 |
135 def SetValues(self, values): |
193 def SetValues(self, values): |
|
194 """ |
|
195 Set default block parameters |
|
196 @param values: Block parameters values |
|
197 """ |
|
198 # Extract block type defined in parameters |
136 blocktype = values.get("type", None) |
199 blocktype = values.get("type", None) |
137 default_name_model = re.compile("%s[0-9]+" % blocktype) |
200 |
|
201 # Define regular expression for determine if block name is block |
|
202 # default name |
|
203 default_name_model = re.compile( |
|
204 "%s[0-9]+" % blocktype if blocktype is not None else ".*") |
|
205 |
|
206 # Select block type in library panel |
138 if blocktype is not None: |
207 if blocktype is not None: |
139 self.LibraryPanel.SelectTreeItem(blocktype, |
208 self.LibraryPanel.SelectTreeItem(blocktype, |
140 values.get("inputs", None)) |
209 values.get("inputs", None)) |
|
210 |
|
211 # For each parameters defined, set corresponding control value |
141 for name, value in values.items(): |
212 for name, value in values.items(): |
142 if name == "name": |
213 if name == "name": |
|
214 # Parameter is block name |
143 if value != "": |
215 if value != "": |
|
216 # Set default block name for testing |
144 self.DefaultBlockName = value |
217 self.DefaultBlockName = value |
|
218 |
|
219 # Test if block name is type default block name and save |
|
220 # block name if not (name have been typed by user) |
145 if default_name_model.match(value) is None: |
221 if default_name_model.match(value) is None: |
146 self.CurrentBlockName = value |
222 self.CurrentBlockName = value |
|
223 |
147 self.BlockName.ChangeValue(value) |
224 self.BlockName.ChangeValue(value) |
148 elif name == "extension": |
225 |
149 self.Inputs.SetValue(value) |
226 else: |
150 elif name == "executionOrder": |
227 control = self.ParamsControl.get(name, None) |
151 self.ExecutionOrder.SetValue(value) |
228 if control is not None: |
152 elif name == "executionControl": |
229 control.SetValue(value) |
153 self.ExecutionControl.SetValue(value) |
230 |
|
231 # Refresh preview panel |
154 self.RefreshPreview() |
232 self.RefreshPreview() |
155 |
233 |
156 def GetValues(self): |
234 def GetValues(self): |
|
235 """ |
|
236 Return block parameters defined in dialog |
|
237 @return: {parameter_name: parameter_value,...} |
|
238 """ |
157 values = self.LibraryPanel.GetSelectedBlock() |
239 values = self.LibraryPanel.GetSelectedBlock() |
158 if self.BlockName.IsEnabled() and self.BlockName.GetValue() != "": |
240 if self.BlockName.IsEnabled() and self.BlockName.GetValue() != "": |
159 values["name"] = self.BlockName.GetValue() |
241 values["name"] = self.BlockName.GetValue() |
160 values["width"], values["height"] = self.Block.GetSize() |
242 values["width"], values["height"] = self.Block.GetSize() |
161 values["extension"] = self.Inputs.GetValue() |
243 values.update({ |
162 values["executionOrder"] = self.ExecutionOrder.GetValue() |
244 name: control.GetValue() |
163 values["executionControl"] = self.ExecutionControl.GetValue() |
245 for name, control in self.ParamsControl.iteritems()}) |
164 return values |
246 return values |
165 |
247 |
166 def OnLibraryTreeItemSelected(self, event): |
248 def OnLibraryTreeItemSelected(self, event): |
|
249 """ |
|
250 Called when block type selected in library panel |
|
251 @param event: wx.TreeEvent |
|
252 """ |
|
253 # Get type selected in library panel |
167 values = self.LibraryPanel.GetSelectedBlock() |
254 values = self.LibraryPanel.GetSelectedBlock() |
|
255 |
|
256 # Get block type informations |
168 blocktype = (self.Controller.GetBlockType(values["type"], |
257 blocktype = (self.Controller.GetBlockType(values["type"], |
169 values["inputs"]) |
258 values["inputs"]) |
170 if values is not None else None) |
259 if values is not None else None) |
171 |
260 |
|
261 # Set input number spin control according to block type informations |
172 if blocktype is not None: |
262 if blocktype is not None: |
173 self.Inputs.SetValue(len(blocktype["inputs"])) |
263 self.Inputs.SetValue(len(blocktype["inputs"])) |
174 self.Inputs.Enable(blocktype["extensible"]) |
264 self.Inputs.Enable(blocktype["extensible"]) |
175 else: |
265 else: |
176 self.Inputs.SetValue(2) |
266 self.Inputs.SetValue(2) |
177 self.Inputs.Enable(False) |
267 self.Inputs.Enable(False) |
178 |
268 |
|
269 # Update block name with default value if block type is a function and |
|
270 # current block name wasn't typed by user |
179 if blocktype is not None and blocktype["type"] != "function": |
271 if blocktype is not None and blocktype["type"] != "function": |
180 self.BlockName.Enable(True) |
272 self.BlockName.Enable(True) |
181 self.BlockName.ChangeValue( |
273 self.BlockName.ChangeValue( |
182 self.CurrentBlockName |
274 self.CurrentBlockName |
183 if self.CurrentBlockName is not None |
275 if self.CurrentBlockName is not None |
185 self.TagName, None, values["type"]+"%d", 0)) |
277 self.TagName, None, values["type"]+"%d", 0)) |
186 else: |
278 else: |
187 self.BlockName.Enable(False) |
279 self.BlockName.Enable(False) |
188 self.BlockName.ChangeValue("") |
280 self.BlockName.ChangeValue("") |
189 |
281 |
|
282 # Refresh preview panel |
190 self.RefreshPreview() |
283 self.RefreshPreview() |
191 |
284 |
192 def OnNameChanged(self, event): |
285 def OnNameChanged(self, event): |
|
286 """ |
|
287 Called when block name value changed |
|
288 @param event: wx.TextEvent |
|
289 """ |
193 if self.BlockName.IsEnabled(): |
290 if self.BlockName.IsEnabled(): |
|
291 # Save block name typed by user |
194 self.CurrentBlockName = self.BlockName.GetValue() |
292 self.CurrentBlockName = self.BlockName.GetValue() |
195 self.RefreshPreview() |
293 self.RefreshPreview() |
196 event.Skip() |
294 event.Skip() |
197 |
295 |
198 def OnInputsChanged(self, event): |
296 def OnInputsChanged(self, event): |
|
297 """ |
|
298 Called when block inputs number changed |
|
299 @param event: wx.SpinEvent |
|
300 """ |
199 if self.Inputs.IsEnabled(): |
301 if self.Inputs.IsEnabled(): |
200 self.RefreshPreview() |
302 self.RefreshPreview() |
201 event.Skip() |
303 event.Skip() |
202 |
304 |
203 def OnExecutionOrderChanged(self, event): |
305 def OnExecutionOrderChanged(self, event): |
|
306 """ |
|
307 Called when block execution order value changed |
|
308 @param event: wx.SpinEvent |
|
309 """ |
204 self.RefreshPreview() |
310 self.RefreshPreview() |
205 event.Skip() |
311 event.Skip() |
206 |
312 |
207 def OnExecutionControlChanged(self, event): |
313 def OnExecutionControlChanged(self, event): |
|
314 """ |
|
315 Called when block execution control value changed |
|
316 @param event: wx.SpinEvent |
|
317 """ |
208 self.RefreshPreview() |
318 self.RefreshPreview() |
209 event.Skip() |
319 event.Skip() |
210 |
320 |
211 def RefreshPreview(self): |
321 def RefreshPreview(self): |
|
322 """ |
|
323 Refresh preview panel of graphic element |
|
324 Override BlockPreviewDialog function |
|
325 """ |
|
326 # Get type selected in library panel |
212 values = self.LibraryPanel.GetSelectedBlock() |
327 values = self.LibraryPanel.GetSelectedBlock() |
|
328 |
|
329 # If a block type is selected in library panel |
213 if values is not None: |
330 if values is not None: |
214 if self.BlockName.IsEnabled(): |
331 blockname = (self.BlockName.GetValue() |
215 blockname = self.BlockName.GetValue() |
332 if self.BlockName.IsEnabled() |
216 else: |
333 else "") |
217 blockname = "" |
334 |
|
335 # Set graphic element displayed, creating a FBD block element |
218 self.Block = FBD_Block(self.Preview, values["type"], |
336 self.Block = FBD_Block(self.Preview, values["type"], |
219 blockname, |
337 blockname, |
220 extension = self.Inputs.GetValue(), |
338 extension = self.Inputs.GetValue(), |
221 inputs = values["inputs"], |
339 inputs = values["inputs"], |
222 executionControl = self.ExecutionControl.GetValue(), |
340 executionControl = self.ExecutionControl.GetValue(), |
223 executionOrder = self.ExecutionOrder.GetValue()) |
341 executionOrder = self.ExecutionOrder.GetValue()) |
|
342 |
|
343 # Reset graphic element displayed |
224 else: |
344 else: |
225 self.Block = None |
345 self.Block = None |
|
346 |
|
347 # Call BlockPreviewDialog function |
226 BlockPreviewDialog.RefreshPreview(self) |
348 BlockPreviewDialog.RefreshPreview(self) |