mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 13:06:59 -04:00
New rotation system (see forum thread).
Major changes: - when rotating, the top left corner of the rectangle stays in place. - ValueViewers get a dc that is pre-rotated/translated for them, i.e. (0,0) is the top-left of the viewer (with ValueViewer::getRotation). - moved 'angle' from individual Styles to the Style base class. - any rotation angle is now possible. angle is still an int for now. This warrants a version bump git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@782 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+35
-17
@@ -94,9 +94,10 @@ intrusive_ptr<Field> read_new<Field>(Reader& reader) {
|
||||
Style::Style(const FieldP& field)
|
||||
: fieldP(field)
|
||||
, z_index(0)
|
||||
, left(0), top(0)
|
||||
, width(0), height(0)
|
||||
, right(0), bottom(0)
|
||||
, left(-1), top(-1)
|
||||
, width(-1), height(-1)
|
||||
, right(-1), bottom(-1)
|
||||
, angle(0)
|
||||
, visible(true)
|
||||
, automatic_side(AUTO_UNKNOWN)
|
||||
, content_dependent(false)
|
||||
@@ -112,6 +113,7 @@ IMPLEMENT_REFLECTION(Style) {
|
||||
REFLECT(top);
|
||||
REFLECT(height);
|
||||
REFLECT(bottom);
|
||||
REFLECT(angle);
|
||||
REFLECT(visible);
|
||||
}
|
||||
|
||||
@@ -130,28 +132,44 @@ int Style::update(Context& ctx) {
|
||||
| top .update(ctx)
|
||||
| height .update(ctx)
|
||||
| bottom .update(ctx)
|
||||
| angle .update(ctx)
|
||||
| visible.update(ctx);
|
||||
// determine automatic_side
|
||||
// determine automatic_side and attachment of rotation point
|
||||
if (automatic_side == AUTO_UNKNOWN) {
|
||||
if (right == 0) automatic_side = (AutomaticSide)(automatic_side | AUTO_RIGHT);
|
||||
else if (width == 0) automatic_side = (AutomaticSide)(automatic_side | AUTO_WIDTH);
|
||||
else automatic_side = (AutomaticSide)(automatic_side | AUTO_LEFT);
|
||||
if (bottom == 0) automatic_side = (AutomaticSide)(automatic_side | AUTO_BOTTOM);
|
||||
else if (height == 0) automatic_side = (AutomaticSide)(automatic_side | AUTO_HEIGHT);
|
||||
else automatic_side = (AutomaticSide)(automatic_side | AUTO_TOP);
|
||||
}
|
||||
if (automatic_side & AUTO_WIDTH){
|
||||
changed=changed;//BREAKPOINT
|
||||
if (right == -1) automatic_side = (AutomaticSide)(automatic_side | AUTO_RIGHT);
|
||||
else if (width == -1) automatic_side = (AutomaticSide)(automatic_side | AUTO_WIDTH);
|
||||
else if (left == -1) automatic_side = (AutomaticSide)(automatic_side | AUTO_LEFT);
|
||||
else automatic_side = (AutomaticSide)(automatic_side | AUTO_LR);
|
||||
if (bottom == -1) automatic_side = (AutomaticSide)(automatic_side | AUTO_BOTTOM);
|
||||
else if (height == -1) automatic_side = (AutomaticSide)(automatic_side | AUTO_HEIGHT);
|
||||
else if (top == -1) automatic_side = (AutomaticSide)(automatic_side | AUTO_TOP);
|
||||
else automatic_side = (AutomaticSide)(automatic_side | AUTO_TB);
|
||||
changed = true;
|
||||
}
|
||||
if (!changed) return CHANGE_NONE;
|
||||
// update the automatic_side
|
||||
if (automatic_side & AUTO_LEFT) left = right - width;
|
||||
else if (automatic_side & AUTO_WIDTH) width = right - left;
|
||||
else right = left + width;
|
||||
else if (automatic_side & AUTO_RIGHT) right = left + width;
|
||||
else {int lr = left + right; left = (lr - width) / 2; right = (lr + width) / 2; }
|
||||
if (automatic_side & AUTO_TOP) top = bottom - height;
|
||||
else if (automatic_side & AUTO_HEIGHT) height = bottom - top;
|
||||
else bottom = top + height;
|
||||
// are there changes?
|
||||
return changed;
|
||||
else if (automatic_side & AUTO_BOTTOM) bottom = top + height;
|
||||
else {int tb = top + bottom; top = (tb - height) / 2; bottom = (tb + height) / 2; }
|
||||
// adjust rotation point
|
||||
if (angle != 0 && (automatic_side & (AUTO_LEFT | AUTO_TOP))) {
|
||||
double s = sin(angle * M_PI / 180), c = cos(angle * M_PI / 180);
|
||||
if (automatic_side & AUTO_LEFT) { // attach right corner instead of left
|
||||
left = left + width * (1 - c);
|
||||
top = top + width * s;
|
||||
}
|
||||
if (automatic_side & AUTO_TOP) { // attach botom corner instead of top
|
||||
left = left - height * s;
|
||||
top = top + height * (1 - c);
|
||||
}
|
||||
}
|
||||
// done
|
||||
return CHANGE_OTHER;
|
||||
}
|
||||
|
||||
void Style::initDependencies(Context& ctx, const Dependency& dep) const {
|
||||
|
||||
+8
-3
@@ -13,6 +13,7 @@
|
||||
#include <util/reflect.hpp>
|
||||
#include <util/alignment.hpp>
|
||||
#include <util/age.hpp>
|
||||
#include <util/rotation.hpp>
|
||||
#include <script/scriptable.hpp>
|
||||
#include <script/dependency.hpp>
|
||||
|
||||
@@ -98,17 +99,21 @@ class Style : public IntrusivePtrVirtualBase {
|
||||
Scriptable<double> left, top; ///< Position of this field
|
||||
Scriptable<double> width, height; ///< Position of this field
|
||||
Scriptable<double> right, bottom; ///< Position of this field
|
||||
Scriptable<int> angle; ///< Rotation of the box
|
||||
Scriptable<bool> visible; ///< Is this field visible?
|
||||
enum AutomaticSide {
|
||||
AUTO_UNKNOWN = 0x00,
|
||||
AUTO_LEFT = 0x01, AUTO_WIDTH = 0x02, AUTO_RIGHT = 0x04,
|
||||
AUTO_TOP = 0x10, AUTO_HEIGHT = 0x20, AUTO_BOTTOM = 0x40,
|
||||
AUTO_LEFT = 0x01, AUTO_WIDTH = 0x02, AUTO_RIGHT = 0x04, AUTO_LR = 0x08,
|
||||
AUTO_TOP = 0x10, AUTO_HEIGHT = 0x20, AUTO_BOTTOM = 0x40, AUTO_TB = 0x80,
|
||||
ATTACH_LEFT = 0x04, ATTACH_CENTER = 0x02, ATTACH_RIGHT = 0x01,
|
||||
ATTACH_TOP = 0x40, ATTACH_MIDDLE = 0x20, ATTACH_BOTTOM = 0x10,
|
||||
} automatic_side : 8; ///< Which of (left, width, right) and (top, height, bottom) is determined automatically?
|
||||
bool content_dependent; ///< Does this style depend on content properties?
|
||||
|
||||
inline RealPoint getPos() const { return RealPoint(left, top ); }
|
||||
inline RealSize getSize() const { return RealSize ( width, height); }
|
||||
inline RealRect getRect() const { return RealRect (left, top, width, height); }
|
||||
inline RealRect getExternalRect() const { return RealRect (left, top, width, height); }
|
||||
inline RealRect getInternalRect() const { return RealRect(0, 0, width, height); }
|
||||
|
||||
/// Get a copy of this style
|
||||
virtual StyleP clone() const = 0;
|
||||
|
||||
@@ -178,7 +178,6 @@ ChoiceStyle::ChoiceStyle(const ChoiceFieldP& field)
|
||||
, choice_images_initialized(false)
|
||||
, combine(COMBINE_NORMAL)
|
||||
, alignment(ALIGN_STRETCH)
|
||||
, angle(0)
|
||||
, thumbnails(nullptr)
|
||||
{}
|
||||
|
||||
@@ -291,7 +290,6 @@ IMPLEMENT_REFLECTION(ChoiceStyle) {
|
||||
REFLECT_N("mask",mask_filename);
|
||||
REFLECT(combine);
|
||||
REFLECT(alignment);
|
||||
REFLECT(angle);
|
||||
REFLECT(font);
|
||||
REFLECT(image);
|
||||
REFLECT(choice_images);
|
||||
|
||||
@@ -153,7 +153,6 @@ class ChoiceStyle : public Style {
|
||||
ImageCombine combine; ///< Combining mode for drawing the images
|
||||
Alignment alignment; ///< Alignment of images
|
||||
Image mask; ///< The actual mask image
|
||||
int angle; ///< Angle by which the images are rotated
|
||||
wxImageList* thumbnails; ///< Thumbnails for the choices
|
||||
vector<ThumbnailStatus> thumbnails_status; ///< Which thumbnails are up to date?
|
||||
// information from image rendering
|
||||
|
||||
@@ -25,14 +25,12 @@ IMPLEMENT_REFLECTION(ImageField) {
|
||||
|
||||
IMPLEMENT_REFLECTION(ImageStyle) {
|
||||
REFLECT_BASE(Style);
|
||||
REFLECT(angle);
|
||||
REFLECT_N("mask", mask_filename);
|
||||
REFLECT_N("default", default_image);
|
||||
}
|
||||
|
||||
int ImageStyle::update(Context& ctx) {
|
||||
return Style ::update(ctx)
|
||||
| angle .update(ctx) * CHANGE_OTHER
|
||||
| mask_filename.update(ctx) * CHANGE_MASK
|
||||
| default_image.update(ctx) * CHANGE_DEFAULT;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ class ImageStyle : public Style {
|
||||
inline ImageStyle(const ImageFieldP& field) : Style(field) {}
|
||||
DECLARE_STYLE_TYPE(Image);
|
||||
|
||||
Scriptable<int> angle; ///< Rotation of images
|
||||
Scriptable<String> mask_filename; ///< Filename for a mask image
|
||||
ScriptableImage default_image; ///< Placeholder
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ TextStyle::TextStyle(const TextFieldP& field)
|
||||
: Style(field)
|
||||
, always_symbol(false), allow_formating(true)
|
||||
, alignment(ALIGN_TOP_LEFT)
|
||||
, angle(0)
|
||||
, padding_left (0), padding_left_min (10000)
|
||||
, padding_right (0), padding_right_min (10000)
|
||||
, padding_top (0), padding_top_min (10000)
|
||||
@@ -73,8 +72,7 @@ int TextStyle::update(Context& ctx) {
|
||||
return Style ::update(ctx)
|
||||
| font .update(ctx) * CHANGE_OTHER
|
||||
| symbol_font.update(ctx) * CHANGE_OTHER
|
||||
| alignment .update(ctx) * CHANGE_OTHER
|
||||
| angle .update(ctx) * CHANGE_OTHER;
|
||||
| alignment .update(ctx) * CHANGE_OTHER;
|
||||
}
|
||||
void TextStyle::initDependencies(Context& ctx, const Dependency& dep) const {
|
||||
Style ::initDependencies(ctx, dep);
|
||||
@@ -100,7 +98,6 @@ IMPLEMENT_REFLECTION(TextStyle) {
|
||||
REFLECT(always_symbol);
|
||||
REFLECT(allow_formating);
|
||||
REFLECT(alignment);
|
||||
REFLECT(angle);
|
||||
REFLECT(padding_left);
|
||||
REFLECT(padding_right);
|
||||
REFLECT(padding_top);
|
||||
|
||||
@@ -35,6 +35,8 @@ class TextField : public Field {
|
||||
|
||||
OptionalScript script; ///< Script to apply to all values
|
||||
OptionalScript default_script; ///< Script that generates the default value
|
||||
//%OptionalScript view_script; ///< Script to apply before viewing
|
||||
//%OptionalScript unview_script; ///< Script to apply after changes to the view
|
||||
bool multi_line; ///< Are newlines allowed in the text?
|
||||
String default_name; ///< Name of "default" value
|
||||
|
||||
@@ -57,7 +59,6 @@ class TextStyle : public Style {
|
||||
bool always_symbol; ///< Should everything be drawn as symbols?
|
||||
bool allow_formating; ///< Is formating (bold/italic/..) allowed?
|
||||
Scriptable<Alignment> alignment; ///< Alignment inside the box
|
||||
Scriptable<int> angle; ///< Angle of the text inside the box
|
||||
double padding_left, padding_left_min; ///< Padding
|
||||
double padding_right, padding_right_min; ///< Padding
|
||||
double padding_top, padding_top_min; ///< Padding
|
||||
@@ -80,14 +81,6 @@ class TextStyle : public Style {
|
||||
virtual void initDependencies(Context&, const Dependency&) const;
|
||||
virtual void checkContentDependencies(Context&, const Dependency&) const;
|
||||
|
||||
/// The rotation to use when drawing
|
||||
inline Rotation getRotation() const {
|
||||
return Rotation(angle, getRect(), 1.0, getStretch());
|
||||
}
|
||||
/// The rotation to use when determining content layout, does not include the stretch factor
|
||||
inline Rotation getRotationNoStretch() const {
|
||||
return Rotation(angle, getRect());
|
||||
}
|
||||
/// Stretch factor to use
|
||||
double getStretch() const;
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ Rotation UnzoomedDataViewer::getRotation() const {
|
||||
return DataViewer::getRotation();
|
||||
} else {
|
||||
if (!stylesheet) stylesheet = set->stylesheet;
|
||||
return Rotation(0, stylesheet->getCardRect(), 1.0, 1.0, true);
|
||||
return Rotation(0, stylesheet->getCardRect(), 1.0, 1.0, ROTATION_ATTACH_TOP_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ class StatsDimension : public IntrusivePtrBase<StatsDimension> {
|
||||
String description; ///< Description, used in status bar
|
||||
int position_hint; ///< Hint for the ordering
|
||||
String icon_filename; ///< Icon for lists
|
||||
Bitmap icon; ///< The loaded icon (optional of course)
|
||||
OptionalScript script; ///< Script that determines the value(s)
|
||||
bool numeric; ///< Are the values numeric? If so, they require special sorting
|
||||
bool show_empty; ///< Should "" be shown?
|
||||
|
||||
@@ -302,7 +302,7 @@ void SymbolFont::drawWithText(RotatedDC& dc, const RealRect& rect, double font_s
|
||||
if (def) {
|
||||
Bitmap bmp = def->getBitmap(*this, dc.trS(font_size));
|
||||
// align symbol
|
||||
sym_rect.size() = dc.trInvS(RealSize(bmp.GetWidth(), bmp.GetHeight()));
|
||||
sym_rect.size() = dc.trInvS(RealSize(bmp));
|
||||
sym_rect.position() = align_in_rect(align, sym_rect.size(), rect);
|
||||
// draw
|
||||
dc.DrawBitmap(bmp, sym_rect.position());
|
||||
|
||||
Reference in New Issue
Block a user