The beginnings of an app for testing the layout constraints of individual
widgets. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21110 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -8,8 +8,15 @@ SimpleTest LayoutTest1 :
|
|||||||
be
|
be
|
||||||
;
|
;
|
||||||
|
|
||||||
|
SimpleTest WidgetLayoutTest :
|
||||||
|
WidgetLayoutTest.cpp
|
||||||
|
:
|
||||||
|
be
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
if $(TARGET_PLATFORM) = libbe_test {
|
if $(TARGET_PLATFORM) = libbe_test {
|
||||||
HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : LayoutTest1
|
HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR)
|
||||||
|
: LayoutTest1 WidgetLayoutTest
|
||||||
: tests!apps ;
|
: tests!apps ;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,773 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Ingo Weinhold <[email protected]>.
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
|
#include <Button.h>
|
||||||
|
#include <Invoker.h>
|
||||||
|
#include <LayoutUtils.h>
|
||||||
|
#include <List.h>
|
||||||
|
#include <Region.h>
|
||||||
|
#include <View.h>
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
|
|
||||||
|
// internal messages
|
||||||
|
enum {
|
||||||
|
MSG_2D_SLIDER_VALUE_CHANGED = '2dsv',
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// missing operators in BPoint
|
||||||
|
|
||||||
|
BPoint
|
||||||
|
operator-(const BPoint& p)
|
||||||
|
{
|
||||||
|
return BPoint(-p.x, -p.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BPoint
|
||||||
|
operator+(const BPoint& p, const BSize& size)
|
||||||
|
{
|
||||||
|
return BPoint(p.x + size.width, p.y + size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// View
|
||||||
|
class View {
|
||||||
|
public:
|
||||||
|
View(BRect frame)
|
||||||
|
: fFrame(frame),
|
||||||
|
fContainer(NULL),
|
||||||
|
fParent(NULL),
|
||||||
|
fChildren(),
|
||||||
|
fViewColor(B_TRANSPARENT_32_BIT)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~View()
|
||||||
|
{
|
||||||
|
// delete children
|
||||||
|
for (int32 i = CountChildren() - 1; i >= 0; i--)
|
||||||
|
delete RemoveChild(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void SetFrame(BRect frame)
|
||||||
|
{
|
||||||
|
if (frame != fFrame && frame.IsValid()) {
|
||||||
|
BRect oldFrame(frame);
|
||||||
|
Invalidate();
|
||||||
|
fFrame = frame;
|
||||||
|
Invalidate();
|
||||||
|
|
||||||
|
FrameChanged(oldFrame, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BRect Frame() const
|
||||||
|
{
|
||||||
|
return fFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
BRect Bounds() const
|
||||||
|
{
|
||||||
|
return BRect(fFrame).OffsetToCopy(B_ORIGIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLocation(BPoint location)
|
||||||
|
{
|
||||||
|
SetFrame(fFrame.OffsetToCopy(location));
|
||||||
|
}
|
||||||
|
|
||||||
|
BPoint Location() const
|
||||||
|
{
|
||||||
|
return fFrame.LeftTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSize(BSize size)
|
||||||
|
{
|
||||||
|
BRect frame(fFrame);
|
||||||
|
frame.right = frame.left + size.width;
|
||||||
|
frame.bottom = frame.top + size.height;
|
||||||
|
SetFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
BSize Size() const
|
||||||
|
{
|
||||||
|
return BSize(Frame());
|
||||||
|
}
|
||||||
|
|
||||||
|
BPoint LocationInContainer() const
|
||||||
|
{
|
||||||
|
BPoint location = fFrame.LeftTop();
|
||||||
|
return (fParent ? fParent->LocationInContainer() + location : location);
|
||||||
|
}
|
||||||
|
|
||||||
|
BRect FrameInContainer() const
|
||||||
|
{
|
||||||
|
BRect frame(fFrame);
|
||||||
|
return frame.OffsetToCopy(LocationInContainer());
|
||||||
|
}
|
||||||
|
|
||||||
|
BPoint ConvertFromContainer(BPoint point) const
|
||||||
|
{
|
||||||
|
return point - LocationInContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
BRect ConvertFromContainer(BRect rect) const
|
||||||
|
{
|
||||||
|
return rect.OffsetBySelf(-LocationInContainer());
|
||||||
|
}
|
||||||
|
|
||||||
|
BPoint ConvertToContainer(BPoint point) const
|
||||||
|
{
|
||||||
|
return point + LocationInContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
BRect ConvertToContainer(BRect rect) const
|
||||||
|
{
|
||||||
|
return rect.OffsetBySelf(LocationInContainer());
|
||||||
|
}
|
||||||
|
|
||||||
|
View* Parent() const
|
||||||
|
{
|
||||||
|
return fParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
BView* Container() const
|
||||||
|
{
|
||||||
|
return fContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddChild(View* child)
|
||||||
|
{
|
||||||
|
if (!child)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (child->Parent() || child->Container()) {
|
||||||
|
fprintf(stderr, "View::AddChild(): view %p already has a parent "
|
||||||
|
"or is the container view\n", child);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fChildren.AddItem(child))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
child->_AddedToParent(this);
|
||||||
|
|
||||||
|
child->Invalidate();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoveChild(View* child)
|
||||||
|
{
|
||||||
|
if (!child)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return RemoveChild(IndexOfChild(child));
|
||||||
|
}
|
||||||
|
|
||||||
|
View* RemoveChild(int32 index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= fChildren.CountItems())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
View* child = ChildAt(index);
|
||||||
|
child->Invalidate();
|
||||||
|
child->_RemovingFromParent();
|
||||||
|
fChildren.RemoveItem(index);
|
||||||
|
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 CountChildren() const
|
||||||
|
{
|
||||||
|
return fChildren.CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
View* ChildAt(int32 index) const
|
||||||
|
{
|
||||||
|
return (View*)fChildren.ItemAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
View* ChildAt(BPoint point) const
|
||||||
|
{
|
||||||
|
for (int32 i = 0; View* child = ChildAt(i); i++) {
|
||||||
|
if (child->Frame().Contains(point))
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
View* AncestorAt(BPoint point, BPoint* localPoint = NULL) const
|
||||||
|
{
|
||||||
|
if (!Bounds().Contains(point))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
View* view = const_cast<View*>(this);
|
||||||
|
|
||||||
|
// Iterate deeper down the hierarchy, until we reach a view that
|
||||||
|
// doesn't have a child at the location.
|
||||||
|
while (true) {
|
||||||
|
View* child = view->ChildAt(point);
|
||||||
|
if (!child) {
|
||||||
|
if (localPoint)
|
||||||
|
*localPoint = point;
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
view = child;
|
||||||
|
point -= view->Frame().LeftTop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 IndexOfChild(View* child) const
|
||||||
|
{
|
||||||
|
return (child ? fChildren.IndexOf(child) : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Invalidate(BRect rect)
|
||||||
|
{
|
||||||
|
if (fContainer) {
|
||||||
|
rect = rect & Bounds();
|
||||||
|
fContainer->Invalidate(rect.OffsetByCopy(LocationInContainer()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Invalidate()
|
||||||
|
{
|
||||||
|
Invalidate(Bounds());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetViewColor(rgb_color color)
|
||||||
|
{
|
||||||
|
fViewColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Draw(BView* container, BRect updateRect)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseUp(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void AddedToContainer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void RemovingFromContainer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void FrameChanged(BRect oldFrame, BRect newFrame)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void _AddedToParent(View* parent)
|
||||||
|
{
|
||||||
|
fParent = parent;
|
||||||
|
|
||||||
|
if (parent->Container()) {
|
||||||
|
Invalidate();
|
||||||
|
_AddedToContainer(parent->Container());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void _RemovingFromParent()
|
||||||
|
{
|
||||||
|
if (fContainer)
|
||||||
|
_RemovingFromContainer();
|
||||||
|
|
||||||
|
fParent = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void _AddedToContainer(BView* container)
|
||||||
|
{
|
||||||
|
fContainer = container;
|
||||||
|
|
||||||
|
AddedToContainer();
|
||||||
|
|
||||||
|
for (int32 i = 0; View* child = ChildAt(i); i++)
|
||||||
|
child->_AddedToContainer(fContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void _RemovingFromContainer()
|
||||||
|
{
|
||||||
|
for (int32 i = 0; View* child = ChildAt(i); i++)
|
||||||
|
child->_RemovingFromContainer();
|
||||||
|
|
||||||
|
RemovingFromContainer();
|
||||||
|
|
||||||
|
fContainer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _Draw(BView* container, BRect updateRect)
|
||||||
|
{
|
||||||
|
//printf("%p->View::_Draw(): ", this);
|
||||||
|
//updateRect.PrintToStream();
|
||||||
|
|
||||||
|
// compute the clipping region
|
||||||
|
BRegion region(Bounds());
|
||||||
|
for (int32 i = 0; View* child = ChildAt(i); i++)
|
||||||
|
region.Exclude(child->Frame());
|
||||||
|
|
||||||
|
if (region.Frame().IsValid()) {
|
||||||
|
// set the clipping region
|
||||||
|
container->ConstrainClippingRegion(®ion);
|
||||||
|
|
||||||
|
// draw the background, if it isn't transparent
|
||||||
|
if (fViewColor.alpha != 0) {
|
||||||
|
container->SetLowColor(fViewColor);
|
||||||
|
container->FillRect(updateRect, B_SOLID_LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw this view
|
||||||
|
Draw(container, updateRect);
|
||||||
|
|
||||||
|
// revert the clipping region
|
||||||
|
region.Set(Bounds());
|
||||||
|
container->ConstrainClippingRegion(®ion);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the children
|
||||||
|
if (CountChildren() > 0) {
|
||||||
|
container->PushState();
|
||||||
|
|
||||||
|
for (int32 i = 0; View* child = ChildAt(i); i++) {
|
||||||
|
BRect childFrame = child->Frame();
|
||||||
|
BRect childUpdateRect = updateRect & childFrame;
|
||||||
|
if (childUpdateRect.IsValid()) {
|
||||||
|
// set origin
|
||||||
|
childUpdateRect.OffsetBy(-childFrame.LeftTop());
|
||||||
|
container->SetOrigin(childFrame.LeftTop());
|
||||||
|
|
||||||
|
// draw
|
||||||
|
child->_Draw(container, childUpdateRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
container->PopState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BRect fFrame;
|
||||||
|
BView* fContainer;
|
||||||
|
View* fParent;
|
||||||
|
BList fChildren;
|
||||||
|
rgb_color fViewColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ViewContainer
|
||||||
|
class ViewContainer : public BView, public View {
|
||||||
|
public:
|
||||||
|
ViewContainer(BRect frame)
|
||||||
|
: BView(frame, "view container", B_FOLLOW_NONE, B_WILL_DRAW),
|
||||||
|
View(frame.OffsetToCopy(B_ORIGIN)),
|
||||||
|
fMouseFocus(NULL)
|
||||||
|
{
|
||||||
|
BView::SetViewColor(B_TRANSPARENT_32_BIT);
|
||||||
|
_AddedToContainer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
View::_Draw(this, updateRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint where)
|
||||||
|
{
|
||||||
|
//printf("ViewContainer::MouseDown((%f, %f))\n", where.x, where.y);
|
||||||
|
// get mouse buttons and modifiers
|
||||||
|
uint32 buttons;
|
||||||
|
int32 modifiers;
|
||||||
|
_GetButtonsAndModifiers(buttons, modifiers);
|
||||||
|
|
||||||
|
// get mouse focus
|
||||||
|
if (!fMouseFocus && (buttons & B_PRIMARY_MOUSE_BUTTON))
|
||||||
|
fMouseFocus = AncestorAt(where);
|
||||||
|
//printf(" mouse focus: %p (this: %p)\n", fMouseFocus, this);
|
||||||
|
|
||||||
|
// call hook
|
||||||
|
if (fMouseFocus) {
|
||||||
|
fMouseFocus->MouseDown(fMouseFocus->ConvertFromContainer(where),
|
||||||
|
buttons, modifiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseUp(BPoint where)
|
||||||
|
{
|
||||||
|
//printf("ViewContainer::MouseUp((%f, %f))\n", where.x, where.y);
|
||||||
|
if (!fMouseFocus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get mouse buttons and modifiers
|
||||||
|
uint32 buttons;
|
||||||
|
int32 modifiers;
|
||||||
|
_GetButtonsAndModifiers(buttons, modifiers);
|
||||||
|
|
||||||
|
// call hook
|
||||||
|
if (fMouseFocus) {
|
||||||
|
fMouseFocus->MouseUp(fMouseFocus->ConvertFromContainer(where),
|
||||||
|
buttons, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unset the mouse focus when the primary button has been released
|
||||||
|
if (!(buttons & B_PRIMARY_MOUSE_BUTTON))
|
||||||
|
fMouseFocus = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 code, const BMessage* message)
|
||||||
|
{
|
||||||
|
//printf("ViewContainer::MouseMoved((%f, %f))\n", where.x, where.y);
|
||||||
|
if (!fMouseFocus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get mouse buttons and modifiers
|
||||||
|
uint32 buttons;
|
||||||
|
int32 modifiers;
|
||||||
|
_GetButtonsAndModifiers(buttons, modifiers);
|
||||||
|
|
||||||
|
// call hook
|
||||||
|
if (fMouseFocus) {
|
||||||
|
fMouseFocus->MouseMoved(fMouseFocus->ConvertFromContainer(where),
|
||||||
|
buttons, modifiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Draw(BView* container, BRect updateRect)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseUp(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _GetButtonsAndModifiers(uint32& buttons, int32& modifiers)
|
||||||
|
{
|
||||||
|
buttons = 0;
|
||||||
|
modifiers = 0;
|
||||||
|
|
||||||
|
if (BMessage* message = Window()->CurrentMessage()) {
|
||||||
|
if (message->FindInt32("buttons", (int32*)&buttons) != B_OK)
|
||||||
|
buttons = 0;
|
||||||
|
if (message->FindInt32("modifiers", modifiers) != B_OK)
|
||||||
|
modifiers = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
View* fMouseFocus;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// TwoDimensionalSliderView
|
||||||
|
class TwoDimensionalSliderView : public View, public BInvoker {
|
||||||
|
public:
|
||||||
|
TwoDimensionalSliderView(BMessage* message = NULL,
|
||||||
|
BMessenger target = BMessenger())
|
||||||
|
: View(BRect(0, 0, 4, 4)),
|
||||||
|
BInvoker(message, target),
|
||||||
|
fMinLocation(0, 0),
|
||||||
|
fMaxLocation(0, 0),
|
||||||
|
fDragging(false)
|
||||||
|
{
|
||||||
|
SetViewColor((rgb_color){0, 120, 0, 255});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLocationRange(BPoint minLocation, BPoint maxLocation)
|
||||||
|
{
|
||||||
|
if (maxLocation.x < minLocation.x)
|
||||||
|
maxLocation.x = minLocation.x;
|
||||||
|
if (maxLocation.y < minLocation.y)
|
||||||
|
maxLocation.y = minLocation.y;
|
||||||
|
|
||||||
|
fMinLocation = minLocation;
|
||||||
|
fMaxLocation = maxLocation;
|
||||||
|
|
||||||
|
// force valid value
|
||||||
|
SetValue(Value());
|
||||||
|
}
|
||||||
|
|
||||||
|
BPoint MinLocation() const
|
||||||
|
{
|
||||||
|
return fMinLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
BPoint MaxLocation() const
|
||||||
|
{
|
||||||
|
return fMaxLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
BPoint Value() const
|
||||||
|
{
|
||||||
|
return Location() - fMinLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetValue(BPoint value)
|
||||||
|
{
|
||||||
|
BPoint location = fMinLocation + value;
|
||||||
|
if (location.x < fMinLocation.x)
|
||||||
|
location.x = fMinLocation.x;
|
||||||
|
if (location.y < fMinLocation.y)
|
||||||
|
location.y = fMinLocation.y;
|
||||||
|
if (location.x > fMaxLocation.x)
|
||||||
|
location.x = fMaxLocation.x;
|
||||||
|
if (location.y > fMaxLocation.y)
|
||||||
|
location.y = fMaxLocation.y;
|
||||||
|
|
||||||
|
if (location != Location()) {
|
||||||
|
SetFrame(Frame().OffsetToCopy(location));
|
||||||
|
|
||||||
|
// send the message
|
||||||
|
if (Message()) {
|
||||||
|
BMessage message(*Message());
|
||||||
|
message.AddPoint("value", Value());
|
||||||
|
InvokeNotify(&message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
if (fDragging)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fOriginalLocation = Frame().LeftTop();
|
||||||
|
fOriginalPoint = ConvertToContainer(where);
|
||||||
|
fDragging = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseUp(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
if (!fDragging || (buttons & B_PRIMARY_MOUSE_BUTTON))
|
||||||
|
return;
|
||||||
|
|
||||||
|
fDragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
if (!fDragging)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BPoint moved = ConvertToContainer(where) - fOriginalPoint;
|
||||||
|
SetValue(fOriginalLocation - fMinLocation + moved);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BPoint fMinLocation;
|
||||||
|
BPoint fMaxLocation;
|
||||||
|
bool fDragging;
|
||||||
|
BPoint fOriginalPoint;
|
||||||
|
BPoint fOriginalLocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// WrapperView
|
||||||
|
class WrapperView : public View {
|
||||||
|
public:
|
||||||
|
WrapperView(BRect frame, BView* view)
|
||||||
|
: View(frame),
|
||||||
|
fView(view),
|
||||||
|
fInsets(1, 1, 1, 1)
|
||||||
|
{
|
||||||
|
SetViewColor((rgb_color){255, 0, 0, 255});
|
||||||
|
}
|
||||||
|
|
||||||
|
BView* GetView() const
|
||||||
|
{
|
||||||
|
return fView;
|
||||||
|
}
|
||||||
|
|
||||||
|
BSize MinSize() const
|
||||||
|
{
|
||||||
|
return _FromViewSize(fView->MinSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
BSize MaxSize() const
|
||||||
|
{
|
||||||
|
return _FromViewSize(fView->MaxSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
BSize PreferredSize() const
|
||||||
|
{
|
||||||
|
return _FromViewSize(fView->PreferredSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void AddedToContainer()
|
||||||
|
{
|
||||||
|
_UpdateViewFrame();
|
||||||
|
|
||||||
|
Container()->AddChild(fView);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void RemovingFromContainer()
|
||||||
|
{
|
||||||
|
Container()->RemoveChild(fView);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void FrameChanged(BRect oldFrame, BRect newFrame)
|
||||||
|
{
|
||||||
|
_UpdateViewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _UpdateViewFrame()
|
||||||
|
{
|
||||||
|
BRect frame(_ViewFrameInContainer());
|
||||||
|
fView->MoveTo(frame.LeftTop());
|
||||||
|
fView->ResizeTo(frame.Width(), frame.Height());
|
||||||
|
}
|
||||||
|
|
||||||
|
BRect _ViewFrame() const
|
||||||
|
{
|
||||||
|
BRect viewFrame(Bounds());
|
||||||
|
viewFrame.left += fInsets.left;
|
||||||
|
viewFrame.top += fInsets.top;
|
||||||
|
viewFrame.right -= fInsets.right;
|
||||||
|
viewFrame.bottom -= fInsets.bottom;
|
||||||
|
|
||||||
|
return viewFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
BRect _ViewFrameInContainer() const
|
||||||
|
{
|
||||||
|
return ConvertToContainer(_ViewFrame());
|
||||||
|
}
|
||||||
|
|
||||||
|
BSize _FromViewSize(BSize size) const
|
||||||
|
{
|
||||||
|
float horizontalInsets = fInsets.left + fInsets.right - 1;
|
||||||
|
float verticalInsets = fInsets.top + fInsets.bottom - 1;
|
||||||
|
return BSize(BLayoutUtils::AddDistances(size.width, horizontalInsets),
|
||||||
|
BLayoutUtils::AddDistances(size.height, verticalInsets));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BView* fView;
|
||||||
|
BRect fInsets;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// TestWindow
|
||||||
|
class TestWindow : public BWindow {
|
||||||
|
public:
|
||||||
|
TestWindow()
|
||||||
|
: BWindow(BRect(100, 100, 700, 500), "Widget Layout",
|
||||||
|
B_TITLED_WINDOW,
|
||||||
|
B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE | B_NOT_RESIZABLE
|
||||||
|
| B_NOT_ZOOMABLE)
|
||||||
|
{
|
||||||
|
ViewContainer* viewContainer = new ViewContainer(Bounds());
|
||||||
|
viewContainer->View::SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
AddChild(viewContainer);
|
||||||
|
|
||||||
|
View* view = new View(BRect(10, 10, 400, 300));
|
||||||
|
viewContainer->View::AddChild(view);
|
||||||
|
view->SetViewColor((rgb_color){200, 200, 240, 255});
|
||||||
|
|
||||||
|
// wrapper view
|
||||||
|
fWrapperView = new WrapperView(BRect(10, 10, 100, 100),
|
||||||
|
new BButton(BRect(0, 0, 9, 9), "test button", "Ooh, press me!",
|
||||||
|
(BMessage*)NULL, B_FOLLOW_NONE,
|
||||||
|
B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE));
|
||||||
|
fWrapperView->GetView()->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
|
||||||
|
view->AddChild(fWrapperView);
|
||||||
|
fWrapperView->SetSize(fWrapperView->PreferredSize());
|
||||||
|
|
||||||
|
// slider view
|
||||||
|
fSliderView = new TwoDimensionalSliderView(
|
||||||
|
new BMessage(MSG_2D_SLIDER_VALUE_CHANGED), this);
|
||||||
|
fSliderView->SetLocationRange(BPoint(30, 40), BPoint(150, 130));
|
||||||
|
view->AddChild(fSliderView);
|
||||||
|
|
||||||
|
_UpdateSliderConstraints();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case MSG_2D_SLIDER_VALUE_CHANGED:
|
||||||
|
{
|
||||||
|
// message->PrintToStream();
|
||||||
|
BPoint sliderLocation(fSliderView->Location());
|
||||||
|
BPoint wrapperLocation(fWrapperView->Location());
|
||||||
|
BSize size(sliderLocation.x - wrapperLocation.x - 1,
|
||||||
|
sliderLocation.y - wrapperLocation.y - 1);
|
||||||
|
fWrapperView->SetSize(size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
BWindow::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _UpdateSliderConstraints()
|
||||||
|
{
|
||||||
|
BPoint wrapperLocation(fWrapperView->Location());
|
||||||
|
BSize minWrapperSize(fWrapperView->MinSize());
|
||||||
|
BSize maxWrapperSize(fWrapperView->MaxSize());
|
||||||
|
|
||||||
|
BPoint minSliderLocation = wrapperLocation + minWrapperSize
|
||||||
|
+ BPoint(1, 1);
|
||||||
|
BPoint maxSliderLocation = wrapperLocation + maxWrapperSize
|
||||||
|
+ BPoint(1, 1);
|
||||||
|
|
||||||
|
BSize sliderSize(fSliderView->Size());
|
||||||
|
BSize parentSize(fSliderView->Parent()->Size());
|
||||||
|
if (maxSliderLocation.x + sliderSize.width > parentSize.width)
|
||||||
|
maxSliderLocation.x = parentSize.width - sliderSize.width;
|
||||||
|
if (maxSliderLocation.y + sliderSize.height > parentSize.height)
|
||||||
|
maxSliderLocation.y = parentSize.height - sliderSize.height;
|
||||||
|
|
||||||
|
fSliderView->SetLocationRange(minSliderLocation, maxSliderLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
WrapperView* fWrapperView;
|
||||||
|
TwoDimensionalSliderView* fSliderView;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
BApplication app("application/x-vnd.haiku.widget-layout-test");
|
||||||
|
|
||||||
|
BWindow* window = new TestWindow;
|
||||||
|
window->Show();
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user