* Made sure the tool tip stays on screen without moving itself below the cursor;
I'm afraid there is nothing left of stippi's earlier solution. This fixes bug #5097. * The alignment as specified in the BToolTip is now respected. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34616 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
3533b6597d
commit
9d6dc833bd
@ -30,126 +30,271 @@ static const uint32 kMsgCloseToolTip = 'clos';
|
|||||||
|
|
||||||
namespace BPrivate {
|
namespace BPrivate {
|
||||||
|
|
||||||
|
|
||||||
class ToolTipView : public BView {
|
class ToolTipView : public BView {
|
||||||
public:
|
public:
|
||||||
ToolTipView(BToolTip* tip)
|
ToolTipView(BToolTip* tip);
|
||||||
:
|
virtual ~ToolTipView();
|
||||||
BView("tool tip", B_WILL_DRAW),
|
|
||||||
fToolTip(tip),
|
|
||||||
fHidden(false)
|
|
||||||
{
|
|
||||||
fToolTip->AcquireReference();
|
|
||||||
SetViewColor(ui_color(B_TOOL_TIP_BACKGROUND_COLOR));
|
|
||||||
|
|
||||||
BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
|
virtual void AttachedToWindow();
|
||||||
layout->SetInsets(5, 5, 5, 5);
|
virtual void DetachedFromWindow();
|
||||||
SetLayout(layout);
|
|
||||||
|
|
||||||
AddChild(fToolTip->View());
|
virtual void FrameResized(float width, float height);
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* dragMessage);
|
||||||
|
|
||||||
|
void HideTip();
|
||||||
|
void ShowTip();
|
||||||
|
void ResetWindowFrame(BPoint where);
|
||||||
|
|
||||||
|
BToolTip* Tip() const { return fToolTip; }
|
||||||
|
bool IsTipHidden() const { return fHidden; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
BToolTip* fToolTip;
|
||||||
|
bool fHidden;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ToolTipView::ToolTipView(BToolTip* tip)
|
||||||
|
:
|
||||||
|
BView("tool tip", B_WILL_DRAW | B_FRAME_EVENTS),
|
||||||
|
fToolTip(tip),
|
||||||
|
fHidden(false)
|
||||||
|
{
|
||||||
|
fToolTip->AcquireReference();
|
||||||
|
SetViewColor(ui_color(B_TOOL_TIP_BACKGROUND_COLOR));
|
||||||
|
|
||||||
|
BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
|
||||||
|
layout->SetInsets(5, 5, 5, 5);
|
||||||
|
SetLayout(layout);
|
||||||
|
|
||||||
|
AddChild(fToolTip->View());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ToolTipView::~ToolTipView()
|
||||||
|
{
|
||||||
|
fToolTip->ReleaseReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ToolTipView::AttachedToWindow()
|
||||||
|
{
|
||||||
|
SetEventMask(B_POINTER_EVENTS, 0);
|
||||||
|
fToolTip->AttachedToWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ToolTipView::DetachedFromWindow()
|
||||||
|
{
|
||||||
|
BToolTipManager* manager = BToolTipManager::Manager();
|
||||||
|
manager->Lock();
|
||||||
|
|
||||||
|
RemoveChild(fToolTip->View());
|
||||||
|
// don't delete this one!
|
||||||
|
fToolTip->DetachedFromWindow();
|
||||||
|
|
||||||
|
manager->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ToolTipView::FrameResized(float width, float height)
|
||||||
|
{
|
||||||
|
BPoint where;
|
||||||
|
GetMouse(&where, NULL, false);
|
||||||
|
|
||||||
|
ResetWindowFrame(ConvertToScreen(where));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ToolTipView::MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* dragMessage)
|
||||||
|
{
|
||||||
|
if (fToolTip->IsSticky()) {
|
||||||
|
ResetWindowFrame(ConvertToScreen(where));
|
||||||
|
} else if (transit == B_ENTERED_VIEW) {
|
||||||
|
// close instantly if the user managed to enter
|
||||||
|
Window()->Quit();
|
||||||
|
} else {
|
||||||
|
// close with the preferred delay in case the mouse just moved
|
||||||
|
HideTip();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~ToolTipView()
|
|
||||||
{
|
|
||||||
fToolTip->ReleaseReference();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void AttachedToWindow()
|
void
|
||||||
{
|
ToolTipView::HideTip()
|
||||||
SetEventMask(B_POINTER_EVENTS, 0);
|
{
|
||||||
fToolTip->AttachedToWindow();
|
if (fHidden)
|
||||||
}
|
return;
|
||||||
|
|
||||||
virtual void DetachedFromWindow()
|
BMessage quit(kMsgCloseToolTip);
|
||||||
{
|
BMessageRunner::StartSending(Window(), &quit,
|
||||||
BToolTipManager* manager = BToolTipManager::Manager();
|
BToolTipManager::Manager()->HideDelay(), 1);
|
||||||
manager->Lock();
|
fHidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
RemoveChild(fToolTip->View());
|
|
||||||
// don't delete this one!
|
|
||||||
fToolTip->DetachedFromWindow();
|
|
||||||
|
|
||||||
manager->Unlock();
|
void
|
||||||
}
|
ToolTipView::ShowTip()
|
||||||
|
{
|
||||||
|
fHidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
|
||||||
const BMessage* dragMessage)
|
/*! Tries to find the right frame to show the tool tip in, trying to use the
|
||||||
{
|
alignment that the tool tip specifies.
|
||||||
if (fToolTip->IsSticky()) {
|
Makes sure the tool tip can be shown on screen in its entirety, ie. it will
|
||||||
// TODO: move window with mouse!
|
resize the window if necessary.
|
||||||
Window()->MoveTo(
|
*/
|
||||||
ConvertToScreen(where) + fToolTip->MouseRelativeLocation());
|
void
|
||||||
} else if (transit == B_ENTERED_VIEW) {
|
ToolTipView::ResetWindowFrame(BPoint where)
|
||||||
// close instantly if the user managed to enter
|
{
|
||||||
Window()->Quit();
|
if (Window() == NULL)
|
||||||
} else {
|
return;
|
||||||
// close with the preferred delay in case the mouse just moved
|
|
||||||
HideTip();
|
BSize size = PreferredSize();
|
||||||
|
|
||||||
|
BScreen screen(Window());
|
||||||
|
BRect screenFrame = screen.Frame().InsetBySelf(2, 2);
|
||||||
|
BPoint offset = fToolTip->MouseRelativeLocation();
|
||||||
|
|
||||||
|
// Ensure that the tip can be placed on screen completely
|
||||||
|
|
||||||
|
if (size.width > screenFrame.Width())
|
||||||
|
size.width = screenFrame.Width();
|
||||||
|
|
||||||
|
if (size.width > where.x - screenFrame.left
|
||||||
|
&& size.width > screenFrame.right - where.x) {
|
||||||
|
// There is no space to put the tip to the left or the right of the
|
||||||
|
// cursor, it can either be below or above it
|
||||||
|
if (size.height > where.y - screenFrame.top
|
||||||
|
&& where.y - screenFrame.top > screenFrame.Height() / 2) {
|
||||||
|
size.height = where.y - offset.y - screenFrame.top;
|
||||||
|
} else if (size.height > screenFrame.bottom - where.y
|
||||||
|
&& screenFrame.bottom - where.y > screenFrame.Height() / 2) {
|
||||||
|
size.height = screenFrame.bottom - where.y - offset.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HideTip()
|
// Find best alignment, starting with the requested one
|
||||||
{
|
|
||||||
if (fHidden)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BMessage quit(kMsgCloseToolTip);
|
BAlignment alignment = fToolTip->Alignment();
|
||||||
BMessageRunner::StartSending(Window(), &quit,
|
BPoint location = where;
|
||||||
BToolTipManager::Manager()->HideDelay(), 1);
|
bool doesNotFit = false;
|
||||||
fHidden = true;
|
|
||||||
|
switch (alignment.horizontal) {
|
||||||
|
case B_ALIGN_LEFT:
|
||||||
|
location.x -= size.width + offset.x;
|
||||||
|
if (location.x < screenFrame.left) {
|
||||||
|
location.x = screenFrame.left;
|
||||||
|
doesNotFit = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case B_ALIGN_CENTER:
|
||||||
|
location.x -= size.width / 2 - offset.x;
|
||||||
|
if (location.x < screenFrame.left) {
|
||||||
|
location.x = screenFrame.left;
|
||||||
|
doesNotFit = true;
|
||||||
|
} else if (location.x + size.width > screenFrame.right) {
|
||||||
|
location.x = screenFrame.right - size.width;
|
||||||
|
doesNotFit = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
location.x += offset.x;
|
||||||
|
if (location.x + size.width > screenFrame.right) {
|
||||||
|
location.x = screenFrame.right - size.width;
|
||||||
|
doesNotFit = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowTip()
|
if ((doesNotFit && alignment.vertical == B_ALIGN_MIDDLE)
|
||||||
{
|
|| (alignment.vertical == B_ALIGN_MIDDLE
|
||||||
fHidden = false;
|
&& alignment.horizontal == B_ALIGN_CENTER))
|
||||||
|
alignment.vertical = B_ALIGN_BOTTOM;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
switch (alignment.vertical) {
|
||||||
|
case B_ALIGN_TOP:
|
||||||
|
location.y = where.y - size.height - offset.y;
|
||||||
|
if (location.y < screenFrame.top) {
|
||||||
|
alignment.vertical = B_ALIGN_BOTTOM;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_ALIGN_MIDDLE:
|
||||||
|
location.y -= size.height / 2 - offset.y;
|
||||||
|
if (location.y < screenFrame.top)
|
||||||
|
location.y = screenFrame.top;
|
||||||
|
else if (location.y + size.height > screenFrame.bottom)
|
||||||
|
location.y = screenFrame.bottom - size.height;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
location.y = where.y + offset.y;
|
||||||
|
if (location.y + size.height > screenFrame.bottom) {
|
||||||
|
alignment.vertical = B_ALIGN_TOP;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
BToolTip* Tip() const { return fToolTip; }
|
where = location;
|
||||||
bool IsTipHidden() const { return fHidden; }
|
|
||||||
|
|
||||||
private:
|
// Cut off any out-of-screen areas
|
||||||
BToolTip* fToolTip;
|
|
||||||
bool fHidden;
|
if (screenFrame.left > where.x) {
|
||||||
};
|
size.width -= where.x - screenFrame.left;
|
||||||
|
where.x = screenFrame.left;
|
||||||
|
} else if (screenFrame.right < where.x + size.width)
|
||||||
|
size.width = screenFrame.right - where.x;
|
||||||
|
|
||||||
|
if (screenFrame.top > where.y) {
|
||||||
|
size.height -= where.y - screenFrame.top;
|
||||||
|
where.y = screenFrame.top;
|
||||||
|
} else if (screenFrame.bottom < where.y + size.height)
|
||||||
|
size.height -= screenFrame.bottom - where.y;
|
||||||
|
|
||||||
|
// Change window frame
|
||||||
|
|
||||||
|
Window()->ResizeTo(size.width, size.height);
|
||||||
|
Window()->MoveTo(where);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
ToolTipWindow::ToolTipWindow(BToolTip* tip, BPoint where)
|
ToolTipWindow::ToolTipWindow(BToolTip* tip, BPoint where)
|
||||||
:
|
:
|
||||||
BWindow(BRect(0, 0, 250, 10), "tool tip", B_BORDERED_WINDOW_LOOK,
|
BWindow(BRect(0, 0, 250, 10).OffsetBySelf(where), "tool tip",
|
||||||
kMenuWindowFeel, B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE
|
B_BORDERED_WINDOW_LOOK, kMenuWindowFeel,
|
||||||
| B_AUTO_UPDATE_SIZE_LIMITS | B_AVOID_FRONT | B_AVOID_FOCUS)
|
B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_AUTO_UPDATE_SIZE_LIMITS
|
||||||
|
| B_AVOID_FRONT | B_AVOID_FOCUS)
|
||||||
{
|
{
|
||||||
SetLayout(new BGroupLayout(B_VERTICAL));
|
SetLayout(new BGroupLayout(B_VERTICAL));
|
||||||
|
|
||||||
BToolTipManager* manager = BToolTipManager::Manager();
|
BToolTipManager* manager = BToolTipManager::Manager();
|
||||||
|
ToolTipView* view = new ToolTipView(tip);
|
||||||
|
|
||||||
manager->Lock();
|
manager->Lock();
|
||||||
AddChild(new ToolTipView(tip));
|
AddChild(view);
|
||||||
manager->Unlock();
|
manager->Unlock();
|
||||||
|
|
||||||
BSize size = ChildAt(0)->PreferredSize();
|
// figure out size and location
|
||||||
ResizeTo(size.width, size.height);
|
|
||||||
//AddChild(BLayoutBuilder::Group<>(B_VERTICAL).Add(new ToolTipView(tip)));
|
|
||||||
|
|
||||||
// figure out location
|
view->ResetWindowFrame(where);
|
||||||
// TODO: take alignment into account!
|
|
||||||
where += tip->MouseRelativeLocation();
|
|
||||||
|
|
||||||
BScreen screen(this);
|
|
||||||
if (screen.IsValid()) {
|
|
||||||
BRect screenFrame = screen.Frame().InsetBySelf(5, 5);
|
|
||||||
BRect frame = Frame().OffsetToSelf(where);
|
|
||||||
if (!screenFrame.Contains(frame)) {
|
|
||||||
if (screenFrame.top > frame.top)
|
|
||||||
where.y -= frame.top - screenFrame.top;
|
|
||||||
else if (screenFrame.bottom < frame.bottom)
|
|
||||||
where.y -= frame.bottom - screenFrame.bottom;
|
|
||||||
if (screenFrame.left > frame.left)
|
|
||||||
where.x -= frame.left - screenFrame.left;
|
|
||||||
else if (screenFrame.right < frame.right)
|
|
||||||
where.x -= frame.right - screenFrame.right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MoveTo(where);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -189,10 +334,11 @@ ToolTipWindow::MessageReceived(BMessage* message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace BPrivate
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
/*static*/ BToolTipManager*
|
/*static*/ BToolTipManager*
|
||||||
|
Loading…
Reference in New Issue
Block a user