1
/***************************************************************************
2
* Copyright (c) 2014 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
25
#include <QContextMenuEvent>
30
#include <QRegularExpression>
31
#include <QRegularExpressionMatch>
34
#include <QWidgetAction>
35
#include <boost/core/ignore_unused.hpp>
38
#include <App/Application.h>
39
#include <App/Document.h>
40
#include <App/DocumentObject.h>
41
#include <Gui/Application.h>
42
#include <Gui/BitmapFactory.h>
43
#include <Gui/Command.h>
44
#include <Gui/Notifications.h>
45
#include <Gui/Selection.h>
46
#include <Gui/SelectionObject.h>
47
#include <Gui/ViewProvider.h>
48
#include <Mod/Sketcher/App/GeometryFacade.h>
49
#include <Mod/Sketcher/App/SketchObject.h>
51
#include "TaskSketcherElements.h"
53
#include "ViewProviderSketch.h"
54
#include "ui_TaskSketcherElements.h"
57
using namespace SketcherGui;
58
using namespace Gui::TaskView;
60
// Translation block for context menu: do not remove
62
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Point Coincidence");
63
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Point on Object");
64
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Vertical Constraint");
65
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Horizontal Constraint");
66
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Parallel Constraint");
67
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Perpendicular Constraint");
68
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Tangent Constraint");
69
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Equal Length");
70
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Symmetric");
71
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Block Constraint");
72
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Lock Constraint");
73
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Horizontal Distance");
74
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Vertical Distance");
75
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Length Constraint");
76
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Radius Constraint");
77
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Diameter Constraint");
78
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Radiam Constraint");
79
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Angle Constraint");
80
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Toggle construction geometry");
81
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Select Constraints");
82
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Select Origin");
83
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Select Horizontal Axis");
84
QT_TRANSLATE_NOOP("SketcherGui::ElementView", "Select Vertical Axis");
87
/// Inserts a QAction into an existing menu
88
/// ICONSTR is the string of the icon in the resource file
89
/// NAMESTR is the text appearing in the contextual menuAction
90
/// CMDSTR is the string registered in the commandManager
91
/// FUNC is the name of the member function to be executed on selection of the menu item
92
/// ACTSONSELECTION is a true/false value to activate the command only if a selection is made
93
#define CONTEXT_ITEM(ICONSTR, NAMESTR, CMDSTR, FUNC, ACTSONSELECTION) \
94
QIcon icon_##FUNC(Gui::BitmapFactory().pixmap(ICONSTR)); \
95
QAction* constr_##FUNC = menu.addAction(icon_##FUNC, tr(NAMESTR), this, SLOT(FUNC())); \
96
constr_##FUNC->setShortcut(QKeySequence(QString::fromUtf8( \
97
Gui::Application::Instance->commandManager().getCommandByName(CMDSTR)->getAccel()))); \
98
if (ACTSONSELECTION) \
99
constr_##FUNC->setEnabled(!items.isEmpty()); \
101
constr_##FUNC->setEnabled(true);
103
/// Defines the member function corresponding to the CONTEXT_ITEM macro
104
#define CONTEXT_MEMBER_DEF(CMDSTR, FUNC) \
105
void ElementView::FUNC() \
107
Gui::Application::Instance->commandManager().runCommandByName(CMDSTR); \
114
class ElementItemDelegate: public QStyledItemDelegate
118
/// Enum containing all controls rendered in this item. Controls in that enum MUST be in order.
119
enum SubControl : int {
128
explicit ElementItemDelegate(ElementView* parent);
129
~ElementItemDelegate() override = default;
131
void paint(QPainter* painter, const QStyleOptionViewItem& option,
132
const QModelIndex& index) const override;
133
bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
134
const QModelIndex& index) override;
136
ElementItem* getElementItem(const QModelIndex& index) const;
138
QRect subControlRect(SubControl element, const QStyleOptionViewItem& option, const QModelIndex& index) const;
139
void drawSubControl(SubControl element, QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
141
const int gap = 4; // 4px of spacing between consecutive elements
144
void itemHovered(QModelIndex);
145
void itemChecked(QModelIndex, Qt::CheckState state);
149
// helper class to store additional information about the listWidget entry.
150
class ElementItem: public QListWidgetItem
153
enum class GeometryState
168
ElementItem(int elementnr,
172
Base::Type geometryType,
175
ViewProviderSketch* sketchView)
176
: ElementNbr(elementnr)
177
, StartingVertex(startingVertex)
178
, MidVertex(midVertex)
179
, EndVertex(endVertex)
180
, GeometryType(std::move(geometryType))
182
, isLineSelected(false)
183
, isStartingPointSelected(false)
184
, isEndPointSelected(false)
185
, isMidPointSelected(false)
186
, clickedOn(SubElementType::none)
187
, hovered(SubElementType::none)
188
, rightClicked(false)
190
, sketchView(sketchView)
193
~ElementItem() override
196
bool canBeHidden() const
198
return State != GeometryState::External;
201
bool isVisible() const
203
if (State != GeometryState::External) {
204
const auto geo = sketchView->getSketchObject()->getGeometry(ElementNbr);
206
auto layer = getSafeGeomLayerId(geo);
208
return layer != static_cast<unsigned int>(Layer::Hidden);
212
// 1. external geometry currently is always visible.
213
// 2. if internal and ElementNbr is out of range, the element
214
// needs to be updated and the return value is not important.
218
QVariant data(int role) const override
220
// In order for content-box to include size of the 4 geometry icons we need to provide
221
// Qt with information about decoration (icon) size. This is hack to work around Qt
222
// limitation of not knowing about padding, border and margin boxes of stylesheets
223
// thus being unable to provide proper sizeHint for stylesheets to render correctly
224
if (role == Qt::DecorationRole) {
225
auto size = listWidget()->iconSize();
227
return QIcon(QPixmap(size));
230
return QListWidgetItem::data(role);
233
bool isGeometrySelected(Sketcher::PointPos pos) const
236
case Sketcher::PointPos::none:
237
return isLineSelected;
238
case Sketcher::PointPos::start:
239
return isStartingPointSelected;
240
case Sketcher::PointPos::end:
241
return isEndPointSelected;
242
case Sketcher::PointPos::mid:
243
return isMidPointSelected;
249
bool isGeometryPreselected(Sketcher::PointPos pos) const
252
case Sketcher::PointPos::none:
253
return hovered == SubElementType::edge;
254
case Sketcher::PointPos::start:
255
return hovered == SubElementType::start;
256
case Sketcher::PointPos::end:
257
return hovered == SubElementType::end;
258
case Sketcher::PointPos::mid:
259
return hovered == SubElementType::mid;
265
Sketcher::SketchObject* getSketchObject() const
267
return sketchView->getSketchObject();
275
Base::Type GeometryType;
279
bool isStartingPointSelected;
280
bool isEndPointSelected;
281
bool isMidPointSelected;
284
SubElementType clickedOn;
285
SubElementType hovered;
291
ViewProviderSketch* sketchView;
295
class ElementFilterList: public QListWidget
300
explicit ElementFilterList(QWidget* parent = nullptr);
301
~ElementFilterList() override;
304
void changeEvent(QEvent* e) override;
305
void languageChange();
308
using filterItemRepr =
309
std::pair<const char*, const int>;// {filter item text, filter item level}
310
inline static const std::vector<filterItemRepr> filterItems = {
311
{QT_TR_NOOP("Normal"), 0},
312
{QT_TR_NOOP("Construction"), 0},
313
{QT_TR_NOOP("Internal"), 0},
314
{QT_TR_NOOP("External"), 0},
315
{QT_TR_NOOP("All types"), 0},
316
{QT_TR_NOOP("Point"), 1},
317
{QT_TR_NOOP("Line"), 1},
318
{QT_TR_NOOP("Circle"), 1},
319
{QT_TR_NOOP("Ellipse"), 1},
320
{QT_TR_NOOP("Arc of circle"), 1},
321
{QT_TR_NOOP("Arc of ellipse"), 1},
322
{QT_TR_NOOP("Arc of hyperbola"), 1},
323
{QT_TR_NOOP("Arc of parabola"), 1},
324
{QT_TR_NOOP("B-spline"), 1}};
326
}// namespace SketcherGui
328
class ElementWidgetIcons
338
ElementWidgetIcons(const ElementWidgetIcons&) = delete;
339
ElementWidgetIcons(ElementWidgetIcons&&) = delete;
340
ElementWidgetIcons& operator=(const ElementWidgetIcons&) = delete;
341
ElementWidgetIcons& operator=(ElementWidgetIcons&&) = delete;
344
getIcon(Base::Type type, Sketcher::PointPos pos,
345
ElementItem::GeometryState icontype = ElementItem::GeometryState::Normal)
347
static ElementWidgetIcons elementicons;
349
return elementicons.getIconImpl(type, pos, icontype);
357
std::piecewise_construct,
358
std::forward_as_tuple(Part::GeomArcOfCircle::getClassTypeId()),
359
std::forward_as_tuple(
360
std::initializer_list<
361
std::pair<const Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>> {
362
{Sketcher::PointPos::none, getMultIcon("Sketcher_Element_Arc_Edge")},
363
{Sketcher::PointPos::start, getMultIcon("Sketcher_Element_Arc_StartingPoint")},
364
{Sketcher::PointPos::end, getMultIcon("Sketcher_Element_Arc_EndPoint")},
365
{Sketcher::PointPos::mid, getMultIcon("Sketcher_Element_Arc_MidPoint")}}));
368
std::piecewise_construct,
369
std::forward_as_tuple(Part::GeomCircle::getClassTypeId()),
370
std::forward_as_tuple(
371
std::initializer_list<
372
std::pair<const Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>> {
373
{Sketcher::PointPos::none, getMultIcon("Sketcher_Element_Circle_Edge")},
374
{Sketcher::PointPos::mid, getMultIcon("Sketcher_Element_Circle_MidPoint")},
378
std::piecewise_construct,
379
std::forward_as_tuple(Part::GeomLineSegment::getClassTypeId()),
380
std::forward_as_tuple(
381
std::initializer_list<
382
std::pair<const Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>> {
383
{Sketcher::PointPos::none, getMultIcon("Sketcher_Element_Line_Edge")},
384
{Sketcher::PointPos::start, getMultIcon("Sketcher_Element_Line_StartingPoint")},
385
{Sketcher::PointPos::end, getMultIcon("Sketcher_Element_Line_EndPoint")},
389
std::piecewise_construct,
390
std::forward_as_tuple(Part::GeomPoint::getClassTypeId()),
391
std::forward_as_tuple(
392
std::initializer_list<
393
std::pair<const Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>> {
394
{Sketcher::PointPos::start,
395
getMultIcon("Sketcher_Element_Point_StartingPoint")},
399
std::piecewise_construct,
400
std::forward_as_tuple(Part::GeomEllipse::getClassTypeId()),
401
std::forward_as_tuple(
402
std::initializer_list<
403
std::pair<const Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>> {
404
{Sketcher::PointPos::none, getMultIcon("Sketcher_Element_Ellipse_Edge_2")},
405
{Sketcher::PointPos::mid, getMultIcon("Sketcher_Element_Ellipse_CentrePoint")},
409
std::piecewise_construct,
410
std::forward_as_tuple(Part::GeomArcOfEllipse::getClassTypeId()),
411
std::forward_as_tuple(
412
std::initializer_list<
413
std::pair<const Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>> {
414
{Sketcher::PointPos::none, getMultIcon("Sketcher_Element_Elliptical_Arc_Edge")},
415
{Sketcher::PointPos::start,
416
getMultIcon("Sketcher_Element_Elliptical_Arc_Start_Point")},
417
{Sketcher::PointPos::end,
418
getMultIcon("Sketcher_Element_Elliptical_Arc_End_Point")},
419
{Sketcher::PointPos::mid,
420
getMultIcon("Sketcher_Element_Elliptical_Arc_Centre_Point")},
424
std::piecewise_construct,
425
std::forward_as_tuple(Part::GeomArcOfHyperbola::getClassTypeId()),
426
std::forward_as_tuple(
427
std::initializer_list<
428
std::pair<const Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>> {
429
{Sketcher::PointPos::none, getMultIcon("Sketcher_Element_Hyperbolic_Arc_Edge")},
430
{Sketcher::PointPos::start,
431
getMultIcon("Sketcher_Element_Hyperbolic_Arc_Start_Point")},
432
{Sketcher::PointPos::end,
433
getMultIcon("Sketcher_Element_Hyperbolic_Arc_End_Point")},
434
{Sketcher::PointPos::mid,
435
getMultIcon("Sketcher_Element_Hyperbolic_Arc_Centre_Point")},
439
std::piecewise_construct,
440
std::forward_as_tuple(Part::GeomArcOfParabola::getClassTypeId()),
441
std::forward_as_tuple(
442
std::initializer_list<
443
std::pair<const Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>> {
444
{Sketcher::PointPos::none, getMultIcon("Sketcher_Element_Parabolic_Arc_Edge")},
445
{Sketcher::PointPos::start,
446
getMultIcon("Sketcher_Element_Parabolic_Arc_Start_Point")},
447
{Sketcher::PointPos::end,
448
getMultIcon("Sketcher_Element_Parabolic_Arc_End_Point")},
449
{Sketcher::PointPos::mid,
450
getMultIcon("Sketcher_Element_Parabolic_Arc_Centre_Point")},
454
std::piecewise_construct,
455
std::forward_as_tuple(Part::GeomBSplineCurve::getClassTypeId()),
456
std::forward_as_tuple(
457
std::initializer_list<
458
std::pair<const Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>> {
459
{Sketcher::PointPos::none, getMultIcon("Sketcher_Element_BSpline_Edge")},
460
{Sketcher::PointPos::start, getMultIcon("Sketcher_Element_BSpline_StartPoint")},
461
{Sketcher::PointPos::end, getMultIcon("Sketcher_Element_BSpline_EndPoint")},
465
std::piecewise_construct,
466
std::forward_as_tuple(Base::Type::badType()),
467
std::forward_as_tuple(
468
std::initializer_list<
469
std::pair<const Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>> {
470
{Sketcher::PointPos::none,
471
getMultIcon("Sketcher_Element_SelectionTypeInvalid")},
475
const QIcon& getIconImpl(Base::Type type, Sketcher::PointPos pos,
476
ElementItem::GeometryState icontype)
479
auto typekey = icons.find(type);
481
if (typekey == icons.end()) {// Not supported Geometry Type - Defaults to invalid icon
482
typekey = icons.find(Base::Type::badType());
483
pos = Sketcher::PointPos::none;
486
auto poskey = typekey->second.find(pos);
488
if (poskey == typekey->second.end()) {// invalid PointPos for type - Provide Invalid icon
489
typekey = icons.find(Base::Type::badType());
490
pos = Sketcher::PointPos::none;
491
poskey = typekey->second.find(pos);
494
if (icontype == ElementItem::GeometryState::Normal)
495
return std::get<0>(poskey->second);
496
else if (icontype == ElementItem::GeometryState::Construction)
497
return std::get<1>(poskey->second);
498
else if (icontype == ElementItem::GeometryState::External)
499
return std::get<2>(poskey->second);
500
else// internal alignment
501
return std::get<3>(poskey->second);
503
// We should never arrive here, as badtype, PointPos::none must exist.
504
throw Base::ValueError("Icon for Invalid is missing!!");
507
std::tuple<QIcon, QIcon, QIcon, QIcon> getMultIcon(const char* name)
509
int hue, sat, val, alp;
510
QIcon Normal = Gui::BitmapFactory().iconFromTheme(name);
511
QImage imgConstr(Normal.pixmap(std::as_const(Normal).availableSizes()[0]).toImage());
512
QImage imgExt(imgConstr);
513
QImage imgInt(imgConstr);
515
// Create construction/external/internal icons by changing colors.
516
for (int ix = 0; ix < imgConstr.width(); ix++) {
517
for (int iy = 0; iy < imgConstr.height(); iy++) {
518
QColor clr(imgConstr.pixelColor(ix, iy));
519
clr.getHsv(&hue, &sat, &val, &alp);
520
if (alp > 127 && hue >= 0) {
521
if (sat > 127 && (hue > 330 || hue < 30)) {// change the color of red points.
522
clr.setHsv((hue + 240) % 360, sat, val, alp);
523
imgConstr.setPixelColor(ix, iy, clr);
524
clr.setHsv((hue + 300) % 360, sat, val, alp);
525
imgExt.setPixelColor(ix, iy, clr);
526
clr.setHsv((hue + 60) % 360,
528
std::min((int)(val * 8 / 7), 255),
530
imgInt.setPixelColor(ix, iy, clr);
532
else if (sat < 64 && val > 192) {// change the color of white edges.
533
clr.setHsv(240, (255 - sat), val, alp);
534
imgConstr.setPixel(ix, iy, clr.rgba());
535
clr.setHsv(300, (255 - sat), val, alp);
536
imgExt.setPixel(ix, iy, clr.rgba());
537
clr.setHsv(60, (int)(255 - sat) / 2, val, alp);
538
imgInt.setPixel(ix, iy, clr.rgba());
543
QIcon Construction = QIcon(QPixmap::fromImage(imgConstr));
544
QIcon External = QIcon(QPixmap::fromImage(imgExt));
545
QIcon Internal = QIcon(QPixmap::fromImage(imgInt));
547
return std::make_tuple(Normal, Construction, External, Internal);
551
std::map<Base::Type, std::map<Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>>
555
ElementView::ElementView(QWidget* parent)
556
: QListWidget(parent)
558
ElementItemDelegate* elementItemDelegate = new ElementItemDelegate(this);
559
setItemDelegate(elementItemDelegate);
562
elementItemDelegate, &ElementItemDelegate::itemHovered, this, &ElementView::onIndexHovered);
565
elementItemDelegate, &ElementItemDelegate::itemChecked, this, &ElementView::onIndexChecked);
568
ElementView::~ElementView()
571
void ElementView::changeLayer(int layer)
573
App::Document* doc = App::GetApplication().getActiveDocument();
578
doc->openTransaction("Geometry Layer Change");
579
std::vector<Gui::SelectionObject> sel = Gui::Selection().getSelectionEx(doc->getName());
580
for (std::vector<Gui::SelectionObject>::iterator ft = sel.begin(); ft != sel.end(); ++ft) {
581
auto sketchobject = dynamic_cast<Sketcher::SketchObject*>(ft->getObject());
583
auto geoids = getGeoIdsOfEdgesFromNames(sketchobject, ft->getSubNames());
585
auto geometry = sketchobject->Geometry.getValues();
586
auto newgeometry(geometry);
588
bool anychanged = false;
589
for (auto geoid : geoids) {
591
>= 0) {// currently only internal geometry can be changed from one layer to another
592
auto currentlayer = getSafeGeomLayerId(geometry[geoid]);
593
if (currentlayer != layer) {
594
auto geo = geometry[geoid]->clone();
595
setSafeGeomLayerId(geo, layer);
596
newgeometry[geoid] = geo;
601
Gui::TranslatedUserWarning(
603
QObject::tr("Unsupported visual layer operation"),
604
QObject::tr("It is currently unsupported to move external geometry to another "
605
"visual layer. External geometry will be omitted"));
610
sketchobject->Geometry.setValues(std::move(newgeometry));
611
sketchobject->solve();
614
doc->commitTransaction();
617
void ElementView::changeLayer(ElementItem* item, int layer)
619
App::Document* doc = App::GetApplication().getActiveDocument();
625
doc->openTransaction("Geometry Layer Change");
627
auto sketchObject = item->getSketchObject();
629
auto geometry = sketchObject->Geometry.getValues();
630
auto newGeometry(geometry);
632
auto geoid = item->ElementNbr;
634
// currently only internal geometry can be changed from one layer to another
636
auto currentLayer = getSafeGeomLayerId(geometry[geoid]);
638
if (currentLayer != layer) {
639
auto geo = geometry[geoid]->clone();
640
setSafeGeomLayerId(geo, layer);
641
newGeometry[geoid] = geo;
643
sketchObject->Geometry.setValues(std::move(newGeometry));
644
sketchObject->solve();
648
Gui::TranslatedUserWarning(
650
QObject::tr("Unsupported visual layer operation"),
651
QObject::tr("It is currently unsupported to move external geometry to another "
652
"visual layer. External geometry will be omitted"));
655
doc->commitTransaction();
658
void ElementView::contextMenuEvent(QContextMenuEvent* event)
661
QList<QListWidgetItem*> items = selectedItems();
663
// NOTE: If extending this context menu, be sure to add the items to the translation block at
664
// the top of this file
666
// CONTEXT_ITEM(ICONSTR,NAMESTR,CMDSTR,FUNC,ACTSONSELECTION)
667
CONTEXT_ITEM("Constraint_PointOnPoint",
669
"Sketcher_ConstrainCoincident",
672
CONTEXT_ITEM("Constraint_PointOnObject",
674
"Sketcher_ConstrainPointOnObject",
675
doPointOnObjectConstraint,
677
CONTEXT_ITEM("Constraint_Horizontal",
678
"Horizontal Constraint",
679
"Sketcher_ConstrainHorizontal",
680
doHorizontalConstraint,
682
CONTEXT_ITEM("Constraint_Vertical",
683
"Vertical Constraint",
684
"Sketcher_ConstrainVertical",
685
doVerticalConstraint,
687
CONTEXT_ITEM("Constraint_Parallel",
688
"Parallel Constraint",
689
"Sketcher_ConstrainParallel",
690
doParallelConstraint,
692
CONTEXT_ITEM("Constraint_Perpendicular",
693
"Perpendicular Constraint",
694
"Sketcher_ConstrainPerpendicular",
695
doPerpendicularConstraint,
697
CONTEXT_ITEM("Constraint_Tangent",
698
"Tangent Constraint",
699
"Sketcher_ConstrainTangent",
702
CONTEXT_ITEM("Constraint_EqualLength",
704
"Sketcher_ConstrainEqual",
707
CONTEXT_ITEM("Constraint_Symmetric",
709
"Sketcher_ConstrainSymmetric",
710
doSymmetricConstraint,
713
"Constraint_Block", "Block Constraint", "Sketcher_ConstrainBlock", doBlockConstraint, true)
715
CONTEXT_ITEM("Constraint_HorizontalDistance",
716
"Horizontal Distance",
717
"Sketcher_ConstrainDistanceX",
718
doHorizontalDistance,
720
CONTEXT_ITEM("Constraint_VerticalDistance",
722
"Sketcher_ConstrainDistanceY",
725
CONTEXT_ITEM("Constraint_Length",
727
"Sketcher_ConstrainDistance",
730
CONTEXT_ITEM("Constraint_Radiam",
732
"Sketcher_ConstrainRadiam",
735
CONTEXT_ITEM("Constraint_Radius",
737
"Sketcher_ConstrainRadius",
740
CONTEXT_ITEM("Constraint_Diameter",
741
"Diameter Constraint",
742
"Sketcher_ConstrainDiameter",
743
doDiameterConstraint,
745
CONTEXT_ITEM("Constraint_InternalAngle",
747
"Sketcher_ConstrainAngle",
751
"Constraint_Lock", "Lock Constraint", "Sketcher_ConstrainLock", doLockConstraint, true)
755
CONTEXT_ITEM("Sketcher_ToggleConstruction",
756
"Toggle construction geometry",
757
"Sketcher_ToggleConstruction",
758
doToggleConstruction,
763
CONTEXT_ITEM("Sketcher_SelectConstraints",
764
"Select Constraints",
765
"Sketcher_SelectConstraints",
769
"Sketcher_SelectOrigin", "Select Origin", "Sketcher_SelectOrigin", doSelectOrigin, false)
770
CONTEXT_ITEM("Sketcher_SelectHorizontalAxis",
771
"Select Horizontal Axis",
772
"Sketcher_SelectHorizontalAxis",
775
CONTEXT_ITEM("Sketcher_SelectVerticalAxis",
776
"Select Vertical Axis",
777
"Sketcher_SelectVerticalAxis",
783
auto submenu = menu.addMenu(tr("Layer"));
785
auto addLayerAction = [submenu, this, items](auto&& name, int layernumber) {
786
auto action = submenu->addAction(std::forward<decltype(name)>(name), [this, layernumber]() {
787
changeLayer(layernumber);
789
action->setEnabled(!items.isEmpty());
793
addLayerAction(tr("Layer 0"), 0);
794
addLayerAction(tr("Layer 1"), 1);
795
addLayerAction(tr("Hidden"), 2);
800
QAction* remove = menu.addAction(tr("Delete"), this, &ElementView::deleteSelectedItems);
801
remove->setShortcut(QKeySequence(QKeySequence::Delete));
802
remove->setEnabled(!items.isEmpty());
804
menu.menuAction()->setIconVisibleInMenu(true);
806
menu.exec(event->globalPos());
809
CONTEXT_MEMBER_DEF("Sketcher_ConstrainCoincident", doPointCoincidence)
810
CONTEXT_MEMBER_DEF("Sketcher_ConstrainPointOnObject", doPointOnObjectConstraint)
811
CONTEXT_MEMBER_DEF("Sketcher_ConstrainHorizontal", doHorizontalConstraint)
812
CONTEXT_MEMBER_DEF("Sketcher_ConstrainVertical", doVerticalConstraint)
813
CONTEXT_MEMBER_DEF("Sketcher_ConstrainParallel", doParallelConstraint)
814
CONTEXT_MEMBER_DEF("Sketcher_ConstrainPerpendicular", doPerpendicularConstraint)
815
CONTEXT_MEMBER_DEF("Sketcher_ConstrainTangent", doTangentConstraint)
816
CONTEXT_MEMBER_DEF("Sketcher_ConstrainEqual", doEqualConstraint)
817
CONTEXT_MEMBER_DEF("Sketcher_ConstrainSymmetric", doSymmetricConstraint)
818
CONTEXT_MEMBER_DEF("Sketcher_ConstrainBlock", doBlockConstraint)
820
CONTEXT_MEMBER_DEF("Sketcher_ConstrainDistanceX", doHorizontalDistance)
821
CONTEXT_MEMBER_DEF("Sketcher_ConstrainDistanceY", doVerticalDistance)
822
CONTEXT_MEMBER_DEF("Sketcher_ConstrainDistance", doLengthConstraint)
823
CONTEXT_MEMBER_DEF("Sketcher_ConstrainRadiam", doRadiamConstraint)
824
CONTEXT_MEMBER_DEF("Sketcher_ConstrainRadius", doRadiusConstraint)
825
CONTEXT_MEMBER_DEF("Sketcher_ConstrainDiameter", doDiameterConstraint)
826
CONTEXT_MEMBER_DEF("Sketcher_ConstrainAngle", doAngleConstraint)
827
CONTEXT_MEMBER_DEF("Sketcher_ConstrainLock", doLockConstraint)
829
CONTEXT_MEMBER_DEF("Sketcher_ToggleConstruction", doToggleConstruction)
831
CONTEXT_MEMBER_DEF("Sketcher_SelectConstraints", doSelectConstraints)
832
CONTEXT_MEMBER_DEF("Sketcher_SelectOrigin", doSelectOrigin)
833
CONTEXT_MEMBER_DEF("Sketcher_SelectHorizontalAxis", doSelectHAxis)
834
CONTEXT_MEMBER_DEF("Sketcher_SelectVerticalAxis", doSelectVAxis)
836
void ElementView::deleteSelectedItems()
838
App::Document* doc = App::GetApplication().getActiveDocument();
842
doc->openTransaction("Delete element");
843
std::vector<Gui::SelectionObject> sel = Gui::Selection().getSelectionEx(doc->getName());
844
for (std::vector<Gui::SelectionObject>::iterator ft = sel.begin(); ft != sel.end(); ++ft) {
845
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(ft->getObject());
847
vp->onDelete(ft->getSubNames());
850
doc->commitTransaction();
853
void ElementView::onIndexHovered(QModelIndex index)
857
Q_EMIT onItemHovered(itemFromIndex(index));
860
void ElementView::onIndexChecked(QModelIndex index, Qt::CheckState state)
862
auto item = itemFromIndex(index);
864
changeLayer(item, static_cast<int>(state == Qt::Checked ? ElementItem::Layer::Default : ElementItem::Layer::Hidden));
867
ElementItem* ElementView::itemFromIndex(const QModelIndex& index)
869
return static_cast<ElementItem*>(QListWidget::itemFromIndex(index));
873
/* ElementItem delegate ---------------------------------------------------- */
874
ElementItemDelegate::ElementItemDelegate(ElementView* parent)
875
: QStyledItemDelegate(parent)
876
{ // This class relies on the parent being an ElementView, see getElementtItem
879
void ElementItemDelegate::paint(QPainter* painter,
880
const QStyleOptionViewItem& option,
881
const QModelIndex& index) const
883
ElementItem* item = getElementItem(index);
889
auto style = option.widget ? option.widget->style() : QApplication::style();
891
QStyleOptionViewItem itemOption = option;
893
initStyleOption(&itemOption, index);
895
if (item->isLineSelected || item->isStartingPointSelected || item->isEndPointSelected
896
|| item->isMidPointSelected) {
897
itemOption.state |= QStyle::State_Active;
900
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &itemOption, painter, option.widget);
902
drawSubControl(SubControl::CheckBox, painter, option, index);
903
drawSubControl(SubControl::LineSelect, painter, option, index);
904
drawSubControl(SubControl::StartSelect, painter, option, index);
905
drawSubControl(SubControl::EndSelect, painter, option, index);
906
drawSubControl(SubControl::MidSelect, painter, option, index);
907
drawSubControl(SubControl::Label, painter, option, index);
910
QRect ElementItemDelegate::subControlRect(SubControl element,
911
const QStyleOptionViewItem& option,
912
const QModelIndex& index) const
914
auto itemOption = option;
916
auto style = option.widget ? option.widget->style() : QApplication::style();
918
initStyleOption(&itemOption, index);
921
style->subElementRect(QStyle::SE_CheckBoxIndicator, &itemOption, option.widget);
923
checkBoxRect.moveTo(gap,
924
option.rect.top() + (option.rect.height() - checkBoxRect.height()) / 2);
926
if (element == SubControl::CheckBox) {
931
style->subElementRect(QStyle::SE_ItemViewItemDecoration, &itemOption, option.widget)
932
.translated(checkBoxRect.right() + gap, 0);
934
unsigned pos = element - SubControl::LineSelect;
936
auto rect = selectRect.translated((selectRect.width() + gap) * pos, 0);
938
if (element != SubControl::Label) {
942
rect.setRight(itemOption.rect.right());
947
void ElementItemDelegate::drawSubControl(SubControl element,
949
const QStyleOptionViewItem& option,
950
const QModelIndex& index) const
952
auto item = getElementItem(index);
953
auto style = option.widget ? option.widget->style() : QApplication::style();
955
auto rect = subControlRect(element, option, index);
957
auto mousePos = option.widget->mapFromGlobal(QCursor::pos());
958
auto isHovered = rect.contains(mousePos);
960
auto drawSelectIcon = [&](Sketcher::PointPos pos) {
961
auto icon = ElementWidgetIcons::getIcon(item->GeometryType, pos, item->State);
963
auto isOptionSelected = option.state & QStyle::State_Selected;
964
auto isOptionHovered = option.state & QStyle::State_MouseOver;
966
// items that user is not interacting with should be fully opaque
967
// only if item is partially selected (so only one part of geometry)
968
// the rest should be dimmed out
969
auto opacity = isOptionHovered || isOptionSelected ? 0.4 : 1.0;
971
if (item->isGeometryPreselected(pos)) {
975
if (item->isGeometrySelected(pos)) {
979
painter->setOpacity(opacity);
980
painter->drawPixmap(rect, icon.pixmap(rect.size()));
986
case SubControl::CheckBox: {
987
QStyleOptionButton checkboxOption;
989
checkboxOption.initFrom(option.widget);
990
checkboxOption.rect = rect;
992
checkboxOption.state.setFlag(QStyle::State_Enabled, item->canBeHidden());
995
checkboxOption.state |= QStyle::State_MouseOver;
998
if (item->isVisible()) {
999
checkboxOption.state |= QStyle::State_On;
1002
checkboxOption.state |= QStyle::State_Off;
1005
style->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck,
1014
drawSelectIcon(Sketcher::PointPos::none);
1019
drawSelectIcon(Sketcher::PointPos::start);
1024
drawSelectIcon(Sketcher::PointPos::end);
1029
drawSelectIcon(Sketcher::PointPos::mid);
1034
QRect rect = subControlRect(SubControl::Label, option, index);
1036
auto labelBoundingBox = painter->fontMetrics().tightBoundingRect(item->label);
1038
painter->drawText(rect.x(),
1039
option.rect.bottom()
1040
- (option.rect.height() - labelBoundingBox.height()) / 2,
1051
bool ElementItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model,
1052
const QStyleOptionViewItem& option, const QModelIndex& index)
1054
auto item = getElementItem(index);
1056
auto getSubElementType = [&](QPoint pos) {
1057
if (subControlRect(SubControl::LineSelect, option, index).contains(pos)) {
1058
return SubElementType::edge;
1059
} else if (subControlRect(SubControl::StartSelect, option, index).contains(pos)) {
1060
return SubElementType::start;
1061
} else if (subControlRect(SubControl::EndSelect, option, index).contains(pos)) {
1062
return SubElementType::end;
1063
} else if (subControlRect(SubControl::MidSelect, option, index).contains(pos)) {
1064
return SubElementType::mid;
1066
// depending on geometry type by default we select either point or edge
1067
return item->GeometryType == Part::GeomPoint::getClassTypeId() ? SubElementType::start : SubElementType::edge;
1071
if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) {
1072
auto mouseEvent = static_cast<QMouseEvent*>(event);
1074
item->clickedOn = getSubElementType(mouseEvent->pos());
1075
item->rightClicked = mouseEvent->button() == Qt::RightButton;
1077
if (item->canBeHidden()) {
1078
QRect checkboxRect = subControlRect(SubControl::CheckBox, option, index);
1080
if (mouseEvent->button() == Qt::LeftButton && checkboxRect.contains(mouseEvent->pos())) {
1081
Q_EMIT itemChecked(index, item->isVisible() ? Qt::Unchecked : Qt::Checked);
1085
else if (event->type() == QEvent::MouseMove) {
1086
auto mouseEvent = static_cast<QMouseEvent*>(event);
1088
item->hovered = getSubElementType(mouseEvent->pos());
1090
Q_EMIT itemHovered(index);
1093
return QStyledItemDelegate::editorEvent(event, model, option, index);
1096
ElementItem* ElementItemDelegate::getElementItem(const QModelIndex& index) const
1098
ElementView* elementView = static_cast<ElementView*>(parent());
1099
return elementView->itemFromIndex(index);
1102
/* Filter element list widget ------------------------------------------------------ */
1104
enum class GeoFilterType
1122
ElementFilterList::ElementFilterList(QWidget* parent)
1123
: QListWidget(parent)
1125
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
1126
"User parameter:BaseApp/Preferences/Mod/Sketcher/General");
1127
int filterState = hGrp->GetInt("ElementFilterState",
1128
INT_MAX);// INT_MAX = 1111111111111111111111111111111 in binary.
1130
for (auto const& filterItem : filterItems) {
1131
Q_UNUSED(filterItem);
1132
auto it = new QListWidgetItem();
1133
it->setFlags(it->flags() | Qt::ItemIsUserCheckable);
1135
bool isChecked = static_cast<bool>(filterState & 1);// get the first bit of filterState
1136
it->setCheckState(isChecked ? Qt::Checked : Qt::Unchecked);
1137
filterState = filterState >> 1;// shift right to get rid of the used bit.
1143
// We need to fix the state of 'All' group checkbox in case it is partially checked.
1144
int indexOfAllTypes = static_cast<int>(GeoFilterType::AllGeosTypes);
1145
if (item(indexOfAllTypes)->checkState() == Qt::Unchecked) {
1146
bool allUnchecked = true;
1147
for (int i = indexOfAllTypes + 1; i < count(); i++) {
1148
if (item(i)->checkState() == Qt::Checked) {
1149
allUnchecked = false;
1154
item(indexOfAllTypes)->setCheckState(Qt::PartiallyChecked);
1158
ElementFilterList::~ElementFilterList()
1161
void ElementFilterList::changeEvent(QEvent* e)
1163
if (e->type() == QEvent::LanguageChange) {
1166
QWidget::changeEvent(e);
1169
void ElementFilterList::languageChange()
1171
assert(static_cast<int>(filterItems.size()) == count());
1173
for (auto const& filterItem : filterItems) {
1174
auto text = QStringLiteral(" ").repeated(filterItem.second - 1)
1175
+ (filterItem.second > 0 ? QStringLiteral("- ") : QStringLiteral(""))
1176
+ tr(filterItem.first);
1177
item(i++)->setText(text);
1182
/* TRANSLATOR SketcherGui::TaskSketcherElements */
1184
TaskSketcherElements::TaskSketcherElements(ViewProviderSketch* sketchView)
1185
: TaskBox(Gui::BitmapFactory().pixmap("Sketcher_CreateLine"), tr("Elements"), true, nullptr)
1186
, sketchView(sketchView)
1187
, ui(new Ui_TaskSketcherElements())
1188
, focusItemIndex(-1)
1189
, previouslySelectedItemIndex(-1)
1190
, previouslyHoveredItemIndex(-1)
1191
, previouslyHoveredType(SubElementType::none)
1192
, isNamingBoxChecked(false)
1194
// we need a separate container widget to add all controls to
1195
proxy = new QWidget(this);
1198
QString cmdKey = QString::fromUtf8("\xe2\x8c\x98");// U+2318
1200
// translate the text (it's offered by Qt's translation files)
1201
// but avoid being picked up by lupdate
1202
const char* ctrlKey = "Ctrl";
1203
QString cmdKey = QShortcut::tr(ctrlKey);
1207
ui->listWidgetElements->setSelectionMode(QAbstractItemView::ExtendedSelection);
1208
ui->listWidgetElements->setEditTriggers(QListWidget::NoEditTriggers);
1209
ui->listWidgetElements->setMouseTracking(true);
1211
createFilterButtonActions();
1212
createSettingsButtonActions();
1216
this->groupLayout()->addWidget(proxy);
1218
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
1219
"User parameter:BaseApp/Preferences/Mod/Sketcher/General");
1220
ui->filterBox->setChecked(hGrp->GetBool("ElementFilterEnabled", true));
1221
ui->filterButton->setEnabled(ui->filterBox->isChecked());
1223
slotElementsChanged();
1226
TaskSketcherElements::~TaskSketcherElements()
1228
connectionElementsChanged.disconnect();
1231
void TaskSketcherElements::connectSignals()
1233
// connecting the needed signals
1234
QObject::connect(ui->listWidgetElements,
1235
&ElementView::itemPressed,
1237
&TaskSketcherElements::onListWidgetElementsItemPressed);
1238
QObject::connect(ui->listWidgetElements,
1239
&ElementView::itemEntered,
1241
&TaskSketcherElements::onListWidgetElementsItemEntered);
1242
QObject::connect(ui->listWidgetElements,
1243
&ElementView::onItemHovered,
1245
&TaskSketcherElements::onListWidgetElementsMouseMoveOnItem);
1246
QObject::connect(filterList,
1247
&QListWidget::itemChanged,
1249
&TaskSketcherElements::onListMultiFilterItemChanged);
1250
QObject::connect(ui->filterBox,
1251
&QCheckBox::stateChanged,
1253
&TaskSketcherElements::onFilterBoxStateChanged);
1255
ui->settingsButton, &QToolButton::clicked, ui->settingsButton, &QToolButton::showMenu);
1256
QObject::connect(std::as_const(ui->settingsButton)->actions()[0],
1259
&TaskSketcherElements::onSettingsExtendedInformationChanged);
1261
ui->filterButton, &QToolButton::clicked, ui->filterButton, &QToolButton::showMenu);
1264
connectionElementsChanged = sketchView->signalElementsChanged.connect(
1265
std::bind(&SketcherGui::TaskSketcherElements::slotElementsChanged, this));
1269
/* filter functions --------------------------------------------------- */
1271
void TaskSketcherElements::createFilterButtonActions()
1273
auto* action = new QWidgetAction(this);
1274
filterList = new ElementFilterList(this);
1275
action->setDefaultWidget(filterList);
1276
std::as_const(ui->filterButton)->addAction(action);
1279
void TaskSketcherElements::onFilterBoxStateChanged(int val)
1282
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
1283
"User parameter:BaseApp/Preferences/Mod/Sketcher/General");
1284
hGrp->SetBool("ElementFilterEnabled", ui->filterBox->checkState() == Qt::Checked);
1286
ui->filterButton->setEnabled(ui->filterBox->checkState() == Qt::Checked);
1287
slotElementsChanged();
1290
void TaskSketcherElements::onListMultiFilterItemChanged(QListWidgetItem* item)
1293
QSignalBlocker sigblk(filterList);
1295
int index = filterList->row(item);
1296
int indexOfAllTypes = static_cast<int>(GeoFilterType::AllGeosTypes);
1298
if (index == indexOfAllTypes) {
1299
for (int i = indexOfAllTypes + 1; i < filterList->count(); i++) {
1300
filterList->item(i)->setCheckState(item->checkState());
1303
else if (index > indexOfAllTypes) {
1304
bool atLeastOneUnchecked = false;
1305
bool atLeastOneChecked = false;
1307
for (int i = indexOfAllTypes + 1; i < filterList->count(); i++) {
1308
if (filterList->item(i)->checkState() == Qt::Checked)
1309
atLeastOneChecked = true;
1310
if (filterList->item(i)->checkState() == Qt::Unchecked)
1311
atLeastOneUnchecked = true;
1313
if (atLeastOneChecked && atLeastOneUnchecked)
1314
filterList->item(indexOfAllTypes)->setCheckState(Qt::PartiallyChecked);
1315
else if (atLeastOneUnchecked)
1316
filterList->item(indexOfAllTypes)->setCheckState(Qt::Unchecked);
1317
else if (atLeastOneChecked)
1318
filterList->item(indexOfAllTypes)->setCheckState(Qt::Checked);
1322
// Save the state of the filter.
1323
int filterState = INT_MIN;// INT_MIN = 000000000000000000000000000000 in binary.
1324
for (int i = filterList->count() - 1; i >= 0; i--) {
1325
bool isChecked = filterList->item(i)->checkState() == Qt::Checked;
1326
filterState = filterState << 1;// we shift left first, else the list is shifted at the end.
1327
filterState = filterState | (isChecked ? 1 : 0);
1329
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
1330
"User parameter:BaseApp/Preferences/Mod/Sketcher/General");
1331
hGrp->SetInt("ElementFilterState", filterState);
1336
void TaskSketcherElements::setItemVisibility(QListWidgetItem* it)
1338
ElementItem* item = static_cast<ElementItem*>(it);
1340
if (ui->filterBox->checkState() == Qt::Unchecked) {
1341
item->setHidden(false);
1345
using GeometryState = ElementItem::GeometryState;
1347
if ((filterList->item(static_cast<int>(GeoFilterType::NormalGeos))->checkState()
1349
&& item->State == GeometryState::Normal)
1350
|| (filterList->item(static_cast<int>(GeoFilterType::ConstructionGeos))->checkState()
1352
&& item->State == GeometryState::Construction)
1353
|| (filterList->item(static_cast<int>(GeoFilterType::InternalGeos))->checkState()
1355
&& item->State == GeometryState::InternalAlignment)
1356
|| (filterList->item(static_cast<int>(GeoFilterType::ExternalGeos))->checkState()
1358
&& item->State == GeometryState::External)
1359
|| (filterList->item(static_cast<int>(GeoFilterType::PointGeos))->checkState()
1361
&& item->GeometryType == Part::GeomPoint::getClassTypeId())
1362
|| (filterList->item(static_cast<int>(GeoFilterType::LineGeos))->checkState()
1364
&& item->GeometryType == Part::GeomLineSegment::getClassTypeId())
1365
|| (filterList->item(static_cast<int>(GeoFilterType::CircleGeos))->checkState()
1367
&& item->GeometryType == Part::GeomCircle::getClassTypeId())
1368
|| (filterList->item(static_cast<int>(GeoFilterType::EllipseGeos))->checkState()
1370
&& item->GeometryType == Part::GeomEllipse::getClassTypeId())
1371
|| (filterList->item(static_cast<int>(GeoFilterType::ArcGeos))->checkState()
1373
&& item->GeometryType == Part::GeomArcOfCircle::getClassTypeId())
1374
|| (filterList->item(static_cast<int>(GeoFilterType::ArcOfEllipseGeos))->checkState()
1376
&& item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId())
1377
|| (filterList->item(static_cast<int>(GeoFilterType::HyperbolaGeos))->checkState()
1379
&& item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId())
1380
|| (filterList->item(static_cast<int>(GeoFilterType::ParabolaGeos))->checkState()
1382
&& item->GeometryType == Part::GeomArcOfParabola::getClassTypeId())
1383
|| (filterList->item(static_cast<int>(GeoFilterType::BSplineGeos))->checkState()
1385
&& item->GeometryType == Part::GeomBSplineCurve::getClassTypeId())) {
1386
item->setHidden(true);
1389
item->setHidden(false);
1392
void TaskSketcherElements::updateVisibility()
1394
for (int i = 0; i < ui->listWidgetElements->count(); i++) {
1395
setItemVisibility(ui->listWidgetElements->item(i));
1399
/*------------------*/
1400
void TaskSketcherElements::onSelectionChanged(const Gui::SelectionChanges& msg)
1403
if (msg.Type == Gui::SelectionChanges::ClrSelection) {
1406
else if (msg.Type == Gui::SelectionChanges::AddSelection
1407
|| msg.Type == Gui::SelectionChanges::RmvSelection) {
1408
bool select = (msg.Type == Gui::SelectionChanges::AddSelection);
1409
// is it this object??
1410
if (strcmp(msg.pDocName, sketchView->getSketchObject()->getDocument()->getName()) == 0
1411
&& strcmp(msg.pObjectName, sketchView->getSketchObject()->getNameInDocument()) == 0) {
1413
ElementItem* modified_item = NULL;
1414
QString expr = QString::fromLatin1(msg.pSubName);
1415
std::string shapetype(msg.pSubName);
1416
// if-else edge vertex
1417
if (shapetype.size() > 4 && shapetype.substr(0, 4) == "Edge") {
1418
QRegularExpression rx(QString::fromLatin1("^Edge(\\d+)$"));
1419
QRegularExpressionMatch match;
1420
boost::ignore_unused(expr.indexOf(rx, 0, &match));
1421
if (match.hasMatch()) {
1423
int ElementId = match.captured(1).toInt(&ok) - 1;
1425
int countItems = ui->listWidgetElements->count();
1426
// TODO: This and the loop below get slow when we have a lot of items.
1427
// Perhaps we should also maintain a map so that we can look up items
1428
// by element number.
1429
for (int i = 0; i < countItems; i++) {
1431
static_cast<ElementItem*>(ui->listWidgetElements->item(i));
1432
if (item->ElementNbr == ElementId) {
1433
item->isLineSelected = select;
1434
modified_item = item;
1441
else if (shapetype.size() > 12 && shapetype.substr(0, 12) == "ExternalEdge") {
1442
QRegularExpression rx(QString::fromLatin1("^ExternalEdge(\\d+)$"));
1443
QRegularExpressionMatch match;
1444
boost::ignore_unused(expr.indexOf(rx, 0, &match));
1445
if (match.hasMatch()) {
1447
int ElementId = -match.captured(1).toInt(&ok) - 2;
1449
int countItems = ui->listWidgetElements->count();
1450
for (int i = 0; i < countItems; i++) {
1452
static_cast<ElementItem*>(ui->listWidgetElements->item(i));
1453
if (item->ElementNbr == ElementId) {
1454
item->isLineSelected = select;
1455
modified_item = item;
1462
else if (shapetype.size() > 6 && shapetype.substr(0, 6) == "Vertex") {
1463
QRegularExpression rx(QString::fromLatin1("^Vertex(\\d+)$"));
1464
QRegularExpressionMatch match;
1465
boost::ignore_unused(expr.indexOf(rx, 0, &match));
1466
if (match.hasMatch()) {
1468
int ElementId = match.captured(1).toInt(&ok) - 1;
1470
// Get the GeoID&Pos
1472
Sketcher::PointPos PosId;
1473
sketchView->getSketchObject()->getGeoVertexIndex(
1474
ElementId, GeoId, PosId);
1476
int countItems = ui->listWidgetElements->count();
1477
for (int i = 0; i < countItems; i++) {
1479
static_cast<ElementItem*>(ui->listWidgetElements->item(i));
1480
if (item->ElementNbr == GeoId) {
1481
modified_item = item;
1483
case Sketcher::PointPos::start:
1484
item->isStartingPointSelected = select;
1486
case Sketcher::PointPos::end:
1487
item->isEndPointSelected = select;
1489
case Sketcher::PointPos::mid:
1490
item->isMidPointSelected = select;
1501
// update the listwidget
1503
QSignalBlocker sigblk(ui->listWidgetElements);
1504
if (modified_item != NULL) {
1505
bool is_selected = modified_item->isSelected();
1506
const bool should_be_selected = modified_item->isLineSelected
1507
|| modified_item->isStartingPointSelected || modified_item->isEndPointSelected
1508
|| modified_item->isMidPointSelected;
1510
// If an element is already selected and a new subelement gets selected
1511
// (eg., if you select the arc of a circle then select the center as well),
1512
// the new subelement won't get highlighted in the list until you mouseover
1513
// the list. To avoid this, we deselect first to trigger a redraw.
1514
if (should_be_selected && is_selected) {
1515
modified_item->setSelected(false);
1516
is_selected = false;
1519
if (should_be_selected != is_selected) {
1520
modified_item->setSelected(should_be_selected);
1527
else if (msg.Type == Gui::SelectionChanges::SetSelection) {
1532
void TaskSketcherElements::onListWidgetElementsItemPressed(QListWidgetItem* it)
1534
// We use itemPressed instead of previously used ItemSelectionChanged because if user click on
1535
// already selected item, ItemSelectionChanged didn't trigger.
1539
ElementItem* itf = static_cast<ElementItem*>(it);
1540
bool rightClickOnSelected = itf->rightClicked
1541
&& (itf->isLineSelected || itf->isStartingPointSelected || itf->isEndPointSelected
1542
|| itf->isMidPointSelected);
1543
itf->rightClicked = false;
1544
if (rightClickOnSelected)// if user right clicked on a selected item, change nothing.
1548
QSignalBlocker sigblk(ui->listWidgetElements);
1550
bool multipleselection = false;
1551
bool multipleconsecutiveselection = false;
1552
if (QApplication::keyboardModifiers() == Qt::ControlModifier)
1553
multipleselection = true;
1554
if (QApplication::keyboardModifiers() == Qt::ShiftModifier)
1555
multipleconsecutiveselection = true;
1557
if (multipleselection
1558
&& multipleconsecutiveselection) {// ctrl takes priority over shift functionality
1559
multipleselection = true;
1560
multipleconsecutiveselection = false;
1563
std::vector<std::string> elementSubNames;
1564
std::string doc_name = sketchView->getSketchObject()->getDocument()->getName();
1565
std::string obj_name = sketchView->getSketchObject()->getNameInDocument();
1567
bool block = this->blockSelection(true);// avoid to be notified by itself
1568
Gui::Selection().clearSelection();
1570
for (int i = 0; i < ui->listWidgetElements->count(); i++) {
1571
ElementItem* item = static_cast<ElementItem*>(ui->listWidgetElements->item(i));
1573
if (!multipleselection && !multipleconsecutiveselection) {
1574
// if not multiple selection, then all are disabled but the one that was just
1576
item->isLineSelected = false;
1577
item->isStartingPointSelected = false;
1578
item->isEndPointSelected = false;
1579
item->isMidPointSelected = false;
1584
if (item->clickedOn == SubElementType::mid
1585
&& (item->GeometryType == Part::GeomArcOfCircle::getClassTypeId()
1586
|| item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId()
1587
|| item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId()
1588
|| item->GeometryType == Part::GeomArcOfParabola::getClassTypeId()
1589
|| item->GeometryType == Part::GeomCircle::getClassTypeId()
1590
|| item->GeometryType == Part::GeomEllipse::getClassTypeId())) {
1591
item->isMidPointSelected = !item->isMidPointSelected;
1593
else if (item->clickedOn == SubElementType::start
1594
&& (item->GeometryType == Part::GeomPoint::getClassTypeId()
1595
|| item->GeometryType == Part::GeomArcOfCircle::getClassTypeId()
1596
|| item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId()
1597
|| item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId()
1598
|| item->GeometryType == Part::GeomArcOfParabola::getClassTypeId()
1599
|| item->GeometryType == Part::GeomLineSegment::getClassTypeId()
1600
|| item->GeometryType == Part::GeomBSplineCurve::getClassTypeId())) {
1601
item->isStartingPointSelected = !item->isStartingPointSelected;
1603
else if (item->clickedOn == SubElementType::end
1604
&& (item->GeometryType == Part::GeomArcOfCircle::getClassTypeId()
1605
|| item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId()
1606
|| item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId()
1607
|| item->GeometryType == Part::GeomArcOfParabola::getClassTypeId()
1608
|| item->GeometryType == Part::GeomLineSegment::getClassTypeId()
1609
|| item->GeometryType == Part::GeomBSplineCurve::getClassTypeId())) {
1610
item->isEndPointSelected = !item->isEndPointSelected;
1612
else if (item->clickedOn == SubElementType::edge
1613
&& item->GeometryType != Part::GeomPoint::getClassTypeId()) {
1614
item->isLineSelected = !item->isLineSelected;
1616
item->clickedOn = SubElementType::none;
1618
else if (multipleconsecutiveselection && previouslySelectedItemIndex >= 0
1619
&& !rightClickOnSelected
1620
&& ((i > focusItemIndex && i < previouslySelectedItemIndex)
1621
|| (i < focusItemIndex && i > previouslySelectedItemIndex))) {
1622
if (item->GeometryType == Part::GeomPoint::getClassTypeId()) {
1623
item->isStartingPointSelected = true;
1626
item->isLineSelected = true;
1630
// first update the listwidget. Item is selected if at least one element of the geo is
1632
bool selected = item->isLineSelected || item->isStartingPointSelected
1633
|| item->isEndPointSelected || item->isMidPointSelected;
1636
QSignalBlocker sigblk(ui->listWidgetElements);
1638
if (item->isSelected() && selected) {
1640
false);// if already selected and changing or adding subelement, ensure
1641
// selection change is triggered, which ensures timely repaint
1642
item->setSelected(selected);
1645
item->setSelected(selected);
1650
std::stringstream ss;
1653
if (item->isLineSelected) {
1654
if (item->ElementNbr >= 0) {
1655
ss << "Edge" << item->ElementNbr + 1;
1658
ss << "ExternalEdge" << -item->ElementNbr - 2;
1660
elementSubNames.push_back(ss.str());
1663
auto selectVertex = [&ss, &elementSubNames](bool subelementselected, int vertexid) {
1664
if (subelementselected) {
1666
ss.str(std::string());
1669
ss << "Vertex" << vertex + 1;
1670
elementSubNames.push_back(ss.str());
1675
selectVertex(item->isStartingPointSelected, item->StartingVertex);
1676
selectVertex(item->isEndPointSelected, item->EndVertex);
1677
selectVertex(item->isMidPointSelected, item->MidVertex);
1680
for (const auto& elementSubName : elementSubNames) {
1681
Gui::Selection().addSelection2(
1684
sketchView->getSketchObject()->convertSubName(elementSubName).c_str());
1687
this->blockSelection(block);
1690
if (focusItemIndex > -1 && focusItemIndex < ui->listWidgetElements->count())
1691
previouslySelectedItemIndex = focusItemIndex;
1693
ui->listWidgetElements->repaint();
1696
void TaskSketcherElements::onListWidgetElementsItemEntered(QListWidgetItem* item)
1698
ui->listWidgetElements->setFocus();
1700
focusItemIndex = ui->listWidgetElements->row(item);
1703
void TaskSketcherElements::onListWidgetElementsMouseMoveOnItem(QListWidgetItem* it)
1705
ElementItem* item = static_cast<ElementItem*>(it);
1708
|| (ui->listWidgetElements->row(item) == previouslyHoveredItemIndex
1709
&& item->hovered == previouslyHoveredType))
1712
Gui::Selection().rmvPreselect();
1714
bool validmid = item->hovered == SubElementType::mid
1715
&& (item->GeometryType == Part::GeomArcOfCircle::getClassTypeId()
1716
|| item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId()
1717
|| item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId()
1718
|| item->GeometryType == Part::GeomArcOfParabola::getClassTypeId()
1719
|| item->GeometryType == Part::GeomCircle::getClassTypeId()
1720
|| item->GeometryType == Part::GeomEllipse::getClassTypeId());
1722
bool validstartpoint = item->hovered == SubElementType::start
1723
&& (item->GeometryType == Part::GeomPoint::getClassTypeId()
1724
|| item->GeometryType == Part::GeomArcOfCircle::getClassTypeId()
1725
|| item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId()
1726
|| item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId()
1727
|| item->GeometryType == Part::GeomArcOfParabola::getClassTypeId()
1728
|| item->GeometryType == Part::GeomLineSegment::getClassTypeId()
1729
|| item->GeometryType == Part::GeomBSplineCurve::getClassTypeId());
1731
bool validendpoint = item->hovered == SubElementType::end
1732
&& (item->GeometryType == Part::GeomArcOfCircle::getClassTypeId()
1733
|| item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId()
1734
|| item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId()
1735
|| item->GeometryType == Part::GeomArcOfParabola::getClassTypeId()
1736
|| item->GeometryType == Part::GeomLineSegment::getClassTypeId()
1737
|| item->GeometryType == Part::GeomBSplineCurve::getClassTypeId());
1739
bool validedge = item->hovered == SubElementType::edge
1740
&& item->GeometryType != Part::GeomPoint::getClassTypeId();
1742
if (validmid || validstartpoint || validendpoint || validedge) {
1743
std::string doc_name = sketchView->getSketchObject()->getDocument()->getName();
1744
std::string obj_name = sketchView->getSketchObject()->getNameInDocument();
1746
std::stringstream ss;
1748
auto preselectvertex = [&](int geoid, Sketcher::PointPos pos) {
1749
int vertex = sketchView->getSketchObject()->getVertexIndexGeoPos(geoid, pos);
1751
ss << "Vertex" << vertex + 1;
1752
Gui::Selection().setPreselect(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
1756
if (item->hovered == SubElementType::start)
1757
preselectvertex(item->ElementNbr, Sketcher::PointPos::start);
1758
else if (item->hovered == SubElementType::end)
1759
preselectvertex(item->ElementNbr, Sketcher::PointPos::end);
1760
else if (item->hovered == SubElementType::mid)
1761
preselectvertex(item->ElementNbr, Sketcher::PointPos::mid);
1762
else if (item->hovered == SubElementType::edge) {
1763
if (item->ElementNbr >= 0) {
1764
ss << "Edge" << item->ElementNbr + 1;
1767
ss << "ExternalEdge" << -item->ElementNbr - 2;
1769
Gui::Selection().setPreselect(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
1773
previouslyHoveredItemIndex = ui->listWidgetElements->row(item);
1774
previouslyHoveredType = item->hovered;
1777
void TaskSketcherElements::leaveEvent(QEvent* event)
1780
Gui::Selection().rmvPreselect();
1781
ui->listWidgetElements->clearFocus();
1784
void TaskSketcherElements::slotElementsChanged()
1787
// Build up ListView with the elements
1788
Sketcher::SketchObject* sketch = sketchView->getSketchObject();
1789
const std::vector<Part::Geometry*>& vals = sketch->Geometry.getValues();
1791
ui->listWidgetElements->clear();
1793
using GeometryState = ElementItem::GeometryState;
1796
for (std::vector<Part::Geometry*>::const_iterator it = vals.begin(); it != vals.end();
1798
Base::Type type = (*it)->getTypeId();
1799
GeometryState state = GeometryState::Normal;
1801
bool construction = Sketcher::GeometryFacade::getConstruction(*it);
1802
bool internalAligned = Sketcher::GeometryFacade::isInternalAligned(*it);
1804
auto layerId = getSafeGeomLayerId(*it);
1806
if (internalAligned)
1807
state = GeometryState::InternalAlignment;
1808
else if (construction)// Caution, internalAligned geos are construction too. So the 'if' and
1809
// 'else if' cannot be swapped.
1810
state = GeometryState::Construction;
1812
auto IdInformation = [this, i, layerId]() {
1813
if (sketchView->VisualLayerList.getSize() > 1)
1814
return QString::fromLatin1("(Edge%1#ID%2#VL%3)").arg(i).arg(i - 1).arg(layerId);
1816
return QString::fromLatin1("(Edge%1#ID%2)").arg(i).arg(i - 1);
1819
ElementItem* itemN = new ElementItem(
1821
sketchView->getSketchObject()->getVertexIndexGeoPos(i - 1, Sketcher::PointPos::start),
1822
sketchView->getSketchObject()->getVertexIndexGeoPos(i - 1, Sketcher::PointPos::mid),
1823
sketchView->getSketchObject()->getVertexIndexGeoPos(i - 1, Sketcher::PointPos::end),
1826
type == Part::GeomPoint::getClassTypeId()
1827
? (isNamingBoxChecked ? (tr("Point") + IdInformation())
1829
? (QString::fromLatin1("-") + tr("Construction"))
1830
: (internalAligned ? (QString::fromLatin1("-") + tr("Internal"))
1831
: QString::fromLatin1("")))
1832
: (QString::fromLatin1("%1-").arg(i) + tr("Point")))
1833
: type == Part::GeomLineSegment::getClassTypeId()
1834
? (isNamingBoxChecked ? (tr("Line") + IdInformation())
1836
? (QString::fromLatin1("-") + tr("Construction"))
1837
: (internalAligned ? (QString::fromLatin1("-") + tr("Internal"))
1838
: QString::fromLatin1("")))
1839
: (QString::fromLatin1("%1-").arg(i) + tr("Line")))
1840
: type == Part::GeomArcOfCircle::getClassTypeId()
1841
? (isNamingBoxChecked ? (tr("Arc") + IdInformation())
1843
? (QString::fromLatin1("-") + tr("Construction"))
1844
: (internalAligned ? (QString::fromLatin1("-") + tr("Internal"))
1845
: QString::fromLatin1("")))
1846
: (QString::fromLatin1("%1-").arg(i) + tr("Arc")))
1847
: type == Part::GeomCircle::getClassTypeId()
1848
? (isNamingBoxChecked ? (tr("Circle") + IdInformation())
1850
? (QString::fromLatin1("-") + tr("Construction"))
1851
: (internalAligned ? (QString::fromLatin1("-") + tr("Internal"))
1852
: QString::fromLatin1("")))
1853
: (QString::fromLatin1("%1-").arg(i) + tr("Circle")))
1854
: type == Part::GeomEllipse::getClassTypeId()
1855
? (isNamingBoxChecked ? (tr("Ellipse") + IdInformation())
1857
? (QString::fromLatin1("-") + tr("Construction"))
1858
: (internalAligned ? (QString::fromLatin1("-") + tr("Internal"))
1859
: QString::fromLatin1("")))
1860
: (QString::fromLatin1("%1-").arg(i) + tr("Ellipse")))
1861
: type == Part::GeomArcOfEllipse::getClassTypeId()
1862
? (isNamingBoxChecked ? (tr("Elliptical Arc") + IdInformation())
1864
? (QString::fromLatin1("-") + tr("Construction"))
1865
: (internalAligned ? (QString::fromLatin1("-") + tr("Internal"))
1866
: QString::fromLatin1("")))
1867
: (QString::fromLatin1("%1-").arg(i) + tr("Elliptical Arc")))
1868
: type == Part::GeomArcOfHyperbola::getClassTypeId()
1869
? (isNamingBoxChecked ? (tr("Hyperbolic Arc") + IdInformation())
1871
? (QString::fromLatin1("-") + tr("Construction"))
1872
: (internalAligned ? (QString::fromLatin1("-") + tr("Internal"))
1873
: QString::fromLatin1("")))
1874
: (QString::fromLatin1("%1-").arg(i) + tr("Hyperbolic Arc")))
1875
: type == Part::GeomArcOfParabola::getClassTypeId()
1876
? (isNamingBoxChecked ? (tr("Parabolic Arc") + IdInformation())
1878
? (QString::fromLatin1("-") + tr("Construction"))
1879
: (internalAligned ? (QString::fromLatin1("-") + tr("Internal"))
1880
: QString::fromLatin1("")))
1881
: (QString::fromLatin1("%1-").arg(i) + tr("Parabolic Arc")))
1882
: type == Part::GeomBSplineCurve::getClassTypeId()
1883
? (isNamingBoxChecked ? (tr("B-spline") + IdInformation())
1885
? (QString::fromLatin1("-") + tr("Construction"))
1886
: (internalAligned ? (QString::fromLatin1("-") + tr("Internal"))
1887
: QString::fromLatin1("")))
1888
: (QString::fromLatin1("%1-").arg(i) + tr("B-spline")))
1889
: (isNamingBoxChecked ? (tr("Other") + IdInformation())
1891
? (QString::fromLatin1("-") + tr("Construction"))
1892
: (internalAligned ? (QString::fromLatin1("-") + tr("Internal"))
1893
: QString::fromLatin1("")))
1894
: (QString::fromLatin1("%1-").arg(i) + tr("Other"))),
1897
ui->listWidgetElements->addItem(itemN);
1899
setItemVisibility(itemN);
1902
const std::vector<Part::Geometry*>& ext_vals =
1903
sketchView->getSketchObject()->getExternalGeometry();
1905
const std::vector<App::DocumentObject*> linkobjs =
1906
sketchView->getSketchObject()->ExternalGeometry.getValues();
1907
const std::vector<std::string> linksubs =
1908
sketchView->getSketchObject()->ExternalGeometry.getSubValues();
1911
for (std::vector<Part::Geometry*>::const_iterator it = ext_vals.begin(); it != ext_vals.end();
1913
Base::Type type = (*it)->getTypeId();
1915
if (j > 2) {// we do not want the H and V axes
1917
auto layerId = getSafeGeomLayerId(*it);
1919
auto IdInformation = [this, j, layerId](bool link) {
1920
if (sketchView->VisualLayerList.getSize() > 1) {
1922
return QString::fromLatin1("(ExternalEdge%1#ID%2#VL%3, ")
1928
return QString::fromLatin1("(ExternalEdge%1#ID%2#VL%3)")
1936
return QString::fromLatin1("(ExternalEdge%1#ID%2, ").arg(j - 2).arg(-j);
1939
return QString::fromLatin1("(ExternalEdge%1#ID%2)").arg(j - 2).arg(-j);
1946
if (isNamingBoxChecked) {
1947
if (size_t(j - 3) < linkobjs.size() && size_t(j - 3) < linksubs.size()) {
1948
linkname = IdInformation(true)
1949
+ QString::fromUtf8(linkobjs[j - 3]->getNameInDocument())
1950
+ QString::fromLatin1(".") + QString::fromUtf8(linksubs[j - 3].c_str())
1951
+ QString::fromLatin1(")");
1954
linkname = IdInformation(false);
1958
GeometryState state = GeometryState::External;
1960
ElementItem* itemN = new ElementItem(
1962
sketchView->getSketchObject()->getVertexIndexGeoPos(-j, Sketcher::PointPos::start),
1963
sketchView->getSketchObject()->getVertexIndexGeoPos(-j, Sketcher::PointPos::mid),
1964
sketchView->getSketchObject()->getVertexIndexGeoPos(-j, Sketcher::PointPos::end),
1967
type == Part::GeomPoint::getClassTypeId()
1968
? (isNamingBoxChecked ? (tr("Point") + linkname)
1969
: (QString::fromLatin1("%1-").arg(i - 2) + tr("Point")))
1970
: type == Part::GeomLineSegment::getClassTypeId()
1971
? (isNamingBoxChecked ? (tr("Line") + linkname)
1972
: (QString::fromLatin1("%1-").arg(i - 2) + tr("Line")))
1973
: type == Part::GeomArcOfCircle::getClassTypeId()
1974
? (isNamingBoxChecked ? (tr("Arc") + linkname)
1975
: (QString::fromLatin1("%1-").arg(i - 2) + tr("Arc")))
1976
: type == Part::GeomCircle::getClassTypeId()
1977
? (isNamingBoxChecked ? (tr("Circle") + linkname)
1978
: (QString::fromLatin1("%1-").arg(i - 2) + tr("Circle")))
1979
: type == Part::GeomEllipse::getClassTypeId()
1980
? (isNamingBoxChecked ? (tr("Ellipse") + linkname)
1981
: (QString::fromLatin1("%1-").arg(i - 2) + tr("Ellipse")))
1982
: type == Part::GeomArcOfEllipse::getClassTypeId()
1983
? (isNamingBoxChecked
1984
? (tr("Elliptical Arc") + linkname)
1985
: (QString::fromLatin1("%1-").arg(i - 2) + tr("Elliptical Arc")))
1986
: type == Part::GeomArcOfHyperbola::getClassTypeId()
1987
? (isNamingBoxChecked
1988
? (tr("Hyperbolic Arc") + linkname)
1989
: (QString::fromLatin1("%1-").arg(i - 2) + tr("Hyperbolic Arc")))
1990
: type == Part::GeomArcOfParabola::getClassTypeId()
1991
? (isNamingBoxChecked
1992
? (tr("Parabolic Arc") + linkname)
1993
: (QString::fromLatin1("%1-").arg(i - 2) + tr("Parabolic Arc")))
1994
: type == Part::GeomBSplineCurve::getClassTypeId()
1995
? (isNamingBoxChecked ? (tr("B-spline") + linkname)
1996
: (QString::fromLatin1("%1-").arg(i - 2) + tr("B-spline")))
1997
: (isNamingBoxChecked ? (tr("Other") + linkname)
1998
: (QString::fromLatin1("%1-").arg(i - 2) + tr("Other"))),
2001
ui->listWidgetElements->addItem(itemN);
2003
setItemVisibility(itemN);
2008
void TaskSketcherElements::clearWidget()
2011
QSignalBlocker sigblk(ui->listWidgetElements);
2012
ui->listWidgetElements->clearSelection();
2016
int countItems = ui->listWidgetElements->count();
2017
for (int i = 0; i < countItems; i++) {
2018
ElementItem* item = static_cast<ElementItem*>(ui->listWidgetElements->item(i));
2020
item->isLineSelected = false;
2021
item->isStartingPointSelected = false;
2022
item->isEndPointSelected = false;
2023
item->isMidPointSelected = false;
2027
void TaskSketcherElements::changeEvent(QEvent* e)
2029
TaskBox::changeEvent(e);
2030
if (e->type() == QEvent::LanguageChange) {
2031
ui->retranslateUi(proxy);
2035
/* Settings menu ==================================================*/
2036
void TaskSketcherElements::createSettingsButtonActions()
2038
QAction* action = new QAction(tr("Extended information"), this);
2040
action->setCheckable(true);
2042
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
2043
"User parameter:BaseApp/Preferences/Mod/Sketcher/Elements");
2045
QSignalBlocker block(this);
2046
action->setChecked(hGrp->GetBool("ExtendedNaming", false));
2049
ui->settingsButton->addAction(action);
2051
isNamingBoxChecked = hGrp->GetBool("ExtendedNaming", false);
2054
void TaskSketcherElements::onSettingsExtendedInformationChanged()
2056
QList<QAction*> acts = ui->settingsButton->actions();
2057
isNamingBoxChecked = acts[0]->isChecked();
2059
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
2060
"User parameter:BaseApp/Preferences/Mod/Sketcher/Elements");
2061
hGrp->SetBool("ExtendedNaming", isNamingBoxChecked);
2063
slotElementsChanged();
2066
#include "TaskSketcherElements.moc"// For Delegate as it is QOBJECT
2067
#include "moc_TaskSketcherElements.cpp"