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
be2222ca
Commit
be2222ca
authored
Dec 05, 2006
by
twanvl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Partially working text editor
parent
b108304f
Changes
18
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
1138 additions
and
47 deletions
+1138
-47
src/data/action/value.cpp
src/data/action/value.cpp
+86
-5
src/data/action/value.hpp
src/data/action/value.hpp
+20
-16
src/data/field/text.hpp
src/data/field/text.hpp
+6
-0
src/data/symbol_font.hpp
src/data/symbol_font.hpp
+1
-0
src/gui/control/card_editor.cpp
src/gui/control/card_editor.cpp
+5
-1
src/gui/value/text.cpp
src/gui/value/text.cpp
+592
-2
src/gui/value/text.hpp
src/gui/value/text.hpp
+103
-1
src/render/text/viewer.cpp
src/render/text/viewer.cpp
+52
-13
src/render/text/viewer.hpp
src/render/text/viewer.hpp
+18
-2
src/render/value/text.hpp
src/render/value/text.hpp
+1
-1
src/render/value/viewer.cpp
src/render/value/viewer.cpp
+4
-1
src/util/action_stack.cpp
src/util/action_stack.cpp
+1
-1
src/util/action_stack.hpp
src/util/action_stack.hpp
+1
-1
src/util/rotation.hpp
src/util/rotation.hpp
+3
-0
src/util/string.cpp
src/util/string.cpp
+4
-0
src/util/string.hpp
src/util/string.hpp
+3
-0
src/util/tagged_string.cpp
src/util/tagged_string.cpp
+213
-0
src/util/tagged_string.hpp
src/util/tagged_string.hpp
+25
-3
No files found.
src/data/action/value.cpp
View file @
be2222ca
...
...
@@ -14,6 +14,7 @@
#include <data/field/color.hpp>
#include <data/field/image.hpp>
#include <data/field/symbol.hpp>
#include <util/tagged_string.hpp>
// ----------------------------------------------------------------------------- : ValueAction
...
...
@@ -35,16 +36,14 @@ class SimpleValueAction : public ValueAction {
swap
(
static_cast
<
T
&>
(
*
valueP
).
*
member
,
new_value
);
}
virtual
bool
merge
(
const
Action
*
action
)
{
virtual
bool
merge
(
const
Action
&
action
)
{
if
(
!
ALLOW_MERGE
)
return
false
;
if
(
const
SimpleValueAction
*
sva
=
dynamic_cast
<
const
SimpleValueAction
*>
(
action
)
)
{
if
(
sva
->
valueP
==
valueP
)
{
TYPE_CASE
(
action
,
SimpleValueAction
)
{
if
(
action
.
valueP
==
valueP
)
{
// adjacent actions on the same value, discard the other one,
// because it only keeps an intermediate value
return
true
;
}
}
else
{
return
false
;
}
return
false
;
}
...
...
@@ -60,3 +59,85 @@ ValueAction* value_action(const SymbolValueP& value, const FileName&
// ----------------------------------------------------------------------------- : Text
TextValueAction
::
TextValueAction
(
const
TextValueP
&
value
,
size_t
start
,
size_t
end
,
size_t
new_end
,
const
Defaultable
<
String
>&
new_value
,
const
String
&
name
)
:
ValueAction
(
value
),
new_value
(
new_value
),
name
(
name
)
,
selection_start
(
start
),
selection_end
(
end
),
new_selection_end
(
new_end
)
{}
String
TextValueAction
::
getName
(
bool
to_undo
)
const
{
return
name
;
}
void
TextValueAction
::
perform
(
bool
to_undo
)
{
swap
(
value
().
value
,
new_value
);
// if (value().value.age < new_value.age) value().value.age = Age();
swap
(
selection_end
,
new_selection_end
);
}
bool
TextValueAction
::
merge
(
const
Action
&
action
)
{
TYPE_CASE
(
action
,
TextValueAction
)
{
if
(
&
action
.
value
()
==
&
value
()
&&
action
.
name
==
name
&&
action
.
selection_start
==
selection_end
)
{
// adjacent edits, keep old value of this, it is older
selection_end
=
action
.
selection_end
;
return
true
;
}
}
return
false
;
}
TextValue
&
TextValueAction
::
value
()
const
{
return
static_cast
<
TextValue
&>
(
*
valueP
);
}
TextValueAction
*
toggle_format_action
(
const
TextValueP
&
value
,
const
String
&
tag
,
size_t
start
,
size_t
end
,
const
String
&
action_name
)
{
if
(
start
>
end
)
swap
(
start
,
end
);
String
new_value
;
const
String
&
str
=
value
->
value
();
// Are we inside the tag we are toggling?
size_t
tagpos
=
in_tag
(
str
,
_
(
"<"
)
+
tag
,
start
,
end
);
if
(
tagpos
==
String
::
npos
)
{
// we are not inside this tag, add it
new_value
=
str
.
substr
(
0
,
start
);
new_value
+=
_
(
"<"
)
+
tag
+
_
(
">"
);
new_value
+=
str
.
substr
(
start
,
end
-
start
);
new_value
+=
_
(
"</"
)
+
tag
+
_
(
">"
);
new_value
+=
str
.
substr
(
end
);
}
else
{
// we are inside this tag, _('remove') it
new_value
=
str
.
substr
(
0
,
start
);
new_value
+=
_
(
"</"
)
+
tag
+
_
(
">"
);
new_value
+=
str
.
substr
(
start
,
end
-
start
);
new_value
+=
_
(
"<"
)
+
tag
+
_
(
">"
);
new_value
+=
str
.
substr
(
end
);
}
// Build action
if
(
start
!=
end
)
{
// don't simplify if start == end, this way we insert <b></b>, allowing the
// user to press Ctrl+B and start typing bold text
new_value
=
simplify_tagged
(
new_value
);
}
if
(
value
->
value
()
==
new_value
)
{
return
nullptr
;
// no changes
}
else
{
return
new
TextValueAction
(
value
,
start
,
end
,
end
,
new_value
,
action_name
);
}
}
TextValueAction
*
typing_action
(
const
TextValueP
&
value
,
size_t
start
,
size_t
end
,
const
String
&
replacement
,
const
String
&
action_name
)
{
bool
reverse
=
start
>
end
;
if
(
reverse
)
swap
(
start
,
end
);
String
new_value
=
tagged_substr_replace
(
value
->
value
(),
start
,
end
,
replacement
);
if
(
value
->
value
()
==
new_value
)
{
// no change
return
nullptr
;
}
else
{
// if (name == _("Backspace")) {
// // HACK: put start after end
if
(
reverse
)
{
return
new
TextValueAction
(
value
,
end
,
start
,
start
+
replacement
.
size
(),
new_value
,
action_name
);
}
else
{
return
new
TextValueAction
(
value
,
start
,
end
,
start
+
replacement
.
size
(),
new_value
,
action_name
);
}
}
}
src/data/action/value.hpp
View file @
be2222ca
...
...
@@ -37,18 +37,9 @@ class ValueAction : public Action {
const
ValueP
valueP
;
///< The modified value
};
/// Utility macro for declaring classes derived from ValueAction
#define DECLARE_VALUE_ACTION(Type) \
protected
:
\
inline
Type
##
Value
&
value
()
const
{
\
return
static_cast
<
Type
##
Value
&>
(
*
valueP
);
\
}
\
public
:
\
virtual
void
perform
(
bool
to_undo
)
// ----------------------------------------------------------------------------- : Simple
/// Action that updates a Value to a new value
ValueAction
*
value_action
(
const
ChoiceValueP
&
value
,
const
Defaultable
<
String
>&
new_value
);
ValueAction
*
value_action
(
const
ColorValueP
&
value
,
const
Defaultable
<
Color
>&
new_value
);
ValueAction
*
value_action
(
const
ImageValueP
&
value
,
const
FileName
&
new_value
);
...
...
@@ -56,17 +47,30 @@ ValueAction* value_action(const SymbolValueP& value, const FileName&
// ----------------------------------------------------------------------------- : Text
/
*
class
Color
ValueAction : public ValueAction {
/
// An action that changes a TextValue
class
Text
ValueAction
:
public
ValueAction
{
public:
ColorValueAction(const ColorValueP& value, const Defaultable<Color>& color
);
TextValueAction
(
const
TextValueP
&
value
,
size_t
start
,
size_t
end
,
size_t
new_end
,
const
Defaultable
<
String
>&
new_value
,
const
String
&
name
);
DECLARE_VALUE_ACTION(Color);
virtual
String
getName
(
bool
to_undo
)
const
;
virtual
void
perform
(
bool
to_undo
);
virtual
bool
merge
(
const
Action
&
action
);
/// The modified selection
size_t
selection_start
,
selection_end
;
private:
Defaultable<Color> color; ///< The new/old color
inline
TextValue
&
value
()
const
;
size_t
new_selection_end
;
Defaultable
<
String
>
new_value
;
String
name
;
};
*/
/// Action for toggleing some formating tag on or off in some range
TextValueAction
*
toggle_format_action
(
const
TextValueP
&
value
,
const
String
&
tag
,
size_t
start
,
size_t
end
,
const
String
&
action_name
);
/// Typing in a TextValue, replace the selection [start...end) with replacement
TextValueAction
*
typing_action
(
const
TextValueP
&
value
,
size_t
start
,
size_t
end
,
const
String
&
replacement
,
const
String
&
action_name
);
// ----------------------------------------------------------------------------- : EOF
#endif
src/data/field/text.hpp
View file @
be2222ca
...
...
@@ -11,6 +11,7 @@
#include <util/prec.hpp>
#include <util/defaultable.hpp>
#include <util/rotation.hpp>
#include <data/field.hpp>
#include <data/font.hpp>
#include <data/symbol_font.hpp>
...
...
@@ -68,6 +69,11 @@ class TextStyle : public Style {
virtual
bool
update
(
Context
&
);
virtual
void
initDependencies
(
Context
&
,
const
Dependency
&
)
const
;
/// The rotation to use when drawing
inline
Rotation
getRotation
()
const
{
return
Rotation
(
angle
,
getRect
());
}
private:
DECLARE_REFLECTION
();
};
...
...
src/data/symbol_font.hpp
View file @
be2222ca
...
...
@@ -76,6 +76,7 @@ class SymbolFont : public Packaged {
/// Size of a single symbol
RealSize
symbolSize
(
Context
&
ctx
,
double
font_size
,
const
DrawableSymbol
&
sym
);
public:
/// Size of the default symbol
RealSize
defaultSymbolSize
(
Context
&
ctx
,
double
font_size
);
...
...
src/gui/control/card_editor.cpp
View file @
be2222ca
...
...
@@ -12,6 +12,7 @@
#include <data/field.hpp>
#include <data/stylesheet.hpp>
#include <data/settings.hpp>
#include <wx/caret.h>
DECLARE_TYPEOF_COLLECTION
(
ValueViewerP
);
DECLARE_TYPEOF_COLLECTION
(
ValueViewer
*
);
...
...
@@ -22,7 +23,10 @@ DataEditor::DataEditor(Window* parent, int id, long style)
:
CardViewer
(
parent
,
id
,
style
)
,
current_viewer
(
nullptr
)
,
current_editor
(
nullptr
)
{}
{
// Create a caret
SetCaret
(
new
wxCaret
(
this
,
1
,
1
));
}
ValueViewerP
DataEditor
::
makeViewer
(
const
StyleP
&
style
)
{
return
style
->
makeEditor
(
*
this
,
style
);
...
...
src/gui/value/text.cpp
View file @
be2222ca
This diff is collapsed.
Click to expand it.
src/gui/value/text.hpp
View file @
be2222ca
...
...
@@ -13,14 +13,116 @@
#include <gui/value/editor.hpp>
#include <render/value/text.hpp>
class
TextValueEditorScrollBar
;
// ----------------------------------------------------------------------------- : TextValueEditor
/// Directions of cursor movement
enum
Movement
{
MOVE_LEFT
///< Always move the cursor to the left
,
MOVE_MID
///< Move in whichever direction the distance to move is shorter (TODO: define shorter)
,
MOVE_RIGHT
///< Always move the cursor to the right
};
/// An editor 'control' for editing TextValues
/** Okay, this class responds to pretty much every event available... :)
*/
class
TextValueEditor
:
public
TextValueViewer
,
public
ValueEditor
{
public:
DECLARE_VALUE_EDITOR
(
Text
);
~
TextValueEditor
();
// --------------------------------------------------- : Events
virtual
void
onFocus
();
virtual
void
onLoseFocus
();
virtual
void
onLeftDown
(
const
RealPoint
&
pos
,
wxMouseEvent
&
);
virtual
void
onLeftUp
(
const
RealPoint
&
pos
,
wxMouseEvent
&
);
virtual
void
onLeftDClick
(
const
RealPoint
&
pos
,
wxMouseEvent
&
);
virtual
void
onRightDown
(
const
RealPoint
&
pos
,
wxMouseEvent
&
);
virtual
void
onMotion
(
const
RealPoint
&
pos
,
wxMouseEvent
&
);
virtual
void
onMouseWheel
(
const
RealPoint
&
pos
,
wxMouseEvent
&
ev
);
virtual
bool
onContextMenu
(
wxMenu
&
m
,
wxContextMenuEvent
&
);
virtual
void
onMenu
(
wxCommandEvent
&
);
virtual
void
onChar
(
wxKeyEvent
&
);
// --------------------------------------------------- : Actions
virtual
void
onValueChange
();
virtual
void
onAction
(
const
ValueAction
&
,
bool
undone
);
// --------------------------------------------------- : Clipboard
virtual
bool
canCopy
()
const
;
virtual
bool
canPaste
()
const
;
virtual
bool
doCopy
();
virtual
bool
doPaste
();
virtual
bool
doDelete
();
// --------------------------------------------------- : Formating
virtual
bool
canFormat
(
int
type
)
const
;
virtual
bool
hasFormat
(
int
type
)
const
;
virtual
void
doFormat
(
int
type
);
// --------------------------------------------------- : Selection
virtual
void
select
(
size_t
start
,
size_t
end
);
virtual
size_t
selectionStart
()
const
{
return
selection_start
;
}
virtual
size_t
selectionEnd
()
const
{
return
selection_end
;
}
// --------------------------------------------------- : Other
virtual
wxCursor
cursor
()
const
;
virtual
void
determineSize
();
virtual
void
onShow
(
bool
);
// --------------------------------------------------- : Data
private:
size_t
selection_start
,
selection_end
;
///< Cursor position/selection (if any)
TextValueEditorScrollBar
*
scrollbar
;
///< Scrollbar for multiline fields in native look
// --------------------------------------------------- : Selection / movement
/// Move the selection to a new location, clears the previously drawn selection
void
moveSelection
(
size_t
new_end
,
bool
also_move_start
=
true
,
Movement
dir
=
MOVE_MID
);
/// Move the selection to a new location, but does not redraw
void
moveSelectionNoRedraw
(
size_t
new_end
,
bool
also_move_start
=
true
,
Movement
dir
=
MOVE_MID
);
/// Replace the current selection with 'replacement', name the action
void
replaceSelection
(
const
String
&
replacement
,
const
String
&
name
);
/// Make sure the selection satisfies its constraints
/** - selection_start and selection_end are inside the text
* - not inside tags
* - the selection does not contain a <sep> or </sep> tag
*
* When correcting the selection, move in the given direction
*/
void
fixSelection
(
Movement
dir
=
MOVE_MID
);
/// Return a position resulting from moving pos outside the range [start...end), in the direction dir
static
size_t
move
(
size_t
pos
,
size_t
start
,
size_t
end
,
Movement
dir
);
/// Move the caret to the selection_end position and show it
void
showCaret
();
/// Position of previous visible & selectable character
size_t
prevCharBoundry
(
size_t
pos
)
const
;
size_t
nextCharBoundry
(
size_t
pos
)
const
;
/// Front of previous word, used witch Ctrl+Left/right
size_t
prevWordBoundry
(
size_t
pos
)
const
;
size_t
nextWordBoundry
(
size_t
pos
)
const
;
// --------------------------------------------------- : Scrolling
friend
class
TextValueEditorScrollBar
;
// virtual void determineSize();
/// Scroll to the given position, called by scrollbar
void
scrollTo
(
int
pos
);
};
// ----------------------------------------------------------------------------- : EOF
...
...
src/render/text/viewer.cpp
View file @
be2222ca
...
...
@@ -32,7 +32,7 @@ struct TextViewer::Line {
/// Index just beyond the last character on this line
size_t
end
()
const
{
return
start
+
positions
.
size
()
-
1
;
}
/// Find the index of the character at the given position on this line
/** Always returns a value in the range [start..end()
)
*/
/** Always returns a value in the range [start..end()
]
*/
size_t
posToIndex
(
double
x
)
const
;
/// Is this line visible using the given rectangle?
...
...
@@ -47,13 +47,12 @@ struct TextViewer::Line {
size_t
TextViewer
::
Line
::
posToIndex
(
double
x
)
const
{
// largest index with pos <= x
vector
<
double
>::
const_iterator
it
1
=
lower_bound
(
positions
.
begin
(),
positions
.
end
(),
x
);
if
(
it
1
==
positions
.
end
())
return
end
()
;
vector
<
double
>::
const_iterator
it
2
=
lower_bound
(
positions
.
begin
(),
positions
.
end
(),
x
);
if
(
it
2
==
positions
.
begin
())
return
start
;
// first index with pos > x
vector
<
double
>::
const_iterator
it2
=
it1
+
1
;
if
(
it2
==
positions
.
end
())
return
it1
-
positions
.
begin
();
if
(
x
-
*
it1
<=
*
it2
-
x
)
return
it1
-
positions
.
begin
();
// it1 is closer
else
return
it2
-
positions
.
begin
();
// it2 is closer
vector
<
double
>::
const_iterator
it1
=
it2
-
1
;
if
(
x
-
*
it1
<=
*
it2
-
x
)
return
it1
-
positions
.
begin
()
+
start
;
// it1 is closer
else
return
it2
-
positions
.
begin
()
+
start
;
// it2 is closer
}
// ----------------------------------------------------------------------------- : TextViewer
...
...
@@ -65,7 +64,7 @@ TextViewer::~TextViewer() {}
// ----------------------------------------------------------------------------- : Drawing
void
TextViewer
::
draw
(
RotatedDC
&
dc
,
const
String
&
text
,
const
TextStyle
&
style
,
Context
&
ctx
,
DrawWhat
what
)
{
Rotater
r
(
dc
,
Rotation
(
style
.
angle
,
style
.
getRect
()
));
Rotater
r
(
dc
,
style
.
getRotation
(
));
if
(
lines
.
empty
())
{
// not prepared yet
prepareElements
(
text
,
style
,
ctx
);
...
...
@@ -81,7 +80,7 @@ void TextViewer::draw(RotatedDC& dc, const String& text, const TextStyle& style,
}
void
TextViewer
::
drawSelection
(
RotatedDC
&
dc
,
const
TextStyle
&
style
,
size_t
sel_start
,
size_t
sel_end
)
{
Rotater
r
(
dc
,
Rotation
(
style
.
angle
,
style
.
getRect
()
));
Rotater
r
(
dc
,
style
.
getRotation
(
));
if
(
sel_start
==
sel_end
)
return
;
if
(
sel_end
<
sel_start
)
swap
(
sel_start
,
sel_end
);
dc
.
SetBrush
(
*
wxBLACK_BRUSH
);
...
...
@@ -109,6 +108,25 @@ void TextViewer::reset() {
// ----------------------------------------------------------------------------- : Positions
const
TextViewer
::
Line
&
TextViewer
::
findLine
(
size_t
index
)
const
{
FOR_EACH_CONST
(
l
,
lines
)
{
if
(
l
.
end
()
>
index
)
return
l
;
}
return
lines
.
front
();
}
size_t
TextViewer
::
moveLine
(
size_t
index
,
int
delta
)
const
{
const
Line
*
line1
=
&
findLine
(
index
);
const
Line
*
line2
=
line1
+
delta
;
if
(
line2
>=
&
lines
.
front
()
&&
line2
<=
&
lines
.
back
())
{
size_t
idx
=
index
-
line1
->
start
;
if
(
idx
<
0
||
idx
>=
line1
->
positions
.
size
())
return
index
;
// can't move
return
line2
->
posToIndex
(
line1
->
positions
[
idx
]);
// character at the same position
}
else
{
return
index
;
// can't move
}
}
size_t
TextViewer
::
lineStart
(
size_t
index
)
const
{
if
(
lines
.
empty
())
return
0
;
return
findLine
(
index
).
start
;
...
...
@@ -119,11 +137,32 @@ size_t TextViewer::lineEnd(size_t index) const {
return
findLine
(
index
).
end
();
}
const
TextViewer
::
Line
&
TextViewer
::
findLine
(
size_t
index
)
const
{
FOR_EACH_CONST
(
l
,
lines
)
{
if
(
l
.
end
()
>
index
)
return
l
;
struct
CompareTop
{
inline
bool
operator
()
(
const
TextViewer
::
Line
&
l
,
double
y
)
const
{
return
l
.
top
<
y
;
}
inline
bool
operator
()
(
double
y
,
const
TextViewer
::
Line
&
l
)
const
{
return
y
<
l
.
top
;
}
};
size_t
TextViewer
::
indexAt
(
const
RealPoint
&
pos
)
const
{
// 1. find the line
vector
<
Line
>::
const_iterator
l
=
lower_bound
(
lines
.
begin
(),
lines
.
end
(),
pos
.
y
,
CompareTop
());
if
(
l
!=
lines
.
begin
())
l
--
;
assert
(
l
!=
lines
.
end
());
// 2. find char on line
return
l
->
posToIndex
(
pos
.
x
);
}
RealRect
TextViewer
::
charRect
(
size_t
index
)
const
{
const
Line
&
l
=
findLine
(
index
);
size_t
pos
=
index
-
l
.
start
;
if
(
pos
>=
l
.
positions
.
size
())
{
return
RealRect
(
l
.
positions
.
back
(),
l
.
top
,
0
,
l
.
line_height
);
}
else
{
return
RealRect
(
l
.
positions
[
pos
],
l
.
top
,
l
.
positions
[
pos
+
1
]
-
l
.
positions
[
pos
],
l
.
line_height
);
}
return
lines
.
front
();
}
double
TextViewer
::
heightOfLastLine
()
const
{
if
(
lines
.
empty
())
return
0
;
else
return
lines
.
back
().
line_height
;
}
// ----------------------------------------------------------------------------- : Elements
...
...
src/render/text/viewer.hpp
View file @
be2222ca
...
...
@@ -56,16 +56,32 @@ class TextViewer {
// --------------------------------------------------- : Positions
/// Find the character index that is before the given index, and which has a nonzero width
size_t
moveLeft
(
size_t
index
)
const
;
/// Find the character index that is before
/after
the given index, and which has a nonzero width
// size_t moveChar(size_t index, int delta
) const;
/// Find the character index that is on a line above/below index
/** If this would move outisde the text, returns the input index */
size_t
moveLine
(
size_t
index
,
int
delta
)
const
;
/// The character index of the start of the line that character #index is on
size_t
lineStart
(
size_t
index
)
const
;
/// The character index past the end of the line that character #index is on
size_t
lineEnd
(
size_t
index
)
const
;
/// Find the index of the character at the given position
/** If the position is before everything returns 0,
* if it is after everything returns text.size().
* The position is in internal coordinates */
size_t
indexAt
(
const
RealPoint
&
pos
)
const
;
/// Find the position of the character at the given index
/** The position is in internal coordinates */
RealPoint
posOf
(
size_t
index
)
const
;
/// Return the rectangle around a single character
RealRect
charRect
(
size_t
index
)
const
;
/// Return the height of the last line
double
heightOfLastLine
()
const
;
private:
// --------------------------------------------------- : More drawing
double
scale
;
/// < Scale when drawing
...
...
src/render/value/text.hpp
View file @
be2222ca
...
...
@@ -25,7 +25,7 @@ class TextValueViewer : public ValueViewer {
virtual
void
onValueChange
();
virtual
void
onStyleChange
();
pr
ivate
:
pr
otected
:
TextViewer
v
;
};
...
...
src/render/value/viewer.cpp
View file @
be2222ca
...
...
@@ -41,7 +41,7 @@ RealRect ValueViewer::boundingBox() const {
void
ValueViewer
::
drawFieldBorder
(
RotatedDC
&
dc
)
{
if
(
viewer
.
drawBorders
()
&&
getField
()
->
editable
)
{
dc
.
SetPen
(
viewer
.
borderPen
(
viewer
.
focusedViewer
()
==
this
));
dc
.
SetPen
(
viewer
.
borderPen
(
isCurrent
()
));
dc
.
SetBrush
(
*
wxTRANSPARENT_BRUSH
);
dc
.
DrawRectangle
(
styleP
->
getRect
().
grow
(
dc
.
trInvS
(
1
)));
}
...
...
@@ -50,6 +50,9 @@ void ValueViewer::drawFieldBorder(RotatedDC& dc) {
bool
ValueViewer
::
nativeLook
()
const
{
return
viewer
.
nativeLook
();
}
bool
ValueViewer
::
isCurrent
()
const
{
return
viewer
.
focusedViewer
()
==
this
;
}
// ----------------------------------------------------------------------------- : Type dispatch
...
...
src/util/action_stack.cpp
View file @
be2222ca
...
...
@@ -33,7 +33,7 @@ void ActionStack::add(Action* action, bool allow_merge) {
FOR_EACH
(
a
,
redo_actions
)
delete
a
;
redo_actions
.
clear
();
// try to merge?
if
(
allow_merge
&&
!
undo_actions
.
empty
()
&&
undo_actions
.
back
()
->
merge
(
action
))
{
if
(
allow_merge
&&
!
undo_actions
.
empty
()
&&
undo_actions
.
back
()
->
merge
(
*
action
))
{
// merged with top undo action
delete
action
;
}
else
{
...
...
src/util/action_stack.hpp
View file @
be2222ca
...
...
@@ -40,7 +40,7 @@ class Action {
/** Either: return false and do nothing
* Or: return true and change this action to incorporate both actions
*/
virtual
bool
merge
(
const
Action
*
action
)
{
return
false
;
}
virtual
bool
merge
(
const
Action
&
action
)
{
return
false
;
}
};
// ----------------------------------------------------------------------------- : Action listeners
...
...
src/util/rotation.hpp
View file @
be2222ca
...
...
@@ -73,9 +73,12 @@ class Rotation {
friend
class
Rotater
;
public:
/// Is the rotation sideways (90 or 270 degrees)?
// Note: angle & 2 == 0 for angle in {0, 180} and != 0 for angle in {90, 270)
inline
bool
sideways
()
const
{
return
(
angle
&
2
)
!=
0
;
}
protected:
/// Is the x axis 'reversed' (after turning sideways)?
inline
bool
revX
()
const
{
return
angle
>=
180
;
}
/// Is the y axis 'reversed' (after turning sideways)?
...
...
src/util/string.cpp
View file @
be2222ca
...
...
@@ -62,6 +62,10 @@ String trim_left(const String& s) {
}
}
String
substr_replace
(
const
String
&
input
,
size_t
start
,
size_t
end
,
const
String
&
replacement
)
{
return
input
.
substr
(
0
,
start
)
+
replacement
+
input
.
substr
(
end
);
}
// ----------------------------------------------------------------------------- : Words
String
last_word
(
const
String
&
s
)
{
...
...
src/util/string.hpp
View file @
be2222ca
...
...
@@ -81,6 +81,9 @@ String trim(const String&);
/// Remove whitespace from the start of a string
String
trim_left
(
const
String
&
);
/// Replace the substring [start...end) of 'input' with 'replacement'
String
substr_replace
(
const
String
&
input
,
size_t
start
,
size_t
end
,
const
String
&
replacement
);
// ----------------------------------------------------------------------------- : Words
/// Returns the last word in a string
...
...
src/util/tagged_string.cpp
View file @
be2222ca
...
...
@@ -7,6 +7,7 @@
// ----------------------------------------------------------------------------- : Includes
#include <util/tagged_string.hpp>
#include <stack>
// ----------------------------------------------------------------------------- : Conversion to/from normal string
...
...
@@ -41,6 +42,44 @@ String escape(const String& str) {
return
ret
;
}
String
fix_old_tags
(
const
String
&
str
)
{
String
ret
;
ret
.
reserve
(
str
.
size
());
stack
<
String
>
tags
;
bool
intag
=
false
;
// invariant : intag => !tags.empty()
for
(
size_t
i
=
0
;
i
<
str
.
size
()
;
++
i
)
{
Char
c
=
str
.
GetChar
(
i
);
if
(
is_substr
(
str
,
i
,
_
(
"</>"
)))
{
i
+=
2
;
// old style close tag, replace by the correct tag type
if
(
!
tags
.
empty
())
{
// need a close tag?
if
(
!
tags
.
top
().
empty
())
{
ret
+=
_
(
"</"
)
+
tags
.
top
()
+
_
(
">"
);
}
tags
.
pop
();
}
intag
=
false
;
}
else
{
ret
+=
c
;
if
(
c
==
_
(
'<'
))
{
intag
=
true
;
tags
.
push
(
wxEmptyString
);
}
else
if
(
c
==
_
(
'>'
)
&&
intag
)
{
intag
=
false
;
if
(
!
starts_with
(
tags
.
top
(),
_
(
"kw"
))
&&
!
starts_with
(
tags
.
top
(),
_
(
"atom"
)))
{
// only keep keyword related stuff
ret
.
resize
(
ret
.
size
()
-
tags
.
top
().
size
()
-
2
);
// remove from output
tags
.
top
()
=
wxEmptyString
;
}
}
else
if
(
intag
)
{
tags
.
top
()
+=
c
;
}
}
}
return
ret
;
}
// ----------------------------------------------------------------------------- : Finding tags
size_t
skip_tag
(
const
String
&
str
,
size_t
start
)
{
...
...
@@ -49,5 +88,179 @@ size_t skip_tag(const String& str, size_t start) {
return
end
==
String
::
npos
?
String
::
npos
:
end
+
1
;
}
size_t
match_close_tag
(
const
String
&
str
,
size_t
start
)
{
String
tag
=
tag_type_at
(
str
,
start
);
String
ctag
=
_
(
"/"
)
+
tag
;
size_t
size
=
str
.
size
();
int
taglevel
=
1
;
for
(
size_t
pos
=
start
+
tag
.
size
()
+
2
;
pos
<
size
;
++
pos
)
{
Char
c
=
str
.
GetChar
(
pos
);
if
(
c
==
_
(
'<'
))
{
if
(
is_substr
(
str
,
pos
+
1
,
tag
))
{
++
taglevel
;
pos
+=
tag
.
size
()
+
1
;
}
else
if
(
is_substr
(
str
,
pos
+
1
,
ctag
))
{
--
taglevel
;
// close tag
if
(
taglevel
==
0
)
return
pos
;
pos
+=
ctag
.
size
()
+
1
;
}
}
}
return
String
::
npos
;
}
size_t
last_start_tag_before
(
const
String
&
str
,
const
String
&
tag
,
size_t
start
)
{
start
=
min
(
str
.
size
(),
start
);
for
(
size_t
pos
=
start
;
pos
>
0
;
--
pos
)
{
if
(
is_substr
(
str
,
pos
-
1
,
tag
))
{
return
pos
-
1
;
}
}
return
String
::
npos
;
}
size_t
in_tag
(
const
String
&
str
,
const
String
&
tag
,
size_t
start
,
size_t
end
)
{
if
(
start
>
end
)
swap
(
start
,
end
);
size_t
pos
=
last_start_tag_before
(
str
,
tag
,
start
);
if
(
pos
==
String
::
npos
)
return
String
::
npos
;
// no tag found before start
size_t
posE
=
match_close_tag
(
str
,
pos
);
if
(
posE
<
end
)
return
String
::
npos
;
// the tag ends before end
return
pos
;
}
String
tag_at
(
const
String
&
str
,
size_t
pos
)
{
size_t
end
=
str
.
find_first_of
(
_
(
">"
),
pos
);
if
(
end
==
String
::
npos
)
return
wxEmptyString
;
return
str
.
substr
(
pos
+
1
,
end
-
pos
-
1
);
}
String
tag_type_at
(
const
String
&
str
,
size_t
pos
)
{
size_t
end
=
str
.
find_first_of
(
_
(
">-"
),
pos
);
if
(
end
==
String
::
npos
)
return
wxEmptyString
;
return
str
.
substr
(
pos
+
1
,
end
-
pos
-
1
);
}
String
close_tag
(
const
String
&
tag
)
{
if
(
tag
.
size
()
<
1
)
return
_
(
"</>"
);
else
return
_
(
"</"
)
+
tag
.
substr
(
1
);
}
String
anti_tag
(
const
String
&
tag
)
{
if
(
!
tag
.
empty
()
&&
tag
.
GetChar
(
0
)
==
_
(
'/'
))
return
_
(
"<"
)
+
tag
.
substr
(
1
)
+
_
(
">"
);
else
return
_
(
"</"
)
+
tag
+
_
(
">"
);
}
// ----------------------------------------------------------------------------- : Global operations
// ----------------------------------------------------------------------------- : Updates
/// Return all open or close tags in the given range from a string
/** for example:
* if close_tags == false, "text<tag>text</tag>text" --> "<tag>"
* if close_tags == true, "text<tag>text</tag>text" --> "</tag>"
*/
String
get_tags
(
const
String
&
str
,
size_t
start
,
size_t
end
,
bool
close_tags
)
{
String
ret
;
bool
intag
=
false
;
bool
keeptag
=
false
;
for
(
size_t
i
=
start
;
i
<
end
;
++
i
)
{
Char
c
=
str
.
GetChar
(
i
);
if
(
c
==
_
(
'<'
)
&&
!
intag
)
{
intag
=
true
;
// is this tag an open tag?
if
(
i
+
1
<
end
&&
(
str
.
GetChar
(
i
+
1
)
==
_
(
'/'
))
==
close_tags
)
{
keeptag
=
true
;
}
}
if
(
intag
&&
keeptag
)
ret
+=
c
;
if
(
c
==
_
(
'>'
))
intag
=
false
;
}
return
ret
;
}
String
tagged_substr_replace
(
const
String
&
input
,
size_t
start
,
size_t
end
,
const
String
&
replacement
)
{
assert
(
start
<=
end
);
size_t
size
=
input
.
size
();
String
ret
;
ret
.
reserve
(
size
+
replacement
.
size
()
-
(
end
-
start
));
// estimated size
return
simplify_tagged
(
substr_replace
(
input
,
start
,
end
,
get_tags
(
input
,
start
,
end
,
true
)
+
// close tags
escape
(
replacement
)
+
get_tags
(
input
,
start
,
end
,
false
)
// open tags
));
}
// ----------------------------------------------------------------------------- : Simplification
String
simplify_tagged
(
const
String
&
str
)
{
return
simplify_tagged_overlap
(
simplify_tagged_merge
(
str
));
}
// Add a tag to a stack of tags, try to cancel it out
// If </tag> is in stack remove it and returns true
// otherwise appends <tag> and returns fales
// (where </tag> is the negation of tag)
bool
add_or_cancel_tag
(
const
String
&
tag
,
String
&
stack
)
{
String
anti
=
anti_tag
(
tag
);
size_t
pos
=
stack
.
find
(
anti
);
if
(
pos
==
String
::
npos
)
{
stack
+=
_
(
"<"
)
+
tag
+
_
(
">"
);
return
false
;
}
else
{
// cancel out with anti tag
stack
=
stack
.
substr
(
0
,
pos
)
+
stack
.
substr
(
pos
+
anti
.
size
());
return
true
;
}
}
String
simplify_tagged_merge
(
const
String
&
str
)
{
String
ret
;
ret
.
reserve
(
str
.
size
());
String
waiting_tags
;
// tags that are waiting to be written to the output
size_t
size
=
str
.
size
();
for
(
size_t
i
=
0
;
i
<
size
;
++
i
)
{
Char
c
=
str
.
GetChar
(
i
);
if
(
c
==
_
(
'<'
))
{
String
tag
=
tag_at
(
str
,
i
);
add_or_cancel_tag
(
tag
,
waiting_tags
);
i
+=
tag
.
size
()
+
1
;
}
else
{
ret
+=
waiting_tags
;
waiting_tags
.
clear
();
ret
+=
c
;
}
}
return
ret
+
waiting_tags
;
}
String
simplify_tagged_overlap
(
const
String
&
str
)
{
String
ret
;
ret
.
reserve
(
str
.
size
());
String
open_tags
;
// tags we are in
size_t
size
=
str
.
size
();
for
(
size_t
i
=
0
;
i
<
size
;
++
i
)
{
Char
c
=
str
.
GetChar
(
i
);
if
(
c
==
_
(
'<'
))
{
String
tag
=
tag_at
(
str
,
i
);
if
(
starts_with
(
tag
,
_
(
"b"
))
||
starts_with
(
tag
,
_
(
"i"
))
||
starts_with
(
tag
,
_
(
"sym"
))
||
starts_with
(
tag
,
_
(
"/b"
))
||
starts_with
(
tag
,
_
(
"/i"
))
||
starts_with
(
tag
,
_
(
"/sym"
)))
{
// optimize this tag
if
(
open_tags
.
find
(
_
(
"<"
)
+
tag
+
_
(
">"
))
==
String
::
npos
)
{
// we are not already inside this tag
add_or_cancel_tag
(
tag
,
open_tags
);
if
(
open_tags
.
find
(
anti_tag
(
tag
))
!=
String
::
npos
)
{
// still not canceled out
i
+=
tag
.
size
()
+
2
;
continue
;
}
}
else
{
// skip this tag, doubling it has no effect
i
+=
tag
.
size
()
+
2
;
add_or_cancel_tag
(
tag
,
open_tags
);
continue
;
}
}
}
ret
+=
c
;
}
return
ret
;
}
src/util/tagged_string.hpp
View file @
be2222ca
...
...
@@ -46,10 +46,17 @@ String fix_old_tags(const String&);
size_t
skip_tag
(
const
String
&
str
,
size_t
start
);
/// Find the position of the closing tag matching the tag at start
/** If not found returns String::npos
*/
/** If not found returns String::npos */
size_t
match_close_tag
(
const
String
&
str
,
size_t
start
);
/// Find the last start tag before position start
/** If not found returns String::npos */
size_t
last_start_tag_before
(
const
String
&
str
,
const
String
&
tag
,
size_t
start
);
/// Is the given range entirely contained in a given tag?
/** If so: return the start position of that tag, otherwise returns String::npos */
size_t
in_tag
(
const
String
&
str
,
const
String
&
tag
,
size_t
start
,
size_t
end
);
/// Return the tag at the given position (without the <>)
String
tag_at
(
const
String
&
str
,
size_t
pos
);
...
...
@@ -80,6 +87,17 @@ String remove_tag_exact(const String& str, const String& tag);
*/
String
remove_tag_contents
(
const
String
&
str
,
const
String
&
tag
);
// ----------------------------------------------------------------------------- : Updates
/// Replace a subsection of 'input' with 'replacement'.
/** The section to replace is indicated by [start...end).
* This function makes sure tags still match. It also attempts to cancel out tags.
* This means that when removing "<x>a</x>" nothing is left,
* but with input "<x>a" -> "<x>" and "</>a" -> "</>".
* Escapes the replacement, i.e. all < in become \1.
*/
String
tagged_substr_replace
(
const
String
&
input
,
size_t
start
,
size_t
end
,
const
String
&
replacement
);
// ----------------------------------------------------------------------------- : Simplification
/// Verify that a string is correctly tagged, if it is not, change it so it is
...
...
@@ -95,10 +113,14 @@ String verify_tagged(const String& str);
*/
String
simplify_tagged
(
const
String
&
str
);
/// Simplify a tagged string by merging adjecent open/close tags "<tag></tag>" --> ""
/// Simplify a tagged string by merging adjecent open/close tags
/** e.g. "<tag></tag>" --> ""
*/
String
simplify_tagged_merge
(
const
String
&
str
);
/// Simplify overlapping formatting tags
/** e.g. "<i>blah<i>blah</i>blah</i>" -> "<i>blahblahblah</i>"
*/
String
simplify_tagged_overlap
(
const
String
&
str
);
// ----------------------------------------------------------------------------- : EOF
...
...
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