- fixed multiple issues in the App objects related to wrong usage of self.obj_options attribute instead of self.app.options attribute

- remade the Film Plugin such that the `skew` feature is now done in length units as opposed with the previous usage of angles
- refactored some big methods from the Film Plugin
This commit is contained in:
Marius Stanciu
2022-03-10 14:22:09 +02:00
committed by Marius
parent da20db5527
commit 31eb06d5a9
6 changed files with 431 additions and 495 deletions

View File

@@ -12,6 +12,9 @@ CHANGELOG for FlatCAM beta
- fixed an issue where using the 'G' shortcut key in Editors will not toggle the grid snap - fixed an issue where using the 'G' shortcut key in Editors will not toggle the grid snap
- fixed an issue in the Excellon Editor where selecting the drills did not highlight them but instead made them invisible (although the selection still worked) - fixed an issue in the Excellon Editor where selecting the drills did not highlight them but instead made them invisible (although the selection still worked)
- fixed an issue in the Gerber Editor where selecting one shape will auto-select all the shapes made with the same aperture - fixed an issue in the Gerber Editor where selecting one shape will auto-select all the shapes made with the same aperture
- fixed multiple issues in the App objects related to wrong usage of self.obj_options attribute instead of self.app.options attribute
- remade the Film Plugin such that the `skew` feature is now done in length units as opposed with the previous usage of angles
- refactored some big methods from the Film Plugin
9.03.2022 9.03.2022
@@ -3454,7 +3457,7 @@ RELEASE 8.993
- working on a new tool: Extract Drills Tool who will create a Excellon object out of the apertures of a Gerber object - working on a new tool: Extract Drills Tool who will create a Excellon object out of the apertures of a Gerber object
- finished the GUI in the Extract Drills Tool - finished the GUI in the Extract Drills Tool
- fixed issue in Film Tool where some parameters names in calls of method export_positive() were not matching the actual parameters name - fixed issue in Film Tool where some parameters names in calls of method export_positive_handler() were not matching the actual parameters name
- finished the Extract Drills Tool - finished the Extract Drills Tool
- fixed a small issue in the DoubleSided Tool - fixed a small issue in the DoubleSided Tool

View File

@@ -111,7 +111,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
grid_skew = FCGridLayout(v_spacing=5, h_spacing=3) grid_skew = FCGridLayout(v_spacing=5, h_spacing=3)
skew_frame.setLayout(grid_skew) skew_frame.setLayout(grid_skew)
self.film_skewx_label = FCLabel('%s:' % _("X angle")) self.film_skewx_label = FCLabel('%s:' % _("X val"))
self.film_skewx_entry = FCDoubleSpinner() self.film_skewx_entry = FCDoubleSpinner()
self.film_skewx_entry.set_range(-999.9999, 999.9999) self.film_skewx_entry.set_range(-999.9999, 999.9999)
self.film_skewx_entry.set_precision(self.decimals) self.film_skewx_entry.set_precision(self.decimals)
@@ -120,7 +120,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
grid_skew.addWidget(self.film_skewx_label, 0, 0) grid_skew.addWidget(self.film_skewx_label, 0, 0)
grid_skew.addWidget(self.film_skewx_entry, 0, 1) grid_skew.addWidget(self.film_skewx_entry, 0, 1)
self.film_skewy_label = FCLabel('%s:' % _("Y angle")) self.film_skewy_label = FCLabel('%s:' % _("Y val"))
self.film_skewy_entry = FCDoubleSpinner() self.film_skewy_entry = FCDoubleSpinner()
self.film_skewy_entry.set_range(-999.9999, 999.9999) self.film_skewy_entry.set_range(-999.9999, 999.9999)
self.film_skewy_entry.set_precision(self.decimals) self.film_skewy_entry.set_precision(self.decimals)
@@ -137,7 +137,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
self.film_skew_ref_combo = FCComboBox2() self.film_skew_ref_combo = FCComboBox2()
self.film_skew_ref_combo.addItems( self.film_skew_ref_combo.addItems(
[_('Center'), _('Bottom Left'), _('Top Left'), _('Bottom Right'), _('Top right')]) [_('Center'), _('Bottom Left')])
grid_skew.addWidget(self.skew_ref_label, 4, 0) grid_skew.addWidget(self.skew_ref_label, 4, 0)
grid_skew.addWidget(self.film_skew_ref_combo, 4, 1) grid_skew.addWidget(self.film_skew_ref_combo, 4, 1)

View File

@@ -446,13 +446,13 @@ class AppObject(QtCore.QObject):
for opt_key, opt_val in app.options.items(): for opt_key, opt_val in app.options.items():
if opt_key.find('geometry' + "_") == 0: if opt_key.find('geometry' + "_") == 0:
oname = opt_key[len('geometry') + 1:] oname = opt_key[len('geometry') + 1:]
default_data[oname] = self.app.options[opt_key] default_data[oname] = app.options[opt_key]
if opt_key.find('tools_') == 0: if opt_key.find('tools_') == 0:
default_data[opt_key] = self.app.options[opt_key] default_data[opt_key] = app.options[opt_key]
new_obj.tools = { new_obj.tools = {
1: { 1: {
'tooldia': float(app.defaults["tools_mill_tooldia"]), 'tooldia': float(app.options["tools_mill_tooldia"]),
'offset': 'Path', 'offset': 'Path',
'offset_value': 0.0, 'offset_value': 0.0,
'type': 'Rough', 'type': 'Rough',

View File

@@ -1020,7 +1020,7 @@ class ExcellonObject(FlatCAMObj, Excellon):
geo_obj.obj_options['type'] = 'Excellon Geometry' geo_obj.obj_options['type'] = 'Excellon Geometry'
geo_obj.obj_options["tools_mill_tooldia"] = str(tooldia) geo_obj.obj_options["tools_mill_tooldia"] = str(tooldia)
geo_obj.obj_options["multidepth"] = app_obj.defaults["tools_mill_multidepth"] geo_obj.obj_options["multidepth"] = app_obj.options["tools_mill_multidepth"]
geo_obj.solid_geometry = [] geo_obj.solid_geometry = []
# in case that the tool used has the same diameter with the hole, and since the maximum resolution # in case that the tool used has the same diameter with the hole, and since the maximum resolution
@@ -1117,7 +1117,7 @@ class ExcellonObject(FlatCAMObj, Excellon):
geo_obj.obj_options['type'] = 'Excellon Geometry' geo_obj.obj_options['type'] = 'Excellon Geometry'
geo_obj.obj_options["tools_mill_tooldia"] = str(tooldia) geo_obj.obj_options["tools_mill_tooldia"] = str(tooldia)
geo_obj.obj_options["tools_mill_multidepth"] = app_obj.defaults["tools_mill_multidepth"] geo_obj.obj_options["tools_mill_multidepth"] = app_obj.options["tools_mill_multidepth"]
geo_obj.solid_geometry = [] geo_obj.solid_geometry = []
# in case that the tool used has the same diameter with the hole, and since the maximum resolution # in case that the tool used has the same diameter with the hole, and since the maximum resolution

View File

@@ -585,12 +585,12 @@ class GerberObject(FlatCAMObj, Gerber):
# store here the default data for Geometry Data # store here the default data for Geometry Data
default_data = {} default_data = {}
for opt_key, opt_val in app_obj.obj_options.items(): for opt_key, opt_val in app_obj.options.items():
if opt_key.find('geometry' + "_") == 0: if opt_key.find('geometry' + "_") == 0:
oname = opt_key[len('geometry') + 1:] oname = opt_key[len('geometry') + 1:]
default_data[oname] = self.app.options[opt_key] default_data[oname] = app_obj.options[opt_key]
if opt_key.find('tools_mill' + "_") == 0: if opt_key.find('tools_mill' + "_") == 0:
default_data[opt_key] = self.app.options[opt_key] default_data[opt_key] = app_obj.options[opt_key]
geo_obj.tools = { geo_obj.tools = {
1: { 1: {
@@ -676,7 +676,7 @@ class GerberObject(FlatCAMObj, Gerber):
def iso_init(geo_obj, app_obj): def iso_init(geo_obj, app_obj):
# Propagate options # Propagate options
geo_obj.obj_options["tools_mill_tooldia"] = str(dia) geo_obj.obj_options["tools_mill_tooldia"] = str(dia)
geo_obj.tool_type = self.app.options["tools_iso_tool_shape"] geo_obj.tool_type = app_obj.options["tools_iso_tool_shape"]
geo_obj.multigeo = True geo_obj.multigeo = True
# if milling type is climb then the move is counter-clockwise around features # if milling type is climb then the move is counter-clockwise around features
@@ -692,12 +692,12 @@ class GerberObject(FlatCAMObj, Gerber):
# store here the default data for Geometry Data # store here the default data for Geometry Data
default_data = {} default_data = {}
for opt_key, opt_val in app_obj.obj_options.items(): for opt_key, opt_val in app_obj.options.items():
if opt_key.find('geometry' + "_") == 0: if opt_key.find('geometry' + "_") == 0:
oname = opt_key[len('geometry') + 1:] oname = opt_key[len('geometry') + 1:]
default_data[oname] = self.app.options[opt_key] default_data[oname] = app_obj.options[opt_key]
if opt_key.find('tools_mill' + "_") == 0: if opt_key.find('tools_mill' + "_") == 0:
default_data[opt_key] = self.app.options[opt_key] default_data[opt_key] = app_obj.options[opt_key]
geo_obj.tools = { geo_obj.tools = {
1: { 1: {
@@ -786,7 +786,7 @@ class GerberObject(FlatCAMObj, Gerber):
""" """
if outname is None: if outname is None:
follow_name = self.obj_options["name"] + "_follow" follow_name = self.options["name"] + "_follow"
else: else:
follow_name = outname follow_name = outname
@@ -808,16 +808,16 @@ class GerberObject(FlatCAMObj, Gerber):
# new_obj.obj_options["tools_mill_tooldia"] = str(self.app.options["tools_iso_tooldia"]) # new_obj.obj_options["tools_mill_tooldia"] = str(self.app.options["tools_iso_tooldia"])
new_obj.solid_geometry = deepcopy(self.follow_geometry) new_obj.solid_geometry = deepcopy(self.follow_geometry)
new_obj.obj_options["tools_mill_tooldia"] = app_obj.defaults["tools_mill_tooldia"] new_obj.obj_options["tools_mill_tooldia"] = app_obj.options["tools_mill_tooldia"]
# store here the default data for Geometry Data # store here the default data for Geometry Data
default_data = {} default_data = {}
for opt_key, opt_val in app_obj.obj_options.items(): for opt_key, opt_val in app_obj.options.items():
if opt_key.find('geometry' + "_") == 0: if opt_key.find('geometry' + "_") == 0:
oname = opt_key[len('geometry') + 1:] oname = opt_key[len('geometry') + 1:]
default_data[oname] = self.app.options[opt_key] default_data[oname] = app_obj.options[opt_key]
if opt_key.find('tools_mill' + "_") == 0: if opt_key.find('tools_mill' + "_") == 0:
default_data[opt_key] = self.app.options[opt_key] default_data[opt_key] = app_obj.options[opt_key]
new_obj.tools = { new_obj.tools = {
1: { 1: {
@@ -1021,10 +1021,7 @@ class GerberObject(FlatCAMObj, Gerber):
# return # return
# for marking apertures, line color and fill color are the same # for marking apertures, line color and fill color are the same
if 'color' in kwargs: color = kwargs['color'] if 'color' in kwargs else self.app.options['gerber_plot_fill']
color = kwargs['color']
else:
color = self.app.options['gerber_plot_fill']
if 'marked_aperture' in kwargs: if 'marked_aperture' in kwargs:
aperture_to_plot_mark = kwargs['marked_aperture'] aperture_to_plot_mark = kwargs['marked_aperture']

View File

@@ -4,6 +4,7 @@
# Date: 3/10/2019 # # Date: 3/10/2019 #
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
import math
from PyQt6 import QtCore, QtWidgets, QtGui from PyQt6 import QtCore, QtWidgets, QtGui
@@ -398,7 +399,7 @@ class Film(AppTool):
filename = str(filename) filename = str(filename)
if str(filename) != "": if str(filename) != "":
self.export_positive(name, boxname, filename, self.export_positive_handler(name, boxname, filename,
scale_stroke_factor=factor, scale_stroke_factor=factor,
scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y, scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y,
scale_reference=scale_reference, scale_reference=scale_reference,
@@ -553,7 +554,7 @@ class Film(AppTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled.")) self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
return return
else: else:
self.export_negative(name, boxname, filename, border, self.export_negative_handler(name, boxname, filename, border,
scale_stroke_factor=factor, scale_stroke_factor=factor,
scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y, scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y,
scale_reference=scale_reference, scale_reference=scale_reference,
@@ -564,7 +565,7 @@ class Film(AppTool):
rounded_box=rounded_box rounded_box=rounded_box
) )
def export_negative(self, obj_name, box_name, filename, boundary, def export_negative_handler(self, obj_name, box_name, filename, boundary,
scale_stroke_factor=0.00, scale_stroke_factor=0.00,
scale_factor_x=1, scale_factor_y=1, scale_reference='center', scale_factor_x=1, scale_factor_y=1, scale_reference='center',
skew_factor_x=None, skew_factor_y=None, skew_reference='center', skew_factor_x=None, skew_factor_y=None, skew_reference='center',
@@ -596,7 +597,7 @@ class Film(AppTool):
Works only in case the object used as box has multiple geometries Works only in case the object used as box has multiple geometries
:return: :return:
""" """
self.app.defaults.report_usage("export_negative()") self.app.defaults.report_usage("export_negative_handler()")
if filename is None: if filename is None:
filename = self.app.options["global_last_save_folder"] filename = self.app.options["global_last_save_folder"]
@@ -620,30 +621,13 @@ class Film(AppTool):
scale_factor_x = scale_factor_x scale_factor_x = scale_factor_x
scale_factor_y = scale_factor_y scale_factor_y = scale_factor_y
def get_complementary(color_param):
# strip the # from the beginning
our_color = color_param[1:]
# convert the string into hex
our_color = int(our_color, 16)
# invert the three bytes
# as good as substracting each of RGB component by 255(FF)
comp_color = 0xFFFFFF ^ our_color
# convert the color back to hex by prefixing a #
comp_color = "#%06X" % comp_color
# return the result
return comp_color
p_size = self.ui.pagesize_combo.get_value() p_size = self.ui.pagesize_combo.get_value()
orientation = self.ui.orientation_radio.get_value() orientation = self.ui.orientation_radio.get_value()
color = obj.obj_options['tools_film_color'] color = obj.obj_options['tools_film_color']
transparency_level = opacity_val transparency_level = opacity_val
def make_negative_film(color, transparency_level, scale_factor_x, scale_factor_y, use_convex_hull, rounded_box): def make_negative_film(color, transparency_level, scale_factor_x, scale_factor_y, use_convex_hull, rounded_box):
self.app.log.debug("FilmTool.export_negative().make_negative_film()") self.app.log.debug("FilmTool.export_negative_handler().make_negative_film()")
self.screen_dpi = self.app.qapp.screens()[0].logicalDotsPerInch() self.screen_dpi = self.app.qapp.screens()[0].logicalDotsPerInch()
@@ -654,85 +638,77 @@ class Film(AppTool):
scale_factor_x += dpi_rate scale_factor_x += dpi_rate
scale_factor_y += dpi_rate scale_factor_y += dpi_rate
# ######################################################################################################## transformed_box_geo = self.transform_geometry(box, scale_factor_x=scale_factor_x,
# the case when the BOX object is a Geometry Object scale_factor_y=scale_factor_y,
if box.kind.lower() == 'geometry': scale_reference=scale_reference,
flat_geo = []
if box.multigeo:
for tool in box.tools:
flat_geo += box.flatten(box.tools[tool]['solid_geometry'])
box_geo = unary_union(flat_geo)
else:
box_geo = unary_union(box.flatten())
else:
box_geo = unary_union(box.flatten())
xmin, ymin, xmax, ymax = box_geo.bounds
ref_scale_val = 'center'
if scale_reference == 'topleft':
ref_scale_val = (xmin, ymax)
elif scale_reference == 'bottomleft':
ref_scale_val = (xmin, ymin)
elif scale_reference == 'topright':
ref_scale_val = (xmax, ymax)
elif scale_reference == 'bottomright':
ref_scale_val = (xmax, ymin)
ref_skew_val = 'center'
if skew_reference == 'topleft':
ref_skew_val = (xmin, ymax)
elif skew_reference == 'bottomleft':
ref_skew_val = (xmin, ymin)
elif skew_reference == 'topright':
ref_skew_val = (xmax, ymax)
elif skew_reference == 'bottomright':
ref_skew_val = (xmax, ymin)
# Transform the box object geometry
transformed_box_geo = box_geo
if scale_factor_x and not scale_factor_y:
transformed_box_geo = affinity.scale(transformed_box_geo, scale_factor_x, 1.0, origin=ref_scale_val)
elif not scale_factor_x and scale_factor_y:
transformed_box_geo = affinity.scale(transformed_box_geo, 1.0, scale_factor_y, origin=ref_scale_val)
elif scale_factor_x and scale_factor_y:
transformed_box_geo = affinity.scale(transformed_box_geo, scale_factor_x, scale_factor_y,
origin=ref_scale_val)
if skew_factor_x and not skew_factor_y:
transformed_box_geo = affinity.skew(transformed_box_geo, skew_factor_x, 0.0, origin=ref_skew_val)
elif not skew_factor_x and skew_factor_y:
transformed_box_geo = affinity.skew(transformed_box_geo, 0.0, skew_factor_y, origin=ref_skew_val)
elif skew_factor_x and skew_factor_y:
transformed_box_geo = affinity.skew(transformed_box_geo, skew_factor_x, skew_factor_y,
origin=ref_skew_val)
if mirror:
if mirror == 'x':
transformed_box_geo = affinity.scale(transformed_box_geo, 1.0, -1.0, origin='center')
if mirror == 'y':
transformed_box_geo = affinity.scale(transformed_box_geo, -1.0, 1.0, origin='center')
if mirror == 'both':
transformed_box_geo = affinity.scale(transformed_box_geo, -1.0, -1.0, origin='center')
bounds = transformed_box_geo.bounds
size = bounds[2] - bounds[0], bounds[3] - bounds[1]
exported_svg = obj.export_svg(scale_stroke_factor=scale_stroke_factor,
scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y,
skew_factor_x=skew_factor_x, skew_factor_y=skew_factor_y, skew_factor_x=skew_factor_x, skew_factor_y=skew_factor_y,
mirror=mirror, skew_reference=skew_reference,
scale_reference=scale_reference, skew_reference=skew_reference, mirror=mirror)
mirror_reference='center'
)
uom = obj.units.lower() transformed_obj_geo = self.transform_geometry(obj, scale_factor_x=scale_factor_x,
scale_factor_y=scale_factor_y,
scale_reference=scale_reference,
skew_factor_x=skew_factor_x, skew_factor_y=skew_factor_y,
skew_reference=skew_reference,
mirror=mirror)
exported_svg = self.create_svg_geometry(transformed_obj_geo, scale_stroke_factor=scale_stroke_factor)
svg_units = obj.units.lower()
bounds = transformed_box_geo.bounds
doc_final = self.create_negative_svg(svg_geo=exported_svg, box_bounds=bounds, r_box=rounded_box,
box_geo=transformed_box_geo, c_hull=use_convex_hull, margin=boundary,
color=color, opacity=transparency_level, svg_units=svg_units)
obj_bounds = obj.bounds()
ret = self.write_output_file(content2save=doc_final, filename=filename, file_type=ftype, p_size=p_size,
orientation=orientation, source_bounds=obj_bounds, box_bounds=bounds)
if ret == 'fail':
return 'fail'
if self.app.options["global_open_style"] is False:
self.app.file_opened.emit("SVG", filename)
self.app.file_saved.emit("SVG", filename)
self.app.inform.emit('[success] %s: %s' % (_("Film file exported to"), filename))
if use_thread is True:
def job_thread_film():
with self.app.proc_container.new(_("Working...")):
try:
make_negative_film(color=color, transparency_level=transparency_level,
scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y,
use_convex_hull=use_convex_hull, rounded_box=rounded_box)
except Exception as e:
self.app.log.error("export_negative_handler() process -> %s" % str(e))
return
self.app.worker_task.emit({'fcn': job_thread_film, 'params': []})
else:
make_negative_film(scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y,
use_convex_hull=use_convex_hull, rounded_box=rounded_box)
def create_negative_svg(self, svg_geo, box_bounds, r_box, box_geo, c_hull, margin, color, opacity, svg_units):
# Change the attributes of the exported SVG
# We don't need stroke-width - wrong, we do when we have lines with certain width
# We set opacity to maximum
# We set the color to the inversed color
root = ET.fromstring(svg_geo)
for child in root:
child.set('fill', self.get_complementary(color))
child.set('opacity', str(opacity))
child.set('stroke', self.get_complementary(color))
uom = svg_units
# Convert everything to strings for use in the xml doc # Convert everything to strings for use in the xml doc
svgwidth = str(size[0] + (2 * boundary)) size = box_bounds[2] - box_bounds[0], box_bounds[3] - box_bounds[1]
svgheight = str(size[1] + (2 * boundary))
minx = str(bounds[0] - boundary) svgwidth = str(size[0] + (2 * margin))
miny = str(bounds[1] + boundary + size[1]) svgheight = str(size[1] + (2 * margin))
minx = str(box_bounds[0] - margin)
miny = str(box_bounds[1] + margin + size[1])
# miny_rect = str(bounds[1] - boundary) # miny_rect = str(bounds[1] - boundary)
# Add a SVG Header and footer to the svg output from shapely # Add a SVG Header and footer to the svg output from shapely
@@ -747,50 +723,24 @@ class Film(AppTool):
svg_header += '<g transform="scale(1,-1)">' svg_header += '<g transform="scale(1,-1)">'
svg_footer = '</g> </svg>' svg_footer = '</g> </svg>'
# Change the attributes of the exported SVG
# We don't need stroke-width - wrong, we do when we have lines with certain width
# We set opacity to maximum
# We set the color to the inversed color
root = ET.fromstring(exported_svg)
for child in root:
child.set('fill', get_complementary(color))
child.set('opacity', str(transparency_level))
child.set('stroke', get_complementary(color))
# first_svg_elem = 'rect x="' + minx + '" ' + 'y="' + miny_rect + '" '
# first_svg_elem += 'width="' + svgwidth + '" ' + 'height="' + svgheight + '" '
# first_svg_elem += 'fill="#000000" opacity="1.0" stroke-width="0.0"'
# first_svg_elem_tag = 'rect'
# first_svg_elem_attribs = {
# 'x': minx,
# 'y': miny_rect,
# 'width': svgwidth,
# 'height': svgheight,
# 'id': 'neg_rect',
# 'style': 'fill:%s;opacity:1.0;stroke-width:0.0' % str(color)
# }
# decide if to round the bounding box for the negative # decide if to round the bounding box for the negative
join_s = 1 if rounded_box else 2 join_s = 1 if r_box else 2
if isinstance(transformed_box_geo, (LineString, LinearRing)): if isinstance(box_geo, (LineString, LinearRing)):
b_geo = Polygon(transformed_box_geo).buffer(boundary, join_style=join_s) b_geo = Polygon(box_geo).buffer(margin, join_style=join_s)
coords_list = list(b_geo.exterior.coords) coords_list = list(b_geo.exterior.coords)
elif isinstance(transformed_box_geo, list) and len(transformed_box_geo) == 1 and \ elif isinstance(box_geo, list) and len(box_geo) == 1 and isinstance(box_geo[0], (LineString, LinearRing)):
isinstance(transformed_box_geo[0], (LineString, LinearRing)): b_geo = Polygon(box_geo[0]).buffer(margin, join_style=join_s)
b_geo = Polygon(transformed_box_geo[0]).buffer(boundary, join_style=join_s)
coords_list = list(b_geo.exterior.coords) coords_list = list(b_geo.exterior.coords)
elif isinstance(transformed_box_geo, Polygon): elif isinstance(box_geo, Polygon):
coords_list = list(transformed_box_geo.exterior.coords) coords_list = list(box_geo.exterior.coords)
elif isinstance(transformed_box_geo, list) and len(transformed_box_geo) == 1 and \ elif isinstance(box_geo, list) and len(box_geo) == 1 and isinstance(box_geo[0], Polygon):
isinstance(transformed_box_geo[0], Polygon): coords_list = list(box_geo[0].exterior.coords)
coords_list = list(transformed_box_geo[0].exterior.coords)
else: else:
if use_convex_hull: if c_hull:
buff_box = transformed_box_geo.convex_hull.buffer(boundary, join_style=join_s) buff_box = box_geo.convex_hull.buffer(margin, join_style=join_s)
else: else:
buff_box = transformed_box_geo.envelope.buffer(boundary, join_style=join_s) buff_box = box_geo.envelope.buffer(margin, join_style=join_s)
box_buff_outline = buff_box.exterior box_buff_outline = buff_box.exterior
coords_list = list(box_buff_outline.coords) coords_list = list(box_buff_outline.coords)
@@ -813,111 +763,27 @@ class Film(AppTool):
# Parse the xml through a xml parser just to add line feeds # Parse the xml through a xml parser just to add line feeds
# and to make it look more pretty for the output # and to make it look more pretty for the output
doc = parse_xml_string(svg_elem) doc = parse_xml_string(svg_elem)
doc_final = doc.toprettyxml() return doc.toprettyxml()
if ftype == 'svg': @staticmethod
try: def get_complementary(color_param):
with open(filename, 'w') as fp: # strip the # from the beginning
fp.write(doc_final) our_color = color_param[1:]
except PermissionError:
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Permission denied, saving not possible.\n"
"Most likely another app is holding the file open and not accessible."))
return 'fail'
elif ftype == 'png':
try:
doc_final = StringIO(doc_final)
drawing = svg2rlg(doc_final)
renderPM.drawToFile(drawing, filename, fmt='PNG')
# if new_png_dpi == default_dpi: # convert the string into hex
# renderPM.drawToFile(drawing, filename, 'PNG') our_color = int(our_color, 16)
# else:
# renderPM.drawToFile(drawing, filename, 'PNG', dpi=new_png_dpi)
except PermissionError:
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Permission denied, saving not possible.\n"
"Most likely another app is holding the file open and not accessible."))
return 'fail'
except Exception as e:
self.app.log.error("FilmTool.export_negative() --> PNG output --> %s" % str(e))
return 'fail'
else: # PDF
if self.units == 'IN':
unit = inch
else:
unit = mm
if p_size == 'Bounds': # invert the three bytes
page_size = None # as good as substracting each of RGB component by 255(FF)
elif orientation == 'p': comp_color = 0xFFFFFF ^ our_color
page_size = portrait(self.ui.pagesize[p_size])
else:
page_size = landscape(self.ui.pagesize[p_size])
try: # convert the color back to hex by prefixing a #
xmin, ymin, xmax, ymax = obj.bounds() comp_color = "#%06X" % comp_color
if page_size:
page_xmax, page_ymax = (
page_size[0] / mm,
page_size[1] / mm
)
else:
page_xmax, page_ymax = xmax, ymax
if xmax < 0 or ymax < 0 or xmin > page_xmax or ymin > page_ymax: # return the result
err_msg = '[ERROR_NOTCL] %s %s' % \ return comp_color
(_("Failed."),
_("The artwork has to be within the selected page size in order to be visible.\n"
"For 'Bounds' page size, it needs to be in the first quadrant."))
self.app.inform.emit(err_msg)
return 'fail'
except Exception as e:
self.app.log.error("FilmTool.export_negative() --> PDF output 1 --> %s" % str(e))
return 'fail'
try: def export_positive_handler(self, obj_name, box_name, filename,
doc_final = StringIO(doc_final)
drawing = svg2rlg(doc_final)
if p_size == 'Bounds':
renderPDF.drawToFile(drawing, filename)
else:
my_canvas = canvas.Canvas(filename, pagesize=page_size)
my_canvas.translate(bounds[0] * unit, bounds[1] * unit)
renderPDF.draw(drawing, my_canvas, 0, 0)
my_canvas.save()
except PermissionError:
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Permission denied, saving not possible.\n"
"Most likely another app is holding the file open and not accessible."))
return 'fail'
except Exception as e:
self.app.log.error("FilmTool.export_negative() --> PDF output Reportlab section --> %s" % str(e))
return 'fail'
if self.app.options["global_open_style"] is False:
self.app.file_opened.emit("SVG", filename)
self.app.file_saved.emit("SVG", filename)
self.app.inform.emit('[success] %s: %s' % (_("Film file exported to"), filename))
if use_thread is True:
def job_thread_film():
with self.app.proc_container.new(_("Working...")):
try:
make_negative_film(color=color, transparency_level=transparency_level,
scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y,
use_convex_hull=use_convex_hull, rounded_box=rounded_box)
except Exception as e:
self.app.log.error("export_negative() process -> %s" % str(e))
return
self.app.worker_task.emit({'fcn': job_thread_film, 'params': []})
else:
make_negative_film(scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y,
use_convex_hull=use_convex_hull, rounded_box=rounded_box)
def export_positive(self, obj_name, box_name, filename,
scale_stroke_factor=0.00, scale_stroke_factor=0.00,
scale_factor_x=1, scale_factor_y=1, scale_reference='center', scale_factor_x=1, scale_factor_y=1, scale_reference='center',
skew_factor_x=None, skew_factor_y=None, skew_reference='center', skew_factor_x=None, skew_factor_y=None, skew_reference='center',
@@ -938,7 +804,7 @@ class Film(AppTool):
:param skew_factor_x: factor to skew the geometry on the X axis :param skew_factor_x: factor to skew the geometry on the X axis
:param skew_factor_y: factor to skew the geometry on the Y axis :param skew_factor_y: factor to skew the geometry on the Y axis
:param skew_reference: reference to use for transformation. :param skew_reference: reference to use for transformation.
Values: 'center', 'bottomleft', 'topleft', 'bottomright', 'topright' Values: 'center', 'bottomleft'
:param mirror: can be 'x' or 'y' or 'both'. Axis on which to mirror the svg geometry :param mirror: can be 'x' or 'y' or 'both'. Axis on which to mirror the svg geometry
:param opacity_val: :param opacity_val:
:param use_thread: if to be run in a separate thread; boolean :param use_thread: if to be run in a separate thread; boolean
@@ -946,12 +812,12 @@ class Film(AppTool):
:return: :return:
""" """
self.app.defaults.report_usage("export_positive()") self.app.defaults.report_usage("export_positive_handler()")
if filename is None: if filename is None:
filename = self.app.options["global_last_save_folder"] filename = self.app.options["global_last_save_folder"]
self.app.log.debug("Film.export_positive() black") self.app.log.debug("Film.export_positive_handler() black")
try: try:
obj = self.app.collection.get_by_name(str(obj_name)) obj = self.app.collection.get_by_name(str(obj_name))
@@ -964,7 +830,7 @@ class Film(AppTool):
return "Could not retrieve object: %s" % box_name return "Could not retrieve object: %s" % box_name
if box is None: if box is None:
self.inform.emit('[WARNING_NOTCL] %s: %s' % (_("No object Box. Using instead"), obj)) self.app.inform.emit('[WARNING_NOTCL] %s: %s' % (_("No object Box. Using instead"), obj))
box = obj box = obj
scale_factor_x = scale_factor_x scale_factor_x = scale_factor_x
@@ -976,7 +842,7 @@ class Film(AppTool):
transparency_level = opacity_val transparency_level = opacity_val
def make_positive_film(color, transparency_level, scale_factor_x, scale_factor_y): def make_positive_film(color, transparency_level, scale_factor_x, scale_factor_y):
self.app.log.debug("FilmTool.export_positive().make_positive_film()") self.app.log.debug("FilmTool.export_positive_handler().make_positive_film()")
self.screen_dpi = self.app.qapp.screens()[0].logicalDotsPerInch() self.screen_dpi = self.app.qapp.screens()[0].logicalDotsPerInch()
@@ -987,98 +853,81 @@ class Film(AppTool):
scale_factor_x += dpi_rate scale_factor_x += dpi_rate
scale_factor_y += dpi_rate scale_factor_y += dpi_rate
if box.kind.lower() == 'geometry': transformed_box_geo = self.transform_geometry(box, scale_factor_x=scale_factor_x,
flat_geo = [] scale_factor_y=scale_factor_y,
if box.multigeo: scale_reference=scale_reference,
for tool in box.tools: skew_factor_x=skew_factor_x, skew_factor_y=skew_factor_y,
flat_geo += box.flatten(box.tools[tool]['solid_geometry']) skew_reference=skew_reference,
box_geo = unary_union(flat_geo) mirror=mirror)
else:
box_geo = unary_union(box.flatten())
else:
box_geo = unary_union(box.flatten())
xmin, ymin, xmax, ymax = box_geo.bounds transformed_obj_geo = self.transform_geometry(obj, scale_factor_x=scale_factor_x,
ref_scale_val = 'center' scale_factor_y=scale_factor_y,
if scale_reference == 'topleft': scale_reference=scale_reference,
ref_scale_val = (xmin, ymax) skew_factor_x=skew_factor_x, skew_factor_y=skew_factor_y,
elif scale_reference == 'bottomleft': skew_reference=skew_reference,
ref_scale_val = (xmin, ymin) mirror=mirror)
elif scale_reference == 'topright':
ref_scale_val = (xmax, ymax)
elif scale_reference == 'bottomright':
ref_scale_val = (xmax, ymin)
ref_skew_val = 'center' exported_svg = self.create_svg_geometry(transformed_obj_geo, scale_stroke_factor=scale_stroke_factor)
if skew_reference == 'topleft':
ref_skew_val = (xmin, ymax)
elif skew_reference == 'bottomleft':
ref_skew_val = (xmin, ymin)
elif skew_reference == 'topright':
ref_skew_val = (xmax, ymax)
elif skew_reference == 'bottomright':
ref_skew_val = (xmax, ymin)
transformed_box_geo = box_geo
if scale_factor_x and not scale_factor_y:
transformed_box_geo = affinity.scale(transformed_box_geo, scale_factor_x, 1.0, origin=ref_scale_val)
elif not scale_factor_x and scale_factor_y:
transformed_box_geo = affinity.scale(transformed_box_geo, 1.0, scale_factor_y, origin=ref_scale_val)
elif scale_factor_x and scale_factor_y:
transformed_box_geo = affinity.scale(transformed_box_geo, scale_factor_x, scale_factor_y,
origin=ref_scale_val)
if skew_factor_x and not skew_factor_y:
transformed_box_geo = affinity.skew(transformed_box_geo, skew_factor_x, 0.0, origin=ref_skew_val)
elif not skew_factor_x and skew_factor_y:
transformed_box_geo = affinity.skew(transformed_box_geo, 0.0, skew_factor_y, origin=ref_skew_val)
elif skew_factor_x and skew_factor_y:
transformed_box_geo = affinity.skew(transformed_box_geo, skew_factor_x, skew_factor_y,
origin=ref_skew_val)
if mirror:
if mirror == 'x':
transformed_box_geo = affinity.scale(transformed_box_geo, 1.0, -1.0, origin='center')
if mirror == 'y':
transformed_box_geo = affinity.scale(transformed_box_geo, -1.0, 1.0, origin='center')
if mirror == 'both':
transformed_box_geo = affinity.scale(transformed_box_geo, -1.0, -1.0, origin='center')
bounds = transformed_box_geo.bounds bounds = transformed_box_geo.bounds
size = bounds[2] - bounds[0], bounds[3] - bounds[1] svg_units = obj.units.lower()
# Define a boundary around SVG
margin = self.ui.boundary_entry.get_value()
exported_svg = obj.export_svg(scale_stroke_factor=scale_stroke_factor, doc_final = self.create_positive_svg(svg_geo=exported_svg, box_bounds=bounds, margin=margin, color=color,
scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y, opacity=transparency_level, svg_units=svg_units)
skew_factor_x=skew_factor_x, skew_factor_y=skew_factor_y,
mirror=mirror,
scale_reference=scale_reference, skew_reference=skew_reference,
mirror_reference='center'
)
obj_bounds = obj.bounds()
ret = self.write_output_file(content2save=doc_final, filename=filename, file_type=ftype, p_size=p_size,
orientation=orientation, source_bounds=obj_bounds, box_bounds=bounds)
if ret == 'fail':
return 'fail'
if self.app.options["global_open_style"] is False:
self.app.file_opened.emit("SVG", filename)
self.app.file_saved.emit("SVG", filename)
self.app.inform.emit('[success] %s: %s' % (_("Film file exported to"), filename))
if use_thread is True:
def job_thread_film():
with self.app.proc_container.new(_("Working...")):
try:
make_positive_film(color=color, transparency_level=transparency_level,
scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y)
except Exception as e:
self.app.log.error("export_positive_handler() process -> %s" % str(e))
return
self.app.worker_task.emit({'fcn': job_thread_film, 'params': []})
else:
make_positive_film(color=color, transparency_level=transparency_level,
scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y)
@staticmethod
def create_positive_svg(svg_geo, box_bounds, margin, color, opacity, svg_units):
# Change the attributes of the exported SVG # Change the attributes of the exported SVG
# We don't need stroke-width # We don't need stroke-width
# We set opacity to maximum # We set opacity to maximum
# We set the colour to WHITE # We set the colour to WHITE
root = ET.fromstring(exported_svg) root = ET.fromstring(svg_geo)
for child in root: for child in root:
child.set('fill', str(color)) child.set('fill', str(color))
child.set('opacity', str(transparency_level)) child.set('opacity', str(opacity))
child.set('stroke', str(color)) child.set('stroke', str(color))
exported_svg = ET.tostring(root) exported_svg = ET.tostring(root)
# This contain the measure units # This contain the measure units
uom = obj.units.lower() uom = svg_units
# Define a boundary around SVG
boundary = self.ui.boundary_entry.get_value()
# Convert everything to strings for use in the xml doc # Convert everything to strings for use in the xml doc
svgwidth = str(size[0] + (2 * boundary)) size = box_bounds[2] - box_bounds[0], box_bounds[3] - box_bounds[1]
svgheight = str(size[1] + (2 * boundary))
minx = str(bounds[0] - boundary) svgwidth = str(size[0] + (2 * margin))
miny = str(bounds[1] + boundary + size[1]) svgheight = str(size[1] + (2 * margin))
minx = str(box_bounds[0] - margin)
miny = str(box_bounds[1] + margin + size[1])
# Add a SVG Header and footer to the svg output from shapely # Add a SVG Header and footer to the svg output from shapely
# The transform flips the Y Axis so that everything renders # The transform flips the Y Axis so that everything renders
@@ -1097,29 +946,28 @@ class Film(AppTool):
# Parse the xml through a xml parser just to add line feeds # Parse the xml through a xml parser just to add line feeds
# and to make it look more pretty for the output # and to make it look more pretty for the output
doc = parse_xml_string(svg_elem) doc = parse_xml_string(svg_elem)
doc_final = doc.toprettyxml() return doc.toprettyxml()
if ftype == 'svg': def write_output_file(self, content2save, filename, file_type, p_size, orientation, source_bounds, box_bounds):
p_msg = '[ERROR_NOTCL] %s' % _("Permission denied, saving not possible.\n"
"Most likely another app is holding the file open and not accessible.")
if file_type == 'svg':
try: try:
with open(filename, 'w') as fp: with open(filename, 'w') as fp:
fp.write(doc_final) fp.write(content2save)
except PermissionError: except PermissionError:
self.app.inform.emit('[ERROR_NOTCL] %s' % self.app.inform.emit(p_msg)
_("Permission denied, saving not possible.\n"
"Most likely another app is holding the file open and not accessible."))
return 'fail' return 'fail'
elif ftype == 'png': elif file_type == 'png':
try: try:
doc_final = StringIO(doc_final) doc_final = StringIO(content2save)
drawing = svg2rlg(doc_final) drawing = svg2rlg(doc_final)
renderPM.drawToFile(drawing, filename, 'PNG') renderPM.drawToFile(drawing, filename, 'PNG')
except PermissionError: except PermissionError:
self.app.inform.emit('[ERROR_NOTCL] %s' % self.app.inform.emit(p_msg)
_("Permission denied, saving not possible.\n"
"Most likely another app is holding the file open and not accessible."))
return 'fail' return 'fail'
except Exception as e: except Exception as e:
self.app.log.error("FilmTool.export_positive() --> PNG output --> %s" % str(e)) self.app.log.error("FilmTool.write_output_file() --> PNG output --> %s" % str(e))
return 'fail' return 'fail'
else: # PDF else: # PDF
try: try:
@@ -1135,7 +983,7 @@ class Film(AppTool):
else: else:
page_size = landscape(self.ui.pagesize[p_size]) page_size = landscape(self.ui.pagesize[p_size])
xmin, ymin, xmax, ymax = obj.bounds() xmin, ymin, xmax, ymax = source_bounds
if page_size: if page_size:
page_xmax, page_ymax = ( page_xmax, page_ymax = (
page_size[0] / mm, page_size[0] / mm,
@@ -1146,50 +994,138 @@ class Film(AppTool):
if xmax < 0 or ymax < 0 or xmin > page_xmax or ymin > page_ymax: if xmax < 0 or ymax < 0 or xmin > page_xmax or ymin > page_ymax:
err_msg = '[ERROR_NOTCL] %s %s' % \ err_msg = '[ERROR_NOTCL] %s %s' % \
(_("Failed."), (
_("Failed."),
_("The artwork has to be within the selected page size in order to be visible.\n" _("The artwork has to be within the selected page size in order to be visible.\n"
"For 'Bounds' page size, it needs to be in the first quadrant.")) "For 'Bounds' page size, it needs to be in the first quadrant.")
)
self.app.inform.emit(err_msg) self.app.inform.emit(err_msg)
return 'fail' return 'fail'
doc_final = StringIO(doc_final) doc_final = StringIO(content2save)
drawing = svg2rlg(doc_final) drawing = svg2rlg(doc_final)
if p_size == 'Bounds': if p_size == 'Bounds':
renderPDF.drawToFile(drawing, filename) renderPDF.drawToFile(drawing, filename)
else: else:
my_canvas = canvas.Canvas(filename, pagesize=page_size) my_canvas = canvas.Canvas(filename, pagesize=page_size)
my_canvas.translate(bounds[0] * unit, bounds[1] * unit) my_canvas.translate(box_bounds[0] * unit, box_bounds[1] * unit)
renderPDF.draw(drawing, my_canvas, 0, 0) renderPDF.draw(drawing, my_canvas, 0, 0)
my_canvas.save() my_canvas.save()
except PermissionError: except PermissionError:
self.app.inform.emit('[ERROR_NOTCL] %s' % self.app.inform.emit(p_msg)
_("Permission denied, saving not possible.\n"
"Most likely another app is holding the file open and not accessible."))
return 'fail' return 'fail'
except Exception as e: except Exception as e:
self.app.log.error("FilmTool.export_positive() --> PDF output --> %s" % str(e)) self.app.log.error("FilmTool.write_output_file() --> PDF output --> %s" % str(e))
return 'fail' return 'fail'
if self.app.options["global_open_style"] is False: @staticmethod
self.app.file_opened.emit("SVG", filename) def transform_geometry(obj, scale_factor_x=None, scale_factor_y=None,
self.app.file_saved.emit("SVG", filename) skew_factor_x=None, skew_factor_y=None,
self.app.inform.emit('[success] %s: %s' % (_("Film file exported to"), filename)) skew_reference='center', scale_reference='center', mirror=None):
"""
Return a transformed geometry made from a Shapely geometry collection property of the `obj` object
if use_thread is True: :return: Shapely geometry transformed
def job_thread_film(): """
with self.app.proc_container.new(_("Working...")):
try:
make_positive_film(color=color, transparency_level=transparency_level,
scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y)
except Exception as e:
self.app.log.error("export_positive() process -> %s" % str(e))
return
self.app.worker_task.emit({'fcn': job_thread_film, 'params': []}) # Make sure we see a Shapely Geometry class and not a list
if obj.kind.lower() == 'geometry':
flat_geo = []
if obj.multigeo:
for tool in obj.tools:
flat_geo += obj.flatten(obj.tools[tool]['solid_geometry'])
transformed_geo = unary_union(flat_geo)
else: else:
make_positive_film(color=color, transparency_level=transparency_level, transformed_geo = unary_union(obj.flatten())
scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y) else:
transformed_geo = unary_union(obj.flatten())
# SCALING
if scale_factor_x or scale_factor_y:
xmin, ymin, xmax, ymax = transformed_geo.bounds
ref_scale_val = 'center'
if scale_reference == 'topleft':
ref_scale_val = (xmin, ymax)
elif scale_reference == 'bottomleft':
ref_scale_val = (xmin, ymin)
elif scale_reference == 'topright':
ref_scale_val = (xmax, ymax)
elif scale_reference == 'bottomright':
ref_scale_val = (xmax, ymin)
if scale_factor_x and not scale_factor_y:
val_x = scale_factor_x
val_y = 0
elif not scale_factor_x and scale_factor_y:
val_x = 0
val_y = scale_factor_y
else:
val_x = scale_factor_x
val_y = scale_factor_y
transformed_geo = affinity.scale(transformed_geo, val_x, val_y, origin=ref_scale_val)
# SKEWING
if skew_factor_x or skew_factor_y:
xmin, ymin, xmax, ymax = transformed_geo.bounds
if skew_reference == 'bottomleft':
ref_skew_val = (xmin, ymin)
if skew_factor_x and not skew_factor_y:
skew_angle_x = math.degrees(math.atan2(skew_factor_x, (ymax - ymin)))
skew_angle_y = 0.0
elif not skew_factor_x and skew_factor_y:
skew_angle_x = 0.0
skew_angle_y = math.degrees(math.atan2(skew_factor_y, (xmax - xmin)))
else:
skew_angle_x = math.degrees(math.atan2(skew_factor_x, (ymax - ymin)))
skew_angle_y = math.degrees(math.atan2(skew_factor_y, (xmax - xmin)))
else:
ref_skew_val = 'center'
if skew_factor_x and not skew_factor_y:
skew_angle_x = math.degrees(math.atan2(skew_factor_x, ((ymax - ymin) * 0.5)))
skew_angle_y = 0.0
elif not skew_factor_x and skew_factor_y:
skew_angle_x = 0.0
skew_angle_y = math.degrees(math.atan2(skew_factor_y, ((xmax - xmin) * 0.5)))
else:
skew_angle_x = math.degrees(math.atan2(skew_factor_x, ((ymax - ymin) * 0.5)))
skew_angle_y = math.degrees(math.atan2(skew_factor_y, ((xmax - xmin) * 0.5)))
transformed_geo = affinity.skew(transformed_geo, skew_angle_x, skew_angle_y, origin=ref_skew_val)
if mirror:
if mirror == 'x':
transformed_geo = affinity.scale(transformed_geo, 1.0, -1.0, origin='center')
if mirror == 'y':
transformed_geo = affinity.scale(transformed_geo, -1.0, 1.0, origin='center')
if mirror == 'both':
transformed_geo = affinity.scale(transformed_geo, -1.0, -1.0, origin='center')
return transformed_geo
@staticmethod
def create_svg_geometry(geom, scale_stroke_factor):
"""
Return SVG geometry made from a Shapely geometry collection property of the `obj` object
:param geom: Shapely geometry collection
:type geom:
:param scale_stroke_factor: multiplication factor for the SVG stroke-width used within shapely's svg export
If 0 or less which is invalid then default to 0.01
This value appears to work for zooming, and getting the output svg line width
to match that viewed on screen with FlatCam
MS: I choose a factor of 0.01 so the scale is right for PCB UV film
:type scale_stroke_factor: float
:return: SVG geometry
:rtype:
"""
if scale_stroke_factor <= 0:
scale_stroke_factor = 0.01
# Convert to a SVG
svg_elem = geom.svg(scale_factor=scale_stroke_factor)
return svg_elem
def reset_fields(self): def reset_fields(self):
self.ui.tf_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex())) self.ui.tf_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
@@ -1399,7 +1335,7 @@ class FilmUI:
adj_grid.addWidget(self.film_skew_cb, 12, 0, 1, 2) adj_grid.addWidget(self.film_skew_cb, 12, 0, 1, 2)
# Skew X # Skew X
self.film_skewx_label = FCLabel('%s:' % _("X angle")) self.film_skewx_label = FCLabel('%s:' % _("X val"))
self.film_skewx_entry = FCDoubleSpinner(callback=self.confirmation_message) self.film_skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_skewx_entry.set_range(-999.9999, 999.9999) self.film_skewx_entry.set_range(-999.9999, 999.9999)
self.film_skewx_entry.set_precision(self.decimals) self.film_skewx_entry.set_precision(self.decimals)
@@ -1409,7 +1345,7 @@ class FilmUI:
adj_grid.addWidget(self.film_skewx_entry, 14, 1) adj_grid.addWidget(self.film_skewx_entry, 14, 1)
# Skew Y # Skew Y
self.film_skewy_label = FCLabel('%s:' % _("Y angle")) self.film_skewy_label = FCLabel('%s:' % _("Y val"))
self.film_skewy_entry = FCDoubleSpinner(callback=self.confirmation_message) self.film_skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_skewy_entry.set_range(-999.9999, 999.9999) self.film_skewy_entry.set_range(-999.9999, 999.9999)
self.film_skewy_entry.set_precision(self.decimals) self.film_skewy_entry.set_precision(self.decimals)
@@ -1426,7 +1362,7 @@ class FilmUI:
self.skew_ref_combo = FCComboBox2() self.skew_ref_combo = FCComboBox2()
self.skew_ref_combo.addItems( self.skew_ref_combo.addItems(
[_('Center'), _('Bottom Left'), _('Top Left'), _('Bottom Right'), _('Top right')]) [_('Center'), _('Bottom Left')])
adj_grid.addWidget(self.skew_ref_label, 18, 0) adj_grid.addWidget(self.skew_ref_label, 18, 0)
adj_grid.addWidget(self.skew_ref_combo, 18, 1) adj_grid.addWidget(self.skew_ref_combo, 18, 1)