fmu-manipulation-toolbox 1.8.3__tar.gz → 1.8.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/PKG-INFO +7 -3
  2. fmu_manipulation_toolbox-1.8.4/fmu_manipulation_toolbox/__version__.py +1 -0
  3. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/assembly.py +15 -9
  4. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/fmu_container.py +131 -66
  5. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/fmu_operations.py +3 -2
  6. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/gui.py +2 -2
  7. fmu_manipulation_toolbox-1.8.4/fmu_manipulation_toolbox/gui_style.py +244 -0
  8. fmu_manipulation_toolbox-1.8.4/fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
  9. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/win32/client_sm.dll +0 -0
  10. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/win32/server_sm.exe +0 -0
  11. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/win64/client_sm.dll +0 -0
  12. fmu_manipulation_toolbox-1.8.4/fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
  13. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/win64/server_sm.exe +0 -0
  14. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox.egg-info/PKG-INFO +7 -3
  15. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/setup.py +21 -19
  16. fmu_manipulation_toolbox-1.8.3/fmu_manipulation_toolbox/__version__.py +0 -1
  17. fmu_manipulation_toolbox-1.8.3/fmu_manipulation_toolbox/gui_style.py +0 -129
  18. fmu_manipulation_toolbox-1.8.3/fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
  19. fmu_manipulation_toolbox-1.8.3/fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
  20. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/LICENSE.txt +0 -0
  21. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/README.md +0 -0
  22. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/__init__.py +0 -0
  23. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/__main__.py +0 -0
  24. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/checker.py +0 -0
  25. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/cli.py +0 -0
  26. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/help.py +0 -0
  27. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/checkbox-checked-disabled.png +0 -0
  28. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/checkbox-checked-hover.png +0 -0
  29. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/checkbox-checked.png +0 -0
  30. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/checkbox-unchecked-disabled.png +0 -0
  31. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/checkbox-unchecked-hover.png +0 -0
  32. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/checkbox-unchecked.png +0 -0
  33. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/container.png +0 -0
  34. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/drop_fmu.png +0 -0
  35. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Annotation.xsd +0 -0
  36. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2AttributeGroups.xsd +0 -0
  37. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ModelDescription.xsd +0 -0
  38. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ScalarVariable.xsd +0 -0
  39. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Type.xsd +0 -0
  40. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Unit.xsd +0 -0
  41. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2VariableDependency.xsd +0 -0
  42. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/fmu.png +0 -0
  43. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/fmu_manipulation_toolbox.png +0 -0
  44. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/help.png +0 -0
  45. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/icon-round.png +0 -0
  46. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/icon.png +0 -0
  47. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/icon_fmu.png +0 -0
  48. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/license.txt +0 -0
  49. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/linux32/client_sm.so +0 -0
  50. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/linux32/server_sm +0 -0
  51. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/linux64/client_sm.so +0 -0
  52. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/linux64/server_sm +0 -0
  53. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/mask.png +0 -0
  54. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/resources/model.png +0 -0
  55. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox/version.py +0 -0
  56. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox.egg-info/SOURCES.txt +0 -0
  57. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox.egg-info/dependency_links.txt +0 -0
  58. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox.egg-info/entry_points.txt +0 -0
  59. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox.egg-info/requires.txt +0 -0
  60. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/fmu_manipulation_toolbox.egg-info/top_level.txt +0 -0
  61. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/setup.cfg +0 -0
  62. {fmu_manipulation_toolbox-1.8.3 → fmu_manipulation_toolbox-1.8.4}/tests/test_suite.py +0 -0
@@ -1,9 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmu_manipulation_toolbox
3
- Version: 1.8.3
4
- Summary: FMU Manipulation Toobox is a python application which help to modify a Functional Mock-up Units (FMUs) without recompilation or to group them into FMU Containers
3
+ Version: 1.8.4
4
+ Summary: FMU Manipulation Toolbox is a python application for modifying Functional Mock-up Units (FMUs) without recompilation or bundling them into FMU Containers
5
5
  Home-page: https://github.com/grouperenault/fmu_manipulation_toolbox/
6
6
  Author: Nicolas.LAURENT@Renault.com
7
+ License: BSD-2-Clause
8
+ Requires-Python: >=3.8
7
9
  License-File: LICENSE.txt
8
10
  Requires-Dist: PySide6>=6.8.0
9
11
  Requires-Dist: xmlschema>=3.3.1
@@ -12,11 +14,13 @@ Requires-Dist: colorama>=0.4.6
12
14
  Dynamic: author
13
15
  Dynamic: description
14
16
  Dynamic: home-page
17
+ Dynamic: license
15
18
  Dynamic: license-file
16
19
  Dynamic: requires-dist
20
+ Dynamic: requires-python
17
21
  Dynamic: summary
18
22
 
19
- FMU Manipulation Toolbox is a python application which help to modify a Functional Mock-up Units (FMUs)
23
+ FMU Manipulation Toolbox is a python application for modifying Functional Mock-up Units (FMUs)
20
24
  without recompilation. It mainly modifies the `modelDescription.xml` file. It is highly customizable.
21
25
 
22
26
  Manipulating the `modelDescription.xml` can be a dangerous thing! Communicating with the FMU-developer and adapting
@@ -7,7 +7,7 @@ import uuid
7
7
  import xml.parsers.expat
8
8
  import zipfile
9
9
 
10
- from .fmu_container import FMUContainer
10
+ from .fmu_container import FMUContainer, AutoWired
11
11
 
12
12
  logger = logging.getLogger("fmu_manipulation_toolbox")
13
13
 
@@ -126,11 +126,17 @@ class AssemblyNode:
126
126
  for port, value in self.start_values.items():
127
127
  container.add_start_value(port.fmu_name, port.port_name, value)
128
128
 
129
- container.add_implicit_rule(auto_input=self.auto_input,
130
- auto_output=self.auto_output,
131
- auto_link=self.auto_link,
132
- auto_parameter=self.auto_parameter,
133
- auto_local=self.auto_local)
129
+ wired = container.add_implicit_rule(auto_input=self.auto_input,
130
+ auto_output=self.auto_output,
131
+ auto_link=self.auto_link,
132
+ auto_parameter=self.auto_parameter,
133
+ auto_local=self.auto_local)
134
+ for input_rule in wired.rule_input:
135
+ self.add_input(input_rule[0], input_rule[1], input_rule[2])
136
+ for output_rule in wired.rule_output:
137
+ self.add_output(output_rule[0], output_rule[1], output_rule[2])
138
+ for link_rule in wired.rule_link:
139
+ self.add_link(link_rule[0], link_rule[1], link_rule[2], link_rule[3])
134
140
 
135
141
  container.make_fmu(self.name, self.step_size, mt=self.mt, profiling=self.profiling, debug=debug)
136
142
 
@@ -498,18 +504,18 @@ class Assembly:
498
504
 
499
505
  self.description_pathname = self.fmu_directory / "SystemStructure.ssd"
500
506
  if self.description_pathname.is_file():
501
- sdd = SSDParser(step_size=self.default_step_size, auto_link=self.default_auto_link,
507
+ sdd = SSDParser(step_size=self.default_step_size, auto_link=False,
502
508
  mt=self.default_mt, profiling=self.default_profiling,
503
- auto_input=self.default_auto_input, auto_output=self.default_auto_output)
509
+ auto_input=False, auto_output=False)
504
510
  self.root = sdd.parse(self.description_pathname)
505
511
  self.root.name = str(self.filename.with_suffix(".fmu"))
506
512
 
507
513
  def make_fmu(self, dump_json=False):
514
+ self.root.make_fmu(self.fmu_directory, debug=self.debug, description_pathname=self.description_pathname)
508
515
  if dump_json:
509
516
  dump_file = Path(self.input_pathname.stem + "-dump").with_suffix(".json")
510
517
  logger.info(f"Dump Json '{dump_file}'")
511
518
  self.write_json(dump_file)
512
- self.root.make_fmu(self.fmu_directory, debug=self.debug, description_pathname=self.description_pathname)
513
519
 
514
520
 
515
521
  class SSDParser:
@@ -146,12 +146,35 @@ class ContainerPort:
146
146
  return f"Port {self.fmu.name}/{self.port.name}"
147
147
 
148
148
  def __hash__(self):
149
- return hash("{self.fmu.name}/{self.port.name}")
149
+ return hash(f"{self}")
150
150
 
151
151
  def __eq__(self, other):
152
152
  return str(self) == str(other)
153
153
 
154
154
 
155
+ class ContainerInput:
156
+ def __init__(self, name: str, cport_to: ContainerPort):
157
+ self.name = name
158
+ self.type_name = cport_to.port.type_name
159
+ self.causality = cport_to.port.causality
160
+ self.cport_list = [cport_to]
161
+ self.vr = None
162
+
163
+ def add_cport(self, cport_to: ContainerPort):
164
+ if cport_to in self.cport_list: # Cannot be reached ! (Assembly prevent this to happen)
165
+ raise FMUContainerError(f"Duplicate INPUT {cport_to} already connected to {self.name}")
166
+
167
+ if cport_to.port.type_name != self.type_name:
168
+ raise FMUContainerError(f"Cannot connect {self.name} of type {self.type_name} to "
169
+ f"{cport_to} of type {cport_to.port.type_name}")
170
+
171
+ if cport_to.port.causality != self.causality:
172
+ raise FMUContainerError(f"Cannot connect {self.causality.upper()} {self.name} to "
173
+ f"{cport_to.port.causality.upper()} {cport_to}")
174
+
175
+ self.cport_list.append(cport_to)
176
+
177
+
155
178
  class Local:
156
179
  def __init__(self, cport_from: ContainerPort):
157
180
  self.name = cport_from.fmu.id + "." + cport_from.port.name # strip .fmu suffix
@@ -190,6 +213,31 @@ class ValueReferenceTable:
190
213
  return vr
191
214
 
192
215
 
216
+ class AutoWired:
217
+ def __init__(self):
218
+ self.rule_input = []
219
+ self.rule_output = []
220
+ self.rule_link = []
221
+ self.nb_param = 0
222
+
223
+ def __repr__(self):
224
+ return (f"{self.nb_param} parameters, {len(self.rule_input) - self.nb_param} inputs,"
225
+ f" {len(self.rule_output)} outputs, {len(self.rule_link)} links.")
226
+
227
+ def add_input(self, from_port, to_fmu, to_port):
228
+ self.rule_input.append([from_port, to_fmu, to_port])
229
+
230
+ def add_parameter(self, from_port, to_fmu, to_port):
231
+ self.rule_input.append([from_port, to_fmu, to_port])
232
+ self.nb_param += 1
233
+
234
+ def add_output(self, from_fmu, from_port, to_port):
235
+ self.rule_output.append([from_fmu, from_port, to_port])
236
+
237
+ def add_link(self, from_fmu, from_port, to_fmu, to_port):
238
+ self.rule_link.append([from_fmu, from_port, to_fmu, to_port])
239
+
240
+
193
241
  class FMUContainer:
194
242
  def __init__(self, identifier: str, fmu_directory: Union[str, Path], description_pathname=None):
195
243
  self.fmu_directory = Path(fmu_directory)
@@ -205,7 +253,7 @@ class FMUContainer:
205
253
  self.stop_time = None
206
254
 
207
255
  # Rules
208
- self.inputs: Dict[str, ContainerPort] = {}
256
+ self.inputs: Dict[str, ContainerInput] = {}
209
257
  self.outputs: Dict[str, ContainerPort] = {}
210
258
  self.locals: Dict[ContainerPort, Local] = {}
211
259
 
@@ -236,17 +284,25 @@ class FMUContainer:
236
284
 
237
285
  self.rules[cport] = rule
238
286
 
287
+ def get_all_cports(self):
288
+ return [ContainerPort(fmu, port_name) for fmu in self.execution_order for port_name in fmu.ports]
289
+
239
290
  def add_input(self, container_port_name: str, to_fmu_filename: str, to_port_name: str):
240
291
  if not container_port_name:
241
292
  container_port_name = to_port_name
242
293
  cport_to = ContainerPort(self.get_fmu(to_fmu_filename), to_port_name)
243
- if not cport_to.port.causality == "input": # check causality
294
+ if cport_to.port.causality not in ("input", "parameter"): # check causality
244
295
  raise FMUContainerError(f"Tried to use '{cport_to}' as INPUT of the container but FMU causality is "
245
296
  f"'{cport_to.port.causality}'.")
246
297
 
298
+ try:
299
+ input_port = self.inputs[container_port_name]
300
+ input_port.add_cport(cport_to)
301
+ except KeyError:
302
+ self.inputs[container_port_name] = ContainerInput(container_port_name, cport_to)
303
+
247
304
  logger.debug(f"INPUT: {to_fmu_filename}:{to_port_name}")
248
305
  self.mark_ruled(cport_to, 'INPUT')
249
- self.inputs[container_port_name] = cport_to
250
306
 
251
307
  def add_output(self, from_fmu_filename: str, from_port_name: str, container_port_name: str):
252
308
  if not container_port_name: # empty is allowed
@@ -254,9 +310,12 @@ class FMUContainer:
254
310
 
255
311
  cport_from = ContainerPort(self.get_fmu(from_fmu_filename), from_port_name)
256
312
  if cport_from.port.causality not in ("output", "local"): # check causality
257
- raise FMUContainerError(f"Tried to use '{cport_from}' as INPUT of the container but FMU causality is "
313
+ raise FMUContainerError(f"Tried to use '{cport_from}' as OUTPUT of the container but FMU causality is "
258
314
  f"'{cport_from.port.causality}'.")
259
315
 
316
+ if container_port_name in self.outputs:
317
+ raise FMUContainerError(f"Duplicate OUTPUT {container_port_name} already connected to {cport_from}")
318
+
260
319
  logger.debug(f"OUTPUT: {from_fmu_filename}:{from_port_name}")
261
320
  self.mark_ruled(cport_from, 'OUTPUT')
262
321
  self.outputs[container_port_name] = cport_from
@@ -302,60 +361,60 @@ class FMUContainer:
302
361
 
303
362
  def find_inputs(self, port_to_connect: FMUPort) -> List[ContainerPort]:
304
363
  candidates = []
305
- for fmu in self.execution_order:
306
- for port in fmu.ports.values():
307
- if (port.causality == 'input' and port.name == port_to_connect.name
308
- and port.type_name == port_to_connect.type_name):
309
- candidates.append(ContainerPort(fmu, port.name))
364
+ for cport in self.get_all_cports():
365
+ if (cport.port.causality == 'input' and cport not in self.rules and cport.port.name == port_to_connect.name
366
+ and cport.port.type_name == port_to_connect.type_name):
367
+ candidates.append(cport)
310
368
  return candidates
311
369
 
312
370
  def add_implicit_rule(self, auto_input=True, auto_output=True, auto_link=True, auto_parameter=False,
313
- auto_local=False):
371
+ auto_local=False) -> AutoWired:
372
+
373
+ auto_wired = AutoWired()
314
374
  # Auto Link outputs
315
- for fmu in self.execution_order:
316
- for port_name in fmu.ports:
317
- cport = ContainerPort(fmu, port_name)
375
+ for cport in self.get_all_cports():
376
+ if cport.port.causality == 'output':
377
+ candidates_cport_list = self.find_inputs(cport.port)
378
+ if auto_link and candidates_cport_list:
379
+ for candidate_cport in candidates_cport_list:
380
+ logger.info(f"AUTO LINK: {cport} -> {candidate_cport}")
381
+ self.add_link(cport.fmu.name, cport.port.name,
382
+ candidate_cport.fmu.name, candidate_cport.port.name)
383
+ auto_wired.add_link(cport.fmu.name, cport.port.name,
384
+ candidate_cport.fmu.name, candidate_cport.port.name)
385
+ elif auto_output and cport not in self.rules:
386
+ logger.info(f"AUTO OUTPUT: Expose {cport}")
387
+ self.add_output(cport.fmu.name, cport.port.name, cport.port.name)
388
+ auto_wired.add_output(cport.fmu.name, cport.port.name, cport.port.name)
389
+ elif cport.port.causality == 'local':
390
+ local_portname = None
391
+ if cport.port.name.startswith("container."):
392
+ local_portname = "container." + cport.fmu.id + "." + cport.port.name[10:]
393
+ logger.info(f"PROFILING: Expose {cport}")
394
+ elif auto_local:
395
+ local_portname = cport.fmu.id + "." + cport.port.name
396
+ logger.info(f"AUTO LOCAL: Expose {cport}")
397
+ if local_portname:
398
+ self.add_output(cport.fmu.name, cport.port.name, local_portname)
399
+ auto_wired.add_output(cport.fmu.name, cport.port.name, local_portname)
400
+
401
+ if auto_input:
402
+ # Auto link inputs
403
+ for cport in self.get_all_cports():
318
404
  if cport not in self.rules:
319
405
  if cport.port.causality == 'parameter' and auto_parameter:
320
406
  parameter_name = cport.fmu.id + "." + cport.port.name
321
407
  logger.info(f"AUTO PARAMETER: {cport} as {parameter_name}")
322
- self.inputs[parameter_name] = cport
323
- self.mark_ruled(cport, 'PARAMETER')
324
- elif cport.port.causality == 'output':
325
- candidates_cport_list = self.find_inputs(cport.port)
326
- if auto_link and candidates_cport_list:
327
- self.locals[cport] = Local(cport)
328
- self.mark_ruled(cport, 'LINK')
329
- for candidate_cport in candidates_cport_list:
330
- self.locals[cport].add_target(candidate_cport)
331
- self.mark_ruled(candidate_cport, 'LINK')
332
- logger.info(f"AUTO LINK: {cport} -> {candidate_cport}")
333
- elif auto_output:
334
- self.mark_ruled(cport, 'OUTPUT')
335
- self.outputs[port_name] = cport
336
- logger.info(f"AUTO OUTPUT: Expose {cport}")
337
- elif cport.port.causality == 'local':
338
- local_portname = None
339
- if port_name.startswith("container."):
340
- local_portname = "container." + cport.fmu.id + "." + port_name[10:]
341
- logger.info(f"PROFILING: Expose {cport}")
342
- elif auto_local:
343
- local_portname = cport.fmu.id + "." + port_name
344
- logger.info(f"AUTO LOCAL: Expose {cport}")
345
- if local_portname:
346
- self.mark_ruled(cport, 'OUTPUT')
347
- self.outputs[local_portname] = cport
408
+ self.add_input(parameter_name, cport.fmu.name, cport.port.name)
409
+ auto_wired.add_parameter(parameter_name, cport.fmu.name, cport.port.name)
410
+ elif cport.port.causality == 'input':
411
+ logger.info(f"AUTO INPUT: Expose {cport}")
412
+ self.add_input(cport.port.name, cport.fmu.name, cport.port.name)
413
+ auto_wired.add_input(cport.port.name, cport.fmu.name, cport.port.name)
348
414
 
349
- if auto_input:
350
- # Auto link inputs
351
- for fmu in self.execution_order:
352
- for port_name in fmu.ports:
353
- cport = ContainerPort(fmu, port_name)
354
- if cport not in self.rules:
355
- if cport.port.causality == 'input':
356
- self.mark_ruled(cport, 'INPUT')
357
- self.inputs[port_name] = cport
358
- logger.info(f"AUTO INPUT: Expose {cport}")
415
+ logger.info(f"Auto-wiring: {auto_wired}")
416
+
417
+ return auto_wired
359
418
 
360
419
  def minimum_step_size(self) -> float:
361
420
  step_size = None
@@ -489,11 +548,12 @@ class FMUContainer:
489
548
  print(f' {local.cport_from.port.xml(vr, name=local.name, causality="local")}', file=xml_file)
490
549
  local.vr = vr
491
550
 
492
- for input_port_name, cport in self.inputs.items():
493
- vr = vr_table.get_vr(cport)
494
- start = self.start_values.get(cport, None)
495
- print(f" {cport.port.xml(vr, name=input_port_name, start=start)}", file=xml_file)
496
- cport.vr = vr
551
+ for input_port_name, input_port in self.inputs.items():
552
+ vr = vr_table.add_vr(input_port.type_name)
553
+ # Get Start and XML from first connected input
554
+ start = self.start_values.get(input_port.cport_list[0], None)
555
+ print(f" {input_port.cport_list[0].port.xml(vr, name=input_port_name, start=start)}", file=xml_file)
556
+ input_port.vr = vr
497
557
 
498
558
  for output_port_name, cport in self.outputs.items():
499
559
  vr = vr_table.get_vr(cport)
@@ -544,7 +604,7 @@ class FMUContainer:
544
604
 
545
605
  # Prepare data structure
546
606
  type_names_list = ("Real", "Integer", "Boolean", "String") # Ordered list
547
- inputs_per_type: Dict[str, List[ContainerPort]] = {} # Container's INPUT
607
+ inputs_per_type: Dict[str, List[ContainerInput]] = {} # Container's INPUT
548
608
  outputs_per_type: Dict[str, List[ContainerPort]] = {} # Container's OUTPUT
549
609
 
550
610
  inputs_fmu_per_type: Dict[str, Dict[str, Dict[ContainerPort, int]]] = {} # [type][fmu]
@@ -568,8 +628,8 @@ class FMUContainer:
568
628
 
569
629
  # Fill data structure
570
630
  # Inputs
571
- for input_port_name, cport in self.inputs.items():
572
- inputs_per_type[cport.port.type_name].append(cport)
631
+ for input_port_name, input_port in self.inputs.items():
632
+ inputs_per_type[input_port.type_name].append(input_port)
573
633
  for cport, value in self.start_values.items():
574
634
  start_values_fmu_per_type[cport.port.type_name][cport.fmu.name][cport] = value
575
635
  # Outputs
@@ -591,23 +651,28 @@ class FMUContainer:
591
651
  print(f"{nb} ", file=txt_file, end='')
592
652
  print("", file=txt_file)
593
653
 
594
- print("# CONTAINER I/O: <VR> <FMU_INDEX> <FMU_VR>", file=txt_file)
654
+ print("# CONTAINER I/O: <VR> <NB> <FMU_INDEX> <FMU_VR> [<FMU_INDEX> <FMU_VR>]", file=txt_file)
595
655
  for type_name in type_names_list:
596
656
  print(f"# {type_name}", file=txt_file)
597
- nb = len(inputs_per_type[type_name])+len(outputs_per_type[type_name])+len(locals_per_type[type_name])
657
+ nb = len(inputs_per_type[type_name]) + len(outputs_per_type[type_name]) + len(locals_per_type[type_name])
658
+ nb_input_link = 0
659
+ for input_port in inputs_per_type[type_name]:
660
+ nb_input_link += len(input_port.cport_list) - 1
661
+
598
662
  if profiling and type_name == "Real":
599
663
  nb += len(self.execution_order)
600
- print(nb, file=txt_file)
664
+ print(f"{nb} {nb+nb_input_link}", file=txt_file)
601
665
  for profiling_port, _ in enumerate(self.execution_order):
602
666
  print(f"{profiling_port} -2 {profiling_port}", file=txt_file)
603
667
  else:
604
- print(nb, file=txt_file)
605
- for cport in inputs_per_type[type_name]:
606
- print(f"{cport.vr} {fmu_rank[cport.fmu.name]} {cport.port.vr}", file=txt_file)
668
+ print(f"{nb} {nb+nb_input_link}", file=txt_file)
669
+ for input_port in inputs_per_type[type_name]:
670
+ cport_string = [f"{fmu_rank[cport.fmu.name]} {cport.port.vr}" for cport in input_port.cport_list]
671
+ print(f"{input_port.vr} {len(input_port.cport_list)}", " ".join(cport_string), file=txt_file)
607
672
  for cport in outputs_per_type[type_name]:
608
- print(f"{cport.vr} {fmu_rank[cport.fmu.name]} {cport.port.vr}", file=txt_file)
673
+ print(f"{cport.vr} 1 {fmu_rank[cport.fmu.name]} {cport.port.vr}", file=txt_file)
609
674
  for local in locals_per_type[type_name]:
610
- print(f"{local.vr} -1 {local.vr}", file=txt_file)
675
+ print(f"{local.vr} 1 -1 {local.vr}", file=txt_file)
611
676
 
612
677
  # LINKS
613
678
  for fmu in self.execution_order:
@@ -313,10 +313,11 @@ class OperationAddRemotingWinAbstract(OperationAbstract):
313
313
  else:
314
314
  os.mkdir(fmu_bin[self.bitness_to])
315
315
 
316
- from_path = Path(__file__).parent / "resources" / self.bitness_to
317
- shutil.copyfile(from_path / "client_sm.dll",
316
+ to_path = Path(__file__).parent / "resources" / self.bitness_to
317
+ shutil.copyfile(to_path / "client_sm.dll",
318
318
  Path(fmu_bin[self.bitness_to]) / Path(attrs['modelIdentifier']).with_suffix(".dll"))
319
319
 
320
+ from_path = Path(__file__).parent / "resources" / self.bitness_from
320
321
  shutil.copyfile(from_path / "server_sm.exe",
321
322
  Path(fmu_bin[self.bitness_from]) / "server_sm.exe")
322
323
 
@@ -11,7 +11,7 @@ from PySide6.QtGui import (QPixmap, QTextCursor, QStandardItem, QIcon, QDesktopS
11
11
  from functools import partial
12
12
  from typing import Optional
13
13
 
14
- from .gui_style import *
14
+ from .gui_style import gui_style
15
15
  from .fmu_operations import *
16
16
  from .assembly import Assembly, AssemblyNode
17
17
  from .checker import checker_list
@@ -728,7 +728,7 @@ Communicating with the FMU-developer and adapting the way the FMU is generated,
728
728
  self.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.RoundPreferFloor)
729
729
 
730
730
  QDir.addSearchPath('images', os.path.join(os.path.dirname(__file__), "resources"))
731
- self.setStyleSheet(gui_style_dark)
731
+ self.setStyleSheet(gui_style)
732
732
 
733
733
  if os.name == 'nt':
734
734
  import ctypes
@@ -0,0 +1,244 @@
1
+ import os
2
+
3
+ if os.name == 'nt':
4
+ gui_style = """
5
+ QWidget {
6
+ font: 10pt "Verdana";
7
+ background: #4b4e51;
8
+ color: #b5bab9;
9
+ }
10
+ QPushButton, QComboBox {
11
+ min-height: 30px;
12
+ padding: 1px 1px 0.2em 0.2em;
13
+ border: 1px solid #282830;
14
+ border-radius: 5px;
15
+ color: #dddddd;
16
+ }
17
+ QPushButton:pressed {
18
+ border: 2px solid #282830;
19
+ }
20
+ QPushButton.info {
21
+ background-color: #4e6749;
22
+ }
23
+ QPushButton.info:hover {
24
+ background-color: #5f7850;
25
+ }
26
+ QPushButton.modify {
27
+ background-color: #98763f;
28
+ }
29
+ QPushButton.modify:hover {
30
+ background-color: #a9874f;
31
+ }
32
+ QPushButton.removal {
33
+ background-color: #692e2e;
34
+ }
35
+ QPushButton.removal:hover {
36
+ background-color: #7a3f3f;
37
+ }
38
+ QPushButton.save {
39
+ background-color: #564967;
40
+ }
41
+ QPushButton.save:hover {
42
+ background-color: #675a78;
43
+ }
44
+ QPushButton.quit {
45
+ background-color: #4571a4;
46
+ }
47
+ QPushButton.quit:hover {
48
+ background-color: #5682b5;
49
+ }
50
+ QPushButton::disabled {
51
+ background-color: gray;
52
+ }
53
+ QToolTip {
54
+ color: black
55
+ }
56
+ QLabel.dropped_fmu {
57
+ background-color: #b5bab9
58
+ }
59
+ QLabel.title {
60
+ font: 14pt bold "Verdana";
61
+ }
62
+ QLabel.dropped_fmu:hover {
63
+ background-color: #c6cbca
64
+ }
65
+ QTextBrowser, QTreeView {
66
+ font: 11pt "Consolas";
67
+ background-color: #282830;
68
+ color: #b5bab9;
69
+ }
70
+ QMenu::item {
71
+ padding: 2px 250px 2px 20px;
72
+ border: 1px solid transparent;
73
+ }
74
+ QMenu::item::indicator, QCheckBox::item::indicator {
75
+ width: 32px;
76
+ height: 32px;
77
+ }
78
+ QMenu::indicator:checked, QCheckBox::indicator:checked {
79
+ image: url(images:checkbox-checked.png);
80
+ }
81
+ QMenu::indicator:checked:hover, QCheckBox::indicator:checked:hover {
82
+ image: url(images:checkbox-checked-hover.png);
83
+ }
84
+ QMenu::indicator:checked:disabled, QCheckBox::indicator:checked:disabled {
85
+ image: url(images:checkbox-checked-disabled.png);
86
+ }
87
+ QMenu::indicator:unchecked, QCheckBox::indicator:unchecked {
88
+ image: url(images:checkbox-unchecked.png);
89
+ }
90
+ QMenu::indicator:unchecked:hover, QCheckBox::indicator:unchecked:hover {
91
+ image: url(images:checkbox-unchecked-hover.png);
92
+ }
93
+ QMenu::indicator:unchecked:disabled, QCheckBox::indicator:unchecked:disabled {
94
+ image: url(images:checkbox-unchecked-disabled.png);
95
+ }
96
+ QCheckBox::item {
97
+ padding: 2px 250px 2px 20px;
98
+ border: 1px solid transparent;
99
+ }
100
+ QTabBar::tab {
101
+ min-height: 30px;
102
+ padding: 1px 1px 0.2em 0.2em;
103
+ color: #dddddd;
104
+ margin: 2px;
105
+ margin-bottom: 0px;
106
+ border: 1px solid #282830;
107
+ border-top-left-radius: 5px;
108
+ border-top-right-radius: 5px;
109
+ }
110
+ QTabBar::tab:selected, QTabBar::tab:hover {
111
+ background-color: #5f7850;
112
+ margin-bottom:-1px;
113
+ }
114
+ QTabBar {
115
+ border-bottom: 1px solid #282830;
116
+ }
117
+ QTabBar::tab:top:last, QTabBar::tab:bottom:last {
118
+ margin-right: 0;
119
+ }
120
+ QTabBar::tab:top:first, QTabBar::tab:bottom:first {
121
+ margin-left: 0;
122
+ }
123
+ """
124
+ else:
125
+ gui_style = """
126
+ QWidget {
127
+ font: 12pt;
128
+ background: #4b4e51;
129
+ color: #b5bab9;
130
+ }
131
+ QPushButton, QComboBox {
132
+ min-height: 30px;
133
+ padding: 1px 1px 0.2em 0.2em;
134
+ border: 1px solid #282830;
135
+ border-radius: 5px;
136
+ color: #dddddd;
137
+ }
138
+ QPushButton:pressed {
139
+ border: 2px solid #282830;
140
+ }
141
+ QPushButton.info {
142
+ background-color: #4e6749;
143
+ }
144
+ QPushButton.info:hover {
145
+ background-color: #5f7850;
146
+ }
147
+ QPushButton.modify {
148
+ background-color: #98763f;
149
+ }
150
+ QPushButton.modify:hover {
151
+ background-color: #a9874f;
152
+ }
153
+ QPushButton.removal {
154
+ background-color: #692e2e;
155
+ }
156
+ QPushButton.removal:hover {
157
+ background-color: #7a3f3f;
158
+ }
159
+ QPushButton.save {
160
+ background-color: #564967;
161
+ }
162
+ QPushButton.save:hover {
163
+ background-color: #675a78;
164
+ }
165
+ QPushButton.quit {
166
+ background-color: #4571a4;
167
+ }
168
+ QPushButton.quit:hover {
169
+ background-color: #5682b5;
170
+ }
171
+ QPushButton::disabled {
172
+ background-color: gray;
173
+ }
174
+ QToolTip {
175
+ color: black
176
+ }
177
+ QLabel.dropped_fmu {
178
+ background-color: #b5bab9
179
+ }
180
+ QLabel.title {
181
+ font: 14pt bold "Verdana";
182
+ }
183
+ QLabel.dropped_fmu:hover {
184
+ background-color: #c6cbca
185
+ }
186
+ QTextBrowser, QTreeView {
187
+ font: 14pt "Courier New";
188
+ background-color: #282830;
189
+ color: #b5bab9;
190
+ }
191
+ QMenu::item {
192
+ padding: 2px 250px 2px 20px;
193
+ border: 1px solid transparent;
194
+ }
195
+ QMenu::item::indicator, QCheckBox::item::indicator {
196
+ width: 32px;
197
+ height: 32px;
198
+ }
199
+ QMenu::indicator:checked, QCheckBox::indicator:checked {
200
+ image: url(images:checkbox-checked.png);
201
+ }
202
+ QMenu::indicator:checked:hover, QCheckBox::indicator:checked:hover {
203
+ image: url(images:checkbox-checked-hover.png);
204
+ }
205
+ QMenu::indicator:checked:disabled, QCheckBox::indicator:checked:disabled {
206
+ image: url(images:checkbox-checked-disabled.png);
207
+ }
208
+ QMenu::indicator:unchecked, QCheckBox::indicator:unchecked {
209
+ image: url(images:checkbox-unchecked.png);
210
+ }
211
+ QMenu::indicator:unchecked:hover, QCheckBox::indicator:unchecked:hover {
212
+ image: url(images:checkbox-unchecked-hover.png);
213
+ }
214
+ QMenu::indicator:unchecked:disabled, QCheckBox::indicator:unchecked:disabled {
215
+ image: url(images:checkbox-unchecked-disabled.png);
216
+ }
217
+ QCheckBox::item {
218
+ padding: 2px 250px 2px 20px;
219
+ border: 1px solid transparent;
220
+ }
221
+ QTabBar::tab {
222
+ min-height: 30px;
223
+ padding: 1px 1px 0.2em 0.2em;
224
+ color: #dddddd;
225
+ margin: 2px;
226
+ margin-bottom: 0px;
227
+ border: 1px solid #282830;
228
+ border-top-left-radius: 5px;
229
+ border-top-right-radius: 5px;
230
+ }
231
+ QTabBar::tab:selected, QTabBar::tab:hover {
232
+ background-color: #5f7850;
233
+ margin-bottom:-1px;
234
+ }
235
+ QTabBar {
236
+ border-bottom: 1px solid #282830;
237
+ }
238
+ QTabBar::tab:top:last, QTabBar::tab:bottom:last {
239
+ margin-right: 0;
240
+ }
241
+ QTabBar::tab:top:first, QTabBar::tab:bottom:first {
242
+ margin-left: 0;
243
+ }
244
+ """
@@ -1,9 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmu_manipulation_toolbox
3
- Version: 1.8.3
4
- Summary: FMU Manipulation Toobox is a python application which help to modify a Functional Mock-up Units (FMUs) without recompilation or to group them into FMU Containers
3
+ Version: 1.8.4
4
+ Summary: FMU Manipulation Toolbox is a python application for modifying Functional Mock-up Units (FMUs) without recompilation or bundling them into FMU Containers
5
5
  Home-page: https://github.com/grouperenault/fmu_manipulation_toolbox/
6
6
  Author: Nicolas.LAURENT@Renault.com
7
+ License: BSD-2-Clause
8
+ Requires-Python: >=3.8
7
9
  License-File: LICENSE.txt
8
10
  Requires-Dist: PySide6>=6.8.0
9
11
  Requires-Dist: xmlschema>=3.3.1
@@ -12,11 +14,13 @@ Requires-Dist: colorama>=0.4.6
12
14
  Dynamic: author
13
15
  Dynamic: description
14
16
  Dynamic: home-page
17
+ Dynamic: license
15
18
  Dynamic: license-file
16
19
  Dynamic: requires-dist
20
+ Dynamic: requires-python
17
21
  Dynamic: summary
18
22
 
19
- FMU Manipulation Toolbox is a python application which help to modify a Functional Mock-up Units (FMUs)
23
+ FMU Manipulation Toolbox is a python application for modifying Functional Mock-up Units (FMUs)
20
24
  without recompilation. It mainly modifies the `modelDescription.xml` file. It is highly customizable.
21
25
 
22
26
  Manipulating the `modelDescription.xml` can be a dangerous thing! Communicating with the FMU-developer and adapting
@@ -1,6 +1,6 @@
1
- from setuptools import setup
2
1
  import os
3
2
  import re
3
+ from setuptools import setup
4
4
 
5
5
  from fmu_manipulation_toolbox.version import __author__ as author, __version__ as default_version
6
6
 
@@ -25,29 +25,29 @@ setup(
25
25
  name="fmu_manipulation_toolbox",
26
26
  version=version,
27
27
  packages=["fmu_manipulation_toolbox"],
28
- package_data={"fmu_manipulation_toolbox": ["resources/win32/client_sm.dll",
29
- "resources/win32/server_sm.exe",
30
- "resources/win64/client_sm.dll",
31
- "resources/win64/server_sm.exe",
32
- "resources/win64/container.dll",
33
- "resources/linux64/client_sm.so",
34
- "resources/linux64/server_sm",
35
- "resources/linux64/container.so",
36
- "resources/linux32/client_sm.so",
37
- "resources/linux32/server_sm",
38
- "resources/license.txt",
39
- "resources/*.png",
40
- "resources/fmi-2.0/*.xsd",
41
- ],
42
- },
28
+ package_data={"fmu_manipulation_toolbox": [
29
+ "resources/win32/client_sm.dll",
30
+ "resources/win32/server_sm.exe",
31
+ "resources/win64/client_sm.dll",
32
+ "resources/win64/server_sm.exe",
33
+ "resources/win64/container.dll",
34
+ "resources/linux64/client_sm.so",
35
+ "resources/linux64/server_sm",
36
+ "resources/linux64/container.so",
37
+ "resources/linux32/client_sm.so",
38
+ "resources/linux32/server_sm",
39
+ "resources/license.txt",
40
+ "resources/*.png",
41
+ "resources/fmi-2.0/*.xsd",
42
+ ]},
43
43
  entry_points={"console_scripts": ["fmutool = fmu_manipulation_toolbox.__main__:main",
44
44
  "fmucontainer = fmu_manipulation_toolbox.cli:fmucontainer"],
45
45
  },
46
46
  author=author,
47
47
  url="https://github.com/grouperenault/fmu_manipulation_toolbox/",
48
- description="FMU Manipulation Toobox is a python application which help to modify a Functional Mock-up Units (FMUs) "
49
- "without recompilation or to group them into FMU Containers",
50
- long_description="""FMU Manipulation Toolbox is a python application which help to modify a Functional Mock-up Units (FMUs)
48
+ description="FMU Manipulation Toolbox is a python application for modifying Functional Mock-up Units "
49
+ "(FMUs) without recompilation or bundling them into FMU Containers",
50
+ long_description="""FMU Manipulation Toolbox is a python application for modifying Functional Mock-up Units (FMUs)
51
51
  without recompilation. It mainly modifies the `modelDescription.xml` file. It is highly customizable.
52
52
 
53
53
  Manipulating the `modelDescription.xml` can be a dangerous thing! Communicating with the FMU-developer and adapting
@@ -61,6 +61,8 @@ FMU Manipulation Toolbox also allows to group FMU's inside FMU Containers.
61
61
  "elementpath >= 4.4.0",
62
62
  "colorama >= 0.4.6",
63
63
  ],
64
+ license="BSD-2-Clause",
65
+ python_requires=">=3.8",
64
66
  )
65
67
 
66
68
  os.remove("fmu_manipulation_toolbox/__version__.py")
@@ -1,129 +0,0 @@
1
- # if os.name == 'nt':
2
- # font = QFont('Consolas')
3
- # font.setPointSize(11)
4
- # else:
5
- # font = QFont('Courier New')
6
- # font.setPointSize(12)
7
- # self.setFont(font)
8
-
9
-
10
- gui_style_dark = """
11
- QWidget {
12
- font: 10pt "Verdana";
13
- background: #4b4e51;
14
- color: #b5bab9;
15
- }
16
- QPushButton, QComboBox {
17
- min-height: 30px;
18
- padding: 1px 1px 0.2em 0.2em;
19
- border: 1px solid #282830;
20
- border-radius: 5px;
21
- color: #dddddd;
22
- }
23
- QPushButton:pressed {
24
- border: 2px solid #282830;
25
- }
26
- QPushButton.info {
27
- background-color: #4e6749;
28
- }
29
- QPushButton.info:hover {
30
- background-color: #5f7850;
31
- }
32
- QPushButton.modify {
33
- background-color: #98763f;
34
- }
35
- QPushButton.modify:hover {
36
- background-color: #a9874f;
37
- }
38
- QPushButton.removal {
39
- background-color: #692e2e;
40
- }
41
- QPushButton.removal:hover {
42
- background-color: #7a3f3f;
43
- }
44
- QPushButton.save {
45
- background-color: #564967;
46
- }
47
- QPushButton.save:hover {
48
- background-color: #675a78;
49
- }
50
- QPushButton.quit {
51
- background-color: #4571a4;
52
- }
53
- QPushButton.quit:hover {
54
- background-color: #5682b5;
55
- }
56
- QPushButton::disabled {
57
- background-color: gray;
58
- }
59
- QToolTip {
60
- color: black
61
- }
62
- QLabel.dropped_fmu {
63
- background-color: #b5bab9
64
- }
65
- QLabel.title {
66
- font: 14pt bold "Verdana";
67
- }
68
- QLabel.dropped_fmu:hover {
69
- background-color: #c6cbca
70
- }
71
- QTextBrowser, QTreeView {
72
- font: 11pt "Consolas";
73
- background-color: #282830;
74
- color: #b5bab9;
75
- }
76
- QMenu::item {
77
- padding: 2px 250px 2px 20px;
78
- border: 1px solid transparent;
79
- }
80
- QMenu::item::indicator, QCheckBox::item::indicator {
81
- width: 32px;
82
- height: 32px;
83
- }
84
- QMenu::indicator:checked, QCheckBox::indicator:checked {
85
- image: url(images:checkbox-checked.png);
86
- }
87
- QMenu::indicator:checked:hover, QCheckBox::indicator:checked:hover {
88
- image: url(images:checkbox-checked-hover.png);
89
- }
90
- QMenu::indicator:checked:disabled, QCheckBox::indicator:checked:disabled {
91
- image: url(images:checkbox-checked-disabled.png);
92
- }
93
- QMenu::indicator:unchecked, QCheckBox::indicator:unchecked {
94
- image: url(images:checkbox-unchecked.png);
95
- }
96
- QMenu::indicator:unchecked:hover, QCheckBox::indicator:unchecked:hover {
97
- image: url(images:checkbox-unchecked-hover.png);
98
- }
99
- QMenu::indicator:unchecked:disabled, QCheckBox::indicator:unchecked:disabled {
100
- image: url(images:checkbox-unchecked-disabled.png);
101
- }
102
- QCheckBox::item {
103
- padding: 2px 250px 2px 20px;
104
- border: 1px solid transparent;
105
- }
106
- QTabBar::tab {
107
- min-height: 30px;
108
- padding: 1px 1px 0.2em 0.2em;
109
- color: #dddddd;
110
- margin: 2px;
111
- margin-bottom: 0px;
112
- border: 1px solid #282830;
113
- border-top-left-radius: 5px;
114
- border-top-right-radius: 5px;
115
- }
116
- QTabBar::tab:selected, QTabBar::tab:hover {
117
- background-color: #5f7850;
118
- margin-bottom:-1px;
119
- }
120
- QTabBar {
121
- border-bottom: 1px solid #282830;
122
- }
123
- QTabBar::tab:top:last, QTabBar::tab:bottom:last {
124
- margin-right: 0;
125
- }
126
- QTabBar::tab:top:first, QTabBar::tab:bottom:first {
127
- margin-left: 0;
128
- }
129
- """