Skip to content
......@@ -23,7 +23,7 @@
import logging
from .Measurement import Measurement, Measurements
from .StandardMeasurement import ValentinaStandardMeasurement
from .ValentinaStandardMeasurement import ValentinaStandardMeasurement
####################################################################################################
......
####################################################################################################
#
# Patro - A Python library to make patterns for fashion design
# Copyright (C) 2018 Fabrice Salvaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
####################################################################################################
####################################################################################################
from pathlib import Path
import yaml
from .StandardMeasurement import Measurement, StandardMeasurement
####################################################################################################
class ValentinaMeasurement(Measurement):
##############################################
def __init__(self, code, name, full_name, description, default_value):
super().__init__(name, full_name, description, default_value)
self._code = code
##############################################
@property
def code(self):
return self._code
@code.setter
def code(self, value):
self._code = value
####################################################################################################
class ValentinaStandardMeasurement(StandardMeasurement):
##############################################
def __init__(self):
super().__init__()
yaml_path = Path(__file__).parent.joinpath('data', 'valentina-standard-measurements.yaml')
with open(yaml_path, 'r') as fh:
data = yaml.load(fh.read())
for topic in data.values():
for code, measurement_data in topic['measurements'].items():
measurement = ValentinaMeasurement(code, *measurement_data)
self.add(measurement)
......@@ -55,7 +55,6 @@ class NodeVisitor(ast.NodeVisitor):
##############################################
# def visit(self, node):
# print(node)
# super(NodeVisitor, self).visit(node)
......@@ -71,7 +70,9 @@ class NodeVisitor(ast.NodeVisitor):
dag = self._calculator.dag
if function.attr == '_function_Line': # catched _function_Line.__calculator__
for arg in node.args:
self._dependencies.append(self._calculator._name_to_point(arg.s))
dependence = self._calculator._name_to_point(arg.s)
self._dependencies.append(dependence)
self.generic_visit(node)
####################################################################################################
......@@ -89,9 +90,14 @@ class Calculator:
self._measurements = measurements
self._dag = DirectedAcyclicGraph()
self._cache = {'__calculator__': self}
self._cache = {'__calculator__': self} # used to eval expressions
self._points = {}
self._current_operation = None
self._current_operation = None # Fixme: ???
self._current_segment = None
if measurements is not None:
for measurement in measurements:
self._cache[measurement.name] = float(measurement)
##############################################
......@@ -112,17 +118,9 @@ class Calculator:
def set_current_segment(self, vector):
self._current_segment = vector
##############################################
def unset_current_segment(self):
self._current_segment = None
# self._logger.info('Unset current segment')
##############################################
def _update_cache(self, named_expression):
# Fixme: private ???
self._cache[named_expression.name] = named_expression.value
# self._logger.debug('Unset current segment')
##############################################
......@@ -149,6 +147,9 @@ class Calculator:
# Define special functions
#
# See in Valentina source
# libs/ifc/ifcdef.cpp
# Fixme: special functions
# increments ?
# Length of curve: Spl_A_B
......@@ -259,7 +260,7 @@ class Expression:
def _compile(self):
expression = self._expression
self._logger.info("expression '{}'".format(expression))
self._logger.debug("expression '{}'".format(expression))
# Python don't accept identifier starting with @
# Replace @foo by __custom__foo
......@@ -296,16 +297,16 @@ class Expression:
break
else:
functions.append(name)
# self._logger.info('Functions ' + str(functions))
# self._logger.debug('Functions ' + str(functions))
for function_call in functions:
parts = function_call.split('_')
function = parts[0]
args = parts[1:]
pythonised_function = '__calculator__._function_' + function + '(' + ', '.join(["'{}'".format(x) for x in args]) + ')'
# self._logger.info('Function {} {} -> {}'.format(function, args, pythonised_function))
# self._logger.debug('Function {} {} -> {}'.format(function, args, pythonised_function))
expression = expression.replace(function_call, pythonised_function)
self._logger.info("Pythonised expression '{}'".format(expression))
self._logger.debug("Pythonised expression '{}'".format(expression))
# Fixme: What is the (supported) grammar ?
# http://beltoforion.de/article.php?a=muparser
......@@ -343,7 +344,7 @@ class Expression:
# self._logger.warning(e)
# self._value = None
self._logger.info('Eval {} = {}'.format(self._expression, self._value))
self._logger.debug('Eval {} = {}'.format(self._expression, self._value))
##############################################
......
......@@ -18,16 +18,15 @@
#
####################################################################################################
"""
"""
####################################################################################################
import logging
from IntervalArithmetic import Interval2D
from Patro.GeometryEngine.Vector import Vector2D
from Patro.GraphicEngine.GraphicScene.GraphicItem import PathStyle
from Patro.GraphicEngine.GraphicScene.Scene import GraphicScene
from . import Calculation
from Patro.Common.Object import ObjectNameMixin
from .Sketch import Sketch
####################################################################################################
......@@ -35,14 +34,10 @@ _module_logger = logging.getLogger(__name__)
####################################################################################################
def vector_to_interval2d(vector):
x, y = vector.x, vector.y
return Interval2D((x, x), (y, y))
####################################################################################################
class Pattern:
"""Class to implement the root of a pattern"""
_logger = _module_logger.getChild('Pattern')
##############################################
......@@ -50,21 +45,16 @@ class Pattern:
def __init__(self, measurements, unit):
self._measurements = measurements
self._calculator = measurements.calculator
self._calculations = []
self._calculation_dict = {}
self._unit = unit
self._scopes = [] # not a dict so as to don't manage renaming
##############################################
@property
def measurements(self):
return self._measurements
@property
def calculator(self):
return self._calculator
@property
def unit(self):
return self._unit
......@@ -72,142 +62,68 @@ class Pattern:
##############################################
@property
def calculations(self):
return self._calculations
def scopes(self):
return iter(self._scopes)
##############################################
def _add_calculation(self, calculation):
# Works as a post init
self._calculations.append(calculation)
self._calculation_dict[calculation.id] = calculation
if hasattr(calculation, 'name'):
self._calculation_dict[calculation.name] = calculation
def scope_names(self):
return [scope.name for scope in self._scopes]
##############################################
def get_calculation_id(self):
return len(self._calculations) + 1 # id > 0
def add_scope(self, name):
scope = PatternScope(self, name)
self._scopes.append(scope)
return scope
##############################################
def has_calculation_id(self, id):
return id in self._calculation_dict
##############################################
def get_calculation(self, id):
return self._calculation_dict[id]
##############################################
def scope(self, id):
def get_point(self, name):
return self._points[name]
# Fixem: try ? for slice
if isinstance(id, int):
return self._scopes[id]
else:
for scope in self._scopes:
if scope.name == id:
return scope
return None
##############################################
def eval(self):
def remove_scope(self, name):
scope = self.scope(name)
if scope is not None:
self._scopes.remove(scope)
self._logger.info('Eval all calculations')
for calculation in self._calculations:
if isinstance(calculation, Calculation.Point):
self._calculator.add_point(calculation)
calculation.eval()
elif isinstance(calculation, Calculation.SimpleInteractiveSpline):
calculation.eval() # for control points
else:
pass
calculation.connect_ancestor_for_expressions()
####################################################################################################
##############################################
class PatternScope(ObjectNameMixin):
def dump(self):
"""Class to implement a pattern scope"""
print("\nDump calculations:")
for calculation in self._calculations:
if isinstance(calculation, Calculation.Point):
print(calculation, calculation.vector)
else:
print(calculation)
for dependency in calculation.dependencies:
print(' ->', dependency)
_logger = _module_logger.getChild('Pattern')
##############################################
@property
def bounding_box(self):
"""Compute the bounding box of the pattern."""
def __init__(self, pattern, name):
bounding_box = None
for calculation in self._calculations:
interval = calculation.geometry().bounding_box
print(calculation.geometry(), interval)
if bounding_box is None:
bounding_box = interval
else:
bounding_box |= interval
super().__init__(name)
self._pattern = pattern
return bounding_box
self._sketch = Sketch(self)
##############################################
def _calculation_to_path_style(self, calculation, **kwargs):
return PathStyle(
stroke_style=calculation.line_style,
stroke_color=calculation.line_color,
**kwargs
)
##############################################
@property
def measurements(self):
return self._pattern.measurements
def detail_scene(self):
"""Generate a graphic scene for the detail mode"""
scene = GraphicScene()
# Fixme: scene bounding box
scene.bounding_box = self.bounding_box
# Fixme: implement a transformer class to prevent if ... ?
for calculation in self._calculations:
if isinstance(calculation, Calculation.Point):
scene.add_coordinate(calculation.name, calculation.vector)
scene.add_circle(calculation.name, '1pt', PathStyle(fill_color='black'))
label_offset = calculation.label_offset
offset = Vector2D(label_offset.x, -label_offset.y) # Fixme: ???
label_position = calculation.vector + offset
if offset:
# arrow must point to the label center and be clipped
scene.add_segment(calculation.vector, label_position, PathStyle(line_width='.5pt'))
scene.add_text(label_position, calculation.name)
if isinstance(calculation, Calculation.LinePropertiesMixin):
path_style = self._calculation_to_path_style(calculation, line_width='2pt')
if isinstance(calculation, Calculation.AlongLinePoint):
scene.add_segment(calculation.first_point.name, calculation.name, path_style)
elif isinstance(calculation, Calculation.EndLinePoint):
scene.add_segment(calculation.base_point.name, calculation.name, path_style)
# elif isinstance(calculation, LineIntersectPoint):
# scene.add_segment(calculation.point1_line1.name, calculation.name, path_style)
# source += r'\draw[{0}] ({1.point1_line1.name}) -- ({1.name});'.format(style, calculation) + '\n'
elif isinstance(calculation, Calculation.NormalPoint):
scene.add_segment(calculation.first_point.name, calculation.name, path_style)
elif isinstance(calculation, Calculation.Line):
path_style = self._calculation_to_path_style(calculation, line_width='4pt')
scene.add_segment(calculation.first_point.name, calculation.second_point.name, path_style)
elif isinstance(calculation, Calculation.SimpleInteractiveSpline):
path_style = self._calculation_to_path_style(calculation, line_width='4pt')
scene.add_cubic_bezier(calculation.first_point.name,
calculation.control_point1, calculation.control_point2,
calculation.second_point.name,
path_style)
return scene
@property
def unit(self):
return self._pattern._unit
@property
def sketch(self):
return self._sketch
####################################################################################################
#
# Patro - A Python library to make patterns for fashion design
# Copyright (C) 2017 Fabrice Salvaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
####################################################################################################
"""
"""
####################################################################################################
import logging
from Patro.GeometryEngine.Vector import Vector2D
from Patro.GraphicEngine.GraphicScene.GraphicItem import GraphicPathStyle, Font
from Patro.GraphicEngine.GraphicScene.Scene import GraphicScene
from . import SketchOperation
from .Calculator import Calculator
####################################################################################################
_module_logger = logging.getLogger(__name__)
####################################################################################################
class Sketch:
# Fixme:
# do we want to have several sketches
# apply a transformation
# share points
_logger = _module_logger.getChild('Sketch')
##############################################
def __init__(self, pattern):
self._pattern = pattern
self._calculator = Calculator(self.measurements)
self._operations = []
self._operation_dict = {}
##############################################
@property
def pattern(self):
return self._pattern
@property
def measurements(self):
return self._pattern.measurements
@property
def calculator(self):
return self._calculator
@property
def unit(self):
return self._pattern.unit
##############################################
@property
def operations(self):
return self._operations
##############################################
def _add_operation(self, operation):
# Works as a post init
self._operations.append(operation)
# Fixme: operation id, only for valentina ?
self._operation_dict[operation.id] = operation
if hasattr(operation, 'name'):
self._operation_dict[operation.name] = operation
##############################################
def has_operation_id(self, id):
return id in self._operation_dict
##############################################
def get_operation(self, id):
return self._operation_dict[id]
##############################################
def eval(self):
self._logger.info('Eval all operations')
for operation in self._operations:
if isinstance(operation, SketchOperation.Point):
self._calculator.add_point(operation)
operation.eval()
elif isinstance(operation, SketchOperation.SimpleInteractiveSpline):
operation.eval() # for control points
else:
pass
operation.connect_ancestor_for_expressions()
##############################################
def dump(self):
print("\nDump operations:")
for operation in self._operations:
if isinstance(operation, SketchOperation.Point):
print(operation, operation.vector)
else:
print(operation)
for dependency in operation.dependencies:
print(' ->', dependency)
##############################################
@property
def bounding_box(self):
"""Compute the bounding box of the pattern."""
# Fixme: to function
# cache ???
bounding_box = None
for operation in self._operations:
interval = operation.geometry().bounding_box
if bounding_box is None:
bounding_box = interval
else:
bounding_box |= interval
return bounding_box
##############################################
def _operation_to_path_style(self, operation, **kwargs):
"""Generate a :class:`GraphicPathStyle` instance for a operation"""
return GraphicPathStyle(
stroke_style=operation.line_style,
stroke_color=operation.line_color,
**kwargs
)
##############################################
def detail_scene(self, scene_cls=GraphicScene):
"""Generate a graphic scene for the detail mode
Scene class can be customised using the *scene_cls* parameter.
"""
scene = scene_cls()
# Fixme: scene bounding box
scene.bounding_box = self.bounding_box
# Fixme: implement a transformer class to prevent if ... ?
font = Font('', 16)
for operation in self._operations:
if isinstance(operation, SketchOperation.Point):
# Register coordinate
scene.add_coordinate(operation.name, operation.vector)
# Draw point and label
scene.circle(operation.name, '1pt',
GraphicPathStyle(fill_color='black'),
user_data=operation,
)
label_offset = operation.label_offset
offset = Vector2D(label_offset.x, -label_offset.y) # Fixme: ???
label_position = operation.vector + offset
if offset:
# arrow must point to the label center and be clipped
scene.segment(operation.vector, label_position,
GraphicPathStyle(line_width='.5pt'),
user_data=operation,
)
scene.text(label_position, operation.name, font, user_data=operation)
if isinstance(operation, SketchOperation.LinePropertiesMixin):
path_style = self._operation_to_path_style(operation, line_width='2pt')
if isinstance(operation, SketchOperation.AlongLinePoint):
scene.segment(operation.first_point.name, operation.name,
path_style,
user_data=operation,
)
elif isinstance(operation, SketchOperation.EndLinePoint):
scene.segment(operation.base_point.name, operation.name,
path_style,
user_data=operation,
)
# elif isinstance(operation, LineIntersectPoint):
# scene.segment(operation.point1_line1.name, operation.name, path_style)
# source += r'\draw[{0}] ({1.point1_line1.name}) -- ({1.name});'.format(style, operation) + '\n'
elif isinstance(operation, SketchOperation.NormalPoint):
scene.segment(operation.first_point.name, operation.name,
path_style,
user_data=operation,
)
# Draw path item like segments and Bézier curves
elif isinstance(operation, SketchOperation.Line):
path_style = self._operation_to_path_style(operation, line_width='4pt')
scene.segment(operation.first_point.name, operation.second_point.name,
path_style,
user_data=operation,
)
elif isinstance(operation, SketchOperation.SimpleInteractiveSpline):
path_style = self._operation_to_path_style(operation, line_width='4pt')
scene.cubic_bezier(operation.first_point.name,
operation.control_point1, operation.control_point2,
operation.second_point.name,
path_style,
user_data=operation,
)
return scene
......@@ -18,10 +18,10 @@
#
####################################################################################################
"""This module defines all the calculations supported by the pattern engine, e.g. the intersection
between two lines.
"""This module defines all the sketch operations supported by the pattern engine, e.g. the
intersection between two lines.
A calculation must be build from the corresponding method of the Pattern class.
A sketch operation must be build from the corresponding method of the Pattern class.
"""
......@@ -29,6 +29,7 @@ A calculation must be build from the corresponding method of the Pattern class.
import logging
from Patro.Common.Object import ObjectGlobalIdMixin
from Patro.GeometryEngine.Bezier import CubicBezier2D
from Patro.GeometryEngine.Line import Line2D
from Patro.GeometryEngine.Segment import Segment2D
......@@ -49,40 +50,38 @@ def quote(x):
####################################################################################################
### class CalculationMetaClass:
### class SketchOperationMetaClass:
###
### _logger = _module_logger.getChild('CalculationMetaClass')
### _logger = _module_logger.getChild('SketchOperationMetaClass')
###
### ##############################################
###
### def __init__(cls, class_name, super_classes, class_attribute_dict):
### # cls._logger.info(str((cls, class_name, super_classes, class_attribute_dict)))
### # cls._logger.debug(str((cls, class_name, super_classes, class_attribute_dict)))
### type.__init__(cls, class_name, super_classes, class_attribute_dict)
####################################################################################################
# metaclass = CalculationMetaClass
class Calculation():
# metaclass = SketchOperationMetaClass
class SketchOperation(ObjectGlobalIdMixin):
"""Baseclass for calculation"""
"""Baseclass for sketch operation"""
_logger = _module_logger.getChild('Calculation')
_logger = _module_logger.getChild('SketchOperation')
##############################################
def __init__(self, pattern, id=None):
def __init__(self, sketch, id=None):
self._pattern = pattern
self._sketch = sketch
# Valentina set an incremental integer id for each calculation (entity)
# id is used to identify operation, see _get_operation
# A calculation which generate a point has also a name
if id is None:
self._id = pattern.get_calculation_id()
else:
if pattern.has_calculation_id(id):
raise NameError("calculation id {} is already attributed".format(id))
else:
self._id = id
try:
super().__init__(id)
except ValueError:
raise NameError("id {} is already attributed".format(id))
self._dag_node = self._dag.add_node(pyid(self), data=self)
self._dependencies = set()
......@@ -90,16 +89,12 @@ class Calculation():
##############################################
@property
def id(self):
return self._id
@property
def pattern(self):
return self._pattern
def sketch(self):
return self._sketch
@property
def _dag(self):
return self._pattern.calculator.dag
return self._sketch.calculator.dag
@property
def dependencies(self):
......@@ -107,39 +102,29 @@ class Calculation():
##############################################
def __repr__(self):
return self.__class__.__name__ + ' {0._id}'.format(self)
##############################################
def __int__(self):
return self._id
##############################################
def _get_calculation(self, calculation):
def _get_operation(self, operation):
"""Return the corresponding :obj:`Calculation` object where *calculation* can be
:obj:`Calculation` instance, an id or a name.
"""Return the corresponding :obj:`SketchOperation` object where *operation* can be
:obj:`SketchOperation` instance, an id or a name.
"""
if isinstance(calculation, Calculation):
return calculation
# elif isinstance(calculation, (int, str)):
if isinstance(operation, SketchOperation):
return operation
# elif isinstance(operation, (int, str)):
else: # must be id or string
return self._pattern.get_calculation(calculation)
return self._sketch.get_operation(operation)
##############################################
def eval(self):
self._logger.info('Eval {}'.format(self))
self._logger.debug('Eval {}'.format(self))
self.eval_internal()
##############################################
def eval_internal(self):
"""Code to evaluate the calculation in subclasses, i.e. to compute internal states like points."""
"""Code to evaluate the operation in subclasses, i.e. to compute internal states like points."""
pass
##############################################
......@@ -149,30 +134,30 @@ class Calculation():
# cf. to_python
args = self.__init__.__code__.co_varnames
args = args[2:-1] # remove self, pattern, id
args = args[2:-1] # remove self, sketch, id
return args
##############################################
def to_python(self):
"""Return the Python code for the calculation"""
"""Return the Python code for the operation"""
args = self._init_args()
values = []
for arg in args:
value = getattr(self, arg)
# if arg == 'pattern':
# value_str = 'pattern'
# if isinstance(value, Pattern):
# value_str = 'pattern'
# if arg == 'sketch':
# value_str = 'sketch'
# if isinstance(value, Sketch):
# value_str = 'sketch'
if value is None:
value_str = 'None'
elif isinstance(value, (int, float)):
value_str = str(value)
elif isinstance(value, str):
value_str = quote(value)
# elif isinstance(value, Calculation):
# elif isinstance(value, SketchOperation):
# value_str = str(value.id)
elif isinstance(value, Point):
value_str = quote(value.name)
......@@ -186,7 +171,7 @@ class Calculation():
else:
value_str = ''
values.append(value_str)
kwargs = ', '.join(['pattern'] + [key + '=' + value for key, value in zip(args, values)])
kwargs = ', '.join(['sketch'] + [key + '=' + value for key, value in zip(args, values)])
return self.__class__.__name__ + '(' + kwargs + ')'
##############################################
......@@ -259,8 +244,8 @@ class FirstSecondPointMixin:
##############################################
def __init__(self, first_point, second_point):
self._first_point = self._get_calculation(first_point)
self._second_point = self._get_calculation(second_point)
self._first_point = self._get_operation(first_point)
self._second_point = self._get_operation(second_point)
self._connect_ancestor(self._first_point, self._second_point)
##############################################
......@@ -280,7 +265,7 @@ class BasePointMixin:
##############################################
def __init__(self, base_point):
self._base_point = self._get_calculation(base_point)
self._base_point = self._get_operation(base_point)
self._connect_ancestor(self._base_point)
##############################################
......@@ -296,7 +281,7 @@ class LengthMixin:
##############################################
def __init__(self, length):
self._length = Expression(length, self._pattern.calculator)
self._length = Expression(length, self._sketch.calculator)
# self._connect_ancestor_for_expressions(self._length)
##############################################
......@@ -312,7 +297,7 @@ class AngleMixin:
##############################################
def __init__(self, angle):
self._angle = Expression(angle, self._pattern.calculator)
self._angle = Expression(angle, self._sketch.calculator)
# self._connect_ancestor_for_expressions(self._angle)
##############################################
......@@ -333,15 +318,15 @@ class LengthAngleMixin(LengthMixin, AngleMixin):
####################################################################################################
class Point(Calculation):
class Point(SketchOperation):
"""Base class for point."""
##############################################
def __init__(self, pattern, name, label_offset, id=None):
def __init__(self, sketch, name, label_offset, id=None):
Calculation.__init__(self, pattern, id)
SketchOperation.__init__(self, sketch, id)
self._name = name
self._label_offset = label_offset
......@@ -364,7 +349,7 @@ class Point(Calculation):
##############################################
def _post_eval_internal(self):
self._logger.info('{0._name} {0._vector}'.format(self))
self._logger.debug('{0._name} {0._vector}'.format(self))
##############################################
......@@ -379,15 +364,15 @@ class SinglePoint(Point):
##############################################
def __init__(self, pattern, name,
def __init__(self, sketch, name,
x, y,
label_offset,
id=None
):
Point.__init__(self, pattern, name, label_offset, id)
self._x = Expression(x, pattern.calculator)
self._y = Expression(y, pattern.calculator)
Point.__init__(self, sketch, name, label_offset, id)
self._x = Expression(x, sketch.calculator)
self._y = Expression(y, sketch.calculator)
# self._connect_ancestor_for_expressions(self._x, self._y)
##############################################
......@@ -419,14 +404,14 @@ class AlongLinePoint(Point, LinePropertiesMixin, FirstSecondPointMixin, LengthMi
##############################################
def __init__(self, pattern, name,
def __init__(self, sketch, name,
first_point, second_point, length,
label_offset,
line_style=None, line_color=None,
id=None,
):
Point.__init__(self, pattern, name, label_offset, id)
Point.__init__(self, sketch, name, label_offset, id)
LinePropertiesMixin.__init__(self, line_style, line_color)
FirstSecondPointMixin.__init__(self, first_point, second_point)
LengthMixin.__init__(self, length)
......@@ -441,9 +426,9 @@ class AlongLinePoint(Point, LinePropertiesMixin, FirstSecondPointMixin, LengthMi
def eval_internal(self):
vector = self._second_point.vector - self._first_point.vector
self._pattern.calculator.set_current_segment(vector)
self._sketch.calculator.set_current_segment(vector)
self._vector = self._first_point.vector + vector.to_normalised()*self._length.value
self._pattern.calculator.unset_current_segment()
self._sketch.calculator.unset_current_segment()
self._post_eval_internal()
####################################################################################################
......@@ -454,14 +439,14 @@ class EndLinePoint(Point, LinePropertiesMixin, BasePointMixin, LengthAngleMixin)
##############################################
def __init__(self, pattern, name,
def __init__(self, sketch, name,
base_point, angle, length,
label_offset,
line_style=None, line_color=None,
id=None,
):
Point.__init__(self, pattern, name, label_offset, id)
Point.__init__(self, sketch, name, label_offset, id)
LinePropertiesMixin.__init__(self, line_style, line_color)
BasePointMixin.__init__(self, base_point)
LengthAngleMixin.__init__(self, length, angle)
......@@ -486,17 +471,17 @@ class LineIntersectPoint(Point):
##############################################
def __init__(self, pattern, name,
def __init__(self, sketch, name,
point1_line1, point2_line1, point1_line2, point2_line2,
label_offset,
id=None,
):
Point.__init__(self, pattern, name, label_offset, id)
self._point1_line1 = self._get_calculation(point1_line1)
self._point2_line1 = self._get_calculation(point2_line1)
self._point1_line2 = self._get_calculation(point1_line2)
self._point2_line2 = self._get_calculation(point2_line2)
Point.__init__(self, sketch, name, label_offset, id)
self._point1_line1 = self._get_operation(point1_line1)
self._point2_line1 = self._get_operation(point2_line1)
self._point1_line2 = self._get_operation(point1_line2)
self._point2_line2 = self._get_operation(point2_line2)
self._connect_ancestor(self._point1_line1, self._point2_line1,
self._point1_line2, self._point2_line2)
......@@ -540,14 +525,14 @@ class NormalPoint(Point, LinePropertiesMixin, FirstSecondPointMixin, LengthAngle
##############################################
def __init__(self, pattern, name,
def __init__(self, sketch, name,
first_point, second_point, angle, length,
label_offset,
line_style=None, line_color=None,
id=None,
):
Point.__init__(self, pattern, name, label_offset, id)
Point.__init__(self, sketch, name, label_offset, id)
LinePropertiesMixin.__init__(self, line_style, line_color)
FirstSecondPointMixin.__init__(self, first_point, second_point)
LengthAngleMixin.__init__(self, length, angle)
......@@ -562,14 +547,14 @@ class NormalPoint(Point, LinePropertiesMixin, FirstSecondPointMixin, LengthAngle
def eval_internal(self):
vector = self._second_point.vector - self._first_point.vector
self._pattern.calculator.set_current_segment(vector)
self._sketch.calculator.set_current_segment(vector)
direction = vector.to_normalised()
direction = direction.normal
angle = self._angle.value
if angle:
direction = direction.rotate(angle)
self._vector = self._first_point.vector + direction*self._length.value
self._pattern.calculator.unset_current_segment()
self._sketch.calculator.unset_current_segment()
self._post_eval_internal()
####################################################################################################
......@@ -580,13 +565,13 @@ class PointOfIntersection(Point, FirstSecondPointMixin):
##############################################
def __init__(self, pattern, name,
def __init__(self, sketch, name,
first_point, second_point,
label_offset,
id=None,
):
Point.__init__(self, pattern, name, label_offset, id)
Point.__init__(self, sketch, name, label_offset, id)
FirstSecondPointMixin.__init__(self, first_point, second_point)
##############################################
......@@ -602,19 +587,19 @@ class PointOfIntersection(Point, FirstSecondPointMixin):
####################################################################################################
class Line(Calculation, LinePropertiesMixin, FirstSecondPointMixin):
class Line(SketchOperation, LinePropertiesMixin, FirstSecondPointMixin):
"""Construct a line defined by two points"""
##############################################
def __init__(self, pattern,
def __init__(self, sketch,
first_point, second_point,
line_style='solid', line_color='black',
id=None,
):
Calculation.__init__(self, pattern, id)
SketchOperation.__init__(self, sketch, id)
LinePropertiesMixin.__init__(self, line_style, line_color)
FirstSecondPointMixin.__init__(self, first_point, second_point)
......@@ -635,13 +620,13 @@ class Line(Calculation, LinePropertiesMixin, FirstSecondPointMixin):
####################################################################################################
class SimpleInteractiveSpline(Calculation, LinePropertiesMixin, FirstSecondPointMixin):
class SimpleInteractiveSpline(SketchOperation, LinePropertiesMixin, FirstSecondPointMixin):
""""Construct a quadratic Bezier curve from two extremity points and two control points"""
##############################################
def __init__(self, pattern,
def __init__(self, sketch,
first_point, second_point,
angle1, length1,
angle2, length2,
......@@ -649,13 +634,13 @@ class SimpleInteractiveSpline(Calculation, LinePropertiesMixin, FirstSecondPoint
id=None,
):
Calculation.__init__(self, pattern, id)
SketchOperation.__init__(self, sketch, id)
LinePropertiesMixin.__init__(self, line_style, line_color)
FirstSecondPointMixin.__init__(self, first_point, second_point)
self._angle1 = Expression(angle1, pattern.calculator)
self._length1 = Expression(length1, pattern.calculator)
self._angle2 = Expression(angle2, pattern.calculator)
self._length2 = Expression(length2, pattern.calculator)
self._angle1 = Expression(angle1, sketch.calculator)
self._length1 = Expression(length1, sketch.calculator)
self._angle2 = Expression(angle2, sketch.calculator)
self._length2 = Expression(length2, sketch.calculator)
# self._connect_ancestor_for_expressions(self._angle1, self._length1, self._angle2, self._length2)
self._control_point1 = None # Fixme: not yet computed
......@@ -700,7 +685,7 @@ class SimpleInteractiveSpline(Calculation, LinePropertiesMixin, FirstSecondPoint
control_point2_offset = Vector2D.from_angle(self._angle2.value)*self._length2.value
self._control_point1 = self.first_point.vector + control_point1_offset
self._control_point2 = self.second_point.vector + control_point2_offset
# self._logger.info("Control points : {} {}".format(self._control_point1, self._control_point2))
# self._logger.debug("Control points : {} {}".format(self._control_point1, self._control_point2))
##############################################
......
......@@ -26,29 +26,29 @@
import inspect
from . import Calculation
from .Pattern import Pattern
from . import SketchOperation
from .Sketch import Sketch
####################################################################################################
def _get_calculations(module):
def _get_sketch_operations(module):
return [item
for item in module.__dict__.values()
if inspect.isclass(item) and issubclass(item, Calculation.Calculation)]
if inspect.isclass(item) and issubclass(item, SketchOperation.SketchOperation)]
####################################################################################################
_calculations = _get_calculations(Calculation)
_sketch_operations = _get_sketch_operations(SketchOperation)
for calculation_class in _calculations:
for operation_cls in _sketch_operations:
def _make_function(calculation_class):
def _make_function(operation_cls):
def function(self, *args, **kwargs):
calculation = calculation_class(self, *args, **kwargs)
self._add_calculation(calculation)
return calculation
sketch_operation = operation_cls(self, *args, **kwargs)
self._add_operation(sketch_operation)
return sketch_operation
return function
function_name = calculation_class.__name__
function_name = operation_cls.__name__
setattr(Pattern, function_name, _make_function(calculation_class))
setattr(Sketch, function_name, _make_function(operation_cls))
####################################################################################################
#
# Patro - A Python library to make patterns for fashion design
# Copyright (C) 2017 Fabrice Salvaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
####################################################################################################
__all__ = [
'QmlApplication',
]
####################################################################################################
import argparse
import logging
import sys
from pathlib import Path
from QtShim.QtCore import (
Property, Signal, QObject,
Qt, QTimer, QUrl,
)
from QtShim.QtGui import QGuiApplication
from QtShim.QtQml import qmlRegisterType, QQmlApplicationEngine
# Fixme: PYSIDE-574 qmlRegisterSingletonType and qmlRegisterUncreatableType missing in QtQml
from QtShim.QtQml import qmlRegisterUncreatableType
from QtShim.QtQuick import QQuickPaintedItem, QQuickView
# from QtShim.QtQuickControls2 import QQuickStyle
from Patro.GraphicEngine.Painter.QtPainter import QtScene, QtQuickPaintedSceneItem
from .rcc import PatroRessource
####################################################################################################
_module_logger = logging.getLogger(__name__)
####################################################################################################
class QmlApplication(QObject):
_logger = _module_logger.getChild('QmlApplication')
##############################################
def __init__(self, application):
super().__init__()
self._application = application
self._scene = None
##############################################
sceneChanged = Signal()
@Property(QtScene, notify=sceneChanged)
def scene(self):
return self._scene
@scene.setter
def scene(self, scene):
if self._scene is not scene:
print('QmlApplication set scene', scene)
self._logger.info('set scene') # Fixme: don't print ???
self._scene = scene
self.sceneChanged.emit()
####################################################################################################
class PathAction(argparse.Action):
##############################################
def __call__(self, parser, namespace, values, option_string=None):
if values is not None:
if isinstance(values, list):
path = [Path(x) for x in values]
else:
path = Path(values)
else:
path = None
setattr(namespace, self.dest, path)
####################################################################################################
class Application(QObject):
instance = None
_logger = _module_logger.getChild('Application')
##############################################
# Fixme: Singleton
@classmethod
def create(cls, *args, **kwargs):
if cls.instance is not None:
raise NameError('Instance exists')
cls.instance = cls(*args, **kwargs)
return cls.instance
##############################################
def __init__(self):
super().__init__()
self._parse_arguments()
self._appplication = QGuiApplication(sys.argv)
self._engine = QQmlApplicationEngine()
self._qml_application = QmlApplication(self)
self._scene = None
# self._load_translation()
self._register_qml_types()
self._set_context_properties()
self._load_qml_main()
# self._run_before_event_loop()
QTimer.singleShot(0, self._post_init)
# self._view = QQuickView()
# self._view.setResizeMode(QQuickView.SizeRootObjectToView)
# self._view.setSource(qml_url)
##############################################
@property
def args(self):
return self._args
@property
def qml_application(self):
return self._qml_application
##############################################
@classmethod
def setup_gui_application(cls):
# QGuiApplication.setApplicationName(APPLICATION_NAME)
# QGuiApplication.setOrganizationName(ORGANISATION_NAME)
QGuiApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
# QQuickStyle.setStyle('Material')
##############################################
def _parse_arguments(self):
parser = argparse.ArgumentParser(
description='Patro',
)
# parser.add_argument(
# '--version',
# action='store_true', default=False,
# help="show version and exit",
# )
parser.add_argument(
'--user-script',
action=PathAction,
default=None,
help='user script to execute',
)
parser.add_argument(
'--user-script-args',
default='',
help="user script args (don't forget to quote)",
)
self._args = parser.parse_args()
##############################################
# def _load_translationt(self):
# locale = QLocale()
# if m_translator.load(locale, '...', '.', ':/translations', '.qm'):
# m_application.installTranslator(m_translator)
# else:
# raise "No translator for locale" locale.name()
##############################################
def _register_qml_types(self):
qmlRegisterUncreatableType(QmlApplication, 'Patro', 1, 0, 'QmlApplication', 'Cannot create QmlApplication')
qmlRegisterUncreatableType(QtScene, 'Patro', 1, 0, 'QtScene', 'Cannot create QtScene')
# qmlRegisterType(QmlApplication, 'Patro', 1, 0, 'QmlApplication')
# qmlRegisterType(QtScene, 'Patro', 1, 0, 'QtScene')
qmlRegisterType(QtQuickPaintedSceneItem, 'Patro', 1, 0, 'PaintedSceneItem')
##############################################
def _set_context_properties(self):
context = self._engine.rootContext()
context.setContextProperty('application', self._qml_application)
##############################################
def _load_qml_main(self):
# self._engine.addImportPath('qrc:///qml')
qml_path = Path(__file__).parent.joinpath('qml', 'main.qml')
qml_url = QUrl.fromLocalFile(str(qml_path))
# QUrl('qrc:/qml/main.qml')
self._engine.load(qml_url)
##############################################
def exec_(self):
# self._view.show()
sys.exit(self._appplication.exec_())
##############################################
def _post_init(self):
# Fixme: ui refresh ???
self._logger.info('post init')
if self._args.user_script is not None:
self.execute_user_script(self._args.user_script)
##############################################
def execute_user_script(self, script_path):
"""Execute an user script provided by file *script_path* in a context where is defined a variable
*application* that is a reference to the application instance.
"""
script_path = Path(script_path).absolute()
self._logger.info('Execute user script: {}'.format(script_path))
try:
source = open(script_path).read()
except FileNotFoundError:
self._logger.info('File {} not found'.format(script_path))
sys.exit(1)
bytecode = compile(source, script_path, 'exec')
exec(bytecode, {'application':self})
self._logger.info('User script done')
/***************************************************************************************************
*
* Patro - A Python library to make patterns for fashion design
* Copyright (C) 2017 Fabrice Salvaire
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
***************************************************************************************************/
import QtQuick 2.11
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
import Patro 1.0
ApplicationWindow {
id: application_window
title: 'Patro'
visible: true
width: 1000
height: 500
property int zoom_step: 10
Component.onCompleted: {
console.info('ApplicationWindow.onCompleted')
// application_window.showMaximized()
}
menuBar: MenuBar {
Menu {
title: qsTr('&File')
Action { text: qsTr('&Open') }
MenuSeparator { }
Action {
text: qsTr('&Quit')
onTriggered: application_window.close()
}
}
Menu {
title: qsTr('&Help')
Action { text: qsTr('&About') }
}
}
header: ToolBar {
RowLayout {
anchors.fill: parent
ToolButton {
icon.source: 'qrc:/icons/36x36/settings-overscan-black.png'
onClicked: scene_view.fit_scene()
}
ToolButton {
icon.source: 'qrc:/icons/36x36/zoom-in-black.png'
onClicked: {
var zoom_factor = 1 + application_window.zoom_step/100
scene_view.zoom_at_center(scene_view.zoom*zoom_factor)
}
}
ToolButton {
icon.source: 'qrc:/icons/36x36/zoom-out-black.png'
onClicked: {
var zoom_factor = 1 - application_window.zoom_step/100
scene_view.zoom_at_center(scene_view.zoom*zoom_factor)
}
}
Item {
Layout.fillWidth: true
}
}
}
footer: ToolBar {
RowLayout {
anchors.fill: parent
Text {
id: position_label
text: ''
}
}
}
PaintedSceneItem {
id: scene_view
anchors.fill: parent
scene: application.scene
focus: true
property int pan_speed: 10
property int pan_step: 10
Keys.onLeftPressed: scene_view.pan_x_y(-pan_step, 0)
Keys.onRightPressed: scene_view.pan_x_y(pan_step, 0)
Keys.onDownPressed: scene_view.pan_x_y(0, -pan_step)
Keys.onUpPressed: scene_view.pan_x_y(0, pan_step)
function pan_x_y(dx, dy) {
var dxy = Qt.point(dx, dy)
console.info('pan', dxy)
scene_view.pan(dxy)
}
MouseArea {
id: scene_mouse_area
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
// var point ???
property var mouse_start
Component.onCompleted: {
mouse_start = null
}
// onClicked: {
// if (mouse.button == Qt.LeftButton) {
// console.info('Mouse left', mouse.x, mouse.y)
// }
// }
onPressed: {
scene_view.focus = true
if (mouse.button == Qt.LeftButton) {
// console.info('Mouse left', mouse.x, mouse.y)
var position = Qt.point(mouse.x, mouse.y)
scene_view.item_at(position)
}
else if (mouse.button == Qt.MiddleButton) {
// console.info('Mouse left', mouse.x, mouse.y)
mouse_start = Qt.point(mouse.x, mouse.y)
}
}
onReleased: {
mouse_start = null
}
onPositionChanged: {
// console.info('onPositionChanged', mouse.button, mouse_start)
if (mouse_start !== null) {
var dx = (mouse.x - mouse_start.x) / scene_view.pan_speed
var dy = (mouse_start.y - mouse.y) / scene_view.pan_speed
// if (dx^2 + dy^2 > 100)
scene_view.pan_x_y(dx, dy)
mouse_start = Qt.point(mouse.x, mouse.y)
} else {
position_label.text = scene_view.format_coordinate(Qt.point(mouse.x, mouse.y))
}
}
onWheel: {
var direction = wheel.angleDelta.y > 0
console.info('Mouse wheel', wheel.x, wheel.y, direction)
var zoom = scene_view.zoom
if (direction)
zoom *= 2
else
zoom /= 2
scene_view.zoom_at(Qt.point(wheel.x, wheel.y), zoom)
}
}
}
}
# -*- Makefile -*-
####################################################################################################
all: patro.rcc PatroRessource.py
####################################################################################################
%.rcc : %.qrc
rcc-qt5 -binary $< -o $@
PatroRessource.py : patro.qrc
pyrcc5 -o $@ $<
####################################################################################################
clean:
rm *.py *.rcc
#! /bin/bash
# see https://material.io/icons/
PATH=$PWD/scripts:$PATH
# copy-icon action star_rate
copy-icon action book
copy-icon action delete
copy-icon action description
copy-icon action find_in_page
copy-icon action open_in_new
copy-icon action search
copy-icon action settings
copy-icon action settings_overscan
copy-icon action zoom_in
copy-icon action zoom_out
copy-icon alert error
copy-icon alert error_outline
copy-icon alert warning
copy-icon av playlist_add
copy-icon content add
copy-icon content add_box
copy-icon content add_circle
copy-icon content clear
copy-icon content create
copy-icon editor title
copy-icon image image
copy-icon file folder
copy-icon file folder_open
copy-icon navigation arrow_back
copy-icon navigation arrow_downward
copy-icon navigation arrow_forward
copy-icon navigation arrow_upward
copy-icon navigation cancel
copy-icon navigation chevron_left
copy-icon navigation chevron_right
copy-icon navigation close
copy-icon navigation first_page
copy-icon navigation last_page
copy-icon navigation refresh
copy-icon toggle star
copy-icon toggle star_border
#! /bin/bash
category=$1
name=$2
dp="36"
mdi_path="/home/doc/material-design-ressources/material-design-icons"
function copy_link() {
colour=$1
dpi=$2
scale=$3
subdir="${category}/drawable-${dpi}"
subdir_dest="../${dp}x${dp}"
src="ic_${name}_${colour}_${dp}dp.png"
target=$(tr "_" "-" <<<"${name}-${colour}${scale}.png")
mkdir -p ${subdir_dest}
cp ${mdi_path}/${subdir}/${src} ${subdir_dest}/${target}
# pushd ${subdir_dest}
# rm -f ${target}
# ln -sf ${src} ${target}
# popd
}
for colour in black ; do
copy_link ${colour} mdpi
done
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/">
<file>qtquickcontrols2.conf</file>
</qresource>
<qresource prefix="/">
<file>icons/36x36/settings-overscan-black.png</file>
<file>icons/36x36/zoom-fit-width.png</file>
<file>icons/36x36/zoom-out-black.png</file>
<file>icons/36x36/zoom-in-black.png</file>
</qresource>
</RCC>
####################################################################################################
"""Common members of all bindings
This is where each member of Qt.py is explicitly defined.
It is based on a 'lowest common denominator' of all bindings;
including members found in each of the 4 bindings.
The '_common_members' dictionary is generated using the
build_membership.sh script.
"""
_common_members = {
'QtCore': [
'QAbstractAnimation',
'QAbstractEventDispatcher',
'QAbstractItemModel',
'QAbstractListModel',
'QAbstractState',
'QAbstractTableModel',
'QAbstractTransition',
'QAnimationGroup',
'QBasicTimer',
'QBitArray',
'QBuffer',
'QByteArray',
'QByteArrayMatcher',
'QChildEvent',
'QCoreApplication',
'QCryptographicHash',
'QDataStream',
'QDate',
'QDateTime',
'QDir',
'QDirIterator',
'QDynamicPropertyChangeEvent',
'QEasingCurve',
'QElapsedTimer',
'QEvent',
'QEventLoop',
'QEventTransition',
'QFile',
'QFileInfo',
'QFileSystemWatcher',
'QFinalState',
'QGenericArgument',
'QGenericReturnArgument',
'QHistoryState',
'QItemSelectionRange',
'QIODevice',
'QLibraryInfo',
'QLine',
'QLineF',
'QLocale',
'QMargins',
'QMetaClassInfo',
'QMetaEnum',
'QMetaMethod',
'QMetaObject',
'QMetaProperty',
'QMimeData',
'QModelIndex',
'QMutex',
'QMutexLocker',
'QObject',
'QParallelAnimationGroup',
'QPauseAnimation',
'QPersistentModelIndex',
'QPluginLoader',
'QPoint',
'QPointF',
'QProcess',
'QProcessEnvironment',
'QPropertyAnimation',
'QReadLocker',
'QReadWriteLock',
'QRect',
'QRectF',
'QRegExp',
'QResource',
'QRunnable',
'QSemaphore',
'QSequentialAnimationGroup',
'QSettings',
'QSignalMapper',
'QSignalTransition',
'QSize',
'QSizeF',
'QSocketNotifier',
'QState',
'QStateMachine',
'QSysInfo',
'QSystemSemaphore',
'QT_TRANSLATE_NOOP',
'QT_TR_NOOP',
'QT_TR_NOOP_UTF8',
'QTemporaryFile',
'QTextBoundaryFinder',
'QTextCodec',
'QTextDecoder',
'QTextEncoder',
'QTextStream',
'QTextStreamManipulator',
'QThread',
'QThreadPool',
'QTime',
'QTimeLine',
'QTimer',
'QTimerEvent',
'QTranslator',
'QUrl',
'QVariantAnimation',
'QWaitCondition',
'QWriteLocker',
'QXmlStreamAttribute',
'QXmlStreamAttributes',
'QXmlStreamEntityDeclaration',
'QXmlStreamEntityResolver',
'QXmlStreamNamespaceDeclaration',
'QXmlStreamNotationDeclaration',
'QXmlStreamReader',
'QXmlStreamWriter',
'Qt',
'QtCriticalMsg',
'QtDebugMsg',
'QtFatalMsg',
'QtMsgType',
'QtSystemMsg',
'QtWarningMsg',
'qAbs',
'qAddPostRoutine',
'qChecksum',
'qCritical',
'qDebug',
'qFatal',
'qFuzzyCompare',
'qIsFinite',
'qIsInf',
'qIsNaN',
'qIsNull',
'qRegisterResourceData',
'qUnregisterResourceData',
'qVersion',
'qWarning',
'qrand',
'qsrand'
],
'QtGui': [
'QAbstractTextDocumentLayout',
'QActionEvent',
'QBitmap',
'QBrush',
'QClipboard',
'QCloseEvent',
'QColor',
'QConicalGradient',
'QContextMenuEvent',
'QCursor',
'QDesktopServices',
'QDoubleValidator',
'QDrag',
'QDragEnterEvent',
'QDragLeaveEvent',
'QDragMoveEvent',
'QDropEvent',
'QFileOpenEvent',
'QFocusEvent',
'QFont',
'QFontDatabase',
'QFontInfo',
'QFontMetrics',
'QFontMetricsF',
'QGradient',
'QGuiApplication',
'QHelpEvent',
'QHideEvent',
'QHoverEvent',
'QIcon',
'QIconDragEvent',
'QIconEngine',
'QImage',
'QImageIOHandler',
'QImageReader',
'QImageWriter',
'QInputEvent',
'QInputMethodEvent',
'QIntValidator',
'QKeyEvent',
'QKeySequence',
'QLinearGradient',
'QMatrix2x2',
'QMatrix2x3',
'QMatrix2x4',
'QMatrix3x2',
'QMatrix3x3',
'QMatrix3x4',
'QMatrix4x2',
'QMatrix4x3',
'QMatrix4x4',
'QMouseEvent',
'QMoveEvent',
'QMovie',
'QPaintDevice',
'QPaintEngine',
'QPaintEngineState',
'QPaintEvent',
'QPainter',
'QPainterPath',
'QPainterPathStroker',
'QPalette',
'QPen',
'QPicture',
'QPictureIO',
'QPixmap',
'QPixmapCache',
'QPolygon',
'QPolygonF',
'QQuaternion',
'QRadialGradient',
'QRegExpValidator',
'QRegion',
'QResizeEvent',
'QSessionManager',
'QShortcutEvent',
'QShowEvent',
'QStandardItem',
'QStandardItemModel',
'QStatusTipEvent',
'QSyntaxHighlighter',
'QTabletEvent',
'QTextBlock',
'QTextBlockFormat',
'QTextBlockGroup',
'QTextBlockUserData',
'QTextCharFormat',
'QTextCursor',
'QTextDocument',
'QTextDocumentFragment',
'QTextFormat',
'QTextFragment',
'QTextFrame',
'QTextFrameFormat',
'QTextImageFormat',
'QTextInlineObject',
'QTextItem',
'QTextLayout',
'QTextLength',
'QTextLine',
'QTextList',
'QTextListFormat',
'QTextObject',
'QTextObjectInterface',
'QTextOption',
'QTextTable',
'QTextTableCell',
'QTextTableCellFormat',
'QTextTableFormat',
'QTouchEvent',
'QTransform',
'QValidator',
'QVector2D',
'QVector3D',
'QVector4D',
'QWhatsThisClickedEvent',
'QWheelEvent',
'QWindowStateChangeEvent',
'qAlpha',
'qBlue',
'qGray',
'qGreen',
'qIsGray',
'qRed',
'qRgb',
'qRgba'
],
# 'QtHelp': [
# 'QHelpContentItem',
# 'QHelpContentModel',
# 'QHelpContentWidget',
# 'QHelpEngine',
# 'QHelpEngineCore',
# 'QHelpIndexModel',
# 'QHelpIndexWidget',
# 'QHelpSearchEngine',
# 'QHelpSearchQuery',
# 'QHelpSearchQueryWidget',
# 'QHelpSearchResultWidget'
# ],
# 'QtMultimedia': [
# 'QAbstractVideoBuffer',
# 'QAbstractVideoSurface',
# 'QAudio',
# 'QAudioDeviceInfo',
# 'QAudioFormat',
# 'QAudioInput',
# 'QAudioOutput',
# 'QVideoFrame',
# 'QVideoSurfaceFormat'
# ],
# 'QtNetwork': [
# 'QAbstractNetworkCache',
# 'QAbstractSocket',
# 'QAuthenticator',
# 'QHostAddress',
# 'QHostInfo',
# 'QLocalServer',
# 'QLocalSocket',
# 'QNetworkAccessManager',
# 'QNetworkAddressEntry',
# 'QNetworkCacheMetaData',
# 'QNetworkConfiguration',
# 'QNetworkConfigurationManager',
# 'QNetworkCookie',
# 'QNetworkCookieJar',
# 'QNetworkDiskCache',
# 'QNetworkInterface',
# 'QNetworkProxy',
# 'QNetworkProxyFactory',
# 'QNetworkProxyQuery',
# 'QNetworkReply',
# 'QNetworkRequest',
# 'QNetworkSession',
# 'QSsl',
# 'QTcpServer',
# 'QTcpSocket',
# 'QUdpSocket'
# ],
# 'QtOpenGL': [
# 'QGL',
# 'QGLContext',
# 'QGLFormat',
# 'QGLWidget'
# ],
# 'QtPrintSupport': [
# 'QAbstractPrintDialog',
# 'QPageSetupDialog',
# 'QPrintDialog',
# 'QPrintEngine',
# 'QPrintPreviewDialog',
# 'QPrintPreviewWidget',
# 'QPrinter',
# 'QPrinterInfo'
# ],
# 'QtSql': [
# 'QSql',
# 'QSqlDatabase',
# 'QSqlDriver',
# 'QSqlDriverCreatorBase',
# 'QSqlError',
# 'QSqlField',
# 'QSqlIndex',
# 'QSqlQuery',
# 'QSqlQueryModel',
# 'QSqlRecord',
# 'QSqlRelation',
# 'QSqlRelationalDelegate',
# 'QSqlRelationalTableModel',
# 'QSqlResult',
# 'QSqlTableModel'
# ],
'QtSvg': [
'QGraphicsSvgItem',
'QSvgGenerator',
'QSvgRenderer',
'QSvgWidget'
],
# 'QtTest': [
# 'QTest'
# ],
'QtWidgets': [
'QAbstractButton',
'QAbstractGraphicsShapeItem',
'QAbstractItemDelegate',
'QAbstractItemView',
'QAbstractScrollArea',
'QAbstractSlider',
'QAbstractSpinBox',
'QAction',
'QActionGroup',
'QApplication',
'QBoxLayout',
'QButtonGroup',
'QCalendarWidget',
'QCheckBox',
'QColorDialog',
'QColumnView',
'QComboBox',
'QCommandLinkButton',
'QCommonStyle',
'QCompleter',
'QDataWidgetMapper',
'QDateEdit',
'QDateTimeEdit',
'QDesktopWidget',
'QDial',
'QDialog',
'QDialogButtonBox',
'QDirModel',
'QDockWidget',
'QDoubleSpinBox',
'QErrorMessage',
'QFileDialog',
'QFileIconProvider',
'QFileSystemModel',
'QFocusFrame',
'QFontComboBox',
'QFontDialog',
'QFormLayout',
'QFrame',
'QGesture',
'QGestureEvent',
'QGestureRecognizer',
'QGraphicsAnchor',
'QGraphicsAnchorLayout',
'QGraphicsBlurEffect',
'QGraphicsColorizeEffect',
'QGraphicsDropShadowEffect',
'QGraphicsEffect',
'QGraphicsEllipseItem',
'QGraphicsGridLayout',
'QGraphicsItem',
'QGraphicsItemGroup',
'QGraphicsLayout',
'QGraphicsLayoutItem',
'QGraphicsLineItem',
'QGraphicsLinearLayout',
'QGraphicsObject',
'QGraphicsOpacityEffect',
'QGraphicsPathItem',
'QGraphicsPixmapItem',
'QGraphicsPolygonItem',
'QGraphicsProxyWidget',
'QGraphicsRectItem',
'QGraphicsRotation',
'QGraphicsScale',
'QGraphicsScene',
'QGraphicsSceneContextMenuEvent',
'QGraphicsSceneDragDropEvent',
'QGraphicsSceneEvent',
'QGraphicsSceneHelpEvent',
'QGraphicsSceneHoverEvent',
'QGraphicsSceneMouseEvent',
'QGraphicsSceneMoveEvent',
'QGraphicsSceneResizeEvent',
'QGraphicsSceneWheelEvent',
'QGraphicsSimpleTextItem',
'QGraphicsTextItem',
'QGraphicsTransform',
'QGraphicsView',
'QGraphicsWidget',
'QGridLayout',
'QGroupBox',
'QHBoxLayout',
'QHeaderView',
'QInputDialog',
'QItemDelegate',
'QItemEditorCreatorBase',
'QItemEditorFactory',
'QKeyEventTransition',
'QLCDNumber',
'QLabel',
'QLayout',
'QLayoutItem',
'QLineEdit',
'QListView',
'QListWidget',
'QListWidgetItem',
'QMainWindow',
'QMdiArea',
'QMdiSubWindow',
'QMenu',
'QMenuBar',
'QMessageBox',
'QMouseEventTransition',
'QPanGesture',
'QPinchGesture',
'QPlainTextDocumentLayout',
'QPlainTextEdit',
'QProgressBar',
'QProgressDialog',
'QPushButton',
'QRadioButton',
'QRubberBand',
'QScrollArea',
'QScrollBar',
'QShortcut',
'QSizeGrip',
'QSizePolicy',
'QSlider',
'QSpacerItem',
'QSpinBox',
'QSplashScreen',
'QSplitter',
'QSplitterHandle',
'QStackedLayout',
'QStackedWidget',
'QStatusBar',
'QStyle',
'QStyleFactory',
'QStyleHintReturn',
'QStyleHintReturnMask',
'QStyleHintReturnVariant',
'QStyleOption',
'QStyleOptionButton',
'QStyleOptionComboBox',
'QStyleOptionComplex',
'QStyleOptionDockWidget',
'QStyleOptionFocusRect',
'QStyleOptionFrame',
'QStyleOptionGraphicsItem',
'QStyleOptionGroupBox',
'QStyleOptionHeader',
'QStyleOptionMenuItem',
'QStyleOptionProgressBar',
'QStyleOptionRubberBand',
'QStyleOptionSizeGrip',
'QStyleOptionSlider',
'QStyleOptionSpinBox',
'QStyleOptionTab',
'QStyleOptionTabBarBase',
'QStyleOptionTabWidgetFrame',
'QStyleOptionTitleBar',
'QStyleOptionToolBar',
'QStyleOptionToolBox',
'QStyleOptionToolButton',
'QStyleOptionViewItem',
'QStylePainter',
'QStyledItemDelegate',
'QSwipeGesture',
'QSystemTrayIcon',
'QTabBar',
'QTabWidget',
'QTableView',
'QTableWidget',
'QTableWidgetItem',
'QTableWidgetSelectionRange',
'QTapAndHoldGesture',
'QTapGesture',
'QTextBrowser',
'QTextEdit',
'QTimeEdit',
'QToolBar',
'QToolBox',
'QToolButton',
'QToolTip',
'QTreeView',
'QTreeWidget',
'QTreeWidgetItem',
'QTreeWidgetItemIterator',
'QUndoCommand',
'QUndoGroup',
'QUndoStack',
'QUndoView',
'QVBoxLayout',
'QWhatsThis',
'QWidget',
'QWidgetAction',
'QWidgetItem',
'QWizard',
'QWizardPage'
],
# 'QtX11Extras': [
# 'QX11Info'
# ],
# 'QtXml': [
# 'QDomAttr',
# 'QDomCDATASection',
# 'QDomCharacterData',
# 'QDomComment',
# 'QDomDocument',
# 'QDomDocumentFragment',
# 'QDomDocumentType',
# 'QDomElement',
# 'QDomEntity',
# 'QDomEntityReference',
# 'QDomImplementation',
# 'QDomNamedNodeMap',
# 'QDomNode',
# 'QDomNodeList',
# 'QDomNotation',
# 'QDomProcessingInstruction',
# 'QDomText',
# 'QXmlAttributes',
# 'QXmlContentHandler',
# 'QXmlDTDHandler',
# 'QXmlDeclHandler',
# 'QXmlDefaultHandler',
# 'QXmlEntityResolver',
# 'QXmlErrorHandler',
# 'QXmlInputSource',
# 'QXmlLexicalHandler',
# 'QXmlLocator',
# 'QXmlNamespaceSupport',
# 'QXmlParseException',
# 'QXmlReader',
# 'QXmlSimpleReader'
# ],
# 'QtXmlPatterns': [
# 'QAbstractMessageHandler',
# 'QAbstractUriResolver',
# 'QAbstractXmlNodeModel',
# 'QAbstractXmlReceiver',
# 'QSourceLocation',
# 'QXmlFormatter',
# 'QXmlItem',
# 'QXmlName',
# 'QXmlNamePool',
# 'QXmlNodeModelIndex',
# 'QXmlQuery',
# 'QXmlResultItems',
# 'QXmlSchema',
# 'QXmlSchemaValidator',
# 'QXmlSerializer'
# ]
'QtQml': [
'qmlRegisterType',
'qmlRegisterUncreatableType',
'QQmlApplicationEngine',
],
'QtQuick': [
'QQuickPaintedItem',
'QQuickView',
],
}
####################################################################################################
"""Misplaced members
These members from the original submodule are misplaced relative PySide2
"""
_misplaced_members = {
'PySide2': {
'QtCore.QStringListModel': 'QtCore.QStringListModel',
'QtGui.QStringListModel': 'QtCore.QStringListModel',
'QtCore.Property': 'QtCore.Property',
'QtCore.Signal': 'QtCore.Signal',
'QtCore.Slot': 'QtCore.Slot',
'QtCore.QAbstractProxyModel': 'QtCore.QAbstractProxyModel',
'QtCore.QSortFilterProxyModel': 'QtCore.QSortFilterProxyModel',
'QtCore.QItemSelection': 'QtCore.QItemSelection',
'QtCore.QItemSelectionModel': 'QtCore.QItemSelectionModel',
'QtCore.QItemSelectionRange': 'QtCore.QItemSelectionRange',
# 'QtUiTools.QUiLoader': ['QtCompat.loadUi', _loadUi],
# 'shiboken2.wrapInstance': ['QtCompat.wrapInstance', _wrapinstance],
# 'shiboken2.getCppPointer': ['QtCompat.getCppPointer', _getcpppointer],
'QtWidgets.qApp': 'QtWidgets.QApplication.instance()',
# 'QtCore.QCoreApplication.translate': [
# 'QtCompat.translate', _translate
# ],
# 'QtWidgets.QApplication.translate': [
# 'QtCompat.translate', _translate
# ],
# 'QtCore.qInstallMessageHandler': [
# 'QtCompat.qInstallMessageHandler', _qInstallMessageHandler
# ],
},
'PyQt5': {
'QtCore.pyqtProperty': 'QtCore.Property',
'QtCore.pyqtSignal': 'QtCore.Signal',
'QtCore.pyqtSlot': 'QtCore.Slot',
'QtCore.QAbstractProxyModel': 'QtCore.QAbstractProxyModel',
'QtCore.QSortFilterProxyModel': 'QtCore.QSortFilterProxyModel',
'QtCore.QStringListModel': 'QtCore.QStringListModel',
'QtCore.QItemSelection': 'QtCore.QItemSelection',
'QtCore.QItemSelectionModel': 'QtCore.QItemSelectionModel',
'QtCore.QItemSelectionRange': 'QtCore.QItemSelectionRange',
# 'uic.loadUi': ['QtCompat.loadUi', _loadUi],
# 'sip.wrapinstance': ['QtCompat.wrapInstance', _wrapinstance],
# 'sip.unwrapinstance': ['QtCompat.getCppPointer', _getcpppointer],
'QtWidgets.qApp': 'QtWidgets.QApplication.instance()',
# 'QtCore.QCoreApplication.translate': [
# 'QtCompat.translate', _translate
# ],
# 'QtWidgets.QApplication.translate': [
# 'QtCompat.translate', _translate
# ],
# 'QtCore.qInstallMessageHandler': [
# 'QtCompat.qInstallMessageHandler', _qInstallMessageHandler
# ],
},
}
####################################################################################################
"""Compatibility Members
This dictionary is used to build Qt.QtCompat objects that provide a consistent
interface for obsolete members, and differences in binding return values.
{
'binding': {
'classname': {
'targetname': 'binding_namespace',
}
}
}
"""
_compatibility_members = {
'PySide2': {
# 'QWidget': {
# 'grab': 'QtWidgets.QWidget.grab',
# },
# 'QHeaderView': {
# 'sectionsClickable': 'QtWidgets.QHeaderView.sectionsClickable',
# 'setSectionsClickable':
# 'QtWidgets.QHeaderView.setSectionsClickable',
# 'sectionResizeMode': 'QtWidgets.QHeaderView.sectionResizeMode',
# 'setSectionResizeMode':
# 'QtWidgets.QHeaderView.setSectionResizeMode',
# 'sectionsMovable': 'QtWidgets.QHeaderView.sectionsMovable',
# 'setSectionsMovable': 'QtWidgets.QHeaderView.setSectionsMovable',
# },
# 'QFileDialog': {
# 'getOpenFileName': 'QtWidgets.QFileDialog.getOpenFileName',
# 'getOpenFileNames': 'QtWidgets.QFileDialog.getOpenFileNames',
# 'getSaveFileName': 'QtWidgets.QFileDialog.getSaveFileName',
# },
},
'PyQt5': {
# 'QWidget': {
# 'grab': 'QtWidgets.QWidget.grab',
# },
# 'QHeaderView': {
# 'sectionsClickable': 'QtWidgets.QHeaderView.sectionsClickable',
# 'setSectionsClickable':
# 'QtWidgets.QHeaderView.setSectionsClickable',
# 'sectionResizeMode': 'QtWidgets.QHeaderView.sectionResizeMode',
# 'setSectionResizeMode':
# 'QtWidgets.QHeaderView.setSectionResizeMode',
# 'sectionsMovable': 'QtWidgets.QHeaderView.sectionsMovable',
# 'setSectionsMovable': 'QtWidgets.QHeaderView.setSectionsMovable',
# },
# 'QFileDialog': {
# 'getOpenFileName': 'QtWidgets.QFileDialog.getOpenFileName',
# 'getOpenFileNames': 'QtWidgets.QFileDialog.getOpenFileNames',
# 'getSaveFileName': 'QtWidgets.QFileDialog.getSaveFileName',
# },
},
}