Merge pull request #5814 from Lawrence37/perspective-lines
GUI improvements for perspective correction
This commit is contained in:
commit
eb01f99bf2
127
rtdata/images/svg/bidirectional-arrow-horizontal-hicontrast.svg
Normal file
127
rtdata/images/svg/bidirectional-arrow-horizontal-hicontrast.svg
Normal file
@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24px"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
inkscape:export-filename="/tmp/template.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="bidirectional-arrow-horizontal-hicontrast.svg">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#E0E1E2"
|
||||
bordercolor="#666768"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="29.288994"
|
||||
inkscape:cx="11.864052"
|
||||
inkscape:cy="11.292624"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1041"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-others="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
inkscape:snap-text-baseline="true"
|
||||
inkscape:snap-page="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid1374"
|
||||
originx="1"
|
||||
originy="1"
|
||||
empspacing="11"
|
||||
dotted="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs815" />
|
||||
<metadata
|
||||
id="metadata818">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Lawrence</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:description>RawTherapee icon.</dc:description>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 5.75,13.5 h 12.5 v -3 H 5.75 Z"
|
||||
id="path857"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 6.4999667,13.5 v 2.25 l -5,-3.75 5,-3.75 v 2.25"
|
||||
id="path853"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 17.5,13.5 v 2.25 l 5,-3.75 -5,-3.75 v 2.25"
|
||||
id="path855" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.2 KiB |
127
rtdata/images/svg/bidirectional-arrow-horizontal-prelight.svg
Normal file
127
rtdata/images/svg/bidirectional-arrow-horizontal-prelight.svg
Normal file
@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24px"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
inkscape:export-filename="/tmp/template.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="bidirectional-arrow-horizontal-prelight.svg">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#E0E1E2"
|
||||
bordercolor="#666768"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="29.288994"
|
||||
inkscape:cx="11.864052"
|
||||
inkscape:cy="11.292624"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1041"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-others="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
inkscape:snap-text-baseline="true"
|
||||
inkscape:snap-page="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid1374"
|
||||
originx="1"
|
||||
originy="1"
|
||||
empspacing="11"
|
||||
dotted="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs815" />
|
||||
<metadata
|
||||
id="metadata818">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Lawrence</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:description>RawTherapee icon.</dc:description>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<path
|
||||
style="fill:#ff6400;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 5.75,13.5 h 12.5 v -3 H 5.75 Z"
|
||||
id="path857"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#ff6400;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 6.4999667,13.5 v 2.25 l -5,-3.75 5,-3.75 v 2.25"
|
||||
id="path853"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#ff6400;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 17.5,13.5 v 2.25 l 5,-3.75 -5,-3.75 v 2.25"
|
||||
id="path855" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.2 KiB |
127
rtdata/images/svg/bidirectional-arrow-vertical-hicontrast.svg
Normal file
127
rtdata/images/svg/bidirectional-arrow-vertical-hicontrast.svg
Normal file
@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24px"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
inkscape:export-filename="/tmp/template.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="bidirectional-arrow-vertical-hicontrast.svg">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#E0E1E2"
|
||||
bordercolor="#666768"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="29.288994"
|
||||
inkscape:cx="11.864052"
|
||||
inkscape:cy="11.292624"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1041"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-others="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
inkscape:snap-text-baseline="true"
|
||||
inkscape:snap-page="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid1374"
|
||||
originx="1"
|
||||
originy="1"
|
||||
empspacing="11"
|
||||
dotted="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs815" />
|
||||
<metadata
|
||||
id="metadata818">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Lawrence</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:description>RawTherapee icon.</dc:description>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 10.5,5.75 v 12.5 h 3 V 5.75 Z"
|
||||
id="path857"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 10.5,6.4999667 H 8.25 l 3.75,-5 3.75,5 H 13.5"
|
||||
id="path853"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 10.5,17.5 H 8.25 l 3.75,5 3.75,-5 H 13.5"
|
||||
id="path855" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.2 KiB |
127
rtdata/images/svg/bidirectional-arrow-vertical-prelight.svg
Normal file
127
rtdata/images/svg/bidirectional-arrow-vertical-prelight.svg
Normal file
@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
sodipodi:docname="bidirectional-arrow-vertical-prelight.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-filename="/tmp/template.png"
|
||||
id="SVGRoot"
|
||||
version="1.1"
|
||||
viewBox="0 0 24 24"
|
||||
height="24px"
|
||||
width="24px">
|
||||
<sodipodi:namedview
|
||||
inkscape:snap-page="true"
|
||||
inkscape:snap-text-baseline="true"
|
||||
inkscape:snap-center="true"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-others="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="1041"
|
||||
inkscape:window-width="1920"
|
||||
showgrid="true"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:cy="11.292624"
|
||||
inkscape:cx="11.864052"
|
||||
inkscape:zoom="29.288994"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666768"
|
||||
pagecolor="#E0E1E2"
|
||||
id="base">
|
||||
<inkscape:grid
|
||||
dotted="false"
|
||||
empspacing="11"
|
||||
originy="1"
|
||||
originx="1"
|
||||
id="grid1374"
|
||||
type="xygrid" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs815" />
|
||||
<metadata
|
||||
id="metadata818">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Lawrence</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:description>RawTherapee icon.</dc:description>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
id="path857"
|
||||
d="m 10.5,5.75 v 12.5 h 3 V 5.75 Z"
|
||||
style="fill:#ff6400;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
id="path853"
|
||||
d="m 10.49995,6.4999667 h -2.25 l 3.75,-5 3.75,5 h -2.25"
|
||||
style="fill:#ff6400;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
id="path855"
|
||||
d="M 10.5,17.5 H 8.25 l 3.75,5 3.75,-5 H 13.5"
|
||||
style="fill:#ff6400;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.2 KiB |
108
rtdata/images/svg/draw.svg
Normal file
108
rtdata/images/svg/draw.svg
Normal file
@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24px"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
inkscape:export-filename="/tmp/template.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="draw.svg">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#E0E1E2"
|
||||
bordercolor="#666768"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="14.298358"
|
||||
inkscape:cx="-1.7458856"
|
||||
inkscape:cy="16.76612"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1041"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-others="true"
|
||||
inkscape:object-nodes="false"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:snap-bbox-midpoints="false"
|
||||
inkscape:document-rotation="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid1374"
|
||||
originx="1"
|
||||
originy="1"
|
||||
empspacing="11"
|
||||
dotted="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs815" />
|
||||
<metadata
|
||||
id="metadata818">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Lawrence</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:description>RawTherapee icon.</dc:description>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<path
|
||||
style="opacity:0.7;fill:#2a7fff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00157;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 19.761765,1 c 1.135523,0 3.238095,2.1025723 3.238095,3.238095 0,1.1355228 -1.57952,1.57952 -1.57952,1.57952 L 18.182245,2.57952 c 0,0 0.443997,-1.57952 1.57952,-1.57952 z M 17.372721,3.3890438 20.610816,6.6271387 7.515719,19.722235 4.277625,16.484141 Z M 3.468101,17.293664 6.706195,20.531759 6.666665,20.571289 1,22.999859 3.42857,17.333193 Z"
|
||||
id="path1658"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="zzcczccccccccccc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
@ -221,8 +221,10 @@ GENERAL_BEFORE;Before
|
||||
GENERAL_CANCEL;Cancel
|
||||
GENERAL_CLOSE;Close
|
||||
GENERAL_CURRENT;Current
|
||||
GENERAL_DELETE_ALL;Delete all
|
||||
GENERAL_DISABLE;Disable
|
||||
GENERAL_DISABLED;Disabled
|
||||
GENERAL_EDIT;Edit
|
||||
GENERAL_ENABLE;Enable
|
||||
GENERAL_ENABLED;Enabled
|
||||
GENERAL_FILE;File
|
||||
@ -1213,6 +1215,7 @@ HISTORY_MSG_PDSHARPEN_RADIUS_BOOST;CS - Corner radius boost
|
||||
HISTORY_MSG_PERSP_CAM_ANGLE;Perspective - Camera
|
||||
HISTORY_MSG_PERSP_CAM_FL;Perspective - Camera
|
||||
HISTORY_MSG_PERSP_CAM_SHIFT;Perspective - Camera
|
||||
HISTORY_MSG_PERSP_CTRL_LINE;Perspective - Control lines
|
||||
HISTORY_MSG_PERSP_METHOD;Perspective - Method
|
||||
HISTORY_MSG_PERSP_PROJ_ANGLE;Perspective - Recovery
|
||||
HISTORY_MSG_PERSP_PROJ_ROTATE;Perspective - PCA rotation
|
||||
@ -1814,6 +1817,7 @@ THRESHOLDSELECTOR_TR;Top-right
|
||||
TOOLBAR_TOOLTIP_COLORPICKER;Lockable Color Picker\n\nWhen the tool is active:\n- Add a picker: <b>left-click</b>.\n- Drag a picker: <b>left-click and drag</b>.\n- Delete a picker: <b>right-click</b>.\n- Delete all pickers: <b>Ctrl</b>+<b>Shift</b>+<b>right-click</b>.\n- Revert to hand tool: <b>right-click</b> outside any picker.
|
||||
TOOLBAR_TOOLTIP_CROP;<b>Crop</b> selection.\nShortcut: <b>c</b>\nMove the crop using <b>Shift</b>+<b>mouse drag</b>.
|
||||
TOOLBAR_TOOLTIP_HAND;Hand tool.\nShortcut: <b>h</b>
|
||||
TOOLBAR_TOOLTIP_PERSPECTIVE;<b>Perspective Correction</b>\n\nEdit control lines to correct perspective distortion. Click this button again to apply correction.
|
||||
TOOLBAR_TOOLTIP_STRAIGHTEN;<b>Straighten</b> / <b>fine rotation</b>.\nShortcut: <b>s</b>\n\nIndicate the vertical or horizontal by drawing a guide line over the image preview. Angle of rotation will be shown next to the guide line. Center of rotation is the geometrical center of the image.
|
||||
TOOLBAR_TOOLTIP_WB;Spot white balance.\nShortcut: <b>w</b>
|
||||
TP_BWMIX_ALGO;Algorithm OYCPM
|
||||
@ -2950,6 +2954,8 @@ TP_PERSPECTIVE_CAMERA_ROLL;Rotation
|
||||
TP_PERSPECTIVE_CAMERA_SHIFT_HORIZONTAL;Horizontal shift
|
||||
TP_PERSPECTIVE_CAMERA_SHIFT_VERTICAL;Vertical shift
|
||||
TP_PERSPECTIVE_CAMERA_YAW;Horizontal
|
||||
TP_PERSPECTIVE_CONTROL_LINES;Control lines
|
||||
TP_PERSPECTIVE_CONTROL_LINES_TOOLTIP;<b>Ctrl</b>+<b>drag</b>: Draw new line\n<b>Right-click</b>: Delete line
|
||||
TP_PERSPECTIVE_HORIZONTAL;Horizontal
|
||||
TP_PERSPECTIVE_LABEL;Perspective
|
||||
TP_PERSPECTIVE_METHOD;Method
|
||||
|
@ -2111,7 +2111,7 @@ static double model_fitness(double *params, void *data)
|
||||
}
|
||||
|
||||
// setup all data structures for fitting and call NM simplex
|
||||
static dt_iop_ashift_nmsresult_t nmsfit(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_iop_ashift_fitaxis_t dir)
|
||||
static dt_iop_ashift_nmsresult_t nmsfit(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_iop_ashift_fitaxis_t dir, int min_line_count)
|
||||
{
|
||||
dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data;
|
||||
|
||||
@ -2227,7 +2227,7 @@ static dt_iop_ashift_nmsresult_t nmsfit(dt_iop_module_t *module, dt_iop_ashift_p
|
||||
// we use vertical lines for fitting
|
||||
fit.linetype |= ASHIFT_LINE_DIRVERT;
|
||||
fit.weight += g->vertical_weight;
|
||||
enough_lines = enough_lines && (g->vertical_count >= MINIMUM_FITLINES);
|
||||
enough_lines = enough_lines && (g->vertical_count >= min_line_count);
|
||||
}
|
||||
|
||||
if(mdir & ASHIFT_FIT_LINES_HOR)
|
||||
@ -2235,7 +2235,7 @@ static dt_iop_ashift_nmsresult_t nmsfit(dt_iop_module_t *module, dt_iop_ashift_p
|
||||
// we use horizontal lines for fitting
|
||||
fit.linetype |= 0;
|
||||
fit.weight += g->horizontal_weight;
|
||||
enough_lines = enough_lines && (g->horizontal_count >= MINIMUM_FITLINES);
|
||||
enough_lines = enough_lines && (g->horizontal_count >= min_line_count);
|
||||
}
|
||||
|
||||
// this needs to come after ASHIFT_FIT_LINES_VERT and ASHIFT_FIT_LINES_HOR
|
||||
@ -2905,7 +2905,7 @@ static int do_clean_structure(dt_iop_module_t *module, dt_iop_ashift_params_t *p
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// helper function to start parameter fit and report about errors
|
||||
static int do_fit(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_iop_ashift_fitaxis_t dir)
|
||||
static int do_fit(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_iop_ashift_fitaxis_t dir, int min_line_count = MINIMUM_FITLINES)
|
||||
{
|
||||
dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data;
|
||||
dt_iop_ashift_nmsresult_t res;
|
||||
@ -2918,7 +2918,7 @@ static int do_fit(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_iop_ash
|
||||
|
||||
g->fitting = 1;
|
||||
|
||||
res = nmsfit(module, p, dir);
|
||||
res = nmsfit(module, p, dir, min_line_count);
|
||||
|
||||
switch(res)
|
||||
{
|
||||
@ -3815,8 +3815,10 @@ void gui_post_expose(struct dt_iop_module_t *self, cairo_t *cr, int32_t width, i
|
||||
|
||||
cairo_restore(cr);
|
||||
}
|
||||
#endif // if 0
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
update the number of selected vertical and horizontal lines
|
||||
// update the number of selected vertical and horizontal lines
|
||||
static void update_lines_count(const dt_iop_ashift_line_t *lines, const int lines_count,
|
||||
int *vertical_count, int *horizontal_count)
|
||||
{
|
||||
@ -3835,6 +3837,9 @@ static void update_lines_count(const dt_iop_ashift_line_t *lines, const int line
|
||||
*horizontal_count = hlines;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RT: BEGIN COMMENT
|
||||
#if 0
|
||||
int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which)
|
||||
{
|
||||
dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data;
|
||||
|
@ -454,7 +454,7 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector<Coord2D> &src,
|
||||
double cost = cos (params->rotate.degree * rtengine::RT_PI / 180.0);
|
||||
double sint = sin (params->rotate.degree * rtengine::RT_PI / 180.0);
|
||||
|
||||
double ascale = ascaleDef > 0 ? ascaleDef : (params->commonTrans.autofill ? getTransformAutoFill (oW, oH, pLCPMap) : 1.0);
|
||||
double ascale = ascaleDef > 0 ? ascaleDef : (params->commonTrans.autofill && params->perspective.render ? getTransformAutoFill (oW, oH, pLCPMap) : 1.0);
|
||||
|
||||
// auxiliary variables for perspective correction
|
||||
// Simple.
|
||||
@ -1182,7 +1182,7 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
|
||||
p_projection_rotate, p_projection_shift_horiz,
|
||||
p_projection_shift_vert, p_projection_scale);
|
||||
|
||||
const double ascale = params->commonTrans.autofill ? getTransformAutoFill(oW, oH, pLCPMap) : 1.0;
|
||||
const double ascale = params->commonTrans.autofill && params->perspective.render ? getTransformAutoFill(oW, oH, pLCPMap) : 1.0;
|
||||
|
||||
const bool darkening = (params->vignetting.amount <= 0.0);
|
||||
const bool useLog = params->commonTrans.method == "log" && highQuality;
|
||||
@ -1471,7 +1471,8 @@ bool ImProcFunctions::needsPerspective () const
|
||||
{
|
||||
return ( (params->perspective.method == "simple") &&
|
||||
(params->perspective.horizontal || params->perspective.vertical) )
|
||||
|| ( (params->perspective.method == "camera_based") && (
|
||||
|| ( (params->perspective.method == "camera_based") &&
|
||||
params->perspective.render && (
|
||||
params->perspective.camera_pitch ||
|
||||
params->perspective.camera_roll ||
|
||||
params->perspective.camera_shift_horiz ||
|
||||
|
@ -225,10 +225,44 @@ void get_view_size(int w, int h, const procparams::PerspectiveParams ¶ms, do
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocates a new array and populates it with ashift lines corresponding to the
|
||||
* provided control lines.
|
||||
*/
|
||||
std::unique_ptr<dt_iop_ashift_line_t[]> toAshiftLines(const std::vector<ControlLine> *lines)
|
||||
{
|
||||
std::unique_ptr<dt_iop_ashift_line_t[]> retval(new dt_iop_ashift_line_t[lines->size()]);
|
||||
|
||||
for (size_t i = 0; i < lines->size(); i++) {
|
||||
const float x1 = (*lines)[i].x1;
|
||||
const float y1 = (*lines)[i].y1;
|
||||
const float x2 = (*lines)[i].x2;
|
||||
const float y2 = (*lines)[i].y2;
|
||||
retval[i].p1[0] = x1;
|
||||
retval[i].p1[1] = y1;
|
||||
retval[i].p1[2] = 1.0f;
|
||||
retval[i].p2[0] = x2;
|
||||
retval[i].p2[1] = y2;
|
||||
retval[i].p2[2] = 1.0f;
|
||||
retval[i].length = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
|
||||
retval[i].width = 1.0f;
|
||||
retval[i].weight = retval[i].length;
|
||||
if ((*lines)[i].type == ControlLine::HORIZONTAL) {
|
||||
retval[i].type = ASHIFT_LINE_HORIZONTAL_SELECTED;
|
||||
} else if ((*lines)[i].type == ControlLine::VERTICAL) {
|
||||
retval[i].type = ASHIFT_LINE_VERTICAL_SELECTED;
|
||||
} else {
|
||||
retval[i].type = ASHIFT_LINE_IRRELEVANT;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *src, bool corr_pitch, bool corr_yaw, const procparams::ProcParams *pparams, const FramesMetaData *metadata)
|
||||
PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *src, bool corr_pitch, bool corr_yaw, const procparams::ProcParams *pparams, const FramesMetaData *metadata, const std::vector<ControlLine> *control_lines)
|
||||
{
|
||||
auto pcp = procparams::PerspectiveParams(pparams->perspective);
|
||||
procparams::PerspectiveParams dflt;
|
||||
@ -252,49 +286,51 @@ PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *sr
|
||||
int tr = getCoarseBitMask(pparams->coarse);
|
||||
int fw, fh;
|
||||
src->getFullSize(fw, fh, tr);
|
||||
int skip = max(float(max(fw, fh)) / 900.f + 0.5f, 1.f);
|
||||
PreviewProps pp(0, 0, fw, fh, skip);
|
||||
int w, h;
|
||||
src->getSize(pp, w, h);
|
||||
std::unique_ptr<Imagefloat> img(new Imagefloat(w, h));
|
||||
if (control_lines == nullptr) {
|
||||
int skip = max(float(max(fw, fh)) / 900.f + 0.5f, 1.f);
|
||||
PreviewProps pp(0, 0, fw, fh, skip);
|
||||
int w, h;
|
||||
src->getSize(pp, w, h);
|
||||
std::unique_ptr<Imagefloat> img(new Imagefloat(w, h));
|
||||
|
||||
ProcParams neutral;
|
||||
neutral.raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST);
|
||||
neutral.raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST);
|
||||
neutral.icm.outputProfile = ColorManagementParams::NoICMString;
|
||||
src->getImage(src->getWB(), tr, img.get(), pp, neutral.toneCurve, neutral.raw);
|
||||
src->convertColorSpace(img.get(), pparams->icm, src->getWB());
|
||||
ProcParams neutral;
|
||||
neutral.raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST);
|
||||
neutral.raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST);
|
||||
neutral.icm.outputProfile = ColorManagementParams::NoICMString;
|
||||
src->getImage(src->getWB(), tr, img.get(), pp, neutral.toneCurve, neutral.raw);
|
||||
src->convertColorSpace(img.get(), pparams->icm, src->getWB());
|
||||
|
||||
neutral.commonTrans.autofill = false; // Ensures crop factor is correct.
|
||||
// TODO: Ensure image borders of rotated image do not get detected as lines.
|
||||
neutral.rotate = pparams->rotate;
|
||||
neutral.distortion = pparams->distortion;
|
||||
neutral.lensProf = pparams->lensProf;
|
||||
ImProcFunctions ipf(&neutral, true);
|
||||
if (ipf.needsTransform(w, h, src->getRotateDegree(), src->getMetaData())) {
|
||||
Imagefloat *tmp = new Imagefloat(w, h);
|
||||
ipf.transform(img.get(), tmp, 0, 0, 0, 0, w, h, w, h,
|
||||
src->getMetaData(), src->getRotateDegree(), false);
|
||||
img.reset(tmp);
|
||||
}
|
||||
neutral.commonTrans.autofill = false; // Ensures crop factor is correct.
|
||||
// TODO: Ensure image borders of rotated image do not get detected as lines.
|
||||
neutral.rotate = pparams->rotate;
|
||||
neutral.distortion = pparams->distortion;
|
||||
neutral.lensProf = pparams->lensProf;
|
||||
ImProcFunctions ipf(&neutral, true);
|
||||
if (ipf.needsTransform(w, h, src->getRotateDegree(), src->getMetaData())) {
|
||||
Imagefloat *tmp = new Imagefloat(w, h);
|
||||
ipf.transform(img.get(), tmp, 0, 0, 0, 0, w, h, w, h,
|
||||
src->getMetaData(), src->getRotateDegree(), false);
|
||||
img.reset(tmp);
|
||||
}
|
||||
|
||||
// allocate the gui buffer
|
||||
g.buf = static_cast<float *>(malloc(sizeof(float) * w * h * 4));
|
||||
g.buf_width = w;
|
||||
g.buf_height = h;
|
||||
// allocate the gui buffer
|
||||
g.buf = static_cast<float *>(malloc(sizeof(float) * w * h * 4));
|
||||
g.buf_width = w;
|
||||
g.buf_height = h;
|
||||
|
||||
img->normalizeFloatTo1();
|
||||
|
||||
img->normalizeFloatTo1();
|
||||
|
||||
#ifdef _OPENMP
|
||||
# pragma omp parallel for
|
||||
#endif
|
||||
for (int y = 0; y < h; ++y) {
|
||||
for (int x = 0; x < w; ++x) {
|
||||
int i = (y * w + x) * 4;
|
||||
g.buf[i] = img->r(y, x);
|
||||
g.buf[i+1] = img->g(y, x);
|
||||
g.buf[i+2] = img->b(y, x);
|
||||
g.buf[i+3] = 1.f;
|
||||
for (int y = 0; y < h; ++y) {
|
||||
for (int x = 0; x < w; ++x) {
|
||||
int i = (y * w + x) * 4;
|
||||
g.buf[i] = img->r(y, x);
|
||||
g.buf[i+1] = img->g(y, x);
|
||||
g.buf[i+2] = img->b(y, x);
|
||||
g.buf[i+3] = 1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,7 +347,20 @@ PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *sr
|
||||
// internally!
|
||||
srand(1);
|
||||
|
||||
auto res = do_get_structure(&module, &p, ASHIFT_ENHANCE_EDGES) && do_fit(&module, &p, fitaxis);
|
||||
bool res;
|
||||
if (control_lines == nullptr) {
|
||||
res = do_get_structure(&module, &p, ASHIFT_ENHANCE_EDGES) && do_fit(&module, &p, fitaxis);
|
||||
} else {
|
||||
std::unique_ptr<dt_iop_ashift_line_t[]> ashift_lines = toAshiftLines(control_lines);
|
||||
dt_iop_ashift_gui_data_t *g = module.gui_data;
|
||||
g->lines_count = control_lines->size();
|
||||
g->lines = ashift_lines.get();
|
||||
g->lines_in_height = fh;
|
||||
g->lines_in_width = fw;
|
||||
update_lines_count(g->lines, g->lines_count, &(g->vertical_count), &(g->horizontal_count));
|
||||
res = do_fit(&module, &p, fitaxis, 2);
|
||||
g->lines = nullptr;
|
||||
}
|
||||
Params retval = {
|
||||
.angle = p.rotation,
|
||||
.pitch = p.camera_pitch,
|
||||
@ -322,7 +371,7 @@ PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *sr
|
||||
if (g.lines) free(g.lines);
|
||||
if (g.points) free(g.points);
|
||||
if (g.points_idx) free(g.points_idx);
|
||||
free(g.buf);
|
||||
if (g.buf) free(g.buf);
|
||||
|
||||
if (!res) {
|
||||
retval.angle = pparams->perspective.camera_roll;
|
||||
|
@ -20,12 +20,32 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "coord2d.h"
|
||||
#include "procparams.h"
|
||||
#include "imagesource.h"
|
||||
#include <vector>
|
||||
|
||||
namespace rtengine {
|
||||
|
||||
namespace procparams
|
||||
{
|
||||
|
||||
class ProcParams;
|
||||
|
||||
}
|
||||
|
||||
class ImageSource;
|
||||
class FramesMetaData;
|
||||
|
||||
class ControlLine
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
HORIZONTAL,
|
||||
VERTICAL
|
||||
};
|
||||
float x1, y1, x2, y2;
|
||||
Type type;
|
||||
};
|
||||
|
||||
class PerspectiveCorrection {
|
||||
public:
|
||||
struct Params
|
||||
@ -35,7 +55,7 @@ public:
|
||||
double yaw;
|
||||
};
|
||||
|
||||
static Params autocompute(ImageSource *src, bool corr_pitch, bool corr_yaw, const procparams::ProcParams *pparams, const FramesMetaData *metadata);
|
||||
static Params autocompute(ImageSource *src, bool corr_pitch, bool corr_yaw, const procparams::ProcParams *pparams, const FramesMetaData *metadata, const std::vector<ControlLine> *control_lines = nullptr);
|
||||
|
||||
//static void autocrop(int width, int height, bool fixratio, const procparams::PerspectiveParams ¶ms, const FramesMetaData *metadata, int &x, int &y, int &w, int &h);
|
||||
};
|
||||
|
@ -1870,6 +1870,7 @@ LensProfParams::LcMode LensProfParams::getMethodNumber(const Glib::ustring& mode
|
||||
|
||||
PerspectiveParams::PerspectiveParams() :
|
||||
method("simple"),
|
||||
render(true),
|
||||
horizontal(0.0),
|
||||
vertical(0.0),
|
||||
camera_crop_factor(0.0),
|
||||
@ -1891,6 +1892,7 @@ bool PerspectiveParams::operator ==(const PerspectiveParams& other) const
|
||||
{
|
||||
return
|
||||
method == other.method
|
||||
&& render == other.render
|
||||
&& horizontal == other.horizontal
|
||||
&& vertical == other.vertical
|
||||
&& camera_focal_length == other.camera_focal_length
|
||||
@ -1904,7 +1906,12 @@ bool PerspectiveParams::operator ==(const PerspectiveParams& other) const
|
||||
&& projection_shift_vert == other.projection_shift_vert
|
||||
&& projection_rotate == other.projection_rotate
|
||||
&& projection_pitch == other.projection_pitch
|
||||
&& projection_yaw == other.projection_yaw;
|
||||
&& projection_yaw == other.projection_yaw
|
||||
// Lines could still be equivalent if the vectors aren't, but this is
|
||||
// rare and a small issue. Besides, a proper comparison requires lots
|
||||
// more code which introduces clutter.
|
||||
&& control_line_values == other.control_line_values
|
||||
&& control_line_types == other.control_line_types;
|
||||
}
|
||||
|
||||
bool PerspectiveParams::operator !=(const PerspectiveParams& other) const
|
||||
@ -5454,6 +5461,8 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
|
||||
saveToKeyfile(!pedited || pedited->perspective.projection_shift_horiz, "Perspective", "ProjectionShiftHorizontal", perspective.projection_shift_horiz, keyFile);
|
||||
saveToKeyfile(!pedited || pedited->perspective.projection_shift_vert, "Perspective", "ProjectionShiftVertical", perspective.projection_shift_vert, keyFile);
|
||||
saveToKeyfile(!pedited || pedited->perspective.projection_yaw, "Perspective", "ProjectionYaw", perspective.projection_yaw, keyFile);
|
||||
saveToKeyfile(!pedited || pedited->perspective.control_lines, "Perspective", "ControlLineValues", perspective.control_line_values, keyFile);
|
||||
saveToKeyfile(!pedited || pedited->perspective.control_lines, "Perspective", "ControlLineTypes", perspective.control_line_types, keyFile);
|
||||
|
||||
// Gradient
|
||||
saveToKeyfile(!pedited || pedited->gradient.enabled, "Gradient", "Enabled", gradient.enabled, keyFile);
|
||||
@ -7137,6 +7146,13 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
|
||||
assignFromKeyfile(keyFile, "Perspective", "ProjectionShiftHorizontal", pedited, perspective.projection_shift_horiz, pedited->perspective.projection_shift_horiz);
|
||||
assignFromKeyfile(keyFile, "Perspective", "ProjectionShiftVertical", pedited, perspective.projection_shift_vert, pedited->perspective.projection_shift_vert);
|
||||
assignFromKeyfile(keyFile, "Perspective", "ProjectionYaw", pedited, perspective.projection_yaw, pedited->perspective.projection_yaw);
|
||||
if (keyFile.has_key("Perspective", "ControlLineValues") && keyFile.has_key("Perspective", "ControlLineTypes")) {
|
||||
perspective.control_line_values = keyFile.get_integer_list("Perspective", "ControlLineValues");
|
||||
perspective.control_line_types = keyFile.get_integer_list("Perspective", "ControlLineTypes");
|
||||
if (pedited) {
|
||||
pedited->perspective.control_lines = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keyFile.has_group("Gradient")) {
|
||||
|
@ -932,6 +932,7 @@ struct LensProfParams {
|
||||
*/
|
||||
struct PerspectiveParams {
|
||||
Glib::ustring method;
|
||||
bool render;
|
||||
double horizontal;
|
||||
double vertical;
|
||||
double camera_crop_factor;
|
||||
@ -946,6 +947,10 @@ struct PerspectiveParams {
|
||||
double projection_shift_horiz;
|
||||
double projection_shift_vert;
|
||||
double projection_yaw;
|
||||
/** A line is stored as 4 integers in this order: x1, y1, x2, y2 */
|
||||
std::vector<int> control_line_values;
|
||||
/** 0 is vertical, 1 is horizontal, undefined otherwise. */
|
||||
std::vector<int> control_line_types;
|
||||
|
||||
PerspectiveParams();
|
||||
|
||||
|
@ -34,6 +34,7 @@ set(NONCLISOURCEFILES
|
||||
colorappearance.cc
|
||||
coloredbar.cc
|
||||
colortoning.cc
|
||||
controllines.cc
|
||||
controlspotpanel.cc
|
||||
coordinateadjuster.cc
|
||||
crop.cc
|
||||
|
492
rtgui/controllines.cc
Normal file
492
rtgui/controllines.cc
Normal file
@ -0,0 +1,492 @@
|
||||
/*
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* Copyright (c) 2020 Lawrence Lee <billee@ucdavis.edu>
|
||||
*
|
||||
* RawTherapee 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.
|
||||
*
|
||||
* RawTherapee 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 RawTherapee. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <memory>
|
||||
|
||||
#include "controllines.h"
|
||||
#include "editcallbacks.h"
|
||||
#include "editwidgets.h"
|
||||
#include "rtsurface.h"
|
||||
|
||||
#include "../rtengine/perspectivecorrection.h"
|
||||
|
||||
using namespace rtengine;
|
||||
|
||||
::ControlLine::~ControlLine() = default;
|
||||
|
||||
ControlLineManager::ControlLineManager():
|
||||
EditSubscriber(ET_OBJECTS),
|
||||
canvas_area(new Rectangle()),
|
||||
cursor(CSHandOpen),
|
||||
draw_mode(false),
|
||||
drawing_line(false),
|
||||
edited(false),
|
||||
prev_obj(-1),
|
||||
selected_object(-1)
|
||||
{
|
||||
canvas_area->filled = true;
|
||||
canvas_area->topLeft = Coord(0, 0);
|
||||
mouseOverGeometry.push_back(canvas_area.get());
|
||||
|
||||
line_icon_h = Cairo::RefPtr<RTSurface>(new RTSurface(
|
||||
"bidirectional-arrow-horizontal-hicontrast.png"));
|
||||
line_icon_v = Cairo::RefPtr<RTSurface>(new RTSurface(
|
||||
"bidirectional-arrow-vertical-hicontrast.png"));
|
||||
line_icon_h_prelight = Cairo::RefPtr<RTSurface>(new RTSurface(
|
||||
"bidirectional-arrow-horizontal-prelight.png"));
|
||||
line_icon_v_prelight = Cairo::RefPtr<RTSurface>(new RTSurface(
|
||||
"bidirectional-arrow-vertical-prelight.png"));
|
||||
}
|
||||
|
||||
ControlLineManager::~ControlLineManager() = default;
|
||||
|
||||
void ControlLineManager::setActive(bool active)
|
||||
{
|
||||
EditDataProvider* provider = getEditProvider();
|
||||
|
||||
if (!provider || (this == provider->getCurrSubscriber()) == active) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
subscribe();
|
||||
|
||||
int ih, iw;
|
||||
provider->getImageSize(iw, ih);
|
||||
canvas_area->bottomRight = Coord(iw, ih);
|
||||
} else {
|
||||
unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlLineManager::setDrawMode(bool draw)
|
||||
{
|
||||
draw_mode = draw;
|
||||
}
|
||||
|
||||
size_t ControlLineManager::size(void) const
|
||||
{
|
||||
return control_lines.size();
|
||||
}
|
||||
|
||||
bool ControlLineManager::button1Pressed(int modifierKey)
|
||||
{
|
||||
EditDataProvider* dataProvider = getEditProvider();
|
||||
|
||||
if (!dataProvider) {
|
||||
return false;
|
||||
}
|
||||
|
||||
drag_delta = Coord(0, 0);
|
||||
|
||||
const int object = dataProvider->getObject();
|
||||
|
||||
if (object > 0) { // A control line.
|
||||
if (object % ::ControlLine::OBJ_COUNT == 2) { // Icon.
|
||||
action = Action::PICKING;
|
||||
} else {
|
||||
selected_object = object;
|
||||
action = Action::DRAGGING;
|
||||
}
|
||||
} else if (draw_mode && (modifierKey & GDK_CONTROL_MASK)) { // Add new line.
|
||||
addLine(dataProvider->posImage, dataProvider->posImage);
|
||||
drawing_line = true;
|
||||
selected_object = mouseOverGeometry.size() - 1; // Select endpoint.
|
||||
action = Action::DRAGGING;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ControlLineManager::button1Released(void)
|
||||
{
|
||||
action = Action::NONE;
|
||||
|
||||
if (selected_object > 0) {
|
||||
mouseOverGeometry[selected_object]->state = Geometry::NORMAL;
|
||||
}
|
||||
|
||||
edited = true;
|
||||
callbacks->lineChanged();
|
||||
drawing_line = false;
|
||||
selected_object = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ControlLineManager::button3Pressed(int modifierKey)
|
||||
{
|
||||
EditDataProvider* provider = getEditProvider();
|
||||
|
||||
action = Action::NONE;
|
||||
|
||||
if (!provider || provider->getObject() < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
action = Action::PICKING;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ControlLineManager::pick1(bool picked)
|
||||
{
|
||||
action = Action::NONE;
|
||||
|
||||
if (!picked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EditDataProvider* provider = getEditProvider();
|
||||
|
||||
if (!provider || provider->getObject() % ::ControlLine::OBJ_COUNT != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Change line type.
|
||||
int object_id = provider->getObject();
|
||||
::ControlLine& line =
|
||||
*control_lines[(object_id - 1) / ::ControlLine::OBJ_COUNT];
|
||||
|
||||
if (line.type == rtengine::ControlLine::HORIZONTAL) {
|
||||
line.icon = line.icon_v;
|
||||
line.type = rtengine::ControlLine::VERTICAL;
|
||||
} else if (line.type == rtengine::ControlLine::VERTICAL) {
|
||||
line.icon = line.icon_h;
|
||||
line.type = rtengine::ControlLine::HORIZONTAL;
|
||||
}
|
||||
|
||||
visibleGeometry[object_id - 1] = line.icon.get();
|
||||
|
||||
edited = true;
|
||||
callbacks->lineChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ControlLineManager::pick3(bool picked)
|
||||
{
|
||||
action = Action::NONE;
|
||||
|
||||
if (!picked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EditDataProvider* provider = getEditProvider();
|
||||
|
||||
if (!provider) {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeLine((provider->getObject() - 1) / ::ControlLine::OBJ_COUNT);
|
||||
prev_obj = -1;
|
||||
selected_object = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ControlLineManager::drag1(int modifierKey)
|
||||
{
|
||||
EditDataProvider* provider = getEditProvider();
|
||||
|
||||
if (!provider || selected_object < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
::ControlLine& control_line =
|
||||
*control_lines[(selected_object - 1) / ::ControlLine::OBJ_COUNT];
|
||||
// 0 == end, 1 == line, 2 == icon, 3 == begin
|
||||
int component = selected_object % ::ControlLine::OBJ_COUNT;
|
||||
Coord mouse = provider->posImage + provider->deltaImage;
|
||||
Coord delta = provider->deltaImage - drag_delta;
|
||||
int ih, iw;
|
||||
provider->getImageSize(iw, ih);
|
||||
|
||||
switch (component) {
|
||||
case (0): // end
|
||||
control_line.end->center = mouse;
|
||||
control_line.end->center.clip(iw, ih);
|
||||
control_line.line->end = control_line.end->center;
|
||||
control_line.end->state = Geometry::DRAGGED;
|
||||
break;
|
||||
|
||||
case (1): { // line
|
||||
// Constrain delta so the end stays above the image.
|
||||
Coord new_delta = control_line.end->center + delta;
|
||||
new_delta.clip(iw, ih);
|
||||
new_delta -= control_line.end->center;
|
||||
// Constrain delta so the beginning stays above the image.
|
||||
new_delta += control_line.begin->center;
|
||||
new_delta.clip(iw, ih);
|
||||
new_delta -= control_line.begin->center;
|
||||
// Move all objects in the control line.
|
||||
control_line.end->center += new_delta;
|
||||
control_line.begin->center += new_delta;
|
||||
control_line.line->end = control_line.end->center;
|
||||
control_line.line->begin = control_line.begin->center;
|
||||
drag_delta += new_delta;
|
||||
control_line.line->state = Geometry::DRAGGED;
|
||||
break;
|
||||
}
|
||||
|
||||
case (3): // begin
|
||||
control_line.begin->center = mouse;
|
||||
control_line.begin->center.clip(iw, ih);
|
||||
control_line.line->begin = control_line.begin->center;
|
||||
control_line.begin->state = Geometry::DRAGGED;
|
||||
break;
|
||||
}
|
||||
|
||||
control_line.icon_h->position.x = (control_line.begin->center.x +
|
||||
control_line.end->center.x) / 2;
|
||||
control_line.icon_h->position.y = (control_line.begin->center.y +
|
||||
control_line.end->center.y) / 2;
|
||||
control_line.icon_v->position.x = control_line.icon_h->position.x;
|
||||
control_line.icon_v->position.y = control_line.icon_h->position.y;
|
||||
|
||||
if (drawing_line) {
|
||||
autoSetLineType(selected_object);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ControlLineManager::getEdited(void) const
|
||||
{
|
||||
return edited;
|
||||
}
|
||||
|
||||
CursorShape ControlLineManager::getCursor(int objectID) const
|
||||
{
|
||||
return cursor;
|
||||
}
|
||||
|
||||
bool ControlLineManager::mouseOver(int modifierKey)
|
||||
{
|
||||
EditDataProvider* provider = getEditProvider();
|
||||
|
||||
if (!provider) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int cur_obj = provider->getObject();
|
||||
|
||||
if (cur_obj == 0) { // Canvas
|
||||
if (draw_mode && modifierKey & GDK_CONTROL_MASK) {
|
||||
cursor = CSCrosshair;
|
||||
} else {
|
||||
cursor = CSHandOpen;
|
||||
}
|
||||
} else if (cur_obj < 0) { // Nothing
|
||||
cursor = CSArrow;
|
||||
} else if (cur_obj % ::ControlLine::OBJ_COUNT == 2) { // Icon
|
||||
visibleGeometry[cur_obj - 1]->state = Geometry::PRELIGHT;
|
||||
cursor = CSArrow;
|
||||
} else { // Object
|
||||
visibleGeometry[cur_obj - 1]->state = Geometry::PRELIGHT;
|
||||
cursor = CSMove2D;
|
||||
}
|
||||
|
||||
if (prev_obj != cur_obj && prev_obj > 0) {
|
||||
visibleGeometry[prev_obj - 1]->state = Geometry::NORMAL;
|
||||
}
|
||||
|
||||
prev_obj = cur_obj;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ControlLineManager::switchOffEditMode(void)
|
||||
{
|
||||
if (callbacks) {
|
||||
callbacks->switchOffEditMode();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlLineManager::setEdited(bool edited)
|
||||
{
|
||||
this->edited = edited;
|
||||
}
|
||||
|
||||
void ControlLineManager::setEditProvider(EditDataProvider* provider)
|
||||
{
|
||||
EditSubscriber::setEditProvider(provider);
|
||||
}
|
||||
|
||||
void ControlLineManager::setLines(const std::vector<rtengine::ControlLine>&
|
||||
lines)
|
||||
{
|
||||
removeAll();
|
||||
|
||||
for (auto&& line : lines) {
|
||||
Coord start(line.x1, line.y1);
|
||||
Coord end(line.x2, line.y2);
|
||||
addLine(start, end, line.type);
|
||||
}
|
||||
}
|
||||
|
||||
void ControlLineManager::addLine(Coord begin, Coord end,
|
||||
rtengine::ControlLine::Type type)
|
||||
{
|
||||
constexpr int line_width = 2;
|
||||
constexpr int handle_radius = 6;
|
||||
std::unique_ptr<Line> line;
|
||||
std::shared_ptr<OPIcon> icon_h, icon_v;
|
||||
std::unique_ptr<Circle> begin_c, end_c;
|
||||
|
||||
line = std::unique_ptr<Line>(new Line());
|
||||
line->datum = Geometry::IMAGE;
|
||||
line->innerLineWidth = line_width;
|
||||
line->begin = begin;
|
||||
line->end = end;
|
||||
|
||||
const Cairo::RefPtr<RTSurface> null_surface =
|
||||
Cairo::RefPtr<RTSurface>(nullptr);
|
||||
|
||||
icon_h = std::make_shared<OPIcon>(line_icon_h, null_surface,
|
||||
line_icon_h_prelight,
|
||||
null_surface, null_surface,
|
||||
Geometry::DP_CENTERCENTER);
|
||||
icon_h->position = Coord((begin.x + end.x) / 2, (begin.y + end.y) / 2);
|
||||
|
||||
icon_v = std::make_shared<OPIcon>(line_icon_v, null_surface,
|
||||
line_icon_v_prelight,
|
||||
null_surface, null_surface,
|
||||
Geometry::DP_CENTERCENTER);
|
||||
icon_v->position = Coord((begin.x + end.x) / 2, (begin.y + end.y) / 2);
|
||||
|
||||
begin_c = std::unique_ptr<Circle>(new Circle());
|
||||
begin_c->datum = Geometry::IMAGE;
|
||||
begin_c->filled = true;
|
||||
begin_c->radius = handle_radius;
|
||||
begin_c->center = begin;
|
||||
|
||||
end_c = std::unique_ptr<Circle>(new Circle());
|
||||
end_c->datum = Geometry::IMAGE;
|
||||
end_c->filled = true;
|
||||
end_c->radius = handle_radius;
|
||||
end_c->center = end;
|
||||
|
||||
std::unique_ptr<::ControlLine> control_line(new ::ControlLine());
|
||||
control_line->begin = std::move(begin_c);
|
||||
control_line->end = std::move(end_c);
|
||||
control_line->icon_h = icon_h;
|
||||
control_line->icon_v = icon_v;
|
||||
|
||||
if (type == rtengine::ControlLine::HORIZONTAL) {
|
||||
control_line->icon = icon_h;
|
||||
} else {
|
||||
control_line->icon = icon_v;
|
||||
}
|
||||
|
||||
control_line->line = std::move(line);
|
||||
control_line->type = type;
|
||||
|
||||
EditSubscriber::visibleGeometry.push_back(control_line->line.get());
|
||||
EditSubscriber::visibleGeometry.push_back(control_line->icon.get());
|
||||
EditSubscriber::visibleGeometry.push_back(control_line->begin.get());
|
||||
EditSubscriber::visibleGeometry.push_back(control_line->end.get());
|
||||
|
||||
EditSubscriber::mouseOverGeometry.push_back(control_line->line.get());
|
||||
EditSubscriber::mouseOverGeometry.push_back(control_line->icon.get());
|
||||
EditSubscriber::mouseOverGeometry.push_back(control_line->begin.get());
|
||||
EditSubscriber::mouseOverGeometry.push_back(control_line->end.get());
|
||||
|
||||
control_lines.push_back(std::move(control_line));
|
||||
}
|
||||
|
||||
void ControlLineManager::autoSetLineType(int object_id)
|
||||
{
|
||||
int line_id = (object_id - 1) / ::ControlLine::OBJ_COUNT;
|
||||
::ControlLine& line = *control_lines[line_id];
|
||||
|
||||
int dx = line.begin->center.x - line.end->center.x;
|
||||
int dy = line.begin->center.y - line.end->center.y;
|
||||
|
||||
if (dx < 0) {
|
||||
dx = -dx;
|
||||
}
|
||||
|
||||
if (dy < 0) {
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
rtengine::ControlLine::Type type;
|
||||
std::shared_ptr<OPIcon> icon;
|
||||
|
||||
if (dx > dy) { // More horizontal than vertical.
|
||||
type = rtengine::ControlLine::HORIZONTAL;
|
||||
icon = line.icon_h;
|
||||
} else {
|
||||
type = rtengine::ControlLine::VERTICAL;
|
||||
icon = line.icon_v;
|
||||
}
|
||||
|
||||
if (type != line.type) { // Need to update line type.
|
||||
line.type = type;
|
||||
line.icon = icon;
|
||||
visibleGeometry[line_id * ::ControlLine::OBJ_COUNT + 1] =
|
||||
line.icon.get();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlLineManager::removeAll(void)
|
||||
{
|
||||
visibleGeometry.clear();
|
||||
mouseOverGeometry.erase(mouseOverGeometry.begin() + 1,
|
||||
mouseOverGeometry.end());
|
||||
control_lines.clear();
|
||||
prev_obj = -1;
|
||||
selected_object = -1;
|
||||
edited = true;
|
||||
callbacks->lineChanged();
|
||||
}
|
||||
|
||||
void ControlLineManager::removeLine(size_t line_id)
|
||||
{
|
||||
if (line_id >= control_lines.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
visibleGeometry.erase(
|
||||
visibleGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id,
|
||||
visibleGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id
|
||||
+ ::ControlLine::OBJ_COUNT
|
||||
);
|
||||
mouseOverGeometry.erase(
|
||||
mouseOverGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id + 1,
|
||||
mouseOverGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id
|
||||
+ ::ControlLine::OBJ_COUNT + 1
|
||||
);
|
||||
control_lines.erase(control_lines.begin() + line_id);
|
||||
|
||||
edited = true;
|
||||
callbacks->lineChanged();
|
||||
}
|
||||
|
||||
void ControlLineManager::toControlLines(std::vector<rtengine::ControlLine>&
|
||||
converted) const
|
||||
{
|
||||
converted.clear();
|
||||
converted.resize(control_lines.size());
|
||||
|
||||
for (unsigned int i = 0; i < control_lines.size(); i++) {
|
||||
converted[i].x1 = control_lines[i]->begin->center.x;
|
||||
converted[i].y1 = control_lines[i]->begin->center.y;
|
||||
converted[i].x2 = control_lines[i]->end->center.x;
|
||||
converted[i].y2 = control_lines[i]->end->center.y;
|
||||
converted[i].type = control_lines[i]->type;
|
||||
}
|
||||
}
|
115
rtgui/controllines.h
Normal file
115
rtgui/controllines.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* Copyright (c) 2020 Lawrence Lee <billee@ucdavis.edu>
|
||||
*
|
||||
* RawTherapee 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.
|
||||
*
|
||||
* RawTherapee 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 RawTherapee. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "editcallbacks.h"
|
||||
#include "../rtengine/perspectivecorrection.h"
|
||||
|
||||
class Circle;
|
||||
class Line;
|
||||
class OPIcon;
|
||||
class Rectangle;
|
||||
class RTSurface;
|
||||
|
||||
struct ControlLine {
|
||||
static constexpr int OBJ_COUNT = 4;
|
||||
std::unique_ptr<Line> line;
|
||||
std::shared_ptr<OPIcon> icon;
|
||||
std::shared_ptr<OPIcon> icon_h, icon_v;
|
||||
std::unique_ptr<Circle> begin, end;
|
||||
rtengine::ControlLine::Type type;
|
||||
|
||||
~ControlLine();
|
||||
};
|
||||
|
||||
class ControlLineManager: EditSubscriber
|
||||
{
|
||||
|
||||
protected:
|
||||
/** Hidden object for capturing mouse events. */
|
||||
std::unique_ptr<Rectangle> canvas_area;
|
||||
rtengine::Coord drag_delta;
|
||||
std::vector<std::unique_ptr<ControlLine>> control_lines;
|
||||
CursorShape cursor;
|
||||
bool draw_mode;
|
||||
bool drawing_line;
|
||||
bool edited;
|
||||
Cairo::RefPtr<RTSurface> line_icon_h, line_icon_v;
|
||||
Cairo::RefPtr<RTSurface> line_icon_h_prelight, line_icon_v_prelight;
|
||||
int prev_obj;
|
||||
int selected_object;
|
||||
|
||||
void addLine(rtengine::Coord begin, rtengine::Coord end,
|
||||
rtengine::ControlLine::Type type = rtengine::ControlLine::VERTICAL);
|
||||
/**
|
||||
* Set the line type of the line containing the object according to the
|
||||
* line's angle.
|
||||
*
|
||||
* If the line is within 45 degrees of a perfectly vertical
|
||||
* line, inclusive, the line type is set to vertical. Otherwise, horizontal.
|
||||
*/
|
||||
void autoSetLineType(int object_id);
|
||||
void removeLine(size_t line_id);
|
||||
|
||||
public:
|
||||
class Callbacks
|
||||
{
|
||||
public:
|
||||
virtual ~Callbacks() {};
|
||||
/** Called when a line changed (added, removed, moved, etc.). */
|
||||
virtual void lineChanged(void) {};
|
||||
/** Called when the EditSubscriber's switchOffEditMode is called. */
|
||||
virtual void switchOffEditMode(void) {};
|
||||
};
|
||||
|
||||
/** Callbacks to invoke. */
|
||||
std::shared_ptr<Callbacks> callbacks;
|
||||
|
||||
ControlLineManager();
|
||||
~ControlLineManager();
|
||||
|
||||
bool getEdited(void) const;
|
||||
void removeAll(void);
|
||||
/** Sets whether or not the lines are visible and interact-able. */
|
||||
void setActive(bool active);
|
||||
/** Set whether or not lines can be drawn and deleted. */
|
||||
void setDrawMode(bool draw);
|
||||
void setEdited(bool edited);
|
||||
void setEditProvider(EditDataProvider* provider);
|
||||
void setLines(const std::vector<rtengine::ControlLine>& lines);
|
||||
/** Returns the number of lines. */
|
||||
size_t size(void) const;
|
||||
/**
|
||||
* Allocates a new array and populates it with copies of the control lines.
|
||||
*/
|
||||
void toControlLines(std::vector<rtengine::ControlLine>& converted) const;
|
||||
|
||||
// EditSubscriber overrides
|
||||
bool button1Pressed(int modifierKey) override;
|
||||
bool button1Released(void) override;
|
||||
bool button3Pressed(int modifierKey) override;
|
||||
bool pick1(bool picked) override;
|
||||
bool pick3(bool picked) override;
|
||||
bool drag1(int modifierKey) override;
|
||||
CursorShape getCursor(int objectID) const override;
|
||||
bool mouseOver(int modifierKey) override;
|
||||
void switchOffEditMode(void) override;
|
||||
};
|
@ -414,7 +414,8 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
||||
action_y = 0;
|
||||
needRedraw = true;
|
||||
}
|
||||
} else if (iarea->getToolMode () == TMHand
|
||||
} else if ((iarea->getToolMode () == TMHand
|
||||
|| iarea->getToolMode() == TMPerspective)
|
||||
&& editSubscriber
|
||||
&& cropgl
|
||||
&& cropgl->inImageArea(iarea->posImage.x, iarea->posImage.y)
|
||||
@ -429,6 +430,8 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
||||
state = SEditPick1;
|
||||
pickedObject = iarea->getObject();
|
||||
pickModifierKey = bstate;
|
||||
} else if (iarea->getToolMode() == TMPerspective) {
|
||||
state = SCropImgMove;
|
||||
}
|
||||
press_x = x;
|
||||
press_y = y;
|
||||
@ -592,7 +595,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
||||
}
|
||||
}
|
||||
} else if (button == 3) {
|
||||
if (iarea->getToolMode () == TMHand) {
|
||||
if (iarea->getToolMode () == TMHand || iarea->getToolMode() == TMPerspective) {
|
||||
EditSubscriber *editSubscriber = iarea->getCurrSubscriber();
|
||||
if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) {
|
||||
needRedraw = editSubscriber->button3Pressed(bstate);
|
||||
@ -764,7 +767,10 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y)
|
||||
|
||||
iarea->setObject(ObjectMOBuffer::getObjectID(cropPos));
|
||||
|
||||
bool elemPicked = iarea->getObject() == pickedObject && bstate == pickModifierKey;
|
||||
int buttonMask = ((state == SEditPick1) ? GDK_BUTTON1_MASK : 0)
|
||||
| ((state == SEditPick2) ? GDK_BUTTON2_MASK : 0)
|
||||
| ((state == SEditPick3) ? GDK_BUTTON3_MASK : 0);
|
||||
bool elemPicked = iarea->getObject() == pickedObject && bstate == (pickModifierKey | buttonMask);
|
||||
|
||||
if (state == SEditPick1) {
|
||||
needRedraw = editSubscriber->pick1 (elemPicked);
|
||||
|
@ -129,19 +129,19 @@ public:
|
||||
@param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys.
|
||||
If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected.
|
||||
@return true if the preview has to be redrawn, false otherwise */
|
||||
bool pick1 (bool picked);
|
||||
virtual bool pick1 (bool picked);
|
||||
|
||||
/** @brief Triggered when the user is releasing mouse button 2 while in action==ES_ACTION_PICKING mode
|
||||
@param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys.
|
||||
If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected.
|
||||
@return true if the preview has to be redrawn, false otherwise */
|
||||
bool pick2 (bool picked);
|
||||
virtual bool pick2 (bool picked);
|
||||
|
||||
/** @brief Triggered when the user is releasing mouse button 3 while in action==ES_ACTION_PICKING mode
|
||||
@param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys.
|
||||
If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected.
|
||||
@return true if the preview has to be redrawn, false otherwise */
|
||||
bool pick3 (bool picked);
|
||||
virtual bool pick3 (bool picked);
|
||||
|
||||
/** @brief Get the geometry to be shown to the user */
|
||||
const std::vector<Geometry*>& getVisibleGeometry ();
|
||||
|
@ -18,6 +18,15 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
class ControlLine;
|
||||
class ProcEvent;
|
||||
}
|
||||
|
||||
class LensGeomListener
|
||||
{
|
||||
public:
|
||||
@ -25,5 +34,6 @@ public:
|
||||
virtual void straightenRequested () = 0;
|
||||
virtual void autoCropRequested () = 0;
|
||||
virtual double autoDistorRequested () = 0;
|
||||
virtual void autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw) = 0;
|
||||
virtual void autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw, const std::vector<rtengine::ControlLine> *lines = nullptr) = 0;
|
||||
virtual void updateTransformPreviewRequested (rtengine::ProcEvent event, bool render_perspective) = 0;
|
||||
};
|
||||
|
@ -354,6 +354,7 @@ void ParamsEdited::set(bool v)
|
||||
perspective.projection_shift_horiz = v;
|
||||
perspective.projection_shift_vert = v;
|
||||
perspective.projection_yaw = v;
|
||||
perspective.control_lines = v;
|
||||
gradient.enabled = v;
|
||||
gradient.degree = v;
|
||||
gradient.feather = v;
|
||||
@ -1026,6 +1027,7 @@ void ParamsEdited::initFrom(const std::vector<rtengine::procparams::ProcParams>&
|
||||
perspective.projection_shift_horiz = perspective.projection_shift_horiz && p.perspective.projection_shift_horiz == other.perspective.projection_shift_horiz;
|
||||
perspective.projection_shift_vert = perspective.projection_shift_vert && p.perspective.projection_shift_vert == other.perspective.projection_shift_vert;
|
||||
perspective.projection_yaw = perspective.projection_yaw && p.perspective.projection_yaw == other.perspective.projection_yaw;
|
||||
perspective.control_lines = perspective.control_lines && p.perspective.control_line_values == other.perspective.control_line_values && p.perspective.control_line_types == other.perspective.control_line_types;
|
||||
gradient.enabled = gradient.enabled && p.gradient.enabled == other.gradient.enabled;
|
||||
gradient.degree = gradient.degree && p.gradient.degree == other.gradient.degree;
|
||||
gradient.feather = gradient.feather && p.gradient.feather == other.gradient.feather;
|
||||
@ -3062,6 +3064,11 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
|
||||
toEdit.perspective.projection_yaw = dontforceSet && options.baBehav[ADDSET_PERSP_PROJ_ANGLE] ? toEdit.perspective.projection_yaw + mods.perspective.projection_yaw : mods.perspective.projection_yaw;
|
||||
}
|
||||
|
||||
if (perspective.control_lines) {
|
||||
toEdit.perspective.control_line_values = mods.perspective.control_line_values;
|
||||
toEdit.perspective.control_line_types = mods.perspective.control_line_types;
|
||||
}
|
||||
|
||||
if (gradient.enabled) {
|
||||
toEdit.gradient.enabled = mods.gradient.enabled;
|
||||
}
|
||||
|
@ -914,6 +914,7 @@ struct PerspectiveParamsEdited {
|
||||
bool projection_shift_horiz;
|
||||
bool projection_shift_vert;
|
||||
bool projection_yaw;
|
||||
bool control_lines;
|
||||
};
|
||||
|
||||
struct GradientParamsEdited {
|
||||
|
@ -20,16 +20,75 @@
|
||||
#include "perspective.h"
|
||||
|
||||
#include "rtimage.h"
|
||||
#include "rtsurface.h"
|
||||
|
||||
#include "../rtengine/procparams.h"
|
||||
|
||||
using namespace rtengine;
|
||||
using namespace rtengine::procparams;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void controlLinesToValues(const std::vector<rtengine::ControlLine>& lines,
|
||||
std::vector<int>& values, std::vector<int>& types)
|
||||
{
|
||||
values.clear();
|
||||
types.clear();
|
||||
|
||||
for (auto&& line : lines) {
|
||||
values.push_back(line.x1);
|
||||
values.push_back(line.y1);
|
||||
values.push_back(line.x2);
|
||||
values.push_back(line.y2);
|
||||
|
||||
int type = -1;
|
||||
switch (line.type) {
|
||||
case rtengine::ControlLine::VERTICAL:
|
||||
type = 0;
|
||||
break;
|
||||
case rtengine::ControlLine::HORIZONTAL:
|
||||
type = 1;
|
||||
break;
|
||||
}
|
||||
types.push_back(type);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<rtengine::ControlLine> valuesToControlLines(
|
||||
const std::vector<int>& values, const std::vector<int>& types)
|
||||
{
|
||||
int line_count = min(values.size() / 4, types.size());
|
||||
std::vector<rtengine::ControlLine> lines(line_count);
|
||||
|
||||
auto values_iter = values.begin();
|
||||
auto types_iter = types.begin();
|
||||
for (auto&& line : lines) {
|
||||
line.x1 = *(values_iter++);
|
||||
line.y1 = *(values_iter++);
|
||||
line.x2 = *(values_iter++);
|
||||
line.y2 = *(values_iter++);
|
||||
|
||||
switch (*(types_iter++)) {
|
||||
case 0:
|
||||
line.type = rtengine::ControlLine::VERTICAL;
|
||||
break;
|
||||
case 1:
|
||||
line.type = rtengine::ControlLine::HORIZONTAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PerspCorrection::PerspCorrection () : FoldableToolPanel(this, "perspective", M("TP_PERSPECTIVE_LABEL"))
|
||||
{
|
||||
|
||||
auto mapper = ProcEventMapper::getInstance();
|
||||
// Normal events.
|
||||
EvPerspCamAngle = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_CAM_ANGLE");
|
||||
EvPerspCamFocalLength = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_CAM_FL");
|
||||
EvPerspCamShift = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_CAM_SHIFT");
|
||||
@ -37,9 +96,25 @@ PerspCorrection::PerspCorrection () : FoldableToolPanel(this, "perspective", M("
|
||||
EvPerspProjAngle = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_PROJ_ANGLE");
|
||||
EvPerspProjRotate = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_PROJ_ROTATE");
|
||||
EvPerspProjShift = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_PROJ_SHIFT");
|
||||
EvPerspRender = mapper->newEvent(TRANSFORM);
|
||||
// Void events.
|
||||
EvPerspCamAngleVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_CAM_ANGLE");
|
||||
EvPerspCamFocalLengthVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_CAM_FL");
|
||||
EvPerspCamShiftVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_CAM_SHIFT");
|
||||
EvPerspProjAngleVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_PROJ_ANGLE");
|
||||
EvPerspProjRotateVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_PROJ_ROTATE");
|
||||
EvPerspProjShiftVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_PROJ_SHIFT");
|
||||
setCamBasedEventsActive();
|
||||
EvPerspControlLines = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_CTRL_LINE");
|
||||
|
||||
lens_geom_listener = nullptr;
|
||||
panel_listener = nullptr;
|
||||
metadata = nullptr;
|
||||
|
||||
Gtk::Image* ipers_draw(new RTImage ("draw.png"));
|
||||
Gtk::Image* ipers_trash = Gtk::manage (new RTImage ("trash-empty.png"));
|
||||
Gtk::Image* ipers_apply = Gtk::manage (new RTImage ("tick.png"));
|
||||
|
||||
Gtk::Image* ipersHL = Gtk::manage (new RTImage ("perspective-horizontal-left-small.png"));
|
||||
Gtk::Image* ipersHR = Gtk::manage (new RTImage ("perspective-horizontal-right-small.png"));
|
||||
Gtk::Image* ipersVL = Gtk::manage (new RTImage ("perspective-vertical-bottom-small.png"));
|
||||
@ -108,6 +183,39 @@ PerspCorrection::PerspCorrection () : FoldableToolPanel(this, "perspective", M("
|
||||
-60, 60, 0.1, 0, ipers_cam_yaw_left, ipers_cam_yaw_right));
|
||||
camera_yaw->setAdjusterListener (this);
|
||||
|
||||
// Begin control lines interface.
|
||||
lines_button_apply = Gtk::manage (new Gtk::Button());
|
||||
lines_button_apply->set_image(*ipers_apply);
|
||||
lines_button_apply->set_tooltip_text(M("GENERAL_APPLY"));
|
||||
lines_button_apply->set_sensitive(false);
|
||||
lines_button_apply->signal_pressed().connect(sigc::mem_fun(
|
||||
*this, &::PerspCorrection::linesApplyButtonPressed));
|
||||
|
||||
lines_button_edit = Gtk::manage (new Gtk::ToggleButton());
|
||||
lines_button_edit->set_image(*ipers_draw);
|
||||
lines_button_edit->set_tooltip_text(M("GENERAL_EDIT"));
|
||||
lines_button_edit->signal_toggled().connect(sigc::mem_fun(
|
||||
*this, &::PerspCorrection::linesEditButtonPressed));
|
||||
|
||||
lines_button_erase = Gtk::manage (new Gtk::Button());
|
||||
lines_button_erase->set_image(*ipers_trash);
|
||||
lines_button_erase->set_tooltip_text(M("GENERAL_DELETE_ALL"));
|
||||
lines_button_erase->set_sensitive(false);
|
||||
lines_button_erase->signal_pressed().connect(sigc::mem_fun(
|
||||
*this, &::PerspCorrection::linesEraseButtonPressed));
|
||||
|
||||
lines = std::unique_ptr<ControlLineManager>(new ControlLineManager());
|
||||
lines->callbacks = std::make_shared<LinesCallbacks>(this);
|
||||
|
||||
Gtk::HBox* control_lines_box = Gtk::manage (new Gtk::HBox());
|
||||
Gtk::Label* control_lines_label = Gtk::manage (new Gtk::Label (M("TP_PERSPECTIVE_CONTROL_LINES") + ": "));
|
||||
control_lines_label->set_tooltip_markup( M("TP_PERSPECTIVE_CONTROL_LINES_TOOLTIP") );
|
||||
control_lines_box->pack_start(*control_lines_label, Gtk::PACK_SHRINK);
|
||||
control_lines_box->pack_start(*lines_button_edit);
|
||||
control_lines_box->pack_start(*lines_button_apply);
|
||||
control_lines_box->pack_start(*lines_button_erase);
|
||||
// End control lines interface.
|
||||
|
||||
auto_pitch = Gtk::manage (new Gtk::Button ());
|
||||
auto_pitch->set_image(*ipers_auto_pitch);
|
||||
auto_pitch->signal_pressed().connect( sigc::bind(sigc::mem_fun(*this, &PerspCorrection::autoCorrectionPressed), auto_pitch) );
|
||||
@ -165,6 +273,9 @@ PerspCorrection::PerspCorrection () : FoldableToolPanel(this, "perspective", M("
|
||||
camera_vbox->pack_start (*camera_roll);
|
||||
camera_vbox->pack_start (*camera_pitch);
|
||||
camera_vbox->pack_start (*camera_yaw);
|
||||
camera_vbox->pack_start (*Gtk::manage (new Gtk::HSeparator()));
|
||||
camera_vbox->pack_start (*control_lines_box);
|
||||
camera_vbox->pack_start (*Gtk::manage (new Gtk::HSeparator()));
|
||||
camera_vbox->pack_start (*auto_hbox);
|
||||
camera_frame->add(*camera_vbox);
|
||||
camera_based->pack_start(*camera_frame);
|
||||
@ -213,6 +324,7 @@ void PerspCorrection::read (const ProcParams* pp, const ParamsEdited* pedited)
|
||||
projection_shift_horiz->setEditedState (pedited->perspective.projection_shift_horiz ? Edited : UnEdited);
|
||||
projection_shift_vert->setEditedState (pedited->perspective.projection_shift_vert ? Edited : UnEdited);
|
||||
projection_yaw->setEditedState (pedited->perspective.projection_yaw ? Edited : UnEdited);
|
||||
lines->setEdited (pedited->perspective.control_lines);
|
||||
}
|
||||
|
||||
horiz->setValue (pp->perspective.horizontal);
|
||||
@ -228,6 +340,8 @@ void PerspCorrection::read (const ProcParams* pp, const ParamsEdited* pedited)
|
||||
projection_shift_horiz->setValue (pp->perspective.projection_shift_horiz);
|
||||
projection_shift_vert->setValue (pp->perspective.projection_shift_vert);
|
||||
projection_yaw->setValue (pp->perspective.projection_yaw);
|
||||
lines->setLines(valuesToControlLines(pp->perspective.control_line_values,
|
||||
pp->perspective.control_line_types));
|
||||
|
||||
if (pedited && !pedited->perspective.method) {
|
||||
method->set_active (2);
|
||||
@ -243,6 +357,8 @@ void PerspCorrection::read (const ProcParams* pp, const ParamsEdited* pedited)
|
||||
void PerspCorrection::write (ProcParams* pp, ParamsEdited* pedited)
|
||||
{
|
||||
|
||||
pp->perspective.render = render;
|
||||
|
||||
pp->perspective.horizontal = horiz->getValue ();
|
||||
pp->perspective.vertical = vert->getValue ();
|
||||
pp->perspective.camera_crop_factor= camera_crop_factor->getValue ();
|
||||
@ -258,6 +374,11 @@ void PerspCorrection::write (ProcParams* pp, ParamsEdited* pedited)
|
||||
pp->perspective.projection_shift_vert = projection_shift_vert->getValue ();
|
||||
pp->perspective.projection_yaw = projection_yaw->getValue ();
|
||||
|
||||
std::vector<rtengine::ControlLine> control_lines;
|
||||
lines->toControlLines(control_lines);
|
||||
controlLinesToValues(control_lines, pp->perspective.control_line_values,
|
||||
pp->perspective.control_line_types);
|
||||
|
||||
if (method->get_active_row_number() == 0) {
|
||||
pp->perspective.method = "simple";
|
||||
} else if (method->get_active_row_number() == 1) {
|
||||
@ -280,6 +401,7 @@ void PerspCorrection::write (ProcParams* pp, ParamsEdited* pedited)
|
||||
pedited->perspective.projection_shift_horiz = projection_shift_horiz->getEditedState();
|
||||
pedited->perspective.projection_shift_vert = projection_shift_vert->getEditedState();
|
||||
pedited->perspective.projection_yaw = projection_yaw->getEditedState();
|
||||
pedited->perspective.control_lines = lines->getEdited();
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,21 +467,21 @@ void PerspCorrection::adjusterChanged(Adjuster* a, double newval)
|
||||
M("TP_PERSPECTIVE_VERTICAL"),
|
||||
vert->getValue()));
|
||||
} else if (a == camera_focal_length || a == camera_crop_factor) {
|
||||
listener->panelChanged (EvPerspCamFocalLength,
|
||||
listener->panelChanged (*event_persp_cam_focal_length,
|
||||
Glib::ustring::compose("%1=%2\n%3=%4",
|
||||
M("TP_PERSPECTIVE_CAMERA_FOCAL_LENGTH"),
|
||||
camera_focal_length->getValue(),
|
||||
M("TP_PERSPECTIVE_CAMERA_CROP_FACTOR"),
|
||||
camera_crop_factor->getValue()));
|
||||
} else if (a == camera_shift_horiz || a == camera_shift_vert) {
|
||||
listener->panelChanged (EvPerspCamShift,
|
||||
listener->panelChanged (*event_persp_cam_shift,
|
||||
Glib::ustring::compose("%1=%2\n%3=%4",
|
||||
M("TP_PERSPECTIVE_CAMERA_SHIFT_HORIZONTAL"),
|
||||
camera_shift_horiz->getValue(),
|
||||
M("TP_PERSPECTIVE_CAMERA_SHIFT_VERTICAL"),
|
||||
camera_shift_vert->getValue()));
|
||||
} else if (a == camera_pitch || a == camera_roll|| a == camera_yaw) {
|
||||
listener->panelChanged (EvPerspCamAngle,
|
||||
listener->panelChanged (*event_persp_cam_angle,
|
||||
Glib::ustring::compose("%1=%2\n%3=%4\n%5=%6",
|
||||
M("TP_PERSPECTIVE_CAMERA_ROLL"),
|
||||
camera_roll->getValue(),
|
||||
@ -368,17 +490,17 @@ void PerspCorrection::adjusterChanged(Adjuster* a, double newval)
|
||||
M("TP_PERSPECTIVE_CAMERA_PITCH"),
|
||||
camera_pitch->getValue()));
|
||||
} else if (a == projection_shift_horiz || a == projection_shift_vert) {
|
||||
listener->panelChanged (EvPerspProjShift,
|
||||
listener->panelChanged (*event_persp_proj_shift,
|
||||
Glib::ustring::compose("%1=%2\n%3=%4",
|
||||
M("TP_PERSPECTIVE_PROJECTION_SHIFT_HORIZONTAL"),
|
||||
projection_shift_horiz->getValue(),
|
||||
M("TP_PERSPECTIVE_PROJECTION_SHIFT_VERTICAL"),
|
||||
projection_shift_vert->getValue()));
|
||||
} else if (a == projection_rotate) {
|
||||
listener->panelChanged (EvPerspProjRotate,
|
||||
listener->panelChanged (*event_persp_proj_rotate,
|
||||
Glib::ustring::format(projection_rotate->getValue()));
|
||||
} else if (a == projection_pitch || a == projection_yaw) {
|
||||
listener->panelChanged (EvPerspProjAngle,
|
||||
listener->panelChanged (*event_persp_proj_angle,
|
||||
Glib::ustring::compose("%1=%2\n%3=%4",
|
||||
M("TP_PERSPECTIVE_PROJECTION_PITCH"),
|
||||
projection_pitch->getValue(),
|
||||
@ -388,6 +510,39 @@ void PerspCorrection::adjusterChanged(Adjuster* a, double newval)
|
||||
}
|
||||
}
|
||||
|
||||
void PerspCorrection::applyControlLines(void)
|
||||
{
|
||||
if (!lens_geom_listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<rtengine::ControlLine> control_lines;
|
||||
int h_count = 0, v_count = 0;
|
||||
double rot = camera_roll->getValue();
|
||||
double pitch = camera_pitch->getValue();
|
||||
double yaw = camera_yaw->getValue();
|
||||
|
||||
lines->toControlLines(control_lines);
|
||||
|
||||
for (unsigned int i = 0; i < lines->size(); i++) {
|
||||
if (control_lines[i].type == rtengine::ControlLine::HORIZONTAL) {
|
||||
h_count++;
|
||||
} else if (control_lines[i].type == rtengine::ControlLine::VERTICAL) {
|
||||
v_count++;
|
||||
}
|
||||
}
|
||||
lens_geom_listener->autoPerspRequested(v_count > 1, h_count > 1, rot, pitch,
|
||||
yaw, &control_lines);
|
||||
|
||||
disableListener();
|
||||
camera_pitch->setValue(pitch);
|
||||
camera_roll->setValue(rot);
|
||||
camera_yaw->setValue(yaw);
|
||||
enableListener();
|
||||
|
||||
adjusterChanged(camera_pitch, pitch);
|
||||
}
|
||||
|
||||
void PerspCorrection::autoCorrectionPressed(Gtk::Button* b)
|
||||
{
|
||||
if (!lens_geom_listener) {
|
||||
@ -427,6 +582,11 @@ void PerspCorrection::methodChanged (void)
|
||||
} else if (method->get_active_row_number() == 1) {
|
||||
pack_start (*camera_based);
|
||||
}
|
||||
|
||||
// If no longer in camera-based mode and control lines are being edited.
|
||||
if (method->get_active_row_number() != 1 && lines_button_edit->get_active()) {
|
||||
lines_button_edit->set_active(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (listener) {
|
||||
@ -454,6 +614,17 @@ void PerspCorrection::setAdjusterBehavior (bool badd, bool camera_focal_length_a
|
||||
projection_yaw->setAddMode(projection_angle_add);
|
||||
}
|
||||
|
||||
void PerspCorrection::setControlLineEditMode(bool active)
|
||||
{
|
||||
// Only camera-based mode supports control lines, so the mode must be
|
||||
// switched if not in camera-based mode.
|
||||
if (method->get_active_row_number() != 1) {
|
||||
method->set_active(1);
|
||||
}
|
||||
|
||||
lines_button_edit->set_active(active);
|
||||
}
|
||||
|
||||
void PerspCorrection::setMetadata (const rtengine::FramesMetaData* metadata)
|
||||
{
|
||||
this->metadata = metadata;
|
||||
@ -497,6 +668,7 @@ void PerspCorrection::setBatchMode (bool batchMode)
|
||||
projection_shift_vert->showEditedCB ();
|
||||
projection_yaw->showEditedCB ();
|
||||
|
||||
lines_button_edit->set_sensitive(false);
|
||||
auto_pitch->set_sensitive(false);
|
||||
auto_yaw->set_sensitive(false);
|
||||
auto_pitch_yaw->set_sensitive(false);
|
||||
@ -549,3 +721,110 @@ void PerspCorrection::setFocalLengthValue (const ProcParams* pparams, const Fram
|
||||
camera_focal_length->setValue(default_focal_length);
|
||||
}
|
||||
}
|
||||
|
||||
void PerspCorrection::switchOffEditMode(void)
|
||||
{
|
||||
lines_button_edit->set_active(false);
|
||||
}
|
||||
|
||||
void PerspCorrection::setEditProvider(EditDataProvider* provider)
|
||||
{
|
||||
lines->setEditProvider(provider);
|
||||
}
|
||||
|
||||
void PerspCorrection::lineChanged(void)
|
||||
{
|
||||
if (listener) {
|
||||
listener->panelChanged(EvPerspControlLines, M("HISTORY_CHANGED"));
|
||||
}
|
||||
}
|
||||
|
||||
void PerspCorrection::linesApplyButtonPressed(void)
|
||||
{
|
||||
if (method->get_active_row_number() == 1) {
|
||||
// Calculate perspective distortion if in camera-based mode.
|
||||
applyControlLines();
|
||||
}
|
||||
lines_button_edit->set_active(false);
|
||||
}
|
||||
|
||||
void PerspCorrection::linesEditButtonPressed(void)
|
||||
{
|
||||
if (lines_button_edit->get_active()) { // Enter edit mode.
|
||||
lines->setActive(true);
|
||||
lines->setDrawMode(true);
|
||||
render = false;
|
||||
if (lens_geom_listener) {
|
||||
lens_geom_listener->updateTransformPreviewRequested(EvPerspRender, false);
|
||||
}
|
||||
lines_button_apply->set_sensitive(true);
|
||||
lines_button_erase->set_sensitive(true);
|
||||
setCamBasedEventsActive(false);
|
||||
if (panel_listener) {
|
||||
panel_listener->controlLineEditModeChanged(true);
|
||||
}
|
||||
} else { // Leave edit mode.
|
||||
setCamBasedEventsActive(true);
|
||||
lines_button_apply->set_sensitive(false);
|
||||
lines_button_erase->set_sensitive(false);
|
||||
render = true;
|
||||
if (lens_geom_listener) {
|
||||
lens_geom_listener->updateTransformPreviewRequested(EvPerspRender, true);
|
||||
}
|
||||
lines->setDrawMode(false);
|
||||
lines->setActive(false);
|
||||
if (panel_listener) {
|
||||
panel_listener->controlLineEditModeChanged(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PerspCorrection::linesEraseButtonPressed(void)
|
||||
{
|
||||
lines->removeAll();
|
||||
}
|
||||
|
||||
void PerspCorrection::requestApplyControlLines(void)
|
||||
{
|
||||
if (lines_button_apply->is_sensitive()) {
|
||||
linesApplyButtonPressed();
|
||||
}
|
||||
}
|
||||
|
||||
void PerspCorrection::setCamBasedEventsActive(bool active)
|
||||
{
|
||||
if (active) {
|
||||
event_persp_cam_focal_length = &EvPerspCamFocalLength;
|
||||
event_persp_cam_shift = &EvPerspCamShift;
|
||||
event_persp_cam_angle = &EvPerspCamAngle;
|
||||
event_persp_proj_shift = &EvPerspProjShift;
|
||||
event_persp_proj_rotate = &EvPerspProjRotate;
|
||||
event_persp_proj_angle = &EvPerspProjAngle;
|
||||
} else {
|
||||
event_persp_cam_focal_length = &EvPerspCamFocalLengthVoid;
|
||||
event_persp_cam_shift = &EvPerspCamShiftVoid;
|
||||
event_persp_cam_angle = &EvPerspCamAngleVoid;
|
||||
event_persp_proj_shift = &EvPerspProjShiftVoid;
|
||||
event_persp_proj_rotate = &EvPerspProjRotateVoid;
|
||||
event_persp_proj_angle = &EvPerspProjAngleVoid;
|
||||
}
|
||||
}
|
||||
|
||||
LinesCallbacks::LinesCallbacks(PerspCorrection* tool):
|
||||
tool(tool)
|
||||
{
|
||||
}
|
||||
|
||||
void LinesCallbacks::lineChanged(void)
|
||||
{
|
||||
if (tool) {
|
||||
tool->lineChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void LinesCallbacks::switchOffEditMode(void)
|
||||
{
|
||||
if (tool) {
|
||||
tool->switchOffEditMode();
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,18 @@
|
||||
#include <gtkmm.h>
|
||||
|
||||
#include "adjuster.h"
|
||||
#include "controllines.h"
|
||||
#include "lensgeomlistener.h"
|
||||
#include "toolpanel.h"
|
||||
|
||||
class PerspCorrectionPanelListener
|
||||
{
|
||||
public:
|
||||
virtual ~PerspCorrectionPanelListener() = default;
|
||||
|
||||
virtual void controlLineEditModeChanged(bool active) = 0;
|
||||
};
|
||||
|
||||
class PerspCorrection final :
|
||||
public ToolParamBlock,
|
||||
public AdjusterListener,
|
||||
@ -31,6 +40,7 @@ class PerspCorrection final :
|
||||
{
|
||||
|
||||
protected:
|
||||
bool render = true;
|
||||
MyComboBoxText* method;
|
||||
Gtk::VBox* simple;
|
||||
Adjuster* horiz;
|
||||
@ -46,6 +56,10 @@ protected:
|
||||
Adjuster* camera_shift_horiz;
|
||||
Adjuster* camera_shift_vert;
|
||||
Adjuster* camera_yaw;
|
||||
std::unique_ptr<ControlLineManager> lines;
|
||||
Gtk::Button* lines_button_apply;
|
||||
Gtk::ToggleButton* lines_button_edit;
|
||||
Gtk::Button* lines_button_erase;
|
||||
Adjuster* projection_pitch;
|
||||
Adjuster* projection_rotate;
|
||||
Adjuster* projection_shift_horiz;
|
||||
@ -54,13 +68,30 @@ protected:
|
||||
rtengine::ProcEvent EvPerspCamFocalLength;
|
||||
rtengine::ProcEvent EvPerspCamShift;
|
||||
rtengine::ProcEvent EvPerspCamAngle;
|
||||
rtengine::ProcEvent EvPerspControlLines;
|
||||
rtengine::ProcEvent EvPerspMethod;
|
||||
rtengine::ProcEvent EvPerspProjShift;
|
||||
rtengine::ProcEvent EvPerspProjRotate;
|
||||
rtengine::ProcEvent EvPerspProjAngle;
|
||||
rtengine::ProcEvent EvPerspRender;
|
||||
rtengine::ProcEvent EvPerspCamFocalLengthVoid;
|
||||
rtengine::ProcEvent EvPerspCamShiftVoid;
|
||||
rtengine::ProcEvent EvPerspCamAngleVoid;
|
||||
rtengine::ProcEvent EvPerspProjShiftVoid;
|
||||
rtengine::ProcEvent EvPerspProjRotateVoid;
|
||||
rtengine::ProcEvent EvPerspProjAngleVoid;
|
||||
rtengine::ProcEvent* event_persp_cam_focal_length;
|
||||
rtengine::ProcEvent* event_persp_cam_shift;
|
||||
rtengine::ProcEvent* event_persp_cam_angle;
|
||||
rtengine::ProcEvent* event_persp_proj_shift;
|
||||
rtengine::ProcEvent* event_persp_proj_rotate;
|
||||
rtengine::ProcEvent* event_persp_proj_angle;
|
||||
LensGeomListener* lens_geom_listener;
|
||||
PerspCorrectionPanelListener* panel_listener;
|
||||
const rtengine::FramesMetaData* metadata;
|
||||
|
||||
void applyControlLines (void);
|
||||
void setCamBasedEventsActive (bool active = true);
|
||||
void setFocalLengthValue (const rtengine::procparams::ProcParams* pparams, const rtengine::FramesMetaData* metadata);
|
||||
|
||||
public:
|
||||
@ -74,12 +105,35 @@ public:
|
||||
|
||||
void adjusterChanged (Adjuster* a, double newval) override;
|
||||
void autoCorrectionPressed (Gtk::Button* b);
|
||||
void lineChanged (void);
|
||||
void linesApplyButtonPressed (void);
|
||||
void linesEditButtonPressed (void);
|
||||
void linesEraseButtonPressed (void);
|
||||
void methodChanged (void);
|
||||
void requestApplyControlLines(void);
|
||||
void setAdjusterBehavior (bool badd, bool camera_focal_length_add, bool camera_shift_add, bool camera_angle_add, bool projection_angle_add, bool projection_shift_add, bool projection_rotate_add);
|
||||
void setControlLineEditMode(bool active);
|
||||
void setEditProvider (EditDataProvider* provider) override;
|
||||
void setLensGeomListener (LensGeomListener* listener)
|
||||
{
|
||||
lens_geom_listener = listener;
|
||||
}
|
||||
void setPerspCorrectionPanelListener(PerspCorrectionPanelListener* listener)
|
||||
{
|
||||
panel_listener = listener;
|
||||
}
|
||||
void setMetadata (const rtengine::FramesMetaData* metadata);
|
||||
void switchOffEditMode (void);
|
||||
void trimValues (rtengine::procparams::ProcParams* pp) override;
|
||||
};
|
||||
|
||||
class LinesCallbacks: public ControlLineManager::Callbacks
|
||||
{
|
||||
protected:
|
||||
PerspCorrection* tool;
|
||||
|
||||
public:
|
||||
explicit LinesCallbacks(PerspCorrection* tool);
|
||||
void lineChanged (void) override;
|
||||
void switchOffEditMode (void) override;
|
||||
};
|
||||
|
@ -77,6 +77,12 @@ ToolBar::ToolBar () : showColPickers(true), listener (nullptr), pickerListener(n
|
||||
|
||||
pack_start (*straTool);
|
||||
|
||||
perspTool = Gtk::manage(new Gtk::ToggleButton());
|
||||
Gtk::Image* perspimg = Gtk::manage(new RTImage("perspective-vertical-bottom.png"));
|
||||
perspTool->set_image(*perspimg);
|
||||
perspTool->set_relief(Gtk::RELIEF_NONE);
|
||||
pack_start(*perspTool);
|
||||
|
||||
|
||||
handTool->set_active (true);
|
||||
current = TMHand;
|
||||
@ -87,12 +93,14 @@ ToolBar::ToolBar () : showColPickers(true), listener (nullptr), pickerListener(n
|
||||
cpConn = colPickerTool->signal_button_press_event().connect_notify( sigc::mem_fun(*this, &ToolBar::colPicker_pressed));
|
||||
cropConn = cropTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::crop_pressed));
|
||||
straConn = straTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::stra_pressed));
|
||||
perspConn = perspTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::persp_pressed));
|
||||
|
||||
handTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_HAND"));
|
||||
wbTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_WB"));
|
||||
colPickerTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_COLORPICKER"));
|
||||
cropTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_CROP"));
|
||||
straTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_STRAIGHTEN"));
|
||||
perspTool->set_tooltip_markup(M("TOOLBAR_TOOLTIP_PERSPECTIVE"));
|
||||
}
|
||||
|
||||
//
|
||||
@ -107,9 +115,10 @@ void ToolBar::setTool (ToolMode tool)
|
||||
ConnectionBlocker handBlocker(handConn);
|
||||
ConnectionBlocker straBlocker(straConn);
|
||||
ConnectionBlocker cropBlocker(cropConn);
|
||||
ConnectionBlocker perspBlocker(perspConn);
|
||||
ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn);
|
||||
|
||||
stopEdit = tool == TMHand && handTool->get_active() && editingMode && !blockEdit;
|
||||
stopEdit = tool == TMHand && (handTool->get_active() || (perspTool && perspTool->get_active())) && editingMode && !blockEdit;
|
||||
|
||||
handTool->set_active (false);
|
||||
|
||||
@ -122,6 +131,9 @@ void ToolBar::setTool (ToolMode tool)
|
||||
if (colPickerTool) {
|
||||
colPickerTool->set_active (false);
|
||||
}
|
||||
if (perspTool) {
|
||||
perspTool->set_active(false);
|
||||
}
|
||||
|
||||
if (tool == TMHand) {
|
||||
handTool->set_active (true);
|
||||
@ -138,6 +150,12 @@ void ToolBar::setTool (ToolMode tool)
|
||||
if (colPickerTool) {
|
||||
colPickerTool->set_active (true);
|
||||
}
|
||||
} else if (tool == TMPerspective) {
|
||||
if (perspTool) {
|
||||
perspTool->set_active(true);
|
||||
// Perspective is a hand tool, but has its own button.
|
||||
handTool->set_image(*handimg);
|
||||
}
|
||||
}
|
||||
|
||||
current = tool;
|
||||
@ -160,6 +178,7 @@ void ToolBar::startEditMode()
|
||||
ConnectionBlocker handBlocker(handConn);
|
||||
ConnectionBlocker straBlocker(straConn);
|
||||
ConnectionBlocker cropBlocker(cropConn);
|
||||
ConnectionBlocker perspBlocker(perspConn);
|
||||
ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn);
|
||||
|
||||
if (current != TMHand) {
|
||||
@ -172,6 +191,9 @@ void ToolBar::startEditMode()
|
||||
|
||||
cropTool->set_active (false);
|
||||
straTool->set_active (false);
|
||||
if (perspTool) {
|
||||
perspTool->set_active(false);
|
||||
}
|
||||
current = TMHand;
|
||||
}
|
||||
handTool->set_active (true);
|
||||
@ -204,6 +226,7 @@ void ToolBar::hand_pressed ()
|
||||
ConnectionBlocker handBlocker(handConn);
|
||||
ConnectionBlocker straBlocker(straConn);
|
||||
ConnectionBlocker cropBlocker(cropConn);
|
||||
ConnectionBlocker perspBlocker(perspConn);
|
||||
ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn);
|
||||
|
||||
if (editingMode && !blockEdit) {
|
||||
@ -222,6 +245,9 @@ void ToolBar::hand_pressed ()
|
||||
|
||||
cropTool->set_active (false);
|
||||
straTool->set_active (false);
|
||||
if (perspTool) {
|
||||
perspTool->set_active(false);
|
||||
}
|
||||
handTool->set_active (true);
|
||||
|
||||
if (current != TMHand) {
|
||||
@ -244,6 +270,7 @@ void ToolBar::wb_pressed ()
|
||||
ConnectionBlocker handBlocker(handConn);
|
||||
ConnectionBlocker straBlocker(straConn);
|
||||
ConnectionBlocker cropBlocker(cropConn);
|
||||
ConnectionBlocker perspBlocker(perspConn);
|
||||
ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn);
|
||||
|
||||
if (current != TMSpotWB) {
|
||||
@ -256,6 +283,9 @@ void ToolBar::wb_pressed ()
|
||||
handTool->set_active (false);
|
||||
cropTool->set_active (false);
|
||||
straTool->set_active (false);
|
||||
if (perspTool) {
|
||||
perspTool->set_active(false);
|
||||
}
|
||||
if (colPickerTool) {
|
||||
colPickerTool->set_active(false);
|
||||
}
|
||||
@ -288,6 +318,9 @@ void ToolBar::colPicker_pressed (GdkEventButton* event)
|
||||
wbTool->set_active (false);
|
||||
}
|
||||
straTool->set_active (false);
|
||||
if (perspTool) {
|
||||
perspTool->set_active(false);
|
||||
}
|
||||
|
||||
if (current != TMColorPicker) {
|
||||
// Disabling all other tools, enabling the Picker tool and entering the "visible pickers" mode
|
||||
@ -359,6 +392,7 @@ void ToolBar::crop_pressed ()
|
||||
ConnectionBlocker handBlocker(handConn);
|
||||
ConnectionBlocker straBlocker(straConn);
|
||||
ConnectionBlocker cropBlocker(cropConn);
|
||||
ConnectionBlocker perspBlocker(perspConn);
|
||||
ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn);
|
||||
|
||||
if (editingMode) {
|
||||
@ -376,6 +410,9 @@ void ToolBar::crop_pressed ()
|
||||
}
|
||||
|
||||
straTool->set_active (false);
|
||||
if (perspTool) {
|
||||
perspTool->set_active(false);
|
||||
}
|
||||
cropTool->set_active (true);
|
||||
|
||||
if (current != TMCropSelect) {
|
||||
@ -399,6 +436,7 @@ void ToolBar::stra_pressed ()
|
||||
ConnectionBlocker handBlocker(handConn);
|
||||
ConnectionBlocker straBlocker(straConn);
|
||||
ConnectionBlocker cropBlocker(cropConn);
|
||||
ConnectionBlocker perspBlocker(perspConn);
|
||||
ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn);
|
||||
|
||||
if (editingMode) {
|
||||
@ -416,6 +454,9 @@ void ToolBar::stra_pressed ()
|
||||
}
|
||||
|
||||
cropTool->set_active (false);
|
||||
if (perspTool) {
|
||||
perspTool->set_active(false);
|
||||
}
|
||||
straTool->set_active (true);
|
||||
|
||||
if (current != TMStraighten) {
|
||||
@ -432,6 +473,35 @@ void ToolBar::stra_pressed ()
|
||||
}
|
||||
}
|
||||
|
||||
void ToolBar::persp_pressed ()
|
||||
{
|
||||
if (listener && !perspTool->get_active()) {
|
||||
listener->toolDeselected(TMPerspective);
|
||||
return;
|
||||
}
|
||||
|
||||
// Unlike other modes, mode switching is handled by the perspective panel.
|
||||
{
|
||||
ConnectionBlocker handBlocker(handConn);
|
||||
ConnectionBlocker straBlocker(straConn);
|
||||
ConnectionBlocker cropBlocker(cropConn);
|
||||
ConnectionBlocker perspBlocker(perspConn);
|
||||
ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn);
|
||||
|
||||
if (editingMode) {
|
||||
stopEditMode();
|
||||
if (listener) {
|
||||
listener->editModeSwitchedOff();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (listener) {
|
||||
listener->toolSelected(TMPerspective);
|
||||
}
|
||||
}
|
||||
|
||||
bool ToolBar::handleShortcutKey (GdkEventKey* event)
|
||||
{
|
||||
|
||||
@ -485,6 +555,11 @@ void ToolBar::setBatchMode()
|
||||
removeIfThere(this, colPickerTool, false);
|
||||
colPickerTool = nullptr;
|
||||
}
|
||||
if (perspTool) {
|
||||
perspConn.disconnect();
|
||||
removeIfThere(this, perspTool, false);
|
||||
perspTool = nullptr;
|
||||
}
|
||||
|
||||
allowNoTool = true;
|
||||
switch (current) {
|
||||
|
@ -30,6 +30,8 @@ class ToolBarListener
|
||||
|
||||
public:
|
||||
virtual ~ToolBarListener() = default;
|
||||
/// Callback when a tool is deselected. WARNING: Not yet called for most tools.
|
||||
virtual void toolDeselected(ToolMode tool) = 0;
|
||||
/// Callback when a tool is selected
|
||||
virtual void toolSelected(ToolMode tool) = 0;
|
||||
|
||||
@ -51,6 +53,7 @@ private:
|
||||
void colPicker_pressed (GdkEventButton* event);
|
||||
void crop_pressed ();
|
||||
void stra_pressed ();
|
||||
void persp_pressed ();
|
||||
bool showColorPickers(bool showCP);
|
||||
void switchColorPickersVisibility();
|
||||
|
||||
@ -60,6 +63,7 @@ protected:
|
||||
Gtk::ToggleButton* colPickerTool;
|
||||
Gtk::ToggleButton* cropTool;
|
||||
Gtk::ToggleButton* straTool;
|
||||
Gtk::ToggleButton* perspTool;
|
||||
ToolBarListener* listener;
|
||||
LockablePickerToolListener* pickerListener;
|
||||
ToolMode current;
|
||||
@ -71,6 +75,7 @@ protected:
|
||||
sigc::connection cpConn;
|
||||
sigc::connection cropConn;
|
||||
sigc::connection straConn;
|
||||
sigc::connection perspConn;
|
||||
|
||||
public:
|
||||
ToolBar ();
|
||||
|
@ -18,4 +18,4 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
enum ToolMode {TMNone = -1, TMHand = 0, TMSpotWB = 1, TMCropSelect = 2, TMStraighten = 3, TMColorPicker = 4};
|
||||
enum ToolMode {TMNone = -1, TMHand = 0, TMSpotWB = 1, TMCropSelect = 2, TMStraighten = 3, TMColorPicker = 4, TMPerspective = 5};
|
||||
|
@ -282,6 +282,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit
|
||||
lensgeom->setLensGeomListener(this);
|
||||
rotate->setLensGeomListener(this);
|
||||
perspective->setLensGeomListener(this);
|
||||
perspective->setPerspCorrectionPanelListener(this);
|
||||
distortion->setLensGeomListener(this);
|
||||
crop->setCropPanelListener(this);
|
||||
icm->setICMPanelListener(this);
|
||||
@ -986,7 +987,7 @@ void ToolPanelCoordinator::straightenRequested()
|
||||
toolBar->setTool(TMStraighten);
|
||||
}
|
||||
|
||||
void ToolPanelCoordinator::autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw)
|
||||
void ToolPanelCoordinator::autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw, const std::vector<rtengine::ControlLine> *lines)
|
||||
{
|
||||
if (!(ipc && (corr_pitch || corr_yaw))) {
|
||||
return;
|
||||
@ -1000,7 +1001,7 @@ void ToolPanelCoordinator::autoPerspRequested (bool corr_pitch, bool corr_yaw, d
|
||||
rtengine::procparams::ProcParams params;
|
||||
ipc->getParams(¶ms);
|
||||
|
||||
auto res = rtengine::PerspectiveCorrection::autocompute(src, corr_pitch, corr_yaw, ¶ms, src->getMetaData());
|
||||
auto res = rtengine::PerspectiveCorrection::autocompute(src, corr_pitch, corr_yaw, ¶ms, src->getMetaData(), lines);
|
||||
rot = res.angle;
|
||||
pitch = res.pitch;
|
||||
yaw = res.yaw;
|
||||
@ -1015,6 +1016,16 @@ double ToolPanelCoordinator::autoDistorRequested()
|
||||
return rtengine::ImProcFunctions::getAutoDistor(ipc->getInitialImage()->getFileName(), 400);
|
||||
}
|
||||
|
||||
void ToolPanelCoordinator::updateTransformPreviewRequested(rtengine::ProcEvent event, bool render_perspective)
|
||||
{
|
||||
if (!ipc) {
|
||||
return;
|
||||
}
|
||||
|
||||
ipc->beginUpdateParams()->perspective.render = render_perspective;
|
||||
ipc->endUpdateParams(event);
|
||||
}
|
||||
|
||||
void ToolPanelCoordinator::spotWBRequested(int size)
|
||||
{
|
||||
|
||||
@ -1035,6 +1046,17 @@ void ToolPanelCoordinator::cropSelectRequested()
|
||||
toolBar->setTool(TMCropSelect);
|
||||
}
|
||||
|
||||
void ToolPanelCoordinator::controlLineEditModeChanged(bool active)
|
||||
{
|
||||
if (!ipc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
toolBar->setTool(TMPerspective);
|
||||
}
|
||||
}
|
||||
|
||||
void ToolPanelCoordinator::saveInputICCReference(const Glib::ustring& fname, bool apply_wb)
|
||||
{
|
||||
if (ipc) {
|
||||
@ -1162,6 +1184,13 @@ void ToolPanelCoordinator::updateTPVScrollbar(bool hide)
|
||||
updateVScrollbars(hide);
|
||||
}
|
||||
|
||||
void ToolPanelCoordinator::toolDeselected(ToolMode tool)
|
||||
{
|
||||
if (tool == TMPerspective) {
|
||||
perspective->requestApplyControlLines();
|
||||
}
|
||||
}
|
||||
|
||||
void ToolPanelCoordinator::toolSelected(ToolMode tool)
|
||||
{
|
||||
GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected
|
||||
@ -1206,6 +1235,20 @@ void ToolPanelCoordinator::toolSelected(ToolMode tool)
|
||||
break;
|
||||
}
|
||||
|
||||
case TMPerspective: {
|
||||
toolBar->blockEditDeactivation(false); // To allow deactivating Locallab when switching to another tool using toolbar
|
||||
perspective->setControlLineEditMode(true);
|
||||
perspective->setExpanded(true);
|
||||
bool isFavorite = checkFavorite(perspective);
|
||||
if (!isFavorite) {
|
||||
isFavorite = checkFavorite(lensgeom);
|
||||
lensgeom->setExpanded(true);
|
||||
}
|
||||
toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(isFavorite ? *favoritePanelSW : *transformPanelSW));
|
||||
prevPage = toolPanelNotebook->get_nth_page(toolPanelNotebook->get_current_page()); // Updating prevPage as "signal_switch_page" event
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ class ToolPanelCoordinator :
|
||||
public LensGeomListener,
|
||||
public SpotWBListener,
|
||||
public CropPanelListener,
|
||||
public PerspCorrectionPanelListener,
|
||||
public ICMPanelListener,
|
||||
public ImageAreaToolListener,
|
||||
public rtengine::ImageTypeListener,
|
||||
@ -313,8 +314,9 @@ public:
|
||||
// rotatelistener interface
|
||||
void straightenRequested () override;
|
||||
void autoCropRequested () override;
|
||||
void autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw) override;
|
||||
void autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw, const std::vector<rtengine::ControlLine> *lines = nullptr) override;
|
||||
double autoDistorRequested () override;
|
||||
void updateTransformPreviewRequested (rtengine::ProcEvent event, bool render_perspective) override;
|
||||
|
||||
// spotwblistener interface
|
||||
void spotWBRequested (int size) override;
|
||||
@ -322,6 +324,9 @@ public:
|
||||
// croppanellistener interface
|
||||
void cropSelectRequested () override;
|
||||
|
||||
// PerspCorrectionPanelListener interface
|
||||
void controlLineEditModeChanged(bool active) override;
|
||||
|
||||
// icmpanellistener interface
|
||||
void saveInputICCReference(const Glib::ustring& fname, bool apply_wb) override;
|
||||
|
||||
@ -338,6 +343,7 @@ public:
|
||||
bool handleShortcutKey(GdkEventKey* event);
|
||||
|
||||
// ToolBarListener interface
|
||||
void toolDeselected(ToolMode tool) override;
|
||||
void toolSelected (ToolMode tool) override;
|
||||
void editModeSwitchedOff () final;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user