Add Widget::is/setTransparent property to paint a widget merged with its background

This fixes problems with tooltips, toolbar popups and context bar popups.
It fixes issue #297 (undo notifications rendering problems).
This commit is contained in:
David Capello 2014-04-19 18:51:42 -03:00
parent 2b3a4d1668
commit a34d181530
8 changed files with 141 additions and 22 deletions

View File

@ -150,21 +150,24 @@ protected:
private:
void openPopup() {
Border border = Border(2, 2, 2, 3)*jguiscale();
Rect rc = getBounds();
rc.y += rc.h;
rc.w *= 3;
m_popupWindow = new PopupWindow("", PopupWindow::kCloseOnClickInOtherWindow);
m_popupWindow->setAutoRemap(false);
m_popupWindow->setBounds(rc);
m_popupWindow->setBorder(border);
m_popupWindow->setBounds(rc + border);
Region rgn(rc.createUnion(getBounds()));
Region rgn(m_popupWindow->getBounds().createUnion(getBounds()));
m_popupWindow->setHotRegion(rgn);
m_brushType = new ButtonSet(3, 1, m_penType,
PART_BRUSH_CIRCLE,
PART_BRUSH_SQUARE,
PART_BRUSH_LINE);
PART_BRUSH_CIRCLE,
PART_BRUSH_SQUARE,
PART_BRUSH_LINE);
m_brushType->ItemChange.connect(&BrushTypeField::onBrushTypeChange, this);
m_brushType->setTransparent(true);
m_brushType->setBgColor(ui::ColorNone);
m_popupWindow->addChild(m_brushType);
m_popupWindow->openWindow();

View File

@ -913,7 +913,8 @@ void SkinTheme::paintBox(PaintEvent& ev)
Widget* widget = static_cast<Widget*>(ev.getSource());
Graphics* g = ev.getGraphics();
g->fillRect(BGCOLOR, g->getClipBounds());
if (!is_transparent(BGCOLOR))
g->fillRect(BGCOLOR, g->getClipBounds());
}
void SkinTheme::paintButton(PaintEvent& ev)
@ -1039,7 +1040,8 @@ void SkinTheme::paintGrid(PaintEvent& ev)
Widget* widget = static_cast<Widget*>(ev.getSource());
Graphics* g = ev.getGraphics();
g->fillRect(BGCOLOR, g->getClipBounds());
if (!is_transparent(BGCOLOR))
g->fillRect(BGCOLOR, g->getClipBounds());
}
void SkinTheme::paintEntry(PaintEvent& ev)
@ -1136,7 +1138,9 @@ void SkinTheme::paintLabel(PaintEvent& ev)
ui::Color fg = widget->getTextColor();
Rect text, rc = widget->getClientBounds();
g->fillRect(bg, rc);
if (!is_transparent(bg))
g->fillRect(bg, rc);
rc.shrink(widget->getBorder());
widget->getTextIconInfo(NULL, &text);
@ -1639,8 +1643,10 @@ void SkinTheme::paintView(PaintEvent& ev)
Graphics* g = ev.getGraphics();
View* widget = static_cast<View*>(ev.getSource());
gfx::Rect bounds = widget->getClientBounds();
ui::Color bg = BGCOLOR;
g->fillRect(BGCOLOR, bounds);
if (!is_transparent(bg))
g->fillRect(bg, bounds);
draw_bounds_nw(g, bounds,
(widget->hasFocus() ?
@ -1687,8 +1693,10 @@ void SkinTheme::paintViewViewport(PaintEvent& ev)
{
Viewport* widget = static_cast<Viewport*>(ev.getSource());
Graphics* g = ev.getGraphics();
ui::Color bg = BGCOLOR;
g->fillRect(BGCOLOR, widget->getClientBounds());
if (!is_transparent(bg))
g->fillRect(bg, widget->getClientBounds());
}
void SkinTheme::paintWindow(PaintEvent& ev)
@ -1720,11 +1728,14 @@ void SkinTheme::paintWindow(PaintEvent& ev)
void SkinTheme::paintPopupWindow(PaintEvent& ev)
{
Widget* widget = static_cast<Widget*>(ev.getSource());
Window* window = static_cast<Window*>(ev.getSource());
Graphics* g = ev.getGraphics();
gfx::Rect pos = window->getClientBounds();
get_style("menubox")->paint(g, pos, NULL, Style::State());
if (!is_transparent(BGCOLOR))
get_style("menubox")->paint(g, pos, NULL, Style::State());
pos.shrink(window->getBorder());
g->drawString(window->getText(),
@ -1814,8 +1825,12 @@ ui::Color SkinTheme::getWidgetBgColor(Widget* widget)
ui::Color c = widget->getBgColor();
bool decorative = widget->isDecorative();
return (!is_transparent(c) ? c: (decorative ? getColor(ThemeColor::Selected):
getColor(ThemeColor::Face)));
if (!is_transparent(c) || widget->getType() == kWindowWidget)
return c;
else if (decorative)
return getColor(ThemeColor::Selected);
else
return getColor(ThemeColor::Face);
}
void SkinTheme::drawTextString(Graphics* g, const char *t, ui::Color fg_color, ui::Color bg_color,

View File

@ -462,6 +462,8 @@ void ToolBar::openPopupWindow(int group_index, ToolGroup* tool_group)
rgn.createUnion(rgn, Region(getBounds()));
m_popupWindow->setHotRegion(rgn);
m_popupWindow->setTransparent(true);
m_popupWindow->setBgColor(ui::ColorNone);
m_popupWindow->setAutoRemap(false);
m_popupWindow->setBounds(rc);
toolstrip->setBounds(rc);
@ -632,6 +634,7 @@ ToolBar::ToolStrip::ToolStrip(ToolGroup* group, ToolBar* toolbar)
m_toolbar = toolbar;
setDoubleBuffered(true);
setTransparent(true);
}
ToolBar::ToolStrip::~ToolStrip()
@ -730,7 +733,6 @@ void ToolBar::ToolStrip::onPaint(PaintEvent& ev)
{
Graphics* g = ev.getGraphics();
gfx::Rect bounds = getClientBounds();
gfx::Rect clip = g->getClipBounds();
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
ToolBox* toolbox = App::instance()->getToolBox();
Rect toolrc;

View File

@ -32,6 +32,10 @@ namespace ui {
Graphics(BITMAP* bmp, int dx, int dy);
~Graphics();
BITMAP* getInternalBitmap() { return m_bmp; }
int getInternalDeltaX() { return m_dx; }
int getInternalDeltaY() { return m_dy; }
gfx::Rect getClipBounds() const;
void setClipBounds(const gfx::Rect& rc);
bool intersectClipRect(const gfx::Rect& rc);

View File

@ -139,8 +139,9 @@ void IntEntry::openPopup()
m_popupWindow = new PopupWindow("", PopupWindow::kCloseOnClickInOtherWindow);
m_popupWindow->setAutoRemap(false);
m_popupWindow->setTransparent(true);
m_popupWindow->setBgColor(ui::ColorNone);
m_popupWindow->setBounds(rc);
m_popupWindow->setBgColor(rgba(0, 0, 0, 0));
m_popupWindow->Close.connect(&IntEntry::onPopupClose, this);
Region rgn(rc.createUnion(getBounds()));
@ -149,6 +150,7 @@ void IntEntry::openPopup()
m_slider = new Slider(m_min, m_max, getValue());
m_slider->setFocusStop(false); // In this way the IntEntry doesn't lost the focus
m_slider->setTransparent(true);
m_slider->Change.connect(&IntEntry::onChangeSlider, this);
m_popupWindow->addChild(m_slider);

View File

@ -155,6 +155,8 @@ TipWindow::TipWindow(const char *text)
: PopupWindow(text, kCloseOnClickInOtherWindow)
, m_arrowAlign(0)
{
setTransparent(true);
makeFixed();
initTheme();
}

View File

@ -76,6 +76,7 @@ Widget::Widget(WidgetType type)
m_preferredSize = NULL;
m_doubleBuffered = false;
m_transparent = false;
}
Widget::~Widget()
@ -655,6 +656,9 @@ void Widget::getDrawableRegion(gfx::Region& region, DrawableRegionFlags flags)
it != windows_list.rend()) {
// Subtract the rectangles
for (++it; it != windows_list.rend(); ++it) {
if (!(*it)->isVisible())
continue;
Region reg1;
(*it)->getRegion(reg1);
region.createSubtraction(region, reg1);
@ -917,7 +921,79 @@ void Widget::flushRedraw()
}
}
bool Widget::isDoubleBuffered()
void Widget::paint(Graphics* graphics, const gfx::Region& drawRegion)
{
if (drawRegion.isEmpty())
return;
std::queue<Widget*> processing;
processing.push(this);
while (!processing.empty()) {
Widget* widget = processing.front();
processing.pop();
ASSERT_VALID_WIDGET(widget);
// If the widget is hidden
if (!widget->isVisible())
continue;
UI_FOREACH_WIDGET(widget->getChildren(), it) {
Widget* child = *it;
processing.push(child);
}
// Intersect drawRegion with widget's drawable region.
Region region;
widget->getDrawableRegion(region, kCutTopWindows);
region.createIntersection(region, drawRegion);
Graphics graphics2(graphics->getInternalBitmap(),
widget->getBounds().x,
widget->getBounds().y);
graphics2.setFont(widget->getFont());
for (Region::const_iterator
it = region.begin(),
end = region.end(); it != end; ++it) {
IntersectClip clip(&graphics2, Rect(*it).offset(
-widget->getBounds().x,
-widget->getBounds().y));
widget->paintEvent(&graphics2);
}
}
}
bool Widget::paintEvent(Graphics* graphics)
{
// For transparent widgets we have to draw the parent first.
if (isTransparent()) {
#if _DEBUG
// In debug mode we can fill the area with Red so we know if the
// we are drawing the parent correctly.
graphics->fillRect(ui::rgba(255, 0, 0), getClientBounds());
#endif _DEBUG
this->flags |= JI_HIDDEN;
gfx::Region rgn(getParent()->getBounds());
rgn.createIntersection(rgn,
gfx::Region(
graphics->getClipBounds().offset(
graphics->getInternalDeltaX(),
graphics->getInternalDeltaY())));
getParent()->paint(graphics, rgn);
this->flags &= ~JI_HIDDEN;
}
PaintEvent ev(this, graphics);
onPaint(ev); // Fire onPaint event
return ev.isPainted();
}
bool Widget::isDoubleBuffered() const
{
return m_doubleBuffered;
}
@ -927,6 +1003,16 @@ void Widget::setDoubleBuffered(bool doubleBuffered)
m_doubleBuffered = doubleBuffered;
}
bool Widget::isTransparent() const
{
return m_transparent;
}
void Widget::setTransparent(bool transparent)
{
m_transparent = transparent;
}
void Widget::invalidate()
{
if (isVisible()) {
@ -1217,9 +1303,7 @@ bool Widget::onProcessMessage(Message* msg)
ASSERT(ptmsg->rect().h > 0);
GraphicsPtr graphics = getGraphics(toClient(ptmsg->rect()));
PaintEvent ev(this, graphics);
onPaint(ev); // Fire onPaint event
return ev.isPainted();
return paintEvent(graphics);
}
case kKeyDownMessage:

View File

@ -296,9 +296,12 @@ namespace ui {
// REFRESH ISSUES
// ===============================================================
bool isDoubleBuffered();
bool isDoubleBuffered() const;
void setDoubleBuffered(bool doubleBuffered);
bool isTransparent() const;
void setTransparent(bool transparent);
void invalidate();
void invalidateRect(const gfx::Rect& rect);
void invalidateRegion(const gfx::Region& region);
@ -376,6 +379,9 @@ namespace ui {
virtual void onSetBgColor();
private:
void paint(Graphics* graphics, const gfx::Region& drawRegion);
bool paintEvent(Graphics* graphics);
base::string m_id; // Widget's id
Theme* m_theme; // Widget's theme
int m_align; // Widget alignment
@ -387,7 +393,8 @@ namespace ui {
WidgetsList m_children; // Sub-widgets
Widget* m_parent; // Who is the parent?
gfx::Size* m_preferredSize;
bool m_doubleBuffered : 1;
bool m_doubleBuffered;
bool m_transparent;
};
} // namespace ui