* 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,78 +30,22 @@ static const uint32 kMsgCloseToolTip = 'clos';
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
|
||||
class ToolTipView : public BView {
|
||||
public:
|
||||
ToolTipView(BToolTip* tip)
|
||||
:
|
||||
BView("tool tip", B_WILL_DRAW),
|
||||
fToolTip(tip),
|
||||
fHidden(false)
|
||||
{
|
||||
fToolTip->AcquireReference();
|
||||
SetViewColor(ui_color(B_TOOL_TIP_BACKGROUND_COLOR));
|
||||
ToolTipView(BToolTip* tip);
|
||||
virtual ~ToolTipView();
|
||||
|
||||
BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
|
||||
layout->SetInsets(5, 5, 5, 5);
|
||||
SetLayout(layout);
|
||||
|
||||
AddChild(fToolTip->View());
|
||||
}
|
||||
|
||||
virtual ~ToolTipView()
|
||||
{
|
||||
fToolTip->ReleaseReference();
|
||||
}
|
||||
|
||||
virtual void AttachedToWindow()
|
||||
{
|
||||
SetEventMask(B_POINTER_EVENTS, 0);
|
||||
fToolTip->AttachedToWindow();
|
||||
}
|
||||
|
||||
virtual void DetachedFromWindow()
|
||||
{
|
||||
BToolTipManager* manager = BToolTipManager::Manager();
|
||||
manager->Lock();
|
||||
|
||||
RemoveChild(fToolTip->View());
|
||||
// don't delete this one!
|
||||
fToolTip->DetachedFromWindow();
|
||||
|
||||
manager->Unlock();
|
||||
}
|
||||
virtual void AttachedToWindow();
|
||||
virtual void DetachedFromWindow();
|
||||
|
||||
virtual void FrameResized(float width, float height);
|
||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||
const BMessage* dragMessage)
|
||||
{
|
||||
if (fToolTip->IsSticky()) {
|
||||
// TODO: move window with mouse!
|
||||
Window()->MoveTo(
|
||||
ConvertToScreen(where) + fToolTip->MouseRelativeLocation());
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
const BMessage* dragMessage);
|
||||
|
||||
void HideTip()
|
||||
{
|
||||
if (fHidden)
|
||||
return;
|
||||
|
||||
BMessage quit(kMsgCloseToolTip);
|
||||
BMessageRunner::StartSending(Window(), &quit,
|
||||
BToolTipManager::Manager()->HideDelay(), 1);
|
||||
fHidden = true;
|
||||
}
|
||||
|
||||
void ShowTip()
|
||||
{
|
||||
fHidden = false;
|
||||
}
|
||||
void HideTip();
|
||||
void ShowTip();
|
||||
void ResetWindowFrame(BPoint where);
|
||||
|
||||
BToolTip* Tip() const { return fToolTip; }
|
||||
bool IsTipHidden() const { return fHidden; }
|
||||
@ -112,44 +56,245 @@ private:
|
||||
};
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ToolTipView::HideTip()
|
||||
{
|
||||
if (fHidden)
|
||||
return;
|
||||
|
||||
BMessage quit(kMsgCloseToolTip);
|
||||
BMessageRunner::StartSending(Window(), &quit,
|
||||
BToolTipManager::Manager()->HideDelay(), 1);
|
||||
fHidden = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ToolTipView::ShowTip()
|
||||
{
|
||||
fHidden = false;
|
||||
}
|
||||
|
||||
|
||||
/*! Tries to find the right frame to show the tool tip in, trying to use the
|
||||
alignment that the tool tip specifies.
|
||||
Makes sure the tool tip can be shown on screen in its entirety, ie. it will
|
||||
resize the window if necessary.
|
||||
*/
|
||||
void
|
||||
ToolTipView::ResetWindowFrame(BPoint where)
|
||||
{
|
||||
if (Window() == NULL)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Find best alignment, starting with the requested one
|
||||
|
||||
BAlignment alignment = fToolTip->Alignment();
|
||||
BPoint location = where;
|
||||
bool doesNotFit = false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ((doesNotFit && alignment.vertical == B_ALIGN_MIDDLE)
|
||||
|| (alignment.vertical == B_ALIGN_MIDDLE
|
||||
&& 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;
|
||||
}
|
||||
|
||||
where = location;
|
||||
|
||||
// Cut off any out-of-screen areas
|
||||
|
||||
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)
|
||||
:
|
||||
BWindow(BRect(0, 0, 250, 10), "tool tip", B_BORDERED_WINDOW_LOOK,
|
||||
kMenuWindowFeel, B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE
|
||||
| B_AUTO_UPDATE_SIZE_LIMITS | B_AVOID_FRONT | B_AVOID_FOCUS)
|
||||
BWindow(BRect(0, 0, 250, 10).OffsetBySelf(where), "tool tip",
|
||||
B_BORDERED_WINDOW_LOOK, kMenuWindowFeel,
|
||||
B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_AUTO_UPDATE_SIZE_LIMITS
|
||||
| B_AVOID_FRONT | B_AVOID_FOCUS)
|
||||
{
|
||||
SetLayout(new BGroupLayout(B_VERTICAL));
|
||||
|
||||
BToolTipManager* manager = BToolTipManager::Manager();
|
||||
ToolTipView* view = new ToolTipView(tip);
|
||||
|
||||
manager->Lock();
|
||||
AddChild(new ToolTipView(tip));
|
||||
AddChild(view);
|
||||
manager->Unlock();
|
||||
|
||||
BSize size = ChildAt(0)->PreferredSize();
|
||||
ResizeTo(size.width, size.height);
|
||||
//AddChild(BLayoutBuilder::Group<>(B_VERTICAL).Add(new ToolTipView(tip)));
|
||||
// figure out size and location
|
||||
|
||||
// figure out location
|
||||
// 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);
|
||||
view->ResetWindowFrame(where);
|
||||
}
|
||||
|
||||
|
||||
@ -189,6 +334,7 @@ ToolTipWindow::MessageReceived(BMessage* message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace BPrivate
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user