View: provide the transform between different coordinate spaces
There's currently no way for an application to convert between view and drawing coordinates with a drawing states stack without keeping track of all the transformations itself, which is not very convenient for helper or library functions. Handle other spaces too, for good measure. Change-Id: Ic8404a1c111e273fff1eebf2f9f59f58246b796c Reviewed-on: https://review.haiku-os.org/c/haiku/+/5775 Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org> Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
parent
423e3645e1
commit
241f109ccb
@ -272,6 +272,74 @@
|
||||
*/
|
||||
|
||||
|
||||
// coordinate spaces
|
||||
|
||||
|
||||
/*!
|
||||
\typedef coordinate_space
|
||||
\brief A coordinate or drawing space.
|
||||
\see \ref coordinatespaces
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\var B_CURRENT_STATE_COORDINATES
|
||||
\brief The current drawing space.
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\var B_PREVIOUS_STATE_COORDINATES
|
||||
\brief The drawing space of the parent state in the stack.
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\var B_VIEW_COORDINATES
|
||||
\brief The base coordinate space of the view.
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\var B_PARENT_VIEW_DRAW_COORDINATES
|
||||
\brief The current drawing space of the parent view.
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\var B_PARENT_VIEW_COORDINATES
|
||||
\brief The base coordinate space of the parent view.
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\var B_WINDOW_COORDINATES
|
||||
\brief The coordinate space of the owning window.
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\var B_SCREEN_COORDINATES
|
||||
\brief The coordinate space of the screen.
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
|
||||
|
||||
// view flags
|
||||
|
||||
|
||||
@ -1903,6 +1971,27 @@ SetViewColor(Parent()->ViewColor());
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\fn BAffineTransform BView::TransformTo(coordinate_space basis) const
|
||||
\brief Return the BAffineTransform to convert from the current drawing
|
||||
space to \a basis.
|
||||
|
||||
\c B_PREVIOUS_STATE_COORDINATES is equivalent to
|
||||
\c B_CURRENT_STATE_COORDINATES when there is no parent state.
|
||||
|
||||
\c B_PARENT_VIEW_DRAW_COORDINATES and \c B_PARENT_VIEW_COORDINATES are
|
||||
equivalent to \c B_WINDOW_COORDINATES when used on a root view.
|
||||
|
||||
\c B_WINDOW_COORDINATES works as \c B_SCREEN_COORDINATES for unattached
|
||||
views.
|
||||
|
||||
\sa Transform()
|
||||
\sa \ref coordinatespaces
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\fn void BView::TranslateBy(double x, double y)
|
||||
\brief Translate the current view by coordinates.
|
||||
|
@ -66,7 +66,5 @@
|
||||
All drawing operations in a BView use coordinates specified in the drawing space.
|
||||
However, the update rect passed to the Draw method (or passed to the Invalidate
|
||||
method) is in the BView base coordinate space. Conversion between the two can
|
||||
be done using the affine transform returned by BView::Transform, or in case the
|
||||
legacy transformation functions are used, by applying the scale and origin returned
|
||||
by the Scale() and Origin() functions.
|
||||
be done using the affine transform returned by BView::TransformTo.
|
||||
*/
|
||||
|
@ -70,6 +70,16 @@ enum {
|
||||
B_FONT_ALL = 0x000001FF
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
B_CURRENT_STATE_COORDINATES,
|
||||
B_PREVIOUS_STATE_COORDINATES,
|
||||
B_VIEW_COORDINATES,
|
||||
B_PARENT_VIEW_DRAW_COORDINATES,
|
||||
B_PARENT_VIEW_COORDINATES,
|
||||
B_WINDOW_COORDINATES,
|
||||
B_SCREEN_COORDINATES
|
||||
} coordinate_space;
|
||||
|
||||
// view flags
|
||||
const uint32 B_FULL_UPDATE_ON_RESIZE = 0x80000000UL; /* 31 */
|
||||
const uint32 _B_RESERVED1_ = 0x40000000UL; /* 30 */
|
||||
@ -324,6 +334,8 @@ public:
|
||||
void ScaleBy(double x, double y);
|
||||
void RotateBy(double angleRadians);
|
||||
|
||||
BAffineTransform TransformTo(coordinate_space basis) const;
|
||||
|
||||
void PushState();
|
||||
void PopState();
|
||||
|
||||
|
@ -358,6 +358,7 @@ enum {
|
||||
// transformation in addition to origin/scale
|
||||
AS_VIEW_SET_TRANSFORM,
|
||||
AS_VIEW_GET_TRANSFORM,
|
||||
AS_VIEW_GET_PARENT_COMPOSITE,
|
||||
|
||||
AS_VIEW_AFFINE_TRANSLATE,
|
||||
AS_VIEW_AFFINE_SCALE,
|
||||
|
@ -45,6 +45,7 @@ enum {
|
||||
B_VIEW_WHICH_VIEW_COLOR_BIT = 0x00100000,
|
||||
B_VIEW_WHICH_LOW_COLOR_BIT = 0x00200000,
|
||||
B_VIEW_WHICH_HIGH_COLOR_BIT = 0x00400000,
|
||||
B_VIEW_PARENT_COMPOSITE_BIT = 0x00800000,
|
||||
|
||||
B_VIEW_ALL_BITS = 0x00ffffff,
|
||||
|
||||
@ -131,6 +132,11 @@ class ViewState {
|
||||
float scale;
|
||||
BAffineTransform transform;
|
||||
|
||||
// composite transformation stack
|
||||
BPoint parent_composite_origin;
|
||||
float parent_composite_scale;
|
||||
BAffineTransform parent_composite_transform;
|
||||
|
||||
// line modes
|
||||
join_mode line_join;
|
||||
cap_mode line_cap;
|
||||
|
@ -170,6 +170,10 @@ ViewState::ViewState()
|
||||
font_flags = font.Flags();
|
||||
font_aliasing = false;
|
||||
|
||||
parent_composite_transform.Reset();
|
||||
parent_composite_scale = 1.0f;
|
||||
parent_composite_origin.Set(0, 0);
|
||||
|
||||
// We only keep the B_VIEW_CLIP_REGION_BIT flag invalidated,
|
||||
// because we should get the clipping region from app_server.
|
||||
// The other flags do not need to be included because the data they
|
||||
@ -340,7 +344,8 @@ ViewState::UpdateFrom(BPrivate::PortLink &link)
|
||||
clipping_region_used = false;
|
||||
}
|
||||
|
||||
valid_flags = ~B_VIEW_CLIP_REGION_BIT;
|
||||
valid_flags = ~(B_VIEW_CLIP_REGION_BIT | B_VIEW_PARENT_COMPOSITE_BIT)
|
||||
| (valid_flags & B_VIEW_PARENT_COMPOSITE_BIT);
|
||||
}
|
||||
|
||||
} // namespace BPrivate
|
||||
@ -1837,6 +1842,8 @@ BView::PushState()
|
||||
|
||||
fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE);
|
||||
|
||||
fState->valid_flags &= ~B_VIEW_PARENT_COMPOSITE_BIT;
|
||||
|
||||
// initialize origin, scale and transform, new states start "clean".
|
||||
fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT
|
||||
| B_VIEW_TRANSFORM_BIT;
|
||||
@ -1989,6 +1996,71 @@ BView::Transform() const
|
||||
}
|
||||
|
||||
|
||||
BAffineTransform
|
||||
BView::TransformTo(coordinate_space basis) const
|
||||
{
|
||||
if (basis == B_CURRENT_STATE_COORDINATES)
|
||||
return B_AFFINE_IDENTITY_TRANSFORM;
|
||||
|
||||
if (!fState->IsValid(B_VIEW_PARENT_COMPOSITE_BIT) && fOwner != NULL) {
|
||||
_CheckLockAndSwitchCurrent();
|
||||
|
||||
fOwner->fLink->StartMessage(AS_VIEW_GET_PARENT_COMPOSITE);
|
||||
|
||||
int32 code;
|
||||
if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
|
||||
fOwner->fLink->Read<BAffineTransform>(&fState->parent_composite_transform);
|
||||
fOwner->fLink->Read<float>(&fState->parent_composite_scale);
|
||||
fOwner->fLink->Read<BPoint>(&fState->parent_composite_origin);
|
||||
}
|
||||
|
||||
fState->valid_flags |= B_VIEW_PARENT_COMPOSITE_BIT;
|
||||
}
|
||||
|
||||
BAffineTransform transform = fState->parent_composite_transform * Transform();
|
||||
float scale = fState->parent_composite_scale * Scale();
|
||||
transform.PreScaleBy(scale, scale);
|
||||
BPoint origin = Origin();
|
||||
origin.x *= fState->parent_composite_scale;
|
||||
origin.y *= fState->parent_composite_scale;
|
||||
origin += fState->parent_composite_origin;
|
||||
transform.TranslateBy(origin);
|
||||
|
||||
if (basis == B_PREVIOUS_STATE_COORDINATES) {
|
||||
transform.TranslateBy(-fState->parent_composite_origin);
|
||||
transform.PreMultiplyInverse(fState->parent_composite_transform);
|
||||
transform.ScaleBy(1.0f / fState->parent_composite_scale);
|
||||
return transform;
|
||||
}
|
||||
|
||||
if (basis == B_VIEW_COORDINATES)
|
||||
return transform;
|
||||
|
||||
origin = B_ORIGIN;
|
||||
|
||||
if (basis == B_PARENT_VIEW_COORDINATES || basis == B_PARENT_VIEW_DRAW_COORDINATES) {
|
||||
BView* parent = Parent();
|
||||
if (parent != NULL) {
|
||||
ConvertToParent(&origin);
|
||||
transform.TranslateBy(origin);
|
||||
if (basis == B_PARENT_VIEW_DRAW_COORDINATES)
|
||||
transform = transform.PreMultiplyInverse(parent->TransformTo(B_VIEW_COORDINATES));
|
||||
return transform;
|
||||
}
|
||||
basis = B_WINDOW_COORDINATES;
|
||||
}
|
||||
|
||||
ConvertToScreen(&origin);
|
||||
if (basis == B_WINDOW_COORDINATES) {
|
||||
BWindow* window = Window();
|
||||
if (window != NULL)
|
||||
origin -= window->Frame().LeftTop();
|
||||
}
|
||||
transform.TranslateBy(origin);
|
||||
return transform;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BView::TranslateBy(double x, double y)
|
||||
{
|
||||
|
@ -1640,6 +1640,23 @@ fDesktop->LockSingleWindow();
|
||||
fLink.Flush();
|
||||
break;
|
||||
}
|
||||
case AS_VIEW_GET_PARENT_COMPOSITE:
|
||||
{
|
||||
DrawState* state = fCurrentView->CurrentState()->PreviousState();
|
||||
|
||||
fLink.StartMessage(B_OK);
|
||||
if (state != NULL) {
|
||||
fLink.Attach<BAffineTransform>(state->CombinedTransform());
|
||||
fLink.Attach<float>(state->CombinedScale());
|
||||
fLink.Attach<BPoint>(state->CombinedOrigin());
|
||||
} else {
|
||||
fLink.Attach<BAffineTransform>(BAffineTransform());
|
||||
fLink.Attach<float>(1.0f);
|
||||
fLink.Attach<BPoint>(B_ORIGIN);
|
||||
}
|
||||
fLink.Flush();
|
||||
break;
|
||||
}
|
||||
case AS_VIEW_AFFINE_TRANSLATE:
|
||||
{
|
||||
double x, y;
|
||||
|
Loading…
Reference in New Issue
Block a user