Fix several bugs with tooltip arrows/location

The tooltip arrow is now aligned to the target. And the tooltip is
relocated to the other side if it intersects its target bounds.
This commit is contained in:
David Capello 2015-05-09 13:20:57 -03:00
parent 06d1929729
commit cea0970d9d
6 changed files with 97 additions and 56 deletions

View File

@ -1764,6 +1764,7 @@ void SkinTheme::paintTooltip(PaintEvent& ev)
{
ui::TipWindow* widget = static_cast<ui::TipWindow*>(ev.getSource());
Graphics* g = ev.getGraphics();
Rect absRc = widget->getBounds();
Rect rc = widget->getClientBounds();
gfx::Color fg = colors.tooltipText();
gfx::Color bg = colors.tooltipFace();
@ -1788,26 +1789,34 @@ void SkinTheme::paintTooltip(PaintEvent& ev)
// Draw arrow in sides
she::Surface* arrow = NULL;
gfx::Rect target(widget->target());
target = target.createIntersect(gfx::Rect(0, 0, ui::display_w(), ui::display_h()));
target.offset(-absRc.getOrigin());
switch (widget->getArrowAlign()) {
case JI_TOP:
arrow = m_part[PART_TOOLTIP_ARROW_N];
g->drawRgbaSurface(arrow, rc.x+rc.w/2-arrow->width()/2, rc.y);
g->drawRgbaSurface(arrow,
target.x+target.w/2-arrow->width()/2,
rc.y);
break;
case JI_BOTTOM:
arrow = m_part[PART_TOOLTIP_ARROW_S];
g->drawRgbaSurface(arrow,
rc.x+rc.w/2-arrow->width()/2,
rc.y+rc.h-arrow->height());
target.x+target.w/2-arrow->width()/2,
rc.y+rc.h-arrow->height());
break;
case JI_LEFT:
arrow = m_part[PART_TOOLTIP_ARROW_W];
g->drawRgbaSurface(arrow, rc.x, rc.y+rc.h/2-arrow->height()/2);
g->drawRgbaSurface(arrow,
rc.x,
target.y+target.h/2-arrow->height()/2);
break;
case JI_RIGHT:
arrow = m_part[PART_TOOLTIP_ARROW_E];
g->drawRgbaSurface(arrow,
rc.x+rc.w-arrow->width(),
rc.y+rc.h/2-arrow->height()/2);
rc.x+rc.w-arrow->width(),
target.y+target.h/2-arrow->height()/2);
break;
}

View File

@ -60,7 +60,7 @@ static const char* kStatusBarFace = "status_bar_face";
class StatusBar::CustomizedTipWindow : public ui::TipWindow {
public:
CustomizedTipWindow(const char* text)
: ui::TipWindow(text)
: ui::TipWindow(text, gfx::Rect())
{
}

View File

@ -549,12 +549,13 @@ void ToolBar::openTipWindow(int group_index, Tool* tool)
else
return;
m_tipWindow = new TipWindow(tooltip.c_str());
Rect toolrc = getToolGroupBounds(group_index);
Point arrow = tool ? getToolPositionInGroup(group_index, tool): Point(0, 0);
m_tipWindow = new TipWindow(tooltip.c_str(), gfx::Rect(arrow, toolrc.getSize()));
m_tipWindow->setArrowAlign(JI_TOP | JI_RIGHT);
m_tipWindow->remapWindow();
Rect toolrc = getToolGroupBounds(group_index);
Point arrow = tool ? getToolPositionInGroup(group_index, tool): Point(0, 0);
int w = m_tipWindow->getBounds().w;
int h = m_tipWindow->getBounds().h;
int x = toolrc.x - w + (tool && m_popupWindow && m_popupWindow->isVisible() ? arrow.x-m_popupWindow->getBounds().w: 0);

View File

@ -215,8 +215,8 @@ public:
return false;
return
rc.x <= x+w && rc.x+rc.w > x &&
rc.y <= y+h && rc.y+rc.h > y;
rc.x < x+w && rc.x+rc.w > x &&
rc.y < y+h && rc.y+rc.h > y;
}
// Returns the union rectangle between this and rc rectangle.

View File

@ -96,67 +96,95 @@ bool TooltipManager::onProcessMessage(Message* msg)
void TooltipManager::onTick()
{
if (!m_tipWindow) {
m_tipWindow.reset(new TipWindow(m_target.tipInfo.text.c_str()));
gfx::Rect bounds = m_target.widget->getBounds();
m_tipWindow.reset(new TipWindow(m_target.tipInfo.text.c_str(), bounds));
int x = get_mouse_position().x+12*guiscale();
int y = get_mouse_position().y+12*guiscale();
int w, h;
m_tipWindow->setArrowAlign(m_target.tipInfo.arrowAlign);
m_tipWindow->remapWindow();
int w = m_tipWindow->getBounds().w;
int h = m_tipWindow->getBounds().h;
w = m_tipWindow->getBounds().w;
h = m_tipWindow->getBounds().h;
int arrowAlign = m_target.tipInfo.arrowAlign;
int trycount = 0;
for (; trycount < 4; ++trycount) {
switch (arrowAlign) {
case JI_TOP | JI_LEFT:
x = bounds.x + bounds.w;
y = bounds.y + bounds.h;
break;
case JI_TOP | JI_RIGHT:
x = bounds.x - w;
y = bounds.y + bounds.h;
break;
case JI_BOTTOM | JI_LEFT:
x = bounds.x + bounds.w;
y = bounds.y - h;
break;
case JI_BOTTOM | JI_RIGHT:
x = bounds.x - w;
y = bounds.y - h;
break;
case JI_TOP:
x = bounds.x + bounds.w/2 - w/2;
y = bounds.y + bounds.h;
break;
case JI_BOTTOM:
x = bounds.x + bounds.w/2 - w/2;
y = bounds.y - h;
break;
case JI_LEFT:
x = bounds.x + bounds.w;
y = bounds.y + bounds.h/2 - h/2;
break;
case JI_RIGHT:
x = bounds.x - w;
y = bounds.y + bounds.h/2 - h/2;
break;
}
switch (m_target.tipInfo.arrowAlign) {
case JI_TOP | JI_LEFT:
x = bounds.x + bounds.w;
y = bounds.y + bounds.h;
break;
case JI_TOP | JI_RIGHT:
x = bounds.x - w;
y = bounds.y + bounds.h;
break;
case JI_BOTTOM | JI_LEFT:
x = bounds.x + bounds.w;
y = bounds.y - h;
break;
case JI_BOTTOM | JI_RIGHT:
x = bounds.x - w;
y = bounds.y - h;
break;
case JI_TOP:
x = bounds.x + bounds.w/2 - w/2;
y = bounds.y + bounds.h;
break;
case JI_BOTTOM:
x = bounds.x + bounds.w/2 - w/2;
y = bounds.y - h;
break;
case JI_LEFT:
x = bounds.x + bounds.w;
y = bounds.y + bounds.h/2 - h/2;
break;
case JI_RIGHT:
x = bounds.x - w;
y = bounds.y + bounds.h/2 - h/2;
x = MID(0, x, ui::display_w()-w);
y = MID(0, y, ui::display_h()-h);
if (bounds.intersects(gfx::Rect(x, y, w, h))) {
switch (trycount) {
case 0:
case 2:
// Switch position
if (arrowAlign & (JI_TOP | JI_BOTTOM)) arrowAlign ^= JI_TOP | JI_BOTTOM;
if (arrowAlign & (JI_LEFT | JI_RIGHT)) arrowAlign ^= JI_LEFT | JI_RIGHT;
break;
case 1:
// Rotate positions
if (arrowAlign & (JI_TOP | JI_LEFT)) arrowAlign ^= JI_TOP | JI_LEFT;
if (arrowAlign & (JI_BOTTOM | JI_RIGHT)) arrowAlign ^= JI_BOTTOM | JI_RIGHT;
break;
}
}
else {
m_tipWindow->setArrowAlign(arrowAlign);
m_tipWindow->positionWindow(x, y);
m_tipWindow->openWindow();
break;
}
}
m_tipWindow->positionWindow(
MID(0, x, ui::display_w()-w),
MID(0, y, ui::display_h()-h));
m_tipWindow->openWindow();
// No enough room for the tooltip
if (trycount == 4) {
m_tipWindow.reset();
m_timer->stop();
}
}
m_timer->stop();
}
// TipWindow
TipWindow::TipWindow(const char *text)
TipWindow::TipWindow(const char* text, gfx::Rect& target)
: PopupWindow(text, kCloseOnClickInOtherWindow)
, m_arrowAlign(0)
, m_target(target)
{
setTransparent(true);

View File

@ -56,12 +56,14 @@ namespace ui {
class TipWindow : public PopupWindow {
public:
TipWindow(const char *text);
TipWindow(const char* text, gfx::Rect& target);
~TipWindow();
int getArrowAlign() const;
void setArrowAlign(int arrowAlign);
const gfx::Rect& target() const { return m_target; }
protected:
bool onProcessMessage(Message* msg) override;
void onPreferredSize(PreferredSizeEvent& ev) override;
@ -70,6 +72,7 @@ namespace ui {
private:
int m_arrowAlign;
gfx::Rect m_target;
};
} // namespace ui