Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/gui/symbols/area_symbol_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ void AreaSymbolSettings::loadPatterns()
pattern_list->addItem(pattern.name);
if (pattern.type == AreaSymbol::FillPattern::PointPattern)
{
auto editor = new PointSymbolEditorWidget(controller, pattern.point, PointSymbolEditorWidget::AreaSymbolElement, 16);
auto editor = new PointSymbolEditorWidget(controller, pattern.point, nullptr, PointSymbolEditorWidget::AreaSymbolElement, 16);
connect(editor, &PointSymbolEditorWidget::symbolEdited, this, &SymbolPropertiesWidget::propertiesModified );
addPropertiesGroup(pattern.name, editor);
}
Expand Down Expand Up @@ -457,7 +457,7 @@ void AreaSymbolSettings::addPattern(AreaSymbol::FillPattern::Type type)
{
active_pattern->point = new PointSymbol();
active_pattern->point->setRotatable(true);
auto editor = new PointSymbolEditorWidget(controller, active_pattern->point, PointSymbolEditorWidget::AreaSymbolElement, 16);
auto editor = new PointSymbolEditorWidget(controller, active_pattern->point, nullptr, PointSymbolEditorWidget::AreaSymbolElement, 16);
connect(editor, &PointSymbolEditorWidget::symbolEdited, this, &SymbolPropertiesWidget::propertiesModified );
if (pattern_list->currentRow() == int(symbol->patterns.size()) - 1)
{
Expand Down
4 changes: 2 additions & 2 deletions src/gui/symbols/line_symbol_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ LineSymbolSettings::LineSymbolSettings(LineSymbol* symbol, SymbolSettingDialog*
symbol->ensurePointSymbols(tr("Start symbol"), tr("Mid symbol"), tr("End symbol"), tr("Dash symbol"));
for (auto point_symbol : { symbol->getStartSymbol(), symbol->getMidSymbol(), symbol->getEndSymbol(), symbol->getDashSymbol() })
{
point_symbol_editor = new PointSymbolEditorWidget(controller, point_symbol, PointSymbolEditorWidget::LineSymbolElement, 16);
point_symbol_editor = new PointSymbolEditorWidget(controller, point_symbol, nullptr, PointSymbolEditorWidget::LineSymbolElement, 16);
addPropertiesGroup(point_symbol->getName(), point_symbol_editor);
connect(point_symbol_editor, &PointSymbolEditorWidget::symbolEdited, this, &LineSymbolSettings::pointSymbolEdited);
}
Expand Down Expand Up @@ -818,7 +818,7 @@ void LineSymbolSettings::reset(Symbol* symbol)
this->symbol->ensurePointSymbols(tr("Start symbol"), tr("Mid symbol"), tr("End symbol"), tr("Dash symbol"));
for (auto point_symbol : { this->symbol->getStartSymbol(), this->symbol->getMidSymbol(), this->symbol->getEndSymbol(), this->symbol->getDashSymbol() })
{
point_symbol_editor = new PointSymbolEditorWidget(controller, point_symbol, PointSymbolEditorWidget::LineSymbolElement, 16);
point_symbol_editor = new PointSymbolEditorWidget(controller, point_symbol, nullptr, PointSymbolEditorWidget::LineSymbolElement, 16);
connect(point_symbol_editor, &PointSymbolEditorWidget::symbolEdited, this, &LineSymbolSettings::pointSymbolEdited);

int index = indexOfPropertiesGroup(point_symbol->getName()); // existing symbol editor
Expand Down
178 changes: 177 additions & 1 deletion src/gui/symbols/point_symbol_editor_widget.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Copyright 2012, 2013 Thomas Schöps
* Copyright 2012-2019, 2024, 2025 Kai Pastor
* Copyright 2025 Matthias Kühlewein
*
* This file is part of OpenOrienteering.
*
Expand Down Expand Up @@ -64,6 +65,7 @@
#include "core/map.h"
#include "core/objects/object.h"
#include "core/symbols/area_symbol.h"
#include "core/symbols/combined_symbol.h"
#include "core/symbols/line_symbol.h"
#include "core/symbols/point_symbol.h"
#include "core/symbols/symbol.h"
Expand All @@ -78,12 +80,13 @@

namespace OpenOrienteering {

PointSymbolEditorWidget::PointSymbolEditorWidget(MapEditorController* controller, PointSymbol* symbol, SymbolRole role, qreal offset_y, QWidget* parent)
PointSymbolEditorWidget::PointSymbolEditorWidget(MapEditorController* controller, PointSymbol* symbol, Map* source_map, SymbolRole role, qreal offset_y, QWidget* parent)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Early feedback:
I don't think we should add another parameter. The source map is implicitly known, via controller and symbol.
(Another suggested workflow was copy-and-paste. This would use a different Map, with all complications. And you wouldn't get that Map at constuction time, before "Paste".)

Copy link
Member Author

@dl3sdo dl3sdo Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also didn't like to add a new parameter but had not found a better alternative.
The newly created controller being passed to PointSymbolEditorWidget only knows the preview map but does not know the source_map, neither does the symbol. There is certainly the previously active controller who 'knows' the source map but I don't know how PointSymbolEditorWidget can access it.
MapEditorController describes itself as a 'HACK' for being used in the symbol editor for the preview. MapEditorController could be extended to store the source map in addition as it's already considering the symbol editing usecase.

: QWidget(parent)
, symbol(symbol)
, object_origin_coord(0, offset_y)
, offset_y(offset_y)
, map(controller->getMap())
, source_map(source_map)
, controller(controller)
, permanent_preview(role == PrimarySymbol)
{
Expand Down Expand Up @@ -226,6 +229,11 @@ PointSymbolEditorWidget::PointSymbolEditorWidget(MapEditorController* controller
add_coord_button = new QPushButton(QIcon(QString::fromLatin1(":/images/plus.png")), QString{});
delete_coord_button = new QPushButton(QIcon(QString::fromLatin1(":/images/minus.png")), QString{});
center_coords_button = new QPushButton(tr("Center by coordinate average"));
if (source_map)
{
import_objects_button = new QPushButton(tr("Import from selected objects"));
import_objects_button->setEnabled(source_map->getNumSelectedObjects() > 0);
}

// Layout
auto* left_layout = new QVBoxLayout();
Expand All @@ -237,6 +245,8 @@ PointSymbolEditorWidget::PointSymbolEditorWidget(MapEditorController* controller
element_buttons_layout->addWidget(add_element_button, 1, 2);
element_buttons_layout->addWidget(delete_element_button, 1, 3);
element_buttons_layout->addWidget(center_all_elements_button, 2, 1, 1, 4);
if (source_map)
element_buttons_layout->addWidget(import_objects_button, 3, 1, 1, 4);
element_buttons_layout->setColumnStretch(5, 1);
left_layout->addLayout(element_buttons_layout);

Expand Down Expand Up @@ -292,6 +302,8 @@ PointSymbolEditorWidget::PointSymbolEditorWidget(MapEditorController* controller
connect(add_coord_button, &QPushButton::clicked, this, &PointSymbolEditorWidget::addCoordClicked);
connect(delete_coord_button, &QPushButton::clicked, this, &PointSymbolEditorWidget::deleteCoordClicked);
connect(center_coords_button, &QPushButton::clicked, this, &PointSymbolEditorWidget::centerCoordsClicked);
if (source_map)
connect(import_objects_button, &QPushButton::clicked, this, &PointSymbolEditorWidget::importSelectedObjects);
}

PointSymbolEditorWidget::~PointSymbolEditorWidget()
Expand Down Expand Up @@ -1013,6 +1025,170 @@ Symbol* PointSymbolEditorWidget::getCurrentElementSymbol()
}


void PointSymbolEditorWidget::importSelectedObjects()
{
auto selection_center = determineSelectionCenter();
const auto previous_elements_count = element_list->count();
for (const auto object : source_map->selectedObjects())
{
switch (object->getSymbol()->getType())
{
case Symbol::Point:
importPointObject(object, selection_center);
break;
case Symbol::Area:
importAreaObject(object, selection_center);
break;
case Symbol::Line:
importLineObject(object, selection_center);
break;
case Symbol::Combined:
importCombinedObject(object, selection_center);
break;
default:
;
}
}
if (previous_elements_count != element_list->count())
{
map->updateAllObjectsWithSymbol(symbol);
emit symbolEdited();
}
}

MapCoordF PointSymbolEditorWidget::determineSelectionCenter()
{
const auto only_point_objects = std::all_of(source_map->selectedObjectsBegin(), source_map->selectedObjectsEnd(), [](auto const* object) { return object->getType() == Object::Point; });
if (only_point_objects)
{
QPointF sum = std::accumulate(source_map->selectedObjectsBegin(), source_map->selectedObjectsEnd(), QPointF{0.0,0.0}, [](const QPointF& sum, const auto* object) {
return QPointF{sum.x() + object->asPoint()->getCoordF().x(), sum.y() + object->asPoint()->getCoordF().y()};
});
return MapCoordF(sum.x() / source_map->getNumSelectedObjects(), sum.y() / source_map->getNumSelectedObjects());
}

QRectF rect;
source_map->includeSelectionRect(rect);
return MapCoordF(rect.center());
}

void PointSymbolEditorWidget::importPointObject(const Object* object, MapCoordF& selection_center)
{
const auto point_symbol = object->getSymbol()->asPoint();
const auto point_object = object->asPoint();
if (point_symbol->getInnerColor() || point_symbol->getOuterColor())
{
auto* new_symbol = new PointSymbol();
new_symbol->setInnerColor(point_symbol->getInnerColor());
new_symbol->setInnerRadius(point_symbol->getInnerRadius());
new_symbol->setOuterColor(point_symbol->getOuterColor());
new_symbol->setOuterWidth(point_symbol->getOuterWidth());
auto* new_object = new PointObject(new_symbol);
const MapCoordF new_coords = point_object->getCoordF() - selection_center;
new_object->setPosition(new_coords);
addNewSymbol(new_object, new_symbol);
}
for (int i = 0; i < point_symbol->getNumElements(); ++i)
{
auto* element_symbol = point_symbol->getElementSymbol(i);
auto* element_object = point_symbol->getElementObject(i);
switch (element_object->getSymbol()->getType())
{
case Symbol::Point:
{
auto* new_symbol = element_symbol->asPoint()->duplicate();
auto* new_object = element_object->asPoint()->duplicate();
const MapCoordF distance_to_center = point_object->getCoordF() - selection_center;
new_object->move(MapCoord(distance_to_center));
addNewSymbol(new_object, new_symbol);
}
break;
case Symbol::Area:
{
auto* new_symbol = element_symbol->asArea()->duplicate();
auto* new_object = element_object->asPath()->duplicate();
const MapCoordF distance_to_center = point_object->getCoordF() - selection_center;
new_object->move(MapCoord(distance_to_center));
addNewSymbol(new_object, new_symbol);
}
break;
case Symbol::Line:
{
auto* new_symbol = element_symbol->asLine()->duplicate();
auto* new_object = element_object->asPath()->duplicate();
const MapCoordF distance_to_center = point_object->getCoordF() - selection_center;
new_object->move(MapCoord(distance_to_center));
addNewSymbol(new_object, new_symbol);
}
break;
default:
Q_UNREACHABLE();
}
}
}

void PointSymbolEditorWidget::importAreaObject(const Object* object, MapCoordF& selection_center)
{
auto* new_symbol = object->getSymbol()->asArea()->duplicate();
auto* new_object = object->asPath()->duplicate();
new_object->move(MapCoord(-selection_center));
addNewSymbol(new_object, new_symbol);
}

void PointSymbolEditorWidget::importLineObject(const Object* object, MapCoordF& selection_center)
{
auto* new_symbol = object->getSymbol()->asLine()->duplicate();
auto* new_object = object->asPath()->duplicate();
new_object->move(MapCoord(-selection_center));
addNewSymbol(new_object, new_symbol);
}

void PointSymbolEditorWidget::importCombinedObject(const Object* object, MapCoordF& selection_center)
{
const auto combined_symbol = object->getSymbol()->asCombined();

for (int i = 0; i < combined_symbol->getNumParts(); ++i)
{
auto part = combined_symbol->getPart(i);
if (!part)
continue;
switch (part->getType())
{
case Symbol::Area:
{
auto area_object = object->asPath()->duplicate();
area_object->setSymbol(part, false);
importAreaObject(area_object, selection_center);
}
break;
case Symbol::Line:
{
auto line_object = object->asPath()->duplicate();
line_object->setSymbol(part, false);
importLineObject(line_object, selection_center);
}
break;
case Symbol::Combined:
{
auto combined_object = object->asPath()->duplicate();
combined_object->setSymbol(part, false);
importCombinedObject(combined_object, selection_center);
}
break;
default:
;
}
}
}

void PointSymbolEditorWidget::addNewSymbol(Object* new_object, Symbol* new_symbol)
{
int row = (element_list->currentRow() < 0) ? element_list->count() : (element_list->currentRow() + 1);
symbol->addElement(row - 1, new_object, new_symbol);
element_list->insertItem(row, getLabelForSymbol(new_symbol));
element_list->setCurrentRow(row);
}


// ### PointSymbolEditorTool ###

Expand Down
14 changes: 13 additions & 1 deletion src/gui/symbols/point_symbol_editor_widget.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@ friend class PointSymbolEditorActivity;
/** Construct a new widget.
* @param controller The controller of the preview map
* @param symbol The point symbol to be edited
* @param source_map The source map
* @param role The role of the symbol to be edited
* @param offset_y The vertical offset of the point symbol preview/editor from the origin
* @param parent Standard QWidget parentship
*/
PointSymbolEditorWidget(MapEditorController* controller, PointSymbol* symbol, SymbolRole role = PrimarySymbol, qreal offset_y = 0, QWidget* parent = nullptr);
PointSymbolEditorWidget(MapEditorController* controller, PointSymbol* symbol, Map* source_map, SymbolRole role = PrimarySymbol, qreal offset_y = 0, QWidget* parent = nullptr);

~PointSymbolEditorWidget() override;

Expand Down Expand Up @@ -130,6 +131,8 @@ private slots:
void deleteCoordClicked();
void centerCoordsClicked();

void importSelectedObjects();

private:
void initElementList();
void updateCoordsTable();
Expand All @@ -142,6 +145,13 @@ private slots:
Symbol* getCurrentElementSymbol();
Object* getCurrentElementObject();

void importPointObject(const Object* object, MapCoordF& selection_center);
void importAreaObject(const Object* object, MapCoordF& selection_center);
void importLineObject(const Object* object, MapCoordF& selection_center);
void importCombinedObject(const Object* object, MapCoordF& selection_center);
MapCoordF determineSelectionCenter();
void addNewSymbol(Object* new_object, Symbol* new_symbol);

PointSymbol* const symbol;
PointObject* midpoint_object = nullptr;
const MapCoordF object_origin_coord;
Expand All @@ -151,6 +161,7 @@ private slots:
QListWidget* element_list;
QPushButton* delete_element_button;
QPushButton* center_all_elements_button;
QPushButton* import_objects_button;

QStackedWidget* element_properties_widget;

Expand Down Expand Up @@ -179,6 +190,7 @@ private slots:
const qreal offset_y;
PointSymbolEditorActivity* activity;
Map* map;
Map* source_map;
MapEditorController* controller;
const bool permanent_preview;
};
Expand Down
4 changes: 2 additions & 2 deletions src/gui/symbols/point_symbol_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ PointSymbolSettings::PointSymbolSettings(PointSymbol* symbol, SymbolSettingDialo
: SymbolPropertiesWidget(symbol, dialog),
symbol(symbol)
{
symbol_editor = new PointSymbolEditorWidget(dialog->getPreviewController(), symbol);
symbol_editor = new PointSymbolEditorWidget(dialog->getPreviewController(), symbol, dialog->getSourceMap());
connect(symbol_editor, &PointSymbolEditorWidget::symbolEdited, this, &SymbolPropertiesWidget::propertiesModified );

layout = new QVBoxLayout();
Expand Down Expand Up @@ -81,7 +81,7 @@ void PointSymbolSettings::reset(Symbol* symbol)
layout->removeWidget(symbol_editor);
delete(symbol_editor);

symbol_editor = new PointSymbolEditorWidget(dialog->getPreviewController(), this->symbol);
symbol_editor = new PointSymbolEditorWidget(dialog->getPreviewController(), this->symbol, dialog->getSourceMap());
connect(symbol_editor, &PointSymbolEditorWidget::symbolEdited, this, &SymbolPropertiesWidget::propertiesModified );
layout->addWidget(symbol_editor);
}
Expand Down