Move control lines code to new files
This commit is contained in:
parent
cef97eefea
commit
06caf40598
@ -20,12 +20,20 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "coord2d.h"
|
#include <vector>
|
||||||
#include "procparams.h"
|
|
||||||
#include "imagesource.h"
|
|
||||||
|
|
||||||
namespace rtengine {
|
namespace rtengine {
|
||||||
|
|
||||||
|
namespace procparams
|
||||||
|
{
|
||||||
|
|
||||||
|
class ProcParams;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ImageSource;
|
||||||
|
class FramesMetaData;
|
||||||
|
|
||||||
class ControlLine
|
class ControlLine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -34,6 +34,7 @@ set(NONCLISOURCEFILES
|
|||||||
colorappearance.cc
|
colorappearance.cc
|
||||||
coloredbar.cc
|
coloredbar.cc
|
||||||
colortoning.cc
|
colortoning.cc
|
||||||
|
controllines.cc
|
||||||
controlspotpanel.cc
|
controlspotpanel.cc
|
||||||
coordinateadjuster.cc
|
coordinateadjuster.cc
|
||||||
crop.cc
|
crop.cc
|
||||||
|
457
rtgui/controllines.cc
Normal file
457
rtgui/controllines.cc
Normal file
@ -0,0 +1,457 @@
|
|||||||
|
/*
|
||||||
|
* 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(CSCrosshair),
|
||||||
|
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];
|
||||||
|
int component = selected_object % ::ControlLine::OBJ_COUNT; // 0 == end, 1 == line, 2 == icon, 3 == begin
|
||||||
|
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 = CSPlus;
|
||||||
|
} else {
|
||||||
|
cursor = CSCrosshair;
|
||||||
|
}
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
116
rtgui/controllines.h
Normal file
116
rtgui/controllines.h
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
};
|
@ -782,431 +782,6 @@ void PerspCorrection::setCamBasedEventsActive(bool active)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlLineManager::ControlLineManager():
|
|
||||||
EditSubscriber(ET_OBJECTS),
|
|
||||||
canvas_area(new Rectangle()),
|
|
||||||
cursor(CSCrosshair),
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
|
|
||||||
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];
|
|
||||||
int component = selected_object % ::ControlLine::OBJ_COUNT; // 0 == end, 1 == line, 2 == icon, 3 == begin
|
|
||||||
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 = CSPlus;
|
|
||||||
} else {
|
|
||||||
cursor = CSCrosshair;
|
|
||||||
}
|
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LinesCallbacks::LinesCallbacks(PerspCorrection* tool):
|
LinesCallbacks::LinesCallbacks(PerspCorrection* tool):
|
||||||
tool(tool)
|
tool(tool)
|
||||||
{
|
{
|
||||||
|
@ -21,94 +21,9 @@
|
|||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
|
|
||||||
#include "adjuster.h"
|
#include "adjuster.h"
|
||||||
#include "editcallbacks.h"
|
#include "controllines.h"
|
||||||
#include "editwidgets.h"
|
|
||||||
#include "lensgeomlistener.h"
|
#include "lensgeomlistener.h"
|
||||||
#include "toolpanel.h"
|
#include "toolpanel.h"
|
||||||
#include "../rtengine/perspectivecorrection.h"
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PerspCorrection final :
|
class PerspCorrection final :
|
||||||
public ToolParamBlock,
|
public ToolParamBlock,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user