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 <[email protected]> Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
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
|
// 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)
|
\fn void BView::TranslateBy(double x, double y)
|
||||||
\brief Translate the current view by coordinates.
|
\brief Translate the current view by coordinates.
|
||||||
|
|||||||
@@ -66,7 +66,5 @@
|
|||||||
All drawing operations in a BView use coordinates specified in the drawing space.
|
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
|
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
|
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
|
be done using the affine transform returned by BView::TransformTo.
|
||||||
legacy transformation functions are used, by applying the scale and origin returned
|
|
||||||
by the Scale() and Origin() functions.
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -70,6 +70,16 @@ enum {
|
|||||||
B_FONT_ALL = 0x000001FF
|
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
|
// view flags
|
||||||
const uint32 B_FULL_UPDATE_ON_RESIZE = 0x80000000UL; /* 31 */
|
const uint32 B_FULL_UPDATE_ON_RESIZE = 0x80000000UL; /* 31 */
|
||||||
const uint32 _B_RESERVED1_ = 0x40000000UL; /* 30 */
|
const uint32 _B_RESERVED1_ = 0x40000000UL; /* 30 */
|
||||||
@@ -324,6 +334,8 @@ public:
|
|||||||
void ScaleBy(double x, double y);
|
void ScaleBy(double x, double y);
|
||||||
void RotateBy(double angleRadians);
|
void RotateBy(double angleRadians);
|
||||||
|
|
||||||
|
BAffineTransform TransformTo(coordinate_space basis) const;
|
||||||
|
|
||||||
void PushState();
|
void PushState();
|
||||||
void PopState();
|
void PopState();
|
||||||
|
|
||||||
|
|||||||
@@ -358,6 +358,7 @@ enum {
|
|||||||
// transformation in addition to origin/scale
|
// transformation in addition to origin/scale
|
||||||
AS_VIEW_SET_TRANSFORM,
|
AS_VIEW_SET_TRANSFORM,
|
||||||
AS_VIEW_GET_TRANSFORM,
|
AS_VIEW_GET_TRANSFORM,
|
||||||
|
AS_VIEW_GET_PARENT_COMPOSITE,
|
||||||
|
|
||||||
AS_VIEW_AFFINE_TRANSLATE,
|
AS_VIEW_AFFINE_TRANSLATE,
|
||||||
AS_VIEW_AFFINE_SCALE,
|
AS_VIEW_AFFINE_SCALE,
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ enum {
|
|||||||
B_VIEW_WHICH_VIEW_COLOR_BIT = 0x00100000,
|
B_VIEW_WHICH_VIEW_COLOR_BIT = 0x00100000,
|
||||||
B_VIEW_WHICH_LOW_COLOR_BIT = 0x00200000,
|
B_VIEW_WHICH_LOW_COLOR_BIT = 0x00200000,
|
||||||
B_VIEW_WHICH_HIGH_COLOR_BIT = 0x00400000,
|
B_VIEW_WHICH_HIGH_COLOR_BIT = 0x00400000,
|
||||||
|
B_VIEW_PARENT_COMPOSITE_BIT = 0x00800000,
|
||||||
|
|
||||||
B_VIEW_ALL_BITS = 0x00ffffff,
|
B_VIEW_ALL_BITS = 0x00ffffff,
|
||||||
|
|
||||||
@@ -131,6 +132,11 @@ class ViewState {
|
|||||||
float scale;
|
float scale;
|
||||||
BAffineTransform transform;
|
BAffineTransform transform;
|
||||||
|
|
||||||
|
// composite transformation stack
|
||||||
|
BPoint parent_composite_origin;
|
||||||
|
float parent_composite_scale;
|
||||||
|
BAffineTransform parent_composite_transform;
|
||||||
|
|
||||||
// line modes
|
// line modes
|
||||||
join_mode line_join;
|
join_mode line_join;
|
||||||
cap_mode line_cap;
|
cap_mode line_cap;
|
||||||
|
|||||||
@@ -170,6 +170,10 @@ ViewState::ViewState()
|
|||||||
font_flags = font.Flags();
|
font_flags = font.Flags();
|
||||||
font_aliasing = false;
|
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,
|
// We only keep the B_VIEW_CLIP_REGION_BIT flag invalidated,
|
||||||
// because we should get the clipping region from app_server.
|
// because we should get the clipping region from app_server.
|
||||||
// The other flags do not need to be included because the data they
|
// 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;
|
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
|
} // namespace BPrivate
|
||||||
@@ -1837,6 +1842,8 @@ BView::PushState()
|
|||||||
|
|
||||||
fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE);
|
fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE);
|
||||||
|
|
||||||
|
fState->valid_flags &= ~B_VIEW_PARENT_COMPOSITE_BIT;
|
||||||
|
|
||||||
// initialize origin, scale and transform, new states start "clean".
|
// initialize origin, scale and transform, new states start "clean".
|
||||||
fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT
|
fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT
|
||||||
| B_VIEW_TRANSFORM_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
|
void
|
||||||
BView::TranslateBy(double x, double y)
|
BView::TranslateBy(double x, double y)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1640,6 +1640,23 @@ fDesktop->LockSingleWindow();
|
|||||||
fLink.Flush();
|
fLink.Flush();
|
||||||
break;
|
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:
|
case AS_VIEW_AFFINE_TRANSLATE:
|
||||||
{
|
{
|
||||||
double x, y;
|
double x, y;
|
||||||
|
|||||||
Reference in New Issue
Block a user