Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
magicseteditor
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
magicseteditor
Commits
a56a8454
Commit
a56a8454
authored
Jul 08, 2007
by
twanvl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New symbol part list control that shows previews and has a built in editor
parent
767efcdb
Changes
28
Show whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
838 additions
and
325 deletions
+838
-325
src/data/action/symbol.cpp
src/data/action/symbol.cpp
+118
-70
src/data/action/symbol.hpp
src/data/action/symbol.hpp
+30
-17
src/data/action/symbol_part.cpp
src/data/action/symbol_part.cpp
+2
-2
src/data/format/image_to_symbol.cpp
src/data/format/image_to_symbol.cpp
+6
-6
src/data/symbol.cpp
src/data/symbol.cpp
+18
-0
src/data/symbol.hpp
src/data/symbol.hpp
+13
-8
src/gfx/bezier.cpp
src/gfx/bezier.cpp
+1
-1
src/gui/symbol/basic_shape_editor.cpp
src/gui/symbol/basic_shape_editor.cpp
+10
-3
src/gui/symbol/basic_shape_editor.hpp
src/gui/symbol/basic_shape_editor.hpp
+1
-1
src/gui/symbol/control.cpp
src/gui/symbol/control.cpp
+6
-6
src/gui/symbol/control.hpp
src/gui/symbol/control.hpp
+2
-1
src/gui/symbol/part_list.cpp
src/gui/symbol/part_list.cpp
+401
-93
src/gui/symbol/part_list.hpp
src/gui/symbol/part_list.hpp
+58
-39
src/gui/symbol/select_editor.cpp
src/gui/symbol/select_editor.cpp
+53
-35
src/gui/symbol/window.cpp
src/gui/symbol/window.cpp
+13
-10
src/gui/symbol/window.hpp
src/gui/symbol/window.hpp
+3
-2
src/main.cpp
src/main.cpp
+4
-0
src/render/symbol/filter.cpp
src/render/symbol/filter.cpp
+23
-0
src/render/symbol/filter.hpp
src/render/symbol/filter.hpp
+6
-5
src/render/symbol/viewer.cpp
src/render/symbol/viewer.cpp
+14
-6
src/render/symbol/viewer.hpp
src/render/symbol/viewer.hpp
+5
-3
src/resource/msw/mse.rc
src/resource/msw/mse.rc
+14
-0
src/resource/msw/tool/group.png
src/resource/msw/tool/group.png
+0
-0
src/resource/msw/tool/mode_symmetry.png
src/resource/msw/tool/mode_symmetry.png
+0
-0
src/resource/msw/tool/ungroup.png
src/resource/msw/tool/ungroup.png
+0
-0
src/util/real_point.hpp
src/util/real_point.hpp
+8
-1
src/util/vector2d.hpp
src/util/vector2d.hpp
+28
-16
src/util/window_id.hpp
src/util/window_id.hpp
+1
-0
No files found.
src/data/action/symbol.cpp
View file @
a56a8454
...
...
@@ -18,13 +18,17 @@ DECLARE_TYPEOF_COLLECTION(ControlPointP);
// ----------------------------------------------------------------------------- : Utility
String
action_name_for
(
const
set
<
SymbolPartP
>&
parts
,
const
String
&
action
)
{
return
format_string
(
action
,
parts
.
size
()
==
1
?
_TYPE_
(
"shape"
)
:
_TYPE_
(
"shapes"
));
return
format_string
(
action
,
parts
.
size
()
==
1
?
(
*
parts
.
begin
())
->
name
:
_TYPE_
(
"shapes"
));
}
SymbolPartsAction
::
SymbolPartsAction
(
const
set
<
SymbolPartP
>&
parts
)
:
parts
(
parts
)
{}
// ----------------------------------------------------------------------------- : Moving symbol parts
SymbolPartMoveAction
::
SymbolPartMoveAction
(
const
set
<
SymbolPartP
>&
parts
,
const
Vector2D
&
delta
)
:
parts
(
parts
)
:
SymbolPartsAction
(
parts
)
,
delta
(
delta
),
moved
(
-
delta
)
,
min_pos
(
Vector2D
::
infinity
()),
max_pos
(
-
Vector2D
::
infinity
())
,
constrain
(
false
)
...
...
@@ -32,10 +36,8 @@ SymbolPartMoveAction::SymbolPartMoveAction(const set<SymbolPartP>& parts, const
{
// Determine min/max_pos
FOR_EACH
(
p
,
parts
)
{
if
(
SymbolShape
*
s
=
p
->
isSymbolShape
())
{
min_pos
=
piecewise_min
(
min_pos
,
s
->
min_pos
);
max_pos
=
piecewise_max
(
max_pos
,
s
->
max_pos
);
}
min_pos
=
piecewise_min
(
min_pos
,
p
->
min_pos
);
max_pos
=
piecewise_max
(
max_pos
,
p
->
max_pos
);
}
}
...
...
@@ -46,19 +48,27 @@ String SymbolPartMoveAction::getName(bool to_undo) const {
void
SymbolPartMoveAction
::
perform
(
bool
to_undo
)
{
// move the points back
FOR_EACH
(
p
,
parts
)
{
if
(
SymbolShape
*
s
=
p
->
isSymbolShape
())
{
movePart
(
*
p
);
}
moved
=
-
moved
;
}
void
SymbolPartMoveAction
::
movePart
(
SymbolPart
&
part
)
{
if
(
SymbolShape
*
s
=
part
.
isSymbolShape
())
{
s
->
min_pos
-=
moved
;
s
->
max_pos
-=
moved
;
FOR_EACH
(
pnt
,
s
->
points
)
{
pnt
->
pos
-=
moved
;
}
}
else
if
(
SymbolSymmetry
*
s
=
p
->
isSymbolSymmetry
())
{
}
else
if
(
SymbolSymmetry
*
s
=
part
.
isSymbolSymmetry
())
{
s
->
center
-=
moved
;
}
else
if
(
SymbolGroup
*
g
=
part
.
isSymbolGroup
())
{
FOR_EACH
(
p
,
g
->
parts
)
{
movePart
(
*
p
);
}
g
->
calculateBoundsNonRec
();
}
else
{
throw
InternalError
(
_
(
"Invalid symbol part type"
));
}
}
moved
=
-
moved
;
}
void
SymbolPartMoveAction
::
move
(
const
Vector2D
&
deltaDelta
)
{
...
...
@@ -75,27 +85,35 @@ void SymbolPartMoveAction::move(const Vector2D& deltaDelta) {
// ----------------------------------------------------------------------------- : Rotating symbol parts
SymbolPartMatrixAction
::
SymbolPartMatrixAction
(
const
set
<
SymbolPartP
>&
parts
,
const
Vector2D
&
center
)
:
parts
(
parts
)
:
SymbolPartsAction
(
parts
)
,
center
(
center
)
{}
void
SymbolPartMatrixAction
::
transform
(
const
Vector2D
&
mx
,
const
Vector2D
&
my
)
{
// Transform each p
oin
t
void
SymbolPartMatrixAction
::
transform
(
const
Matrix2D
&
m
)
{
// Transform each p
ar
t
FOR_EACH
(
p
,
parts
)
{
if
(
SymbolShape
*
s
=
p
->
isSymbolShape
())
{
transform
(
*
p
,
m
);
}
}
void
SymbolPartMatrixAction
::
transform
(
SymbolPart
&
part
,
const
Matrix2D
&
m
)
{
if
(
SymbolShape
*
s
=
part
.
isSymbolShape
())
{
FOR_EACH
(
pnt
,
s
->
points
)
{
pnt
->
pos
=
(
pnt
->
pos
-
center
).
mul
(
mx
,
my
)
+
center
;
pnt
->
delta_before
=
pnt
->
delta_before
.
mul
(
mx
,
my
)
;
pnt
->
delta_after
=
pnt
->
delta_after
.
mul
(
mx
,
my
)
;
pnt
->
pos
=
((
pnt
->
pos
-
center
)
*
m
)
+
center
;
pnt
->
delta_before
=
pnt
->
delta_before
*
m
;
pnt
->
delta_after
=
pnt
->
delta_after
*
m
;
}
// bounds change after transforming
s
->
calculateBounds
();
}
else
if
(
SymbolSymmetry
*
s
=
p
->
isSymbolSymmetry
())
{
s
->
handle
=
s
->
handle
.
mul
(
mx
,
my
);
}
else
if
(
SymbolSymmetry
*
s
=
part
.
isSymbolSymmetry
())
{
s
->
handle
=
s
->
handle
*
m
;
}
else
if
(
SymbolGroup
*
g
=
part
.
isSymbolGroup
())
{
FOR_EACH
(
p
,
g
->
parts
)
{
transform
(
*
p
,
m
);
}
g
->
calculateBoundsNonRec
();
}
else
{
throw
InternalError
(
_
(
"Invalid symbol part type"
));
}
}
}
...
...
@@ -130,8 +148,8 @@ void SymbolPartRotateAction::rotateTo(double newAngle) {
void
SymbolPartRotateAction
::
rotateBy
(
double
deltaAngle
)
{
// Rotation 'matrix'
transform
(
Vector2D
(
cos
(
deltaAngle
),
-
sin
(
deltaAngle
)),
Vector2D
(
sin
(
deltaAngle
),
cos
(
deltaAngle
))
Matrix2D
(
cos
(
deltaAngle
),
-
sin
(
deltaAngle
)
,
sin
(
deltaAngle
),
cos
(
deltaAngle
))
);
}
...
...
@@ -170,8 +188,8 @@ void SymbolPartShearAction::move(const Vector2D& deltaShear) {
void
SymbolPartShearAction
::
shearBy
(
const
Vector2D
&
shear
)
{
// Shear 'matrix'
transform
(
Vector2D
(
1
,
shear
.
x
),
Vector2D
(
shear
.
y
,
1
)
Matrix2D
(
1
,
shear
.
x
,
shear
.
y
,
1
)
);
}
...
...
@@ -180,7 +198,7 @@ void SymbolPartShearAction::shearBy(const Vector2D& shear) {
SymbolPartScaleAction
::
SymbolPartScaleAction
(
const
set
<
SymbolPartP
>&
parts
,
int
scaleX
,
int
scaleY
)
:
parts
(
parts
)
:
SymbolPartsAction
(
parts
)
,
scaleX
(
scaleX
),
scaleY
(
scaleY
)
,
constrain
(
false
)
,
snap
(
0
)
...
...
@@ -189,10 +207,8 @@ SymbolPartScaleAction::SymbolPartScaleAction(const set<SymbolPartP>& parts, int
old_min
=
Vector2D
(
1e6
,
1e6
);
Vector2D
old_max
(
-
1e6
,
-
1e6
);
FOR_EACH
(
p
,
parts
)
{
if
(
SymbolShape
*
s
=
p
->
isSymbolShape
())
{
old_min
=
piecewise_min
(
old_min
,
s
->
min_pos
);
old_max
=
piecewise_max
(
old_max
,
s
->
max_pos
);
}
old_min
=
piecewise_min
(
old_min
,
p
->
min_pos
);
old_max
=
piecewise_max
(
old_max
,
p
->
max_pos
);
}
// new == old
new_min
=
new_real_min
=
old_min
;
...
...
@@ -244,9 +260,13 @@ void SymbolPartScaleAction::update() {
}
void
SymbolPartScaleAction
::
transformAll
()
{
Vector2D
scale
=
new_size
.
div
(
old_size
);
FOR_EACH
(
p
,
parts
)
{
if
(
SymbolShape
*
s
=
p
->
isSymbolShape
())
{
transformPart
(
*
p
);
}
}
void
SymbolPartScaleAction
::
transformPart
(
SymbolPart
&
part
)
{
if
(
SymbolShape
*
s
=
part
.
isSymbolShape
())
{
Vector2D
scale
=
new_size
.
div
(
old_size
);
s
->
min_pos
=
transform
(
s
->
min_pos
);
s
->
max_pos
=
transform
(
s
->
max_pos
);
// make sure that max >= min
...
...
@@ -259,12 +279,16 @@ void SymbolPartScaleAction::transformAll() {
pnt
->
delta_before
=
pnt
->
delta_before
.
mul
(
scale
);
pnt
->
delta_after
=
pnt
->
delta_after
.
mul
(
scale
);
}
}
else
if
(
SymbolSymmetry
*
s
=
p
->
isSymbolSymmetry
())
{
}
else
if
(
SymbolSymmetry
*
s
=
part
.
isSymbolSymmetry
())
{
throw
"TODO"
;
}
else
if
(
SymbolGroup
*
g
=
part
.
isSymbolGroup
())
{
FOR_EACH
(
p
,
g
->
parts
)
{
transformPart
(
*
p
);
}
g
->
calculateBoundsNonRec
();
}
else
{
throw
InternalError
(
_
(
"Invalid symbol part type"
));
}
}
}
Vector2D
SymbolPartScaleAction
::
transform
(
const
Vector2D
&
v
)
{
...
...
@@ -274,11 +298,18 @@ Vector2D SymbolPartScaleAction::transform(const Vector2D& v) {
// ----------------------------------------------------------------------------- : Change combine mode
CombiningModeAction
::
CombiningModeAction
(
const
set
<
SymbolPartP
>&
parts
,
SymbolShapeCombine
mode
)
{
CombiningModeAction
::
CombiningModeAction
(
const
set
<
SymbolPartP
>&
parts
,
SymbolShapeCombine
mode
)
:
SymbolPartsAction
(
parts
)
{
FOR_EACH
(
p
,
parts
)
{
if
(
p
->
isSymbolShape
())
{
this
->
parts
.
push_back
(
make_pair
(
static_pointer_cast
<
SymbolShape
>
(
p
),
mode
));
add
(
p
,
mode
);
}
}
void
CombiningModeAction
::
add
(
const
SymbolPartP
&
part
,
SymbolShapeCombine
mode
)
{
if
(
part
->
isSymbolShape
())
{
this
->
parts
.
push_back
(
make_pair
(
static_pointer_cast
<
SymbolShape
>
(
part
),
mode
));
}
else
if
(
SymbolGroup
*
g
=
part
->
isSymbolGroup
())
{
FOR_EACH
(
p
,
g
->
parts
)
add
(
p
,
mode
);
}
}
...
...
@@ -294,16 +325,28 @@ void CombiningModeAction::perform(bool to_undo) {
// ----------------------------------------------------------------------------- : Change name
SymbolPartNameAction
::
SymbolPartNameAction
(
const
SymbolPartP
&
part
,
const
String
&
name
)
SymbolPartNameAction
::
SymbolPartNameAction
(
const
SymbolPartP
&
part
,
const
String
&
name
,
size_t
old_cursor
,
size_t
new_cursor
)
:
part
(
part
),
part_name
(
name
)
,
new_cursor
(
old_cursor
),
old_cursor
(
new_cursor
)
// will be swapped
{}
String
SymbolPartNameAction
::
getName
(
bool
to_undo
)
const
{
return
_ACTION_
(
"change shape name"
);
}
bool
SymbolPartNameAction
::
merge
(
const
Action
&
action
)
{
TYPE_CASE
(
action
,
SymbolPartNameAction
)
{
if
(
action
.
part
==
part
)
{
// adjacent actions on the same part, discard the other one,
// because it only keeps an intermediate value
return
true
;
}
}
return
false
;
}
void
SymbolPartNameAction
::
perform
(
bool
to_undo
)
{
swap
(
part
->
name
,
part_name
);
swap
(
old_cursor
,
new_cursor
);
}
// ----------------------------------------------------------------------------- : Add symbol part
...
...
@@ -313,7 +356,7 @@ AddSymbolPartAction::AddSymbolPartAction(Symbol& symbol, const SymbolPartP& part
{}
String
AddSymbolPartAction
::
getName
(
bool
to_undo
)
const
{
return
format_string
(
_ACTION_
(
"add"
),
part
->
name
);
return
format_string
(
_ACTION_
(
"add
part
"
),
part
->
name
);
}
void
AddSymbolPartAction
::
perform
(
bool
to_undo
)
{
...
...
@@ -407,8 +450,8 @@ void DuplicateSymbolPartsAction::getParts(set<SymbolPartP>& parts) {
// ----------------------------------------------------------------------------- : Reorder symbol parts
ReorderSymbolPartsAction
::
ReorderSymbolPartsAction
(
Symbol
&
symbol
,
size_t
part_id1
,
size_t
part_id2
)
:
symbol
(
symbol
),
part_id1
(
part_id1
),
part_id2
(
part_id2
)
ReorderSymbolPartsAction
::
ReorderSymbolPartsAction
(
Symbol
&
symbol
,
size_t
old_position
,
size_t
new_position
)
:
symbol
(
symbol
),
old_position
(
old_position
),
new_position
(
new_position
)
{}
String
ReorderSymbolPartsAction
::
getName
(
bool
to_undo
)
const
{
...
...
@@ -416,9 +459,12 @@ String ReorderSymbolPartsAction::getName(bool to_undo) const {
}
void
ReorderSymbolPartsAction
::
perform
(
bool
to_undo
)
{
assert
(
part_id1
<
symbol
.
parts
.
size
());
assert
(
part_id2
<
symbol
.
parts
.
size
());
swap
(
symbol
.
parts
[
part_id1
],
symbol
.
parts
[
part_id2
]);
assert
(
old_position
<
symbol
.
parts
.
size
());
assert
(
new_position
<
symbol
.
parts
.
size
());
SymbolPartP
part
=
symbol
.
parts
.
at
(
old_position
);
symbol
.
parts
.
erase
(
symbol
.
parts
.
begin
()
+
old_position
);
symbol
.
parts
.
insert
(
symbol
.
parts
.
begin
()
+
new_position
,
part
);
swap
(
old_position
,
new_position
);
}
// ----------------------------------------------------------------------------- : Group symbol parts
...
...
@@ -439,6 +485,7 @@ GroupSymbolPartsAction::GroupSymbolPartsAction(Symbol& symbol, const set<SymbolP
group
->
name
=
_
(
"Group"
);
FOR_EACH
(
p
,
symbol
.
parts
)
{
if
(
parts
.
find
(
p
)
!=
parts
.
end
())
{
// add to group instead
group
->
parts
.
push_back
(
p
);
if
(
!
done
)
{
done
=
true
;
...
...
@@ -449,6 +496,7 @@ GroupSymbolPartsAction::GroupSymbolPartsAction(Symbol& symbol, const set<SymbolP
old_part_list
.
push_back
(
p
);
}
}
group
->
calculateBounds
();
}
String
GroupSymbolPartsAction
::
getName
(
bool
to_undo
)
const
{
return
_ACTION_
(
"group parts"
);
...
...
src/data/action/symbol.hpp
View file @
a56a8454
...
...
@@ -20,16 +20,24 @@
// ----------------------------------------------------------------------------- : Transform symbol part
/// Anything that changes
a part
/// Anything that changes
one or more parts
class
SymbolPartAction
:
public
Action
{};
/// Anything that changes a set of parts
class
SymbolPartsAction
:
public
SymbolPartAction
{
public:
SymbolPartsAction
(
const
set
<
SymbolPartP
>&
parts
);
const
set
<
SymbolPartP
>
parts
;
///< Affected parts
};
/// Anything that changes a part as displayed in the part list
class
SymbolPartListAction
:
public
SymbolPartAction
{};
// ----------------------------------------------------------------------------- : Moving symbol parts
/// Move some symbol parts
class
SymbolPartMoveAction
:
public
SymbolPartAction
{
class
SymbolPartMoveAction
:
public
SymbolPart
s
Action
{
public:
SymbolPartMoveAction
(
const
set
<
SymbolPartP
>&
parts
,
const
Vector2D
&
delta
=
Vector2D
());
...
...
@@ -40,10 +48,11 @@ class SymbolPartMoveAction : public SymbolPartAction {
void
move
(
const
Vector2D
&
delta
);
private:
set
<
SymbolPartP
>
parts
;
///< Parts to move
Vector2D
delta
;
///< How much to move
Vector2D
moved
;
///< How much has been moved
Vector2D
min_pos
,
max_pos
;
///< Bounding box of the thing we are moving
void
movePart
(
SymbolPart
&
part
);
///< Move a single part
public:
bool
constrain
;
///< Constrain movement?
int
snap
;
///< Snap to grid?
...
...
@@ -52,7 +61,7 @@ class SymbolPartMoveAction : public SymbolPartAction {
// ----------------------------------------------------------------------------- : Rotating symbol parts
/// Transforming symbol parts using a matrix
class
SymbolPartMatrixAction
:
public
SymbolPartAction
{
class
SymbolPartMatrixAction
:
public
SymbolPart
s
Action
{
public:
SymbolPartMatrixAction
(
const
set
<
SymbolPartP
>&
parts
,
const
Vector2D
&
center
);
...
...
@@ -61,9 +70,9 @@ class SymbolPartMatrixAction : public SymbolPartAction {
protected:
/// Perform the transformation using the given matrix
void
transform
(
const
Vector2D
&
mx
,
const
Vector2D
&
my
);
void
transform
(
const
Matrix2D
&
m
);
void
transform
(
SymbolPart
&
part
,
const
Matrix2D
&
m
);
set
<
SymbolPartP
>
parts
;
///< Parts to transform
Vector2D
center
;
///< Center to transform around
};
...
...
@@ -114,7 +123,7 @@ class SymbolPartShearAction : public SymbolPartMatrixAction {
// ----------------------------------------------------------------------------- : Scaling symbol parts
/// Scale some symbol parts
class
SymbolPartScaleAction
:
public
SymbolPartAction
{
class
SymbolPartScaleAction
:
public
SymbolPart
s
Action
{
public:
SymbolPartScaleAction
(
const
set
<
SymbolPartP
>&
parts
,
int
scaleX
,
int
scaleY
);
...
...
@@ -127,13 +136,13 @@ class SymbolPartScaleAction : public SymbolPartAction {
void
update
();
private:
set
<
SymbolPartP
>
parts
;
///< Parts to scale
Vector2D
old_min
,
old_size
;
///< the original pos/size
Vector2D
new_real_min
,
new_real_size
;
///< the target pos/sizevoid shearBy(const Vector2D& shear)
Vector2D
new_min
,
new_size
;
///< the target pos/size after applying constrains
int
scaleX
,
scaleY
;
///< to what corner are we attached?
/// Transform everything in the parts
void
transformAll
();
void
transformPart
(
SymbolPart
&
);
/// Transform a single vector
inline
Vector2D
transform
(
const
Vector2D
&
v
);
public:
...
...
@@ -144,7 +153,7 @@ class SymbolPartScaleAction : public SymbolPartAction {
// ----------------------------------------------------------------------------- : Change combine mode
/// Change the name of a symbol part
class
CombiningModeAction
:
public
SymbolPart
List
Action
{
class
CombiningModeAction
:
public
SymbolPart
s
Action
{
public:
// All parts must be SymbolParts
CombiningModeAction
(
const
set
<
SymbolPartP
>&
parts
,
SymbolShapeCombine
mode
);
...
...
@@ -153,22 +162,26 @@ class CombiningModeAction : public SymbolPartListAction {
virtual
void
perform
(
bool
to_undo
);
private:
void
add
(
const
SymbolPartP
&
,
SymbolShapeCombine
mode
);
vector
<
pair
<
SymbolShapeP
,
SymbolShapeCombine
>
>
parts
;
///< Affected parts with new combining modes
};
// ----------------------------------------------------------------------------- : Change name
/// Change the name of a symbol part
class
SymbolPartNameAction
:
public
SymbolPart
List
Action
{
class
SymbolPartNameAction
:
public
SymbolPartAction
{
public:
SymbolPartNameAction
(
const
SymbolPartP
&
part
,
const
String
&
name
);
SymbolPartNameAction
(
const
SymbolPartP
&
part
,
const
String
&
name
,
size_t
old_cursor
,
size_t
new_cursor
);
virtual
String
getName
(
bool
to_undo
)
const
;
virtual
void
perform
(
bool
to_undo
);
virtual
bool
merge
(
const
Action
&
action
);
p
rivate
:
p
ublic
:
SymbolPartP
part
;
///< Affected part
String
part_name
;
///< New name
size_t
old_cursor
;
///< Cursor position
size_t
new_cursor
;
///< Cursor position
};
// ----------------------------------------------------------------------------- : Add symbol part
...
...
@@ -224,10 +237,10 @@ class DuplicateSymbolPartsAction : public SymbolPartListAction {
// ----------------------------------------------------------------------------- : Reorder symbol parts
/// Change the position of a part in a symbol, by
swapping two parts
.
/// Change the position of a part in a symbol, by
moving a part
.
class
ReorderSymbolPartsAction
:
public
SymbolPartListAction
{
public:
ReorderSymbolPartsAction
(
Symbol
&
symbol
,
size_t
part_id1
,
size_t
part_id2
);
ReorderSymbolPartsAction
(
Symbol
&
symbol
,
size_t
old_position
,
size_t
new_position
);
virtual
String
getName
(
bool
to_undo
)
const
;
virtual
void
perform
(
bool
to_undo
);
...
...
@@ -235,7 +248,7 @@ class ReorderSymbolPartsAction : public SymbolPartListAction {
private:
Symbol
&
symbol
;
///< Symbol to swap the parts in
public:
size_t
part_id1
,
part_id2
;
///< Indices of parts to swap
size_t
old_position
,
new_position
;
///< Positions to move from and to
};
...
...
src/data/action/symbol_part.cpp
View file @
a56a8454
...
...
@@ -349,8 +349,8 @@ SinglePointRemoveAction::SinglePointRemoveAction(const SymbolShapeP& shape, UInt
Vector2D
p
=
c
.
pointAt
(
t
);
Vector2D
distP
=
point
->
pos
-
p
;
// adjust handle sizes
point1
.
other
.
delta_after
*=
ssqrt
(
d
istP
.
dot
(
point1
.
other
.
delta_after
)
/
point1
.
other
.
delta_after
.
lengthSqr
())
+
1
;
point2
.
other
.
delta_before
*=
ssqrt
(
d
istP
.
dot
(
point2
.
other
.
delta_before
)
/
point2
.
other
.
delta_before
.
lengthSqr
())
+
1
;
point1
.
other
.
delta_after
*=
ssqrt
(
d
ot
(
distP
,
point1
.
other
.
delta_after
)
/
point1
.
other
.
delta_after
.
lengthSqr
())
+
1
;
point2
.
other
.
delta_before
*=
ssqrt
(
d
ot
(
distP
,
point2
.
other
.
delta_before
)
/
point2
.
other
.
delta_before
.
lengthSqr
())
+
1
;
// unlock if needed
if
(
point1
.
other
.
lock
==
LOCK_SIZE
)
point1
.
other
.
lock
=
LOCK_DIR
;
...
...
src/data/format/image_to_symbol.cpp
View file @
a56a8454
...
...
@@ -245,7 +245,7 @@ void mark_corners(SymbolShape& shape) {
Vector2D
after
=
.6
*
shape
.
getPoint
(
i
+
1
)
->
pos
+
.2
*
shape
.
getPoint
(
i
+
2
)
->
pos
+
.1
*
shape
.
getPoint
(
i
+
3
)
->
pos
+
.1
*
shape
.
getPoint
(
i
+
4
)
->
pos
;
before
=
(
before
-
current
.
pos
).
normalized
();
after
=
(
after
-
current
.
pos
).
normalized
();
if
(
before
.
dot
(
after
)
>=
-
0.25
f
)
{
if
(
dot
(
before
,
after
)
>=
-
0.25
f
)
{
// corner
current
.
lock
=
LOCK_FREE
;
}
else
{
...
...
@@ -285,8 +285,8 @@ void merge_corners(SymbolShape& shape) {
for
(
int
j
=
0
;
j
<
4
;
++
j
)
{
Vector2D
a_
=
(
shape
.
getPoint
(
i
-
j
-
1
)
->
pos
-
prev
.
pos
).
normalized
();
Vector2D
b_
=
(
shape
.
getPoint
(
i
+
j
)
->
pos
-
cur
.
pos
).
normalized
();
double
a_dot
=
a_
.
dot
(
ab
);
double
b_dot
=
-
b_
.
dot
(
ab
);
double
a_dot
=
dot
(
a_
,
ab
);
double
b_dot
=
-
dot
(
b_
,
ab
);
if
(
a_dot
<
min_a_dot
)
{
min_a_dot
=
a_dot
;
a
=
a_
;
...
...
@@ -300,8 +300,8 @@ void merge_corners(SymbolShape& shape) {
// t a + ab = u b, solve for t,u
// Gives us:
// t = ab cross b / b cross a
double
tden
=
max
(
0.00000001
,
b
.
cross
(
a
));
double
t
=
ab
.
cross
(
b
)
/
tden
;
double
tden
=
max
(
0.00000001
,
cross
(
b
,
a
));
double
t
=
cross
(
ab
,
b
)
/
tden
;
// do these tangent lines intersect, and not too far away?
// if so, then the intersection point is the merged point
if
(
t
>=
0
&&
t
<
20.0
)
{
...
...
@@ -358,7 +358,7 @@ void straighten(SymbolShape& shape) {
Vector2D
bb
=
next
.
delta_before
.
normalized
();
// if the area beneath the polygon formed by the handles is small
// then it is a straight line
double
cpDot
=
abs
(
aa
.
cross
(
ab
))
+
abs
(
bb
.
cross
(
ab
));
double
cpDot
=
abs
(
cross
(
aa
,
ab
))
+
abs
(
cross
(
bb
,
ab
));
if
(
cpDot
<
treshold
)
{
cur
.
segment_after
=
next
.
segment_before
=
SEGMENT_LINE
;
cur
.
delta_after
=
next
.
delta_before
=
Vector2D
();
...
...
src/data/symbol.cpp
View file @
a56a8454
...
...
@@ -94,6 +94,11 @@ Vector2D& ControlPoint::getOther(WhichHandle wh) {
// ----------------------------------------------------------------------------- : SymbolPart
void
SymbolPart
::
calculateBounds
()
{
min_pos
=
Vector2D
::
infinity
();
max_pos
=
-
Vector2D
::
infinity
();
}
IMPLEMENT_REFLECTION
(
SymbolPart
)
{
REFLECT_IF_NOT_READING
{
String
type
=
typeName
();
...
...
@@ -235,6 +240,19 @@ SymbolPartP SymbolGroup::clone() const {
return
part
;
}
void
SymbolGroup
::
calculateBounds
()
{
FOR_EACH
(
p
,
parts
)
p
->
calculateBounds
();
calculateBoundsNonRec
();
}
void
SymbolGroup
::
calculateBoundsNonRec
()
{
min_pos
=
Vector2D
::
infinity
();
max_pos
=
-
Vector2D
::
infinity
();
FOR_EACH
(
p
,
parts
)
{
min_pos
=
piecewise_min
(
min_pos
,
p
->
min_pos
);
max_pos
=
piecewise_max
(
max_pos
,
p
->
max_pos
);
}
}
IMPLEMENT_REFLECTION
(
SymbolGroup
)
{
REFLECT_BASE
(
SymbolPart
);
REFLECT
(
parts
);
...
...
src/data/symbol.hpp
View file @
a56a8454
...
...
@@ -112,6 +112,9 @@ class SymbolPart : public IntrusivePtrVirtualBase {
public:
/// Name/label for this part
String
name
;
/// Position and size of the part.
/** this is the smallest axis aligned bounding box that fits around the part */
Vector2D
min_pos
,
max_pos
;
/// Type of this part
virtual
String
typeName
()
const
=
0
;
...
...
@@ -130,6 +133,9 @@ class SymbolPart : public IntrusivePtrVirtualBase {
virtual
SymbolGroup
*
isSymbolGroup
()
{
return
nullptr
;
}
virtual
const
SymbolGroup
*
isSymbolGroup
()
const
{
return
nullptr
;
}
/// Calculate the position and size of the part (min_pos and max_pos)
virtual
void
calculateBounds
();
DECLARE_REFLECTION_VIRTUAL
();
};
...
...
@@ -162,9 +168,6 @@ class SymbolShape : public SymbolPart {
SymbolShapeCombine
combine
;
// Center of rotation, relative to the part, when the part is scaled to [0..1]
Vector2D
rotation_center
;
/// Position and size of the part
/// this is the smallest axis aligned bounding box that fits around the part
Vector2D
min_pos
,
max_pos
;
SymbolShape
();
...
...
@@ -183,7 +186,7 @@ class SymbolShape : public SymbolPart {
void
enforceConstraints
();
/// Calculate the position and size of the part
void
calculateBounds
();
v
irtual
v
oid
calculateBounds
();
DECLARE_REFLECTION
();
};
...
...
@@ -221,7 +224,7 @@ class SymbolSymmetry : public SymbolPart {
/// A group of symbol parts
class
SymbolGroup
:
public
SymbolPart
{
public:
vector
<
SymbolPartP
>
parts
;
///< The parts in this group
vector
<
SymbolPartP
>
parts
;
///< The parts in this group
, first item is on top
virtual
String
typeName
()
const
;
virtual
SymbolPartP
clone
()
const
;
...
...
@@ -229,16 +232,18 @@ class SymbolGroup : public SymbolPart {
virtual
SymbolGroup
*
isSymbolGroup
()
{
return
this
;
}
virtual
const
SymbolGroup
*
isSymbolGroup
()
const
{
return
this
;
}
virtual
void
calculateBounds
();
/// re-calculate the bounds, but not of the contained parts
void
calculateBoundsNonRec
();
DECLARE_REFLECTION
();
};
// ----------------------------------------------------------------------------- : Symbol
/// An editable symbol, consists of any number of SymbolParts
class
Symbol
:
public
IntrusivePtrBase
<
Symbol
>
{
class
Symbol
:
public
SymbolGroup
{
public:
/// The parts of this symbol, first item is on top
vector
<
SymbolPartP
>
parts
;
/// Actions performed on this symbol and the parts in it
ActionStack
actions
;
...
...
src/gfx/bezier.cpp
View file @
a56a8454
...
...
@@ -203,7 +203,7 @@ bool pos_on_line(const Vector2D& pos, double range, const Vector2D& p1, const Ve
Vector2D
p21
=
p2
-
p1
;
double
p21len
=
p21
.
lengthSqr
();
if
(
p21len
<
0.00001
)
return
false
;
// line is too short
t
=
p21
.
dot
(
pos
-
p1
)
/
p21len
;
// 'time' on line p1->p2
t
=
dot
(
p21
,
pos
-
p1
)
/
p21len
;
// 'time' on line p1->p2
if
(
t
<
0
||
t
>
1
)
return
false
;
// outside segment
pOut
=
p1
+
p21
*
t
;
// point on line
Vector2D
dist
=
pOut
-
pos
;
// distance to line
...
...
src/gui/symbol/basic_shape_editor.cpp
View file @
a56a8454
...
...
@@ -9,7 +9,9 @@
#include <gui/symbol/basic_shape_editor.hpp>
#include <gui/util.hpp>
#include <util/window_id.hpp>
#include <data/settings.hpp>
#include <data/action/symbol.hpp>
#include <data/action/symbol_part.hpp>
#include <wx/spinctrl.h>
// ----------------------------------------------------------------------------- : SymbolBasicShapeEditor
...
...
@@ -108,7 +110,7 @@ void SymbolBasicShapeEditor::onMouseDrag (const Vector2D& from, const Vector2D&
// Resize the object
if
(
drawing
)
{
end
=
to
;
makeShape
(
start
,
end
,
ev
.
ControlDown
(),
ev
.
ShiftDown
());
makeShape
(
start
,
end
,
ev
.
ControlDown
(),
settings
.
symbol_grid_snap
,
ev
.
ShiftDown
());
control
.
Refresh
(
false
);
}
}
...
...
@@ -119,7 +121,7 @@ void SymbolBasicShapeEditor::onKeyChange(wxKeyEvent& ev) {
if
(
drawing
)
{
if
(
ev
.
GetKeyCode
()
==
WXK_CONTROL
||
ev
.
GetKeyCode
()
==
WXK_SHIFT
)
{
// changed constrains
makeShape
(
start
,
end
,
ev
.
ControlDown
(),
ev
.
ShiftDown
());
makeShape
(
start
,
end
,
ev
.
ControlDown
(),
settings
.
symbol_grid_snap
,
ev
.
ShiftDown
());
control
.
Refresh
(
false
);
}
else
if
(
ev
.
GetKeyCode
()
==
WXK_ESCAPE
)
{
// cancel drawing
...
...
@@ -156,7 +158,12 @@ inline double sgn(double d) {
return
d
<
0
?
-
1
:
1
;
}
void
SymbolBasicShapeEditor
::
makeShape
(
const
Vector2D
&
a
,
const
Vector2D
&
b
,
bool
constrained
,
bool
centered
)
{
void
SymbolBasicShapeEditor
::
makeShape
(
Vector2D
a
,
Vector2D
b
,
bool
constrained
,
bool
snap
,
bool
centered
)
{
// snap
if
(
snap
)
{
a
=
snap_vector
(
a
,
settings
.
symbol_grid_size
);
b
=
snap_vector
(
b
,
settings
.
symbol_grid_size
);
}
// constrain
Vector2D
size
=
b
-
a
;
if
(
constrained
)
{
...
...
src/gui/symbol/basic_shape_editor.hpp
View file @
a56a8454
...
...
@@ -63,7 +63,7 @@ class SymbolBasicShapeEditor : public SymbolEditorBase {
/** when centered: a = center, b-a = radius
* otherwise: a = top left, b = bottom right
*/
void
makeShape
(
const
Vector2D
&
a
,
const
Vector2D
&
b
,
bool
constrained
,
bool
centered
);
void
makeShape
(
Vector2D
a
,
Vector2D
b
,
bool
constrained
,
bool
snap
,
bool
centered
);
/// Make the shape, centered in c, with radius r
void
makeCenteredShape
(
const
Vector2D
&
c
,
Vector2D
r
,
bool
constrained
);
...
...
src/gui/symbol/control.cpp
View file @
a56a8454
...
...
@@ -162,20 +162,20 @@ void SymbolControl::draw(DC& dc) {
SymbolViewer
::
draw
(
dc
);
// draw grid
if
(
settings
.
symbol_grid
)
{
wxSize
s
=
dc
.
GetSize
();
double
lines
=
settings
.
symbol_grid_size
;
double
end
=
rotation
.
trS
(
1
);
for
(
int
i
=
0
;
i
<=
lines
;
++
i
)
{
int
x
=
(
int
)
floor
(
rotation
.
trS
(
i
/
lines
-
0.0001
));
//dc.SetPen(Color(0, i%5 == 0 ? 64 : 31, 0));
//dc.SetPen(Color(i%5 == 0 ? 64 : 31, 0, 0));
dc
.
SetLogicalFunction
(
wxAND
);
dc
.
SetPen
(
i
%
5
==
0
?
Color
(
191
,
255
,
191
)
:
Color
(
191
,
255
,
191
));
dc
.
DrawLine
(
x
,
0
,
x
,
s
.
y
);
dc
.
DrawLine
(
0
,
x
,
s
.
x
,
x
);
dc
.
DrawLine
(
x
,
0
,
x
,
end
);
dc
.
DrawLine
(
0
,
x
,
end
,
x
);
dc
.
SetLogicalFunction
(
wxOR
);
dc
.
SetPen
(
i
%
5
==
0
?
Color
(
0
,
63
,
0
)
:
Color
(
0
,
31
,
0
));
dc
.
DrawLine
(
x
,
0
,
x
,
s
.
y
);
dc
.
DrawLine
(
0
,
x
,
s
.
x
,
x
);
dc
.
DrawLine
(
x
,
0
,
x
,
end
);
dc
.
DrawLine
(
0
,
x
,
end
,
x
);
}
dc
.
SetLogicalFunction
(
wxCOPY
);
}
...
...
@@ -251,7 +251,7 @@ void SymbolControl::onUpdateUI(wxUpdateUIEvent& ev) {
ev
.
Check
(
editor
->
modeToolId
()
==
ev
.
GetId
());
if
(
ev
.
GetId
()
==
ID_MODE_POINTS
)
{
// can only edit points when a single part is selected <TODO?>
ev
.
Enable
(
selected_parts
.
size
()
==
1
);
ev
.
Enable
(
selected_parts
.
size
()
==
1
&&
(
*
selected_parts
.
begin
())
->
isSymbolShape
()
);
}
break
;
case
ID_MODE_PAINT
:
...
...
src/gui/symbol/control.hpp
View file @
a56a8454
...
...
@@ -72,7 +72,8 @@ class SymbolControl : public wxControl, public SymbolViewer {
public:
/// What parts are selected?
set
<
SymbolPartP
>
selected_parts
;
SymbolShapeP
selected_shape
;
// if there is a single selection
SymbolPartP
highlight_part
;
///< part the mouse cursor is over
SymbolShapeP
selected_shape
;
///< if there is a single selection
/// Parent window
SymbolWindow
*
parent
;
...
...
src/gui/symbol/part_list.cpp
View file @
a56a8454
...
...
@@ -9,147 +9,455 @@
#include <gui/symbol/part_list.hpp>
#include <gui/util.hpp>
#include <data/action/symbol.hpp>
#include <wx/imaglist.h>
#include <gfx/gfx.hpp>
#include <render/symbol/filter.hpp>
#include <wx/dcbuffer.h>
#include <wx/caret.h>
// ----------------------------------------------------------------------------- : Constructor
DECLARE_TYPEOF_COLLECTION
(
SymbolPartP
);
SymbolPartList
::
SymbolPartList
(
Window
*
parent
,
int
id
,
SymbolP
symbol
)
:
wxListCtrl
(
parent
,
id
,
wxDefaultPosition
,
wxDefaultSize
,
wxLC_REPORT
|
wxLC_NO_HEADER
|
wxLC_VIRTUAL
|
wxLC_EDIT_LABELS
)
// ----------------------------------------------------------------------------- : Events
DEFINE_EVENT_TYPE
(
EVENT_PART_SELECT
);
DEFINE_EVENT_TYPE
(
EVENT_PART_ACTIVATE
);
// ----------------------------------------------------------------------------- : SymbolPartList
SymbolPartList
::
SymbolPartList
(
Window
*
parent
,
int
id
,
set
<
SymbolPartP
>&
selection
,
SymbolP
symbol
)
:
wxScrolledWindow
(
parent
,
id
,
wxDefaultPosition
,
wxDefaultSize
,
wxSUNKEN_BORDER
|
wxVSCROLL
)
,
selection
(
selection
)
,
state_icons
(
9
,
8
)
{
// Create image list
wxImageList
*
images
=
new
wxImageList
(
16
,
16
);
// NOTE: this is based on the order of the SymbolShapeCombine and SymbolSymmetryType enums!
images
->
Add
(
load_resource_image
(
_
(
"combine_or"
)));
images
->
Add
(
load_resource_image
(
_
(
"combine_sub"
)));
images
->
Add
(
load_resource_image
(
_
(
"combine_and"
)));
images
->
Add
(
load_resource_image
(
_
(
"combine_xor"
)));
images
->
Add
(
load_resource_image
(
_
(
"combine_over"
)));
images
->
Add
(
load_resource_image
(
_
(
"combine_border"
)));
images
->
Add
(
load_resource_image
(
_
(
"symmetry_rotation"
)));
images
->
Add
(
load_resource_image
(
_
(
"symmetry_reflection"
)));
AssignImageList
(
images
,
wxIMAGE_LIST_SMALL
);
// create columns
InsertColumn
(
0
,
_
(
"Name"
));
state_icons
.
Add
(
load_resource_image
(
_
(
"icon_combine_merge"
)));
state_icons
.
Add
(
load_resource_image
(
_
(
"icon_combine_subtract"
)));
state_icons
.
Add
(
load_resource_image
(
_
(
"icon_combine_intersection"
)));
state_icons
.
Add
(
load_resource_image
(
_
(
"icon_combine_difference"
)));
state_icons
.
Add
(
load_resource_image
(
_
(
"icon_combine_overlap"
)));
state_icons
.
Add
(
load_resource_image
(
_
(
"icon_combine_border"
)));
state_icons
.
Add
(
load_resource_image
(
_
(
"icon_symmetry_rotation"
)));
state_icons
.
Add
(
load_resource_image
(
_
(
"icon_symmetry_reflection"
)));
state_icons
.
Add
(
load_resource_image
(
_
(
"icon_symbol_group"
)));
// view symbol
setSymbol
(
symbol
);
}
// ----------------------------------------------------------------------------- : View events
void
SymbolPartList
::
onChangeSymbol
()
{
typing_in
=
SymbolPartP
();
cursor
=
0
;
update
();
}
void
SymbolPartList
::
onAction
(
const
Action
&
action
,
bool
undone
)
{
TYPE_CASE
(
action
,
ReorderSymbolPartsAction
)
{
if
(
selected
==
(
long
)
action
.
part_id1
)
{
selectItem
((
long
)
action
.
part_id2
);
}
else
if
(
selected
==
(
long
)
action
.
part_id2
)
{
selectItem
((
long
)
action
.
part_id1
);
TYPE_CASE
(
action
,
SymbolPartNameAction
)
{
if
(
typing_in
==
action
.
part
)
{
cursor
=
action
.
new_cursor
;
}
Refresh
(
false
);
if
(
true
)
return
;
}
TYPE_CASE_
(
action
,
SymbolPartListAction
)
{
update
();
return
;
}
TYPE_CASE
(
action
,
SymbolPartsAction
)
{
symbol_preview
.
up_to_date
=
false
;
updateParts
(
action
.
parts
);
if
(
true
)
return
;
}
TYPE_CASE_
(
action
,
SymbolPartAction
)
{
symbol_preview
.
up_to_date
=
false
;
// some part changed, but we don't know which one, assume it is the selection
updateParts
(
selection
);
return
;
}
}
// ----------------------------------------------------------------------------- : Other
wxSize
SymbolPartList
::
DoGetBestSize
()
const
{
wxSize
ws
=
GetSize
(),
cs
=
GetClientSize
();
const
int
w
=
110
;
const
int
h
=
ITEM_HEIGHT
;
return
wxSize
(
w
,
h
)
+
ws
-
cs
;
}
String
SymbolPartList
::
OnGetItemText
(
long
item
,
long
col
)
const
{
assert
(
col
==
0
);
return
getPart
(
item
)
->
name
;
void
SymbolPartList
::
update
()
{
// count items
number_of_items
=
childCount
(
symbol
);
SetVirtualSize
(
110
,
number_of_items
*
(
ITEM_HEIGHT
+
1
));
// invalidate previews
symbol_preview
.
up_to_date
=
false
;
for
(
size_t
i
=
0
;
i
<
part_previews
.
size
()
;
++
i
)
{
part_previews
[
i
].
up_to_date
=
false
;
}
// refresh
Refresh
(
false
);
}
void
SymbolPartList
::
updateParts
(
const
set
<
SymbolPartP
>&
parts
)
{
symbol_preview
.
up_to_date
=
false
;
int
i
=
0
;
FOR_EACH
(
p
,
symbol
->
parts
)
{
updatePart
(
parts
,
i
,
false
,
p
);
}
// refresh
Refresh
(
false
);
}
int
SymbolPartList
::
OnGetItemImage
(
long
item
)
const
{
return
getPart
(
item
)
->
icon
();
void
SymbolPartList
::
updatePart
(
const
set
<
SymbolPartP
>&
parts
,
int
&
i
,
bool
parent_updated
,
const
SymbolPartP
&
part
)
{
bool
update
=
parent_updated
||
parts
.
find
(
part
)
!=
parts
.
end
();
if
(
update
)
{
part_previews
[
i
].
up_to_date
=
false
;
}
++
i
;
if
(
SymbolGroup
*
g
=
part
->
isSymbolGroup
())
{
FOR_EACH
(
p
,
g
->
parts
)
{
updatePart
(
parts
,
i
,
update
,
p
);
}
}
}
SymbolPartP
SymbolPartList
::
getPart
(
long
item
)
const
{
return
symbol
->
parts
.
at
(
item
);
// ----------------------------------------------------------------------------- : Events
void
SymbolPartList
::
onLeftDown
(
wxMouseEvent
&
ev
)
{
// find item under cursor
if
(
ev
.
GetX
()
<
0
||
ev
.
GetX
()
>=
GetClientSize
().
x
)
return
;
SymbolPartP
part
=
findItem
(
ev
.
GetY
()
/
(
ITEM_HEIGHT
+
1
));
if
(
part
)
{
// toggle/select
if
(
!
ev
.
ShiftDown
())
{
selection
.
clear
();
}
if
(
selection
.
find
(
part
)
!=
selection
.
end
())
{
selection
.
erase
(
part
);
}
else
{
selection
.
insert
(
part
);
}
if
(
!
ev
.
ShiftDown
())
{
// drag item
mouse_down_on
=
part
;
drop_position
=
-
1
;
CaptureMouse
();
}
sendEvent
(
EVENT_PART_SELECT
);
Refresh
(
false
);
}
ev
.
Skip
();
// for focus
}
void
SymbolPartList
::
selectItem
(
long
item
)
{
selected
=
(
long
)
item
;
long
count
=
GetItemCount
();
for
(
long
i
=
0
;
i
<
count
;
++
i
)
{
SetItemState
(
i
,
i
==
selected
?
wxLIST_STATE_SELECTED
|
wxLIST_STATE_FOCUSED
:
0
,
wxLIST_STATE_SELECTED
|
wxLIST_STATE_FOCUSED
);
void
SymbolPartList
::
onLeftUp
(
wxMouseEvent
&
ev
)
{
if
(
HasCapture
())
ReleaseMouse
();
if
(
mouse_down_on
&&
drop_position
!=
-
1
)
{
// move part
// find old position
vector
<
SymbolPartP
>::
const_iterator
it
=
find
(
symbol
->
parts
.
begin
(),
symbol
->
parts
.
end
(),
mouse_down_on
);
mouse_down_on
=
SymbolPartP
();
if
(
it
==
symbol
->
parts
.
end
())
{
Refresh
(
false
);
return
;
}
size_t
old_position
=
it
-
symbol
->
parts
.
begin
();
// find new position
size_t
new_position
;
SymbolPartP
drop_before
=
findItem
(
drop_position
);
it
=
find
(
symbol
->
parts
.
begin
(),
symbol
->
parts
.
end
(),
drop_before
);
if
(
it
==
symbol
->
parts
.
end
())
{
new_position
=
number_of_items
-
1
;
}
else
{
new_position
=
it
-
symbol
->
parts
.
begin
();
if
(
old_position
<
new_position
)
new_position
-=
1
;
}
// move part
if
(
old_position
!=
new_position
)
{
symbol
->
actions
.
add
(
new
ReorderSymbolPartsAction
(
*
symbol
,
old_position
,
new_position
));
}
else
{
Refresh
(
false
);
}
}
else
{
mouse_down_on
=
SymbolPartP
();
}
}
void
SymbolPartList
::
onMotion
(
wxMouseEvent
&
ev
)
{
if
(
mouse_down_on
)
{
int
new_drop_position
=
(
ev
.
GetY
()
+
ITEM_HEIGHT
/
2
)
/
(
ITEM_HEIGHT
+
1
);
if
(
new_drop_position
<
0
||
new_drop_position
>
number_of_items
)
new_drop_position
=
-
1
;
// TODO: make sure it is not in a group
if
(
drop_position
!=
new_drop_position
)
{
drop_position
=
new_drop_position
;
Refresh
(
false
);
}
}
}
void
SymbolPartList
::
onLeftDClick
(
wxMouseEvent
&
ev
)
{
// double click = activate
sendEvent
(
EVENT_PART_ACTIVATE
);
}
void
SymbolPartList
::
getSelectedParts
(
set
<
SymbolPartP
>&
sel
)
{
sel
.
clear
();
long
count
=
GetItemCount
();
for
(
long
i
=
0
;
i
<
count
;
++
i
)
{
bool
selected
=
GetItemState
(
i
,
wxLIST_STATE_SELECTED
);
if
(
selected
)
sel
.
insert
(
symbol
->
parts
.
at
(
i
));
void
SymbolPartList
::
onChar
(
wxKeyEvent
&
ev
)
{
if
(
typing_in
)
{
// Typing in name
String
new_name
=
typing_in
->
name
;
switch
(
ev
.
GetKeyCode
())
{
case
WXK_HOME
:
if
(
cursor
!=
0
)
{
cursor
=
0
;
Refresh
(
false
);
// TODO: without refresh
}
break
;
case
WXK_END
:
if
(
cursor
!=
typing_in
->
name
.
size
())
{
cursor
=
typing_in
->
name
.
size
();
Refresh
(
false
);
}
break
;
case
WXK_LEFT
:
if
(
cursor
>
0
)
{
--
cursor
;
Refresh
(
false
);
}
break
;
case
WXK_RIGHT
:
if
(
cursor
<
typing_in
->
name
.
size
())
{
++
cursor
;
Refresh
(
false
);
}
break
;
case
WXK_BACK
:
if
(
cursor
>
0
&&
cursor
<=
typing_in
->
name
.
size
())
{
String
new_name
=
typing_in
->
name
;
new_name
.
erase
(
cursor
-
1
,
1
);
symbol
->
actions
.
add
(
new
SymbolPartNameAction
(
typing_in
,
new_name
,
cursor
,
cursor
-
1
));
}
break
;
case
WXK_DELETE
:
if
(
cursor
<
typing_in
->
name
.
size
())
{
String
new_name
=
typing_in
->
name
;
new_name
.
erase
(
cursor
,
1
);
symbol
->
actions
.
add
(
new
SymbolPartNameAction
(
typing_in
,
new_name
,
cursor
,
cursor
));
}
break
;
default:
// See gui/value/text.cpp
#ifdef __WXMSW__
if
(
ev
.
GetKeyCode
()
>=
_
(
' '
)
&&
ev
.
GetKeyCode
()
==
(
int
)
ev
.
GetRawKeyCode
())
{
#else
if
(
ev
.
GetKeyCode
()
>=
_
(
' '
)
/*&& ev.GetKeyCode() == (int)ev.GetRawKeyCode()*/
)
{
#endif
#ifdef UNICODE
Char
key
=
ev
.
GetUnicodeKey
();
#else
Char
key
=
(
Char
)
ev
.
GetKeyCode
();
#endif
String
new_name
=
typing_in
->
name
;
new_name
.
insert
(
cursor
,
1
,
key
);
symbol
->
actions
.
add
(
new
SymbolPartNameAction
(
typing_in
,
new_name
,
cursor
,
cursor
+
1
));
}
}
}
// Move up/down?
}
void
SymbolPartList
::
selectParts
(
const
set
<
SymbolPartP
>&
sel
)
{
long
count
=
GetItemCount
();
for
(
long
i
=
0
;
i
<
count
;
++
i
)
{
// is that part selected?
bool
selected
=
sel
.
find
(
symbol
->
parts
.
at
(
i
))
!=
sel
.
end
();
SetItemState
(
i
,
selected
?
wxLIST_STATE_SELECTED
:
0
,
wxLIST_STATE_SELECTED
);
void
SymbolPartList
::
onSize
(
wxSizeEvent
&
)
{
Refresh
(
false
);
}
void
SymbolPartList
::
sendEvent
(
int
type
)
{
wxCommandEvent
ev
(
type
,
GetId
());
ProcessEvent
(
ev
);
}
// ----------------------------------------------------------------------------- : Items
SymbolPartP
SymbolPartList
::
findItem
(
int
i
)
const
{
FOR_EACH
(
p
,
symbol
->
parts
)
{
SymbolPartP
f
=
findItem
(
i
,
p
);
if
(
f
)
return
f
;
}
return
SymbolPartP
();
}
SymbolPartP
SymbolPartList
::
findItem
(
int
&
i
,
const
SymbolPartP
&
part
)
{
if
(
i
<
0
)
return
SymbolPartP
();
if
(
i
==
0
)
return
part
;
i
-=
1
;
// sub item?
if
(
SymbolGroup
*
g
=
part
->
isSymbolGroup
())
{
FOR_EACH
(
p
,
g
->
parts
)
{
if
(
findItem
(
i
,
p
))
return
part
;
}
}
return
SymbolPartP
();
}
void
SymbolPartList
::
update
(
)
{
if
(
symbol
->
parts
.
empty
())
{
// deleting all items requires a full refresh on win32
SetItemCount
(
0
);
Refresh
(
true
)
;
int
SymbolPartList
::
childCount
(
const
SymbolPartP
&
part
)
{
if
(
SymbolGroup
*
g
=
part
->
isSymbolGroup
())
{
int
count
=
0
;
FOR_EACH
(
p
,
g
->
parts
)
count
+=
1
+
childCount
(
p
);
return
count
;
}
else
{
SetItemCount
((
long
)
symbol
->
parts
.
size
()
);
Refresh
(
false
);
return
0
;
}
}
// ----------------------------------------------------------------------------- :
Event handling
// ----------------------------------------------------------------------------- :
Text editor
void
SymbolPartList
::
onSelect
(
wxListEvent
&
ev
)
{
selected
=
ev
.
GetIndex
();
ev
.
Skip
();
// ----------------------------------------------------------------------------- : Drawing
void
SymbolPartList
::
onPaint
(
wxPaintEvent
&
)
{
wxBufferedPaintDC
dc
(
this
);
DoPrepareDC
(
dc
);
OnDraw
(
dc
);
}
void
SymbolPartList
::
onDeselect
(
wxListEvent
&
ev
)
{
selected
=
-
1
;
ev
.
Skip
();
void
SymbolPartList
::
OnDraw
(
DC
&
dc
)
{
// init
dc
.
SetFont
(
*
wxNORMAL_FONT
);
// clear background
wxSize
size
=
GetClientSize
();
dc
.
SetPen
(
*
wxTRANSPARENT_PEN
);
dc
.
SetBrush
(
wxSystemSettings
::
GetColour
(
wxSYS_COLOUR_WINDOW
));
dc
.
DrawRectangle
(
0
,
0
,
size
.
x
,
size
.
y
);
// items
int
i
=
0
;
FOR_EACH
(
p
,
symbol
->
parts
)
{
drawItem
(
dc
,
0
,
i
,
false
,
p
);
}
// drag/drop indicator
if
(
mouse_down_on
&&
drop_position
!=
-
1
)
{
dc
.
SetPen
(
wxPen
(
wxSystemSettings
::
GetColour
(
wxSYS_COLOUR_WINDOWTEXT
),
3
));
int
y
=
drop_position
*
(
ITEM_HEIGHT
+
1
)
-
1
;
dc
.
DrawLine
(
0
,
y
,
size
.
x
,
y
);
dc
.
DrawLine
(
0
,
y
-
3
,
0
,
y
+
3
);
dc
.
DrawLine
(
size
.
x
-
1
,
y
-
3
,
size
.
x
-
1
,
y
+
3
);
}
// hide caret
if
(
selection
.
size
()
!=
1
)
{
typing_in
=
SymbolPartP
();
wxCaret
*
caret
=
GetCaret
();
if
(
caret
)
caret
->
Hide
();
}
}
void
SymbolPartList
::
onLabelEdit
(
wxListEvent
&
ev
){
symbol
->
actions
.
add
(
new
SymbolPartNameAction
(
getPart
(
ev
.
GetIndex
()),
ev
.
GetLabel
())
);
void
SymbolPartList
::
drawItem
(
DC
&
dc
,
int
x
,
int
&
i
,
bool
parent_active
,
const
SymbolPartP
&
part
)
{
wxSize
size
=
GetClientSize
();
int
w
=
size
.
x
-
x
;
int
y
=
i
*
(
ITEM_HEIGHT
+
1
);
// draw item : highlight
Color
background
;
dc
.
SetPen
(
*
wxTRANSPARENT_PEN
);
bool
active
=
selection
.
find
(
part
)
!=
selection
.
end
();
if
(
active
)
{
background
=
wxSystemSettings
::
GetColour
(
wxSYS_COLOUR_HIGHLIGHT
);
dc
.
SetBrush
(
background
);
dc
.
DrawRectangle
(
x
,
y
,
w
,
ITEM_HEIGHT
);
dc
.
SetTextForeground
(
wxSystemSettings
::
GetColour
(
wxSYS_COLOUR_HIGHLIGHTTEXT
));
}
else
if
(
parent_active
)
{
background
=
wxSystemSettings
::
GetColour
(
wxSYS_COLOUR_HIGHLIGHT
);
dc
.
SetTextForeground
(
wxSystemSettings
::
GetColour
(
wxSYS_COLOUR_WINDOWTEXT
));
}
else
{
background
=
wxSystemSettings
::
GetColour
(
wxSYS_COLOUR_WINDOW
);
dc
.
SetTextForeground
(
wxSystemSettings
::
GetColour
(
wxSYS_COLOUR_WINDOWTEXT
));
}
// draw item : name
int
h
=
dc
.
GetCharHeight
();
dc
.
DrawText
(
part
->
name
,
ITEM_HEIGHT
+
x
+
3
,
y
+
(
ITEM_HEIGHT
-
h
)
/
2
);
// draw item : icon
dc
.
SetBrush
(
lerp
(
background
,
wxColour
(
0
,
128
,
0
),
0.7
));
dc
.
DrawRectangle
(
x
,
y
,
ITEM_HEIGHT
,
ITEM_HEIGHT
);
dc
.
DrawBitmap
(
symbolPreview
(),
x
,
y
);
dc
.
DrawBitmap
(
itemPreview
(
i
,
part
),
x
,
y
);
// draw item : border
wxPen
line_pen
=
lerp
(
wxSystemSettings
::
GetColour
(
wxSYS_COLOUR_WINDOW
),
wxSystemSettings
::
GetColour
(
wxSYS_COLOUR_WINDOWTEXT
),
0.5
);
dc
.
SetPen
(
line_pen
);
dc
.
DrawLine
(
x
+
ITEM_HEIGHT
,
y
,
x
+
ITEM_HEIGHT
,
y
+
ITEM_HEIGHT
+
1
);
// line after image
dc
.
DrawLine
(
x
,
y
+
ITEM_HEIGHT
,
size
.
x
,
y
+
ITEM_HEIGHT
);
// line below
// update caret
if
(
selection
.
size
()
==
1
&&
active
)
{
updateCaret
(
dc
,
x
+
ITEM_HEIGHT
+
3
,
y
+
(
ITEM_HEIGHT
-
h
)
/
2
,
h
,
part
);
}
// move down
i
+=
1
;
// draw more?
if
(
SymbolShape
*
s
=
part
->
isSymbolShape
())
{
// combine state
state_icons
.
Draw
(
s
->
combine
,
dc
,
size
.
x
-
10
,
y
+
1
);
}
else
if
(
SymbolSymmetry
*
s
=
part
->
isSymbolSymmetry
())
{
// kind of symmetry
state_icons
.
Draw
(
s
->
kind
,
dc
,
size
.
x
-
10
,
y
+
1
);
// TODO: show clip mode?
}
else
if
(
SymbolGroup
*
g
=
part
->
isSymbolGroup
())
{
state_icons
.
Draw
(
SYMMETRY_REFLECTION
+
1
,
dc
,
size
.
x
-
10
,
y
+
1
);
FOR_EACH
(
p
,
g
->
parts
)
drawItem
(
dc
,
x
+
5
,
i
,
active
||
parent_active
,
p
);
// draw bar on the left
int
new_y
=
i
*
(
ITEM_HEIGHT
+
1
);
y
+=
ITEM_HEIGHT
+
1
;
if
(
y
!=
new_y
)
{
dc
.
SetPen
(
line_pen
);
dc
.
SetBrush
(
background
);
dc
.
DrawRectangle
(
x
-
1
,
y
-
1
,
5
+
1
,
new_y
-
y
+
1
);
}
}
else
{
throw
"Unknown symbol part type"
;
}
}
void
SymbolPartList
::
onSize
(
wxSizeEvent
&
ev
)
{
wxSize
s
=
GetClientSize
();
SetColumnWidth
(
0
,
s
.
GetWidth
()
-
2
);
const
Image
&
SymbolPartList
::
itemPreview
(
int
i
,
const
SymbolPartP
&
part
)
{
if
((
size_t
)
i
>=
part_previews
.
size
())
part_previews
.
resize
(
i
+
1
);
Preview
&
p
=
part_previews
[
i
];
if
(
!
p
.
up_to_date
)
{
SolidFillSymbolFilter
filter
(
*
wxBLACK
,
Color
(
255
,
128
,
128
));
// temporary symbol
SymbolP
sym
(
new
Symbol
);
sym
->
parts
.
push_back
(
part
);
Image
img
;
if
(
SymbolShape
*
s
=
part
->
isSymbolShape
())
{
if
(
s
->
combine
==
SYMBOL_COMBINE_SUBTRACT
)
{
// temporarily render using subtract instead, otherwise we don't see anything
s
->
combine
=
SYMBOL_COMBINE_BORDER
;
img
=
render_symbol
(
sym
,
filter
,
0.08
,
ITEM_HEIGHT
*
4
);
s
->
combine
=
SYMBOL_COMBINE_SUBTRACT
;
}
else
{
img
=
render_symbol
(
sym
,
filter
,
0.08
,
ITEM_HEIGHT
*
4
);
}
}
else
{
img
=
render_symbol
(
sym
,
filter
,
0.08
,
ITEM_HEIGHT
*
4
);
}
resample
(
img
,
p
.
image
);
p
.
up_to_date
=
true
;
}
return
p
.
image
;
}
const
Image
&
SymbolPartList
::
symbolPreview
()
{
if
(
!
symbol_preview
.
up_to_date
)
{
SolidFillSymbolFilter
filter
(
AColor
(
0
,
0
,
0
,
40
),
AColor
(
255
,
255
,
255
,
40
));
Image
img
=
render_symbol
(
symbol
,
filter
,
0.06
,
ITEM_HEIGHT
*
4
);
resample
(
img
,
symbol_preview
.
image
);
symbol_preview
.
up_to_date
=
true
;
}
return
symbol_preview
.
image
;
}
void
SymbolPartList
::
onDrag
(
wxMouseEvent
&
ev
)
{
if
(
!
ev
.
Dragging
()
||
selected
==
-
1
)
return
;
// reorder the list of parts
int
flags
;
long
item
=
HitTest
(
ev
.
GetPosition
(),
flags
);
if
(
flags
&
wxLIST_HITTEST_ONITEM
)
{
if
(
item
>
0
)
EnsureVisible
(
item
-
1
);
if
(
item
<
GetItemCount
()
-
1
)
EnsureVisible
(
item
+
1
);
if
(
item
!=
selected
)
{
// swap the two items
symbol
->
actions
.
add
(
new
ReorderSymbolPartsAction
(
*
symbol
,
item
,
selected
));
selectItem
(
item
);
// deselect all other items, to prevent 'lassoing' them
void
SymbolPartList
::
updateCaret
(
DC
&
dc
,
int
x
,
int
y
,
int
h
,
const
SymbolPartP
&
part
)
{
// make caret
wxCaret
*
caret
=
GetCaret
();
if
(
!
caret
)
{
caret
=
new
wxCaret
(
this
,
1
,
h
);
SetCaret
(
caret
);
}
// move caret
if
(
typing_in
!=
part
)
{
typing_in
=
part
;
cursor
=
typing_in
->
name
.
size
();
}
cursor
=
min
(
cursor
,
typing_in
->
name
.
size
());
int
w
;
dc
.
GetTextExtent
(
typing_in
->
name
.
substr
(
0
,
cursor
),
&
w
,
nullptr
);
caret
->
Move
(
x
+
w
,
y
);
if
(
!
caret
->
IsVisible
())
caret
->
Show
();
}
// ----------------------------------------------------------------------------- : Event table
BEGIN_EVENT_TABLE
(
SymbolPartList
,
wxListCtrl
)
EVT_LIST_ITEM_SELECTED
(
wxID_ANY
,
SymbolPartList
::
onSelect
)
EVT_LIST_ITEM_DESELECTED
(
wxID_ANY
,
SymbolPartList
::
onDeselect
)
EVT_LIST_END_LABEL_EDIT
(
wxID_ANY
,
SymbolPartList
::
onLabelEdit
)
EVT_SIZE
(
SymbolPartList
::
onSize
)
EVT_MOTION
(
SymbolPartList
::
onDrag
)
BEGIN_EVENT_TABLE
(
SymbolPartList
,
wxScrolledWindow
)
EVT_LEFT_DOWN
(
SymbolPartList
::
onLeftDown
)
EVT_LEFT_DCLICK
(
SymbolPartList
::
onLeftDClick
)
EVT_LEFT_UP
(
SymbolPartList
::
onLeftUp
)
EVT_MOTION
(
SymbolPartList
::
onMotion
)
EVT_CHAR
(
SymbolPartList
::
onChar
)
EVT_PAINT
(
SymbolPartList
::
onPaint
)
EVT_SIZE
(
SymbolPartList
::
onSize
)
END_EVENT_TABLE
()
src/gui/symbol/part_list.hpp
View file @
a56a8454
...
...
@@ -11,61 +11,80 @@
#include <util/prec.hpp>
#include <data/symbol.hpp>
#include <wx/listctrl.h>
// ----------------------------------------------------------------------------- :
SymbolPartList
// ----------------------------------------------------------------------------- :
Events
// A list view of parts of a symbol
class
SymbolPartList
:
public
wxListCtrl
,
public
SymbolView
{
public:
SymbolPartList
(
Window
*
parent
,
int
id
,
SymbolP
symbol
=
SymbolP
());
DECLARE_EVENT_TYPE
(
EVENT_PART_SELECT
,
<
not
used
>
)
DECLARE_EVENT_TYPE
(
EVENT_PART_ACTIVATE
,
<
not
used
>
)
/// Update the list
void
update
();
/// Handle EVENT_PART_SELECT events
#define EVT_PART_SELECT( id, handler) EVT_COMMAND(id, EVENT_PART_SELECT, handler)
/// Handle EVENT_PART_ACTIVATE events
#define EVT_PART_ACTIVATE(id, handler) EVT_COMMAND(id, EVENT_PART_ACTIVATE, handler)
/// Is there a selection?
inline
bool
hasSelection
()
const
{
return
selected
!=
-
1
;
}
/// Return the last part that was selected
/** @pre hasSelection()
*/
inline
SymbolPartP
getSelection
()
const
{
return
getPart
(
selected
);
}
// ----------------------------------------------------------------------------- : SymbolPartList
/// Get a set of selected parts
void
getSelectedParts
(
set
<
SymbolPartP
>&
sel
);
/// Select the specified parts, and nothing else
void
selectParts
(
const
set
<
SymbolPartP
>&
sel
);
class
SymbolPartList
:
public
wxScrolledWindow
,
public
SymbolView
{
public:
SymbolPartList
(
Window
*
parent
,
int
id
,
set
<
SymbolPartP
>&
selection
,
SymbolP
symbol
=
SymbolP
());
/// Another symbol is being viewed
void
onChangeSymbol
();
virtual
void
onChangeSymbol
();
/// Event handler for changes to the symbol
virtual
void
onAction
(
const
Action
&
a
,
bool
undone
);
virtual
void
onAction
(
const
Action
&
,
bool
);
protected:
/// Get the text of an item
virtual
String
OnGetItemText
(
long
item
,
long
col
)
const
;
/// Get the icon of an item
virtual
int
OnGetItemImage
(
long
item
)
const
;
/// Update the control
void
update
();
/// Update only a subset of the parts
void
updateParts
(
const
set
<
SymbolPartP
>&
parts
);
protected:
virtual
wxSize
DoGetBestSize
()
const
;
private:
/// The selected item, or -1 if there is no selection
long
selected
;
set
<
SymbolPartP
>&
selection
;
///< Store selection here
SymbolPartP
mouse_down_on
;
int
drop_position
;
int
number_of_items
;
/// Get a part from the symbol
SymbolPartP
getPart
(
long
item
)
const
;
SymbolPartP
typing_in
;
size_t
cursor
;
/// Select an item, also in the list control
/// Deselects all other items
void
selectItem
(
long
item
);
wxImageList
state_icons
;
struct
Preview
{
Preview
()
:
up_to_date
(
false
),
image
(
25
,
25
)
{}
bool
up_to_date
;
Image
image
;
};
Preview
symbol_preview
;
///< Preview of the whole symbol
vector
<
Preview
>
part_previews
;
static
const
int
ITEM_HEIGHT
=
25
;
// --------------------------------------------------- : Event handling
DECLARE_EVENT_TABLE
();
void
onSelect
(
wxListEvent
&
ev
);
void
onDeselect
(
wxListEvent
&
ev
);
void
onLabelEdit
(
wxListEvent
&
ev
);
void
onSize
(
wxSizeEvent
&
ev
);
void
onDrag
(
wxMouseEvent
&
ev
);
void
onLeftDown
(
wxMouseEvent
&
ev
);
void
onLeftDClick
(
wxMouseEvent
&
ev
);
void
onLeftUp
(
wxMouseEvent
&
ev
);
void
onMotion
(
wxMouseEvent
&
ev
);
void
onChar
(
wxKeyEvent
&
ev
);
void
onPaint
(
wxPaintEvent
&
);
void
onSize
(
wxSizeEvent
&
);
void
OnDraw
(
DC
&
dc
);
void
sendEvent
(
int
type
);
void
drawItem
(
DC
&
dc
,
int
x
,
int
&
i
,
bool
parent_active
,
const
SymbolPartP
&
part
);
const
Image
&
itemPreview
(
int
i
,
const
SymbolPartP
&
part
);
const
Image
&
symbolPreview
();
void
updatePart
(
const
set
<
SymbolPartP
>&
parts
,
int
&
i
,
bool
parent_updated
,
const
SymbolPartP
&
part
);
SymbolPartP
findItem
(
int
i
)
const
;
static
SymbolPartP
findItem
(
int
&
i
,
const
SymbolPartP
&
part
);
static
int
childCount
(
const
SymbolPartP
&
part
);
void
updateCaret
(
DC
&
dc
,
int
x
,
int
y
,
int
h
,
const
SymbolPartP
&
part
);
};
// ----------------------------------------------------------------------------- : EOF
...
...
src/gui/symbol/select_editor.cpp
View file @
a56a8454
...
...
@@ -37,11 +37,7 @@ SymbolSelectEditor::SymbolSelectEditor(SymbolControl* control, bool rotate)
handleShearY
=
wxBitmap
(
rotate_image
(
shear
,
90
));
handleCenter
=
wxBitmap
(
load_resource_image
(
_
(
"handle_center"
)));
// Make sure all parts have updated bounds
FOR_EACH
(
p
,
getSymbol
()
->
parts
)
{
if
(
SymbolShape
*
s
=
p
->
isSymbolShape
())
{
s
->
calculateBounds
();
}
}
getSymbol
()
->
calculateBounds
();
resetActions
();
}
...
...
@@ -132,24 +128,32 @@ void SymbolSelectEditor::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
void
SymbolSelectEditor
::
onUpdateUI
(
wxUpdateUIEvent
&
ev
)
{
if
(
ev
.
GetId
()
>=
ID_SYMBOL_COMBINE
&&
ev
.
GetId
()
<
ID_SYMBOL_COMBINE_MAX
)
{
if
(
control
.
selected_parts
.
empty
())
{
ev
.
Check
(
false
);
ev
.
Enable
(
false
);
}
else
{
ev
.
Enable
(
true
);
bool
enable
=
false
;
bool
check
=
true
;
FOR_EACH
(
p
,
control
.
selected_parts
)
{
if
(
SymbolShape
*
s
=
p
->
isSymbolShape
())
{
enable
=
true
;
if
(
s
->
combine
!=
ev
.
GetId
()
-
ID_SYMBOL_COMBINE
)
{
check
=
false
;
break
;
}
}
// disable when symmetries are selected?
}
ev
.
Check
(
check
);
}
ev
.
Enable
(
enable
);
ev
.
Check
(
enable
&&
check
);
}
else
if
(
ev
.
GetId
()
==
ID_EDIT_DUPLICATE
)
{
ev
.
Enable
(
!
control
.
selected_parts
.
empty
());
}
else
if
(
ev
.
GetId
()
==
ID_EDIT_GROUP
)
{
ev
.
Enable
(
control
.
selected_parts
.
size
()
>=
2
);
}
else
if
(
ev
.
GetId
()
==
ID_EDIT_UNGROUP
)
{
// is a group selected
FOR_EACH
(
p
,
control
.
selected_parts
)
{
if
(
p
->
isSymbolGroup
())
{
ev
.
Enable
(
true
);
return
;
}
}
ev
.
Enable
(
false
);
}
else
{
ev
.
Enable
(
false
);
// we don't know about this item
}
...
...
@@ -165,10 +169,15 @@ void SymbolSelectEditor::onCommand(int id) {
control
.
Refresh
(
false
);
}
else
if
(
id
==
ID_EDIT_DUPLICATE
&&
!
isEditing
())
{
// duplicate selection, not when dragging
DuplicateSymbolPartsAction
*
action
=
new
DuplicateSymbolPartsAction
(
*
getSymbol
(),
control
.
selected_parts
);
getSymbol
()
->
actions
.
add
(
action
);
getSymbol
()
->
actions
.
add
(
new
DuplicateSymbolPartsAction
(
*
getSymbol
(),
control
.
selected_parts
));
control
.
Refresh
(
false
);
}
else
if
(
id
==
ID_EDIT_GROUP
&&
!
isEditing
())
{
// group selection, not when dragging
getSymbol
()
->
actions
.
add
(
new
GroupSymbolPartsAction
(
*
getSymbol
(),
control
.
selected_parts
));
control
.
Refresh
(
false
);
}
else
if
(
id
==
ID_EDIT_UNGROUP
&&
!
isEditing
())
{
// ungroup selection, not when dragging
getSymbol
()
->
actions
.
add
(
new
UngroupSymbolPartsAction
(
*
getSymbol
(),
control
.
selected_parts
));
control
.
Refresh
(
false
);
}
}
...
...
@@ -383,6 +392,7 @@ void SymbolSelectEditor::onChar(wxKeyEvent& ev) {
if
(
ev
.
GetKeyCode
()
==
WXK_DELETE
)
{
// delete selected parts
getSymbol
()
->
actions
.
add
(
new
RemoveSymbolPartsAction
(
*
getSymbol
(),
control
.
selected_parts
));
if
(
control
.
selected_parts
.
find
(
highlightPart
)
!=
control
.
selected_parts
.
end
())
highlightPart
=
SymbolPartP
();
// deleted it
control
.
selected_parts
.
clear
();
resetActions
();
control
.
Refresh
(
false
);
...
...
@@ -441,15 +451,25 @@ double SymbolSelectEditor::angleTo(const Vector2D& pos) {
}
SymbolPartP
SymbolSelectEditor
::
findPart
(
const
Vector2D
&
pos
)
{
FOR_EACH
(
p
,
getSymbol
()
->
parts
)
{
if
(
SymbolShape
*
s
=
p
->
isSymbolShape
())
{
if
(
point_in_shape
(
pos
,
*
s
))
return
p
;
}
else
if
(
SymbolSymmetry
*
s
=
p
->
isSymbolSymmetry
())
{
SymbolPartP
find_part
(
const
SymbolPartP
&
part
,
const
Vector2D
&
pos
)
{
if
(
SymbolShape
*
s
=
part
->
isSymbolShape
())
{
if
(
point_in_shape
(
pos
,
*
s
))
return
part
;
}
else
if
(
SymbolSymmetry
*
s
=
part
->
isSymbolSymmetry
())
{
// TODO
}
else
if
(
SymbolGroup
*
g
=
part
->
isSymbolGroup
())
{
FOR_EACH
(
p
,
g
->
parts
)
{
if
(
find_part
(
p
,
pos
))
return
part
;
}
}
else
{
throw
InternalError
(
_
(
"Invalid symbol part type"
));
}
return
SymbolPartP
();
}
SymbolPartP
SymbolSelectEditor
::
findPart
(
const
Vector2D
&
pos
)
{
FOR_EACH
(
p
,
getSymbol
()
->
parts
)
{
SymbolPartP
found
=
find_part
(
p
,
pos
);
if
(
found
)
return
found
;
}
return
SymbolPartP
();
}
...
...
@@ -459,10 +479,8 @@ void SymbolSelectEditor::updateBoundingBox() {
minV
=
Vector2D
::
infinity
();
maxV
=
-
Vector2D
::
infinity
();
FOR_EACH
(
p
,
control
.
selected_parts
)
{
if
(
SymbolShape
*
s
=
p
->
isSymbolShape
())
{
minV
=
piecewise_min
(
minV
,
s
->
min_pos
);
maxV
=
piecewise_max
(
maxV
,
s
->
max_pos
);
}
minV
=
piecewise_min
(
minV
,
p
->
min_pos
);
maxV
=
piecewise_max
(
maxV
,
p
->
max_pos
);
}
/* // Find rotation center
center = Vector2D(0,0);
...
...
src/gui/symbol/window.cpp
View file @
a56a8454
...
...
@@ -74,6 +74,9 @@ void SymbolWindow::init(Window* parent, SymbolP symbol) {
menuEdit
->
Append
(
ID_EDIT_UNDO
,
_
(
"undo"
),
_MENU_1_
(
"undo"
,
wxEmptyString
),
_HELP_
(
"undo"
));
menuEdit
->
Append
(
ID_EDIT_REDO
,
_
(
"redo"
),
_MENU_1_
(
"redo"
,
wxEmptyString
),
_HELP_
(
"redo"
));
menuEdit
->
AppendSeparator
();
menuEdit
->
Append
(
ID_EDIT_GROUP
,
_
(
"group"
),
_MENU_
(
"group"
),
_HELP_
(
"group"
));
menuEdit
->
Append
(
ID_EDIT_UNGROUP
,
_
(
"ungroup"
),
_MENU_
(
"ungroup"
),
_HELP_
(
"ungroup"
));
menuEdit
->
AppendSeparator
();
menuEdit
->
Append
(
ID_EDIT_DUPLICATE
,
_
(
"duplicate"
),
_MENU_
(
"duplicate"
),
_HELP_
(
"duplicate"
));
menuBar
->
Append
(
menuEdit
,
_MENU_
(
"edit"
));
...
...
@@ -82,6 +85,7 @@ void SymbolWindow::init(Window* parent, SymbolP symbol) {
menuTool
->
Append
(
ID_MODE_ROTATE
,
_
(
"mode_rotate"
),
_MENU_
(
"rotate"
),
_HELP_
(
"rotate"
),
wxITEM_CHECK
);
menuTool
->
Append
(
ID_MODE_POINTS
,
_
(
"mode_curve"
),
_MENU_
(
"points"
),
_HELP_
(
"points"
),
wxITEM_CHECK
);
menuTool
->
Append
(
ID_MODE_SHAPES
,
_
(
"circle"
),
_MENU_
(
"basic shapes"
),
_HELP_
(
"basic shapes"
),
wxITEM_CHECK
);
menuTool
->
Append
(
ID_MODE_SYMMETRY
,
_
(
"mode_symmetry"
),
_MENU_
(
"symmetry"
),
_HELP_
(
"symmetry"
),
wxITEM_CHECK
);
menuTool
->
Append
(
ID_MODE_PAINT
,
_
(
"mode_paint"
),
_MENU_
(
"paint"
),
_HELP_
(
"paint"
),
wxITEM_CHECK
);
menuBar
->
Append
(
menuTool
,
_MENU_
(
"tool"
));
...
...
@@ -118,11 +122,11 @@ void SymbolWindow::init(Window* parent, SymbolP symbol) {
// Controls
control
=
new
SymbolControl
(
this
,
ID_CONTROL
,
symbol
);
parts
=
new
SymbolPartList
(
this
,
ID_PART_LIST
,
symbol
);
parts
=
new
SymbolPartList
(
this
,
ID_PART_LIST
,
control
->
selected_parts
,
symbol
);
// Lay out
wxSizer
*
es
=
new
wxBoxSizer
(
wxHORIZONTAL
);
es
->
Add
(
em
,
0
,
wxEXPAND
|
wxTOP
|
wxBOTTOM
|
wxALIGN_CENTER
,
1
);
es
->
Add
(
em
,
1
,
wxEXPAND
|
wxTOP
|
wxBOTTOM
|
wxALIGN_CENTER
,
1
);
emp
->
SetSizer
(
es
);
wxSizer
*
s
=
new
wxBoxSizer
(
wxHORIZONTAL
);
...
...
@@ -246,21 +250,21 @@ void SymbolWindow::onUpdateUI(wxUpdateUIEvent& ev) {
}
void
SymbolWindow
::
onSelectFromList
(
wx
List
Event
&
ev
)
{
void
SymbolWindow
::
onSelectFromList
(
wx
Command
Event
&
ev
)
{
if
(
inSelectionEvent
)
return
;
inSelectionEvent
=
true
;
parts
->
getSelectedParts
(
control
->
selected_parts
);
control
->
onUpdateSelection
();
inSelectionEvent
=
false
;
}
void
SymbolWindow
::
onActivateFromList
(
wxListEvent
&
ev
)
{
control
->
activatePart
(
control
->
getSymbol
()
->
parts
.
at
(
ev
.
GetIndex
()));
void
SymbolWindow
::
onActivateFromList
(
wxCommandEvent
&
ev
)
{
//% control->activatePart(control->getSymbol()->parts.at(ev.GetIndex()));
// TODO
}
void
SymbolWindow
::
onSelectFromControl
()
{
if
(
inSelectionEvent
)
return
;
inSelectionEvent
=
true
;
parts
->
selectParts
(
control
->
selected_parts
);
parts
->
Refresh
(
false
);
inSelectionEvent
=
false
;
}
...
...
@@ -280,7 +284,6 @@ BEGIN_EVENT_TABLE(SymbolWindow, wxFrame)
EVT_TOOL_RANGE
(
ID_CHILD_MIN
,
ID_CHILD_MAX
,
SymbolWindow
::
onExtraTool
)
EVT_UPDATE_UI
(
wxID_ANY
,
SymbolWindow
::
onUpdateUI
)
EVT_LIST_ITEM_SELECTED
(
ID_PART_LIST
,
SymbolWindow
::
onSelectFromList
)
EVT_LIST_ITEM_DESELECTED
(
ID_PART_LIST
,
SymbolWindow
::
onSelectFromList
)
EVT_LIST_ITEM_ACTIVATED
(
ID_PART_LIST
,
SymbolWindow
::
onActivateFromList
)
EVT_PART_SELECT
(
ID_PART_LIST
,
SymbolWindow
::
onSelectFromList
)
EVT_PART_ACTIVATE
(
ID_PART_LIST
,
SymbolWindow
::
onActivateFromList
)
END_EVENT_TABLE
()
src/gui/symbol/window.hpp
View file @
a56a8454
...
...
@@ -14,6 +14,7 @@
#include <wx/listctrl.h>
class
SymbolControl
;
//%%class SymbolPartList;
class
SymbolPartList
;
DECLARE_POINTER_TYPE
(
SymbolValue
);
DECLARE_POINTER_TYPE
(
Set
);
...
...
@@ -62,9 +63,9 @@ class SymbolWindow : public Frame {
void
onUpdateUI
(
wxUpdateUIEvent
&
);
/// Changing selected parts in the list
void
onSelectFromList
(
wx
List
Event
&
ev
);
void
onSelectFromList
(
wx
Command
Event
&
ev
);
/// Activating a part: open the point editor
void
onActivateFromList
(
wx
List
Event
&
ev
);
void
onActivateFromList
(
wx
Command
Event
&
ev
);
bool
inSelectionEvent
;
///< Prevent recursion in onSelect...
...
...
src/main.cpp
View file @
a56a8454
...
...
@@ -96,6 +96,10 @@ bool MSE::OnInit() {
// Installer; install it
Installer
::
installFrom
(
argv
[
1
],
true
);
return
false
;
}
else
if
(
arg
==
_
(
"--symbol-editor"
))
{
Window
*
wnd
=
new
SymbolWindow
(
nullptr
);
wnd
->
Show
();
return
true
;
}
else
if
(
arg
==
_
(
"--create-installer"
))
{
// create an installer
Installer
inst
;
...
...
src/render/symbol/filter.cpp
View file @
a56a8454
...
...
@@ -12,6 +12,29 @@
#include <util/error.hpp>
#include <script/value.hpp> // for some strange reason the profile build needs this :(
// ----------------------------------------------------------------------------- : Color
template
<>
void
GetDefaultMember
::
handle
(
const
AColor
&
col
)
{
handle
((
const
Color
&
)
col
);
}
template
<>
void
Reader
::
handle
(
AColor
&
col
)
{
UInt
r
,
g
,
b
,
a
;
if
(
wxSscanf
(
getValue
().
c_str
(),
_
(
"rgb(%u,%u,%u)"
),
&
r
,
&
g
,
&
b
))
{
col
.
Set
(
r
,
g
,
b
);
col
.
alpha
=
255
;
}
else
if
(
wxSscanf
(
getValue
().
c_str
(),
_
(
"rgba(%u,%u,%u,%u)"
),
&
r
,
&
g
,
&
b
,
&
a
))
{
col
.
Set
(
r
,
g
,
b
);
col
.
alpha
=
a
;
}
}
template
<>
void
Writer
::
handle
(
const
AColor
&
col
)
{
if
(
col
.
alpha
==
255
)
{
handle
(
String
::
Format
(
_
(
"rgb(%u,%u,%u)"
),
col
.
Red
(),
col
.
Green
(),
col
.
Blue
()));
}
else
{
handle
(
String
::
Format
(
_
(
"rgba(%u,%u,%u,%u)"
),
col
.
Red
(),
col
.
Green
(),
col
.
Blue
(),
col
.
alpha
));
}
}
// ----------------------------------------------------------------------------- : Symbol filtering
void
filter_symbol
(
Image
&
symbol
,
const
SymbolFilter
&
filter
)
{
...
...
src/render/symbol/filter.hpp
View file @
a56a8454
...
...
@@ -20,9 +20,10 @@ class SymbolFilter;
/// Color with alpha channel
class
AColor
:
public
Color
{
public:
int
alpha
;
///< The alpha value, in the range [0..255]
inline
AColor
(
int
r
,
int
g
,
int
b
,
int
a
=
255
)
:
Color
(
r
,
g
,
b
),
alpha
(
a
)
{}
inline
AColor
(
const
Color
&
color
,
int
a
=
255
)
:
Color
(
color
),
alpha
(
a
)
{}
Byte
alpha
;
///< The alpha value, in the range [0..255]
inline
AColor
()
:
alpha
(
0
)
{}
inline
AColor
(
Byte
r
,
Byte
g
,
Byte
b
,
Byte
a
=
255
)
:
Color
(
r
,
g
,
b
),
alpha
(
a
)
{}
inline
AColor
(
const
Color
&
color
,
Byte
a
=
255
)
:
Color
(
color
),
alpha
(
a
)
{}
};
// ----------------------------------------------------------------------------- : Symbol filtering
...
...
@@ -69,14 +70,14 @@ intrusive_ptr<SymbolFilter> read_new<SymbolFilter>(Reader& reader);
class
SolidFillSymbolFilter
:
public
SymbolFilter
{
public:
inline
SolidFillSymbolFilter
()
{}
inline
SolidFillSymbolFilter
(
Color
fill_color
,
Color
border_color
)
inline
SolidFillSymbolFilter
(
const
AColor
&
fill_color
,
const
AColor
&
border_color
)
:
fill_color
(
fill_color
),
border_color
(
border_color
)
{}
virtual
AColor
color
(
double
x
,
double
y
,
SymbolSet
point
)
const
;
virtual
String
fillType
()
const
;
virtual
bool
operator
==
(
const
SymbolFilter
&
that
)
const
;
private:
Color
fill_color
,
border_color
;
A
Color
fill_color
,
border_color
;
DECLARE_REFLECTION
();
};
...
...
src/render/symbol/viewer.cpp
View file @
a56a8454
...
...
@@ -72,10 +72,8 @@ void SymbolViewer::draw(DC& dc) {
}
}
}
// Draw all parts, in reverse order (bottom to top)
FOR_EACH_REVERSE
(
p
,
symbol
->
parts
)
{
combineSymbolPart
(
dc
,
*
p
,
paintedSomething
,
buffersFilled
,
borderDC
,
interiorDC
);
}
// Draw all parts
combineSymbolPart
(
dc
,
*
symbol
,
paintedSomething
,
buffersFilled
,
borderDC
,
interiorDC
);
// Output the final parts from the buffer
if
(
buffersFilled
)
{
...
...
@@ -118,7 +116,8 @@ void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paint
}
else
if
(
const
SymbolSymmetry
*
s
=
part
.
isSymbolSymmetry
())
{
// symmetry, already handled above
}
else
if
(
const
SymbolGroup
*
g
=
part
.
isSymbolGroup
())
{
FOR_EACH_CONST
(
p
,
g
->
parts
)
{
// Draw all parts, in reverse order (bottom to top)
FOR_EACH_CONST_REVERSE
(
p
,
g
->
parts
)
{
combineSymbolPart
(
dc
,
*
p
,
paintedSomething
,
buffersFilled
,
borderDC
,
interiorDC
);
}
}
...
...
@@ -147,6 +146,10 @@ void SymbolViewer::highlightPart(DC& dc, const SymbolShape& shape, HighlightStyl
dc
.
SetBrush
(
*
wxTRANSPARENT_BRUSH
);
dc
.
SetPen
(
wxPen
(
Color
(
255
,
0
,
0
),
2
));
dc
.
DrawPolygon
((
int
)
points
.
size
(),
&
points
[
0
]);
}
else
if
(
style
==
HIGHLIGHT_BORDER_DOT
)
{
dc
.
SetBrush
(
*
wxTRANSPARENT_BRUSH
);
dc
.
SetPen
(
wxPen
(
Color
(
255
,
0
,
0
),
1
,
wxDOT
));
dc
.
DrawPolygon
((
int
)
points
.
size
(),
&
points
[
0
]);
}
else
{
dc
.
SetLogicalFunction
(
wxOR
);
dc
.
SetBrush
(
Color
(
0
,
0
,
64
));
...
...
@@ -164,8 +167,13 @@ void SymbolViewer::highlightPart(DC& dc, const SymbolSymmetry& sym) {
// TODO
}
void
SymbolViewer
::
highlightPart
(
DC
&
dc
,
const
SymbolGroup
&
group
,
HighlightStyle
style
)
{
if
(
style
==
HIGHLIGHT_BORDER
)
{
dc
.
SetBrush
(
*
wxTRANSPARENT_BRUSH
);
dc
.
SetPen
(
wxPen
(
Color
(
255
,
0
,
0
),
2
));
dc
.
DrawRectangle
(
rotation
.
tr
(
RealRect
(
group
.
min_pos
,
RealSize
(
group
.
max_pos
-
group
.
min_pos
))));
}
FOR_EACH_CONST
(
part
,
group
.
parts
)
{
highlightPart
(
dc
,
*
part
,
style
);
highlightPart
(
dc
,
*
part
,
(
HighlightStyle
)(
style
|
HIGHLIGHT_LESS
)
);
}
}
...
...
src/render/symbol/viewer.hpp
View file @
a56a8454
...
...
@@ -21,9 +21,11 @@ Image render_symbol(const SymbolP& symbol, double border_radius = 0.05, int size
// ----------------------------------------------------------------------------- : Symbol Viewer
enum
HighlightStyle
{
HIGHLIGHT_BORDER
,
HIGHLIGHT_INTERIOR
enum
HighlightStyle
{
HIGHLIGHT_BORDER
=
0x01
,
HIGHLIGHT_INTERIOR
=
0x02
,
HIGHLIGHT_LESS
=
0x10
,
HIGHLIGHT_BORDER_DOT
=
HIGHLIGHT_BORDER
|
HIGHLIGHT_LESS
};
/// Class that knows how to draw a symbol
...
...
src/resource/msw/mse.rc
View file @
a56a8454
...
...
@@ -87,10 +87,13 @@ tool/mode_select IMAGE "tool/mode_select.png"
tool/mode_rotate IMAGE "tool/mode_rotate.png"
tool/mode_curve IMAGE "tool/mode_curve.png"
tool/mode_paint IMAGE "tool/mode_paint.png"
tool/mode_symmetry IMAGE "tool/mode_symmetry.png"
tool/apply IMAGE "tool/apply.png"
tool/duplicate IMAGE "tool/duplicate.png"
tool/grid IMAGE "tool/grid.png"
tool/grid_snap IMAGE "tool/grid_snap.png"
tool/group IMAGE "tool/group.png"
tool/ungroup IMAGE "tool/ungroup.png"
combine_or IMAGE "../common/combine_or.png"
combine_sub IMAGE "../common/combine_sub.png"
...
...
@@ -102,6 +105,17 @@ combine_over IMAGE "../common/combine_over.png"
combine_border IMAGE "../common/combine_border.png"
symmetry_rotation IMAGE "../common/symmetry_rotation.png"
symmetry_reflection IMAGE "../common/symmetry_reflection.png"
symbol_group IMAGE "../common/symbol_group.png"
icon_combine_merge IMAGE "../common/icon_combine_merge.png"
icon_combine_subtract IMAGE "../common/icon_combine_subtract.png"
icon_combine_intersection IMAGE "../common/icon_combine_intersection.png"
icon_combine_difference IMAGE "../common/icon_combine_difference.png"
icon_combine_overlap IMAGE "../common/icon_combine_overlap.png"
icon_combine_border IMAGE "../common/icon_combine_border.png"
icon_symmetry_rotation IMAGE "../common/icon_symmetry_rotation.png"
icon_symmetry_reflection IMAGE "../common/icon_symmetry_reflection.png"
icon_symbol_group IMAGE "../common/icon_symbol_group.png"
handle_rotate IMAGE "../common/handle_rotate.png"
handle_shear_x IMAGE "../common/handle_shear_x.png"
...
...
src/resource/msw/tool/group.png
0 → 100644
View file @
a56a8454
149 Bytes
src/resource/msw/tool/mode_symmetry.png
0 → 100644
View file @
a56a8454
146 Bytes
src/resource/msw/tool/ungroup.png
0 → 100644
View file @
a56a8454
148 Bytes
src/util/real_point.hpp
View file @
a56a8454
...
...
@@ -37,7 +37,14 @@ class RealSize {
:
width
(
w
),
height
(
h
)
{}
inline
RealSize
(
wxSize
s
)
:
width
(
s
.
GetWidth
()),
height
(
s
.
GetHeight
())
:
width
(
s
.
x
),
height
(
s
.
y
)
{}
inline
explicit
RealSize
(
const
Vector2D
&
v
)
:
width
(
v
.
x
),
height
(
v
.
y
)
{}
/// size of an image
inline
explicit
RealSize
(
const
wxImage
&
img
)
:
width
(
img
.
GetWidth
()),
height
(
img
.
GetHeight
())
{}
/// Negation of a size, negates both components
...
...
src/util/vector2d.hpp
View file @
a56a8454
...
...
@@ -74,15 +74,6 @@ class Vector2D {
x
/=
r
;
y
/=
r
;
}
/// Inner product with another vector
inline
double
dot
(
Vector2D
p2
)
const
{
return
(
x
*
p2
.
x
)
+
(
y
*
p2
.
y
);
}
/// Outer product with another vector
inline
double
cross
(
Vector2D
p2
)
const
{
return
(
x
*
p2
.
y
)
-
(
y
*
p2
.
x
);
}
/// Piecewise multiplication
inline
Vector2D
mul
(
Vector2D
p2
)
{
return
Vector2D
(
x
*
p2
.
x
,
y
*
p2
.
y
);
...
...
@@ -92,11 +83,6 @@ class Vector2D {
return
Vector2D
(
x
/
p2
.
x
,
y
/
p2
.
y
);
}
/// Apply a 'matrix' to this vector
inline
Vector2D
mul
(
Vector2D
mx
,
Vector2D
my
)
{
return
Vector2D
(
dot
(
mx
),
dot
(
my
));
}
/// Returns the square of the length of this vector
inline
double
lengthSqr
()
const
{
return
x
*
x
+
y
*
y
;
...
...
@@ -106,7 +92,7 @@ class Vector2D {
return
sqrt
(
lengthSqr
());
}
/// Returns a normalized version of this vector
/
// i.e. length() == 1
/
** i.e. length() == 1 */
inline
Vector2D
normalized
()
const
{
return
*
this
/
length
();
}
...
...
@@ -122,6 +108,15 @@ class Vector2D {
}
};
/// Inner product of two vectors
inline
double
dot
(
const
Vector2D
&
a
,
const
Vector2D
&
b
)
{
return
(
a
.
x
*
b
.
x
)
+
(
a
.
y
*
b
.
y
);
}
/// Length of the outer product of two vectors
inline
double
cross
(
const
Vector2D
&
a
,
const
Vector2D
&
b
)
{
return
(
a
.
x
*
b
.
y
)
-
(
a
.
y
*
b
.
x
);
}
/// Piecewise minimum
inline
Vector2D
piecewise_min
(
const
Vector2D
&
a
,
const
Vector2D
&
b
)
{
return
Vector2D
(
...
...
@@ -140,6 +135,23 @@ inline Vector2D piecewise_max(const Vector2D& a, const Vector2D& b) {
inline
Vector2D
operator
*
(
double
a
,
const
Vector2D
&
b
)
{
return
b
*
a
;
}
// ----------------------------------------------------------------------------- : Matrix2D
/// A two dimensional transformation matrix, simply two vectors
class
Matrix2D
{
public:
Vector2D
mx
,
my
;
inline
Matrix2D
()
{}
inline
Matrix2D
(
const
Vector2D
&
mx
,
const
Vector2D
&
my
)
:
mx
(
mx
),
my
(
my
)
{}
inline
Matrix2D
(
double
a
,
double
b
,
double
c
,
double
d
)
:
mx
(
a
,
b
),
my
(
c
,
d
)
{}
};
/// vector-matrix product
inline
Vector2D
operator
*
(
const
Vector2D
&
a
,
const
Matrix2D
&
m
)
{
return
Vector2D
(
dot
(
a
,
m
.
mx
),
dot
(
a
,
m
.
my
));
}
// ----------------------------------------------------------------------------- : EOF
#endif
src/util/window_id.hpp
View file @
a56a8454
...
...
@@ -76,6 +76,7 @@ enum MenuID {
,
ID_MODE_ROTATE
,
ID_MODE_POINTS
,
ID_MODE_SHAPES
,
ID_MODE_SYMMETRY
,
ID_MODE_PAINT
,
ID_MODE_MAX
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment