mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-11 09:40:42 +00:00
Move all code to draw windows to ui-lib w/new styles
This commit is contained in:
parent
2883a70e25
commit
a62f12ad09
@ -412,24 +412,6 @@
|
||||
|
||||
<stylesheet>
|
||||
|
||||
<!-- window -->
|
||||
<style id="window">
|
||||
<background color="window_face" part="window" />
|
||||
</style>
|
||||
|
||||
<style id="window_title">
|
||||
<background color="window_titlebar_face" />
|
||||
<text color="window_titlebar_text" align="left" valign="middle" />
|
||||
</style>
|
||||
|
||||
<style id="menubox">
|
||||
<background color="window_face" part="menu" />
|
||||
</style>
|
||||
|
||||
<style id="desktop">
|
||||
<background color="desktop" />
|
||||
</style>
|
||||
|
||||
<!-- scrollbar -->
|
||||
<style id="scrollbar">
|
||||
<background part="scrollbar_bg" repeat="repeat" />
|
||||
@ -835,6 +817,66 @@
|
||||
|
||||
<styles>
|
||||
|
||||
<style id="window_without_title" border="3">
|
||||
<background color="window_face" />
|
||||
<border part="menu" />
|
||||
</style>
|
||||
|
||||
<style id="window_with_title" border="6" border-top="17">
|
||||
<background color="window_face" />
|
||||
<border part="window" />
|
||||
</style>
|
||||
|
||||
<style id="window_title_label" margin-top="5" margin-left="5">
|
||||
<background color="window_titlebar_face" />
|
||||
<text color="window_titlebar_text" align="left middle" />
|
||||
</style>
|
||||
|
||||
<style id="window_close_button" margin-top="3" margin-right="3">
|
||||
<background part="window_button_normal" />
|
||||
<background part="window_button_hot" state="mouse" />
|
||||
<background part="window_button_selected" state="selected" />
|
||||
<icon part="window_close_icon" color="button_normal_text" />
|
||||
<icon part="window_close_icon" color="button_hot_text" state="mouse" />
|
||||
<icon part="window_close_icon" color="button_selected_text" state="selected" />
|
||||
</style>
|
||||
|
||||
<style id="popup_window">
|
||||
<background color="window_face" />
|
||||
<border part="menu" />
|
||||
</style>
|
||||
|
||||
<style id="transparent_popup_window">
|
||||
<!-- nothing (transparent) -->
|
||||
</style>
|
||||
|
||||
<style id="menu">
|
||||
<background color="window_face" />
|
||||
</style>
|
||||
|
||||
<style id="menubox" extends="menu">
|
||||
</style>
|
||||
|
||||
<style id="menubar" extends="menubox">
|
||||
</style>
|
||||
|
||||
<style id="desktop">
|
||||
<background color="desktop" />
|
||||
</style>
|
||||
|
||||
<style id="tooltip_window">
|
||||
<background part="tooltip" />
|
||||
</style>
|
||||
|
||||
<style id="tooltip_window_arrow">
|
||||
<background part="tooltip_arrow" />
|
||||
</style>
|
||||
|
||||
<style id="tooltip_text">
|
||||
<background color="tooltip_face" />
|
||||
<text color="tooltip_text" />
|
||||
</style>
|
||||
|
||||
<style id="label" padding="1">
|
||||
<text color="text" align="left" />
|
||||
<text color="disabled" align="left" state="disabled" />
|
||||
@ -878,7 +920,7 @@
|
||||
<border part="editor_selected" state="selected" />
|
||||
</style>
|
||||
|
||||
<style id="workspace_view" border-top="4">
|
||||
<style id="workspace_view" border-top="4" extends="view">
|
||||
<border part="editor_normal" />
|
||||
<border part="editor_selected" state="focus" />
|
||||
</style>
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -80,12 +80,13 @@ ColorPopup::ColorPopup(bool canPin)
|
||||
m_topBox.addChild(new Separator("", VERTICAL));
|
||||
m_topBox.addChild(&m_hexColorEntry);
|
||||
|
||||
// TODO fix this hack for close button in popup window
|
||||
// Move close button (decorative widget) inside the m_topBox
|
||||
{
|
||||
Widget* closeButton = nullptr;
|
||||
WidgetsList decorators;
|
||||
for (auto child : children()) {
|
||||
if (child->isDecorative()) {
|
||||
if (child->type() == kWindowCloseButtonWidget) {
|
||||
closeButton = child;
|
||||
removeChild(child);
|
||||
break;
|
||||
@ -93,7 +94,9 @@ ColorPopup::ColorPopup(bool canPin)
|
||||
}
|
||||
if (closeButton) {
|
||||
m_topBox.addChild(new BoxFiller);
|
||||
m_topBox.addChild(closeButton);
|
||||
VBox* vbox = new VBox;
|
||||
vbox->addChild(closeButton);
|
||||
m_topBox.addChild(vbox);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -12,7 +12,6 @@
|
||||
|
||||
#include "app/modules/gfx.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/skin/button_icon_impl.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/bind.h"
|
||||
#include "gfx/border.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -8,7 +8,6 @@
|
||||
#define APP_UI_POPUP_FRAME_PIN_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "ui/button.h"
|
||||
#include "ui/popup_window.h"
|
||||
|
||||
namespace app {
|
||||
|
@ -241,8 +241,8 @@ bool PreviewEditorWindow::onProcessMessage(ui::Message* msg)
|
||||
void PreviewEditorWindow::onClose(ui::CloseEvent& ev)
|
||||
{
|
||||
Button* closeButton = dynamic_cast<Button*>(ev.getSource());
|
||||
if (closeButton != NULL &&
|
||||
closeButton->id() == SkinTheme::kThemeCloseButtonId) {
|
||||
if (closeButton &&
|
||||
closeButton->type() == kWindowCloseButtonWidget) {
|
||||
// Here we don't use "setMiniEditorEnabled" to change the state of
|
||||
// "m_isEnabled" because we're coming from a close event of the
|
||||
// window.
|
||||
|
@ -50,61 +50,6 @@ using namespace gfx;
|
||||
using namespace ui;
|
||||
|
||||
const char* SkinTheme::kThemesFolderName = "themes";
|
||||
const char* SkinTheme::kThemeCloseButtonId = "theme_close_button";
|
||||
|
||||
// Controls the "X" button in a window to close it.
|
||||
class WindowCloseButton : public Button {
|
||||
public:
|
||||
WindowCloseButton() : Button("") {
|
||||
setDecorative(true);
|
||||
setId(SkinTheme::kThemeCloseButtonId);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void onSizeHint(SizeHintEvent& ev) override {
|
||||
ev.setSizeHint(SkinTheme::instance()->parts.windowButtonNormal()->size());
|
||||
}
|
||||
|
||||
void onClick(Event& ev) override {
|
||||
Button::onClick(ev);
|
||||
closeWindow();
|
||||
}
|
||||
|
||||
void onPaint(PaintEvent& ev) override {
|
||||
static_cast<SkinTheme*>(theme())->paintWindowButton(ev);
|
||||
}
|
||||
|
||||
bool onProcessMessage(Message* msg) override {
|
||||
switch (msg->type()) {
|
||||
|
||||
case kSetCursorMessage:
|
||||
ui::set_mouse_cursor(kArrowCursor);
|
||||
return true;
|
||||
|
||||
case kKeyDownMessage:
|
||||
if (window()->isForeground() &&
|
||||
static_cast<KeyMessage*>(msg)->scancode() == kKeyEsc) {
|
||||
setSelected(true);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case kKeyUpMessage:
|
||||
if (window()->isForeground() &&
|
||||
static_cast<KeyMessage*>(msg)->scancode() == kKeyEsc) {
|
||||
if (isSelected()) {
|
||||
setSelected(false);
|
||||
closeWindow();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return Button::onProcessMessage(msg);
|
||||
}
|
||||
};
|
||||
|
||||
static const char* cursor_names[kCursorTypes] = {
|
||||
"null", // kNoCursor
|
||||
@ -534,6 +479,21 @@ void SkinTheme::loadXml(const std::string& skinId)
|
||||
*style = ui::Style(base);
|
||||
}
|
||||
|
||||
// Margin
|
||||
{
|
||||
const char* m = xmlStyle->Attribute("margin");
|
||||
const char* l = xmlStyle->Attribute("margin-left");
|
||||
const char* t = xmlStyle->Attribute("margin-top");
|
||||
const char* r = xmlStyle->Attribute("margin-right");
|
||||
const char* b = xmlStyle->Attribute("margin-bottom");
|
||||
gfx::Border margin = ui::Style::UndefinedBorder();
|
||||
if (m || l) margin.left(std::strtol(l ? l: m, nullptr, 10));
|
||||
if (m || t) margin.top(std::strtol(t ? t: m, nullptr, 10));
|
||||
if (m || r) margin.right(std::strtol(r ? r: m, nullptr, 10));
|
||||
if (m || b) margin.bottom(std::strtol(b ? b: m, nullptr, 10));
|
||||
style->setMargin(margin*guiscale());
|
||||
}
|
||||
|
||||
// Border
|
||||
{
|
||||
const char* m = xmlStyle->Attribute("border");
|
||||
@ -541,7 +501,7 @@ void SkinTheme::loadXml(const std::string& skinId)
|
||||
const char* t = xmlStyle->Attribute("border-top");
|
||||
const char* r = xmlStyle->Attribute("border-right");
|
||||
const char* b = xmlStyle->Attribute("border-bottom");
|
||||
gfx::Border border(-1, -1, -1, -1);
|
||||
gfx::Border border = ui::Style::UndefinedBorder();
|
||||
if (m || l) border.left(std::strtol(l ? l: m, nullptr, 10));
|
||||
if (m || t) border.top(std::strtol(t ? t: m, nullptr, 10));
|
||||
if (m || r) border.right(std::strtol(r ? r: m, nullptr, 10));
|
||||
@ -556,7 +516,7 @@ void SkinTheme::loadXml(const std::string& skinId)
|
||||
const char* t = xmlStyle->Attribute("padding-top");
|
||||
const char* r = xmlStyle->Attribute("padding-right");
|
||||
const char* b = xmlStyle->Attribute("padding-bottom");
|
||||
gfx::Border padding(-1, -1, -1, -1);
|
||||
gfx::Border padding = ui::Style::UndefinedBorder();
|
||||
if (m || l) padding.left(std::strtol(l ? l: m, nullptr, 10));
|
||||
if (m || t) padding.top(std::strtol(t ? t: m, nullptr, 10));
|
||||
if (m || r) padding.right(std::strtol(r ? r: m, nullptr, 10));
|
||||
@ -778,10 +738,15 @@ void SkinTheme::initWidget(Widget* widget)
|
||||
}
|
||||
|
||||
case kMenuWidget:
|
||||
widget->setStyle(newStyles.menu());
|
||||
break;
|
||||
|
||||
case kMenuBarWidget:
|
||||
widget->setStyle(newStyles.menubar());
|
||||
break;
|
||||
|
||||
case kMenuBoxWidget:
|
||||
BORDER(0);
|
||||
widget->setChildSpacing(0);
|
||||
widget->setStyle(newStyles.menubox());
|
||||
break;
|
||||
|
||||
case kMenuItemWidget:
|
||||
@ -854,33 +819,36 @@ void SkinTheme::initWidget(Widget* widget)
|
||||
break;
|
||||
|
||||
case kWindowWidget:
|
||||
if (!static_cast<Window*>(widget)->isDesktop()) {
|
||||
if (widget->hasText()) {
|
||||
BORDER4(6 * scale,
|
||||
(4+6) * scale + widget->textHeight(),
|
||||
6 * scale,
|
||||
6 * scale);
|
||||
|
||||
if (!widget->hasFlags(INITIALIZED)) {
|
||||
Button* button = new WindowCloseButton();
|
||||
widget->addChild(button);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BORDER(3 * scale);
|
||||
}
|
||||
if (TipWindow* window = dynamic_cast<TipWindow*>(widget)) {
|
||||
window->setStyle(newStyles.tooltipWindow());
|
||||
window->setArrowStyle(newStyles.tooltipWindowArrow());
|
||||
window->textBox()->setStyle(SkinTheme::instance()->newStyles.tooltipText());
|
||||
}
|
||||
else if (dynamic_cast<TransparentPopupWindow*>(widget)) {
|
||||
widget->setStyle(newStyles.transparentPopupWindow());
|
||||
}
|
||||
else if (dynamic_cast<PopupWindow*>(widget)) {
|
||||
widget->setStyle(newStyles.popupWindow());
|
||||
}
|
||||
else if (static_cast<Window*>(widget)->isDesktop()) {
|
||||
widget->setStyle(newStyles.desktop());
|
||||
}
|
||||
else {
|
||||
BORDER(0);
|
||||
if (widget->hasText()) {
|
||||
widget->setStyle(newStyles.windowWithTitle());
|
||||
}
|
||||
else {
|
||||
widget->setStyle(newStyles.windowWithoutTitle());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
widget->setChildSpacing(4 * scale); // TODO this hard-coded 4 should be configurable in skin.xml
|
||||
case kWindowTitleLabelWidget:
|
||||
widget->setStyle(SkinTheme::instance()->newStyles.windowTitleLabel());
|
||||
break;
|
||||
|
||||
// Tooltip background color
|
||||
if (dynamic_cast<TipWindow*>(widget))
|
||||
widget->setBgColor(SkinTheme::instance()->colors.tooltipFace());
|
||||
else
|
||||
widget->setBgColor(colors.windowFace());
|
||||
case kWindowCloseButtonWidget:
|
||||
widget->setStyle(SkinTheme::instance()->newStyles.windowCloseButton());
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -893,19 +861,6 @@ void SkinTheme::getWindowMask(Widget* widget, Region& region)
|
||||
region = widget->bounds();
|
||||
}
|
||||
|
||||
void SkinTheme::setDecorativeWidgetBounds(Widget* widget)
|
||||
{
|
||||
if (widget->id() == kThemeCloseButtonId) {
|
||||
Widget* window = widget->parent();
|
||||
gfx::Rect rect(parts.windowButtonNormal()->size());
|
||||
|
||||
rect.offset(window->bounds().x2() - 3*guiscale() - rect.w,
|
||||
window->bounds().y + 3*guiscale());
|
||||
|
||||
widget->setBounds(rect);
|
||||
}
|
||||
}
|
||||
|
||||
int SkinTheme::getScrollbarSize()
|
||||
{
|
||||
return dimensions.scrollbarSize();
|
||||
@ -1603,160 +1558,6 @@ void SkinTheme::paintViewViewport(PaintEvent& ev)
|
||||
g->fillRect(bg, widget->clientBounds());
|
||||
}
|
||||
|
||||
void SkinTheme::paintWindow(PaintEvent& ev)
|
||||
{
|
||||
Graphics* g = ev.graphics();
|
||||
Window* window = static_cast<Window*>(ev.getSource());
|
||||
Rect pos = window->clientBounds();
|
||||
Rect cpos = window->clientChildrenBounds();
|
||||
|
||||
if (!window->isDesktop()) {
|
||||
// window frame
|
||||
if (window->hasText()) {
|
||||
styles.window()->paint(g, pos, NULL, Style::State());
|
||||
styles.windowTitle()->paint(g,
|
||||
gfx::Rect(cpos.x, pos.y+5*guiscale(), cpos.w, // TODO this hard-coded 5 should be configurable in skin.xml
|
||||
window->textHeight()),
|
||||
window->text().c_str(), Style::State());
|
||||
}
|
||||
// menubox
|
||||
else {
|
||||
styles.menubox()->paint(g, pos, NULL, Style::State());
|
||||
}
|
||||
}
|
||||
// desktop
|
||||
else {
|
||||
styles.desktop()->paint(g, pos, NULL, Style::State());
|
||||
}
|
||||
}
|
||||
|
||||
void SkinTheme::paintPopupWindow(PaintEvent& ev)
|
||||
{
|
||||
Widget* widget = static_cast<Widget*>(ev.getSource());
|
||||
Window* window = static_cast<Window*>(ev.getSource());
|
||||
Graphics* g = ev.graphics();
|
||||
gfx::Rect pos = window->clientBounds();
|
||||
|
||||
if (!is_transparent(BGCOLOR))
|
||||
styles.menubox()->paint(g, pos, NULL, Style::State());
|
||||
|
||||
pos.shrink(window->border());
|
||||
|
||||
g->drawAlignedUIText(window->text(),
|
||||
colors.text(),
|
||||
window->bgColor(), pos,
|
||||
window->align());
|
||||
}
|
||||
|
||||
void SkinTheme::paintWindowButton(ui::PaintEvent& ev)
|
||||
{
|
||||
// Merge this code with SkinButton class
|
||||
|
||||
ButtonBase* widget = static_cast<ButtonBase*>(ev.getSource());
|
||||
Graphics* g = ev.graphics();
|
||||
Rect rc = widget->clientBounds();
|
||||
SkinPartPtr part;
|
||||
gfx::Color fg;
|
||||
|
||||
if (widget->isSelected()) {
|
||||
fg = colors.buttonSelectedText();
|
||||
part = parts.windowButtonSelected();
|
||||
}
|
||||
else if (widget->hasMouseOver()) {
|
||||
fg = colors.buttonHotText();
|
||||
part = parts.windowButtonHot();
|
||||
}
|
||||
else {
|
||||
fg = colors.buttonNormalText();
|
||||
part = parts.windowButtonNormal();
|
||||
}
|
||||
|
||||
g->fillRect(BGCOLOR, rc);
|
||||
g->drawRgbaSurface(part->bitmap(0), rc.x, rc.y);
|
||||
gfx::Size sz(part->bitmap(0)->width(),
|
||||
part->bitmap(0)->height());
|
||||
|
||||
part = parts.windowCloseIcon();
|
||||
g->drawColoredRgbaSurface(part->bitmap(0), fg,
|
||||
rc.x+sz.w/2-part->bitmap(0)->width()/2,
|
||||
rc.y+sz.h/2-part->bitmap(0)->height()/2);
|
||||
}
|
||||
|
||||
void SkinTheme::paintTooltip(PaintEvent& ev)
|
||||
{
|
||||
ui::TipWindow* widget = static_cast<ui::TipWindow*>(ev.getSource());
|
||||
Graphics* g = ev.graphics();
|
||||
Rect absRc = widget->bounds();
|
||||
Rect rc = widget->clientBounds();
|
||||
gfx::Color fg = colors.tooltipText();
|
||||
gfx::Color bg = colors.tooltipFace();
|
||||
SkinPartPtr tooltipPart = parts.tooltip();
|
||||
|
||||
she::Surface* nw = tooltipPart->bitmapNW();
|
||||
she::Surface* n = tooltipPart->bitmapN();
|
||||
she::Surface* ne = tooltipPart->bitmapNE();
|
||||
she::Surface* e = tooltipPart->bitmapE();
|
||||
she::Surface* se = tooltipPart->bitmapSE();
|
||||
she::Surface* s = tooltipPart->bitmapS();
|
||||
she::Surface* sw = tooltipPart->bitmapSW();
|
||||
she::Surface* w = tooltipPart->bitmapW();
|
||||
|
||||
switch (widget->arrowAlign()) {
|
||||
case TOP | LEFT: nw = parts.tooltipArrow()->bitmapNW(); break;
|
||||
case TOP | RIGHT: ne = parts.tooltipArrow()->bitmapNE(); break;
|
||||
case BOTTOM | LEFT: sw = parts.tooltipArrow()->bitmapSW(); break;
|
||||
case BOTTOM | RIGHT: se = parts.tooltipArrow()->bitmapSE(); break;
|
||||
}
|
||||
|
||||
drawRect(g, rc, nw, n, ne, e, se, s, sw, w);
|
||||
|
||||
// Draw arrow in sides
|
||||
she::Surface* arrow = NULL;
|
||||
gfx::Rect target(widget->target());
|
||||
target = target.createIntersection(gfx::Rect(0, 0, ui::display_w(), ui::display_h()));
|
||||
target.offset(-absRc.origin());
|
||||
|
||||
switch (widget->arrowAlign()) {
|
||||
case TOP:
|
||||
arrow = parts.tooltipArrow()->bitmapN();
|
||||
g->drawRgbaSurface(arrow,
|
||||
target.x+target.w/2-arrow->width()/2,
|
||||
rc.y);
|
||||
break;
|
||||
case BOTTOM:
|
||||
arrow = parts.tooltipArrow()->bitmapS();
|
||||
g->drawRgbaSurface(arrow,
|
||||
target.x+target.w/2-arrow->width()/2,
|
||||
rc.y+rc.h-arrow->height());
|
||||
break;
|
||||
case LEFT:
|
||||
arrow = parts.tooltipArrow()->bitmapW();
|
||||
g->drawRgbaSurface(arrow,
|
||||
rc.x,
|
||||
target.y+target.h/2-arrow->height()/2);
|
||||
break;
|
||||
case RIGHT:
|
||||
arrow = parts.tooltipArrow()->bitmapE();
|
||||
g->drawRgbaSurface(arrow,
|
||||
rc.x+rc.w-arrow->width(),
|
||||
target.y+target.h/2-arrow->height()/2);
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill background
|
||||
g->fillRect(
|
||||
bg, Rect(rc).shrink(
|
||||
Border(
|
||||
w->width(),
|
||||
n->height(),
|
||||
e->width(),
|
||||
s->height())));
|
||||
|
||||
rc.shrink(widget->border());
|
||||
|
||||
g->drawAlignedUIText(widget->text(), fg, bg, rc, widget->align());
|
||||
}
|
||||
|
||||
gfx::Color SkinTheme::getWidgetBgColor(Widget* widget)
|
||||
{
|
||||
gfx::Color c = widget->bgColor();
|
||||
|
@ -39,7 +39,6 @@ namespace app {
|
||||
, public app::gen::ThemeFile<SkinTheme> {
|
||||
public:
|
||||
static const char* kThemesFolderName;
|
||||
static const char* kThemeCloseButtonId;
|
||||
|
||||
static SkinTheme* instance();
|
||||
|
||||
@ -53,7 +52,6 @@ namespace app {
|
||||
ui::Cursor* getCursor(ui::CursorType type) override;
|
||||
void initWidget(ui::Widget* widget) override;
|
||||
void getWindowMask(ui::Widget* widget, gfx::Region& region) override;
|
||||
void setDecorativeWidgetBounds(ui::Widget* widget) override;
|
||||
int getScrollbarSize() override;
|
||||
gfx::Size getEntryCaretSize(ui::Widget* widget) override;
|
||||
|
||||
@ -74,10 +72,6 @@ namespace app {
|
||||
void paintTextBox(ui::PaintEvent& ev) override;
|
||||
void paintViewScrollbar(ui::PaintEvent& ev) override;
|
||||
void paintViewViewport(ui::PaintEvent& ev) override;
|
||||
void paintWindow(ui::PaintEvent& ev) override;
|
||||
void paintPopupWindow(ui::PaintEvent& ev) override;
|
||||
void paintTooltip(ui::PaintEvent& ev) override;
|
||||
void paintWindowButton(ui::PaintEvent& ev);
|
||||
|
||||
int get_button_selected_offset() const { return 0; } // TODO Configurable in xml
|
||||
|
||||
|
@ -401,7 +401,7 @@ void ToolBar::openPopupWindow(int group_index, ToolGroup* tool_group)
|
||||
return;
|
||||
|
||||
// In case this tool contains more than just one tool, show the popup window
|
||||
m_popupWindow = new PopupWindow("", PopupWindow::ClickBehavior::CloseOnClickOutsideHotRegion);
|
||||
m_popupWindow = new TransparentPopupWindow(PopupWindow::ClickBehavior::CloseOnClickOutsideHotRegion);
|
||||
m_closeConn = m_popupWindow->Close.connect(base::Bind<void, ToolBar, ToolBar>(&ToolBar::onClosePopup, this));
|
||||
m_openedRecently = true;
|
||||
|
||||
@ -425,9 +425,6 @@ void ToolBar::openPopupWindow(int group_index, ToolGroup* tool_group)
|
||||
Region rgn(gfx::Rect(rc).enlarge(16*guiscale()));
|
||||
rgn.createUnion(rgn, Region(bounds()));
|
||||
m_popupWindow->setHotRegion(rgn);
|
||||
|
||||
m_popupWindow->setTransparent(true);
|
||||
m_popupWindow->setBgColor(gfx::ColorNone);
|
||||
m_popupWindow->setAutoRemap(false);
|
||||
m_popupWindow->setBounds(rc);
|
||||
toolstrip->setBounds(rc);
|
||||
|
@ -33,7 +33,7 @@ IntEntry::IntEntry(int min, int max, SliderDelegate* sliderDelegate)
|
||||
, m_min(min)
|
||||
, m_max(max)
|
||||
, m_slider(m_min, m_max, m_min, sliderDelegate)
|
||||
, m_popupWindow(NULL)
|
||||
, m_popupWindow(nullptr)
|
||||
, m_changeFromSlider(false)
|
||||
{
|
||||
m_slider.setFocusStop(false); // In this way the IntEntry doesn't lost the focus
|
||||
@ -160,31 +160,26 @@ void IntEntry::openPopup()
|
||||
{
|
||||
m_slider.setValue(getValue());
|
||||
|
||||
m_popupWindow = new TransparentPopupWindow(PopupWindow::ClickBehavior::CloseOnClickInOtherWindow);
|
||||
m_popupWindow->setAutoRemap(false);
|
||||
m_popupWindow->addChild(&m_slider);
|
||||
m_popupWindow->Close.connect(&IntEntry::onPopupClose, this);
|
||||
|
||||
Rect rc = bounds();
|
||||
int sliderH = m_slider.sizeHint().h;
|
||||
|
||||
if (rc.y+rc.h+sliderH < ui::display_h())
|
||||
rc.y += rc.h;
|
||||
else
|
||||
rc.y -= sliderH;
|
||||
|
||||
rc.h = sliderH;
|
||||
gfx::Size sz = m_popupWindow->sizeHint();
|
||||
rc.w = 128*guiscale();
|
||||
if (rc.x+rc.w > ui::display_w())
|
||||
rc.x = rc.x - rc.w + bounds().w;
|
||||
|
||||
m_popupWindow = new PopupWindow("", PopupWindow::ClickBehavior::CloseOnClickInOtherWindow);
|
||||
m_popupWindow->setAutoRemap(false);
|
||||
m_popupWindow->setTransparent(true);
|
||||
m_popupWindow->setBgColor(gfx::ColorNone);
|
||||
rc.x = rc.x-rc.w+bounds().w;
|
||||
if (rc.y+rc.h+sz.h < ui::display_h())
|
||||
rc.y += rc.h;
|
||||
else
|
||||
rc.y -= sz.h;
|
||||
m_popupWindow->setBounds(rc);
|
||||
m_popupWindow->Close.connect(&IntEntry::onPopupClose, this);
|
||||
|
||||
Region rgn(rc.createUnion(bounds()));
|
||||
rgn.createUnion(rgn, Region(bounds()));
|
||||
m_popupWindow->setHotRegion(rgn);
|
||||
|
||||
m_popupWindow->addChild(&m_slider);
|
||||
m_popupWindow->openWindow();
|
||||
}
|
||||
|
||||
|
@ -34,11 +34,17 @@ PopupWindow::PopupWindow(const std::string& text,
|
||||
setWantFocus(false);
|
||||
setAlign(LEFT | TOP);
|
||||
|
||||
if (!withCloseButton)
|
||||
removeDecorativeWidgets();
|
||||
if (!withCloseButton) {
|
||||
// Remove close button
|
||||
for (auto child : children()) {
|
||||
if (child->type() == kWindowCloseButtonWidget) {
|
||||
delete child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initTheme();
|
||||
noBorderNoChildSpacing();
|
||||
}
|
||||
|
||||
PopupWindow::~PopupWindow()
|
||||
@ -172,50 +178,6 @@ bool PopupWindow::onProcessMessage(Message* msg)
|
||||
return Window::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void PopupWindow::onSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
ScreenGraphics g;
|
||||
g.setFont(font());
|
||||
Size resultSize(0, 0);
|
||||
|
||||
if (hasText())
|
||||
resultSize = g.fitString(text(),
|
||||
(clientBounds() - border()).w,
|
||||
align());
|
||||
|
||||
resultSize.w += border().width();
|
||||
resultSize.h += border().height();
|
||||
|
||||
if (!children().empty()) {
|
||||
Size maxSize(0, 0);
|
||||
Size reqSize;
|
||||
|
||||
for (auto child : children()) {
|
||||
reqSize = child->sizeHint();
|
||||
|
||||
maxSize.w = MAX(maxSize.w, reqSize.w);
|
||||
maxSize.h = MAX(maxSize.h, reqSize.h);
|
||||
}
|
||||
|
||||
resultSize.w = MAX(resultSize.w, maxSize.w + border().width());
|
||||
resultSize.h += maxSize.h;
|
||||
}
|
||||
|
||||
ev.setSizeHint(resultSize);
|
||||
}
|
||||
|
||||
void PopupWindow::onPaint(PaintEvent& ev)
|
||||
{
|
||||
theme()->paintPopupWindow(ev);
|
||||
}
|
||||
|
||||
void PopupWindow::onInitTheme(InitThemeEvent& ev)
|
||||
{
|
||||
Widget::onInitTheme(ev);
|
||||
|
||||
setBorder(gfx::Border(3 * guiscale()));
|
||||
}
|
||||
|
||||
void PopupWindow::onHitTest(HitTestEvent& ev)
|
||||
{
|
||||
Window::onHitTest(ev);
|
||||
@ -283,4 +245,12 @@ void PopupWindow::onMakeFixed()
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
TransparentPopupWindow::TransparentPopupWindow(ClickBehavior clickBehavior)
|
||||
: PopupWindow("", clickBehavior)
|
||||
{
|
||||
setTransparent(true);
|
||||
setBgColor(gfx::ColorNone);
|
||||
initTheme();
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -42,9 +42,6 @@ namespace ui {
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(Message* msg) override;
|
||||
void onSizeHint(SizeHintEvent& ev) override;
|
||||
void onPaint(PaintEvent& ev) override;
|
||||
void onInitTheme(InitThemeEvent& ev) override;
|
||||
void onHitTest(HitTestEvent& ev) override;
|
||||
|
||||
virtual void onMakeFloating();
|
||||
@ -61,6 +58,11 @@ namespace ui {
|
||||
bool m_fixed;
|
||||
};
|
||||
|
||||
class TransparentPopupWindow : public PopupWindow {
|
||||
public:
|
||||
TransparentPopupWindow(ClickBehavior clickBehavior);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif
|
||||
|
@ -12,10 +12,17 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
// static
|
||||
gfx::Border Style::UndefinedBorder()
|
||||
{
|
||||
return gfx::Border(-1, -1, -1, -1);
|
||||
}
|
||||
|
||||
Style::Style(const Style* base)
|
||||
: m_insertionPoint(0)
|
||||
, m_border(base ? base->border(): gfx::Border(-1, -1, -1, -1))
|
||||
, m_padding(base ? base->padding(): gfx::Border(-1, -1, -1, -1))
|
||||
, m_margin(base ? base->margin(): Style::UndefinedBorder())
|
||||
, m_border(base ? base->border(): Style::UndefinedBorder())
|
||||
, m_padding(base ? base->padding(): Style::UndefinedBorder())
|
||||
{
|
||||
if (base)
|
||||
m_layers = base->layers();
|
||||
|
@ -85,14 +85,18 @@ namespace ui {
|
||||
|
||||
typedef std::vector<Layer> Layers;
|
||||
|
||||
static gfx::Border UndefinedBorder();
|
||||
|
||||
Style(const Style* base);
|
||||
|
||||
const std::string& id() const { return m_id; }
|
||||
const gfx::Border& margin() const { return m_margin; }
|
||||
const gfx::Border& border() const { return m_border; }
|
||||
const gfx::Border& padding() const { return m_padding; }
|
||||
const Layers& layers() const { return m_layers; }
|
||||
|
||||
void setId(const std::string& id) { m_id = id; }
|
||||
void setMargin(const gfx::Border& value) { m_margin = value; }
|
||||
void setBorder(const gfx::Border& value) { m_border = value; }
|
||||
void setPadding(const gfx::Border& value) { m_padding = value; }
|
||||
void addLayer(const Layer& layer);
|
||||
@ -101,6 +105,7 @@ namespace ui {
|
||||
std::string m_id; // Just for debugging purposes
|
||||
Layers m_layers;
|
||||
int m_insertionPoint;
|
||||
gfx::Border m_margin;
|
||||
gfx::Border m_border;
|
||||
gfx::Border m_padding;
|
||||
};
|
||||
|
220
src/ui/theme.cpp
220
src/ui/theme.cpp
@ -23,6 +23,7 @@
|
||||
#include "ui/system.h"
|
||||
#include "ui/view.h"
|
||||
#include "ui/widget.h"
|
||||
#include "ui/window.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@ -101,18 +102,58 @@ void Theme::regenerate()
|
||||
set_mouse_cursor(type);
|
||||
}
|
||||
|
||||
void Theme::setDecorativeWidgetBounds(Widget* widget)
|
||||
{
|
||||
switch (widget->type()) {
|
||||
|
||||
case kWindowTitleLabelWidget: {
|
||||
Window* window = widget->window();
|
||||
gfx::Rect labelBounds(widget->sizeHint());
|
||||
gfx::Rect windowBounds(window->bounds());
|
||||
gfx::Border margin;
|
||||
if (widget->style())
|
||||
margin = widget->style()->margin();
|
||||
|
||||
labelBounds.offset(
|
||||
windowBounds.x + margin.left(),
|
||||
windowBounds.y + margin.top());
|
||||
|
||||
widget->setBounds(labelBounds);
|
||||
break;
|
||||
}
|
||||
|
||||
case kWindowCloseButtonWidget: {
|
||||
Window* window = widget->window();
|
||||
gfx::Rect buttonBounds(widget->sizeHint());
|
||||
gfx::Rect windowBounds(window->bounds());
|
||||
gfx::Border margin(0, 0, 0, 0);
|
||||
if (widget->style())
|
||||
margin = widget->style()->margin();
|
||||
|
||||
buttonBounds.offset(
|
||||
windowBounds.x2() - margin.right() - buttonBounds.w,
|
||||
windowBounds.y + margin.top());
|
||||
|
||||
widget->setBounds(buttonBounds);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Theme::paintWidget(Graphics* g,
|
||||
const Widget* widget,
|
||||
const Style* style,
|
||||
gfx::Rect rc)
|
||||
const gfx::Rect& bounds)
|
||||
{
|
||||
ASSERT(g);
|
||||
ASSERT(widget);
|
||||
ASSERT(style);
|
||||
|
||||
// External background
|
||||
g->fillRect(widget->bgColor(), rc);
|
||||
g->fillRect(widget->bgColor(), bounds);
|
||||
|
||||
gfx::Rect rc = bounds;
|
||||
for_each_layer(
|
||||
widget, style,
|
||||
[this, g, widget, &rc](const Style::Layer& layer) {
|
||||
@ -120,6 +161,68 @@ void Theme::paintWidget(Graphics* g,
|
||||
});
|
||||
}
|
||||
|
||||
void Theme::paintTooltip(Graphics* g,
|
||||
const Widget* widget,
|
||||
const Style* style,
|
||||
const Style* arrowStyle,
|
||||
const gfx::Rect& bounds,
|
||||
const int arrowAlign,
|
||||
const gfx::Rect& target)
|
||||
{
|
||||
if (style)
|
||||
paintWidget(g, widget, style, bounds);
|
||||
|
||||
// Draw arrow
|
||||
if (arrowStyle) {
|
||||
gfx::Size topLeft;
|
||||
gfx::Size center;
|
||||
gfx::Size bottomRight;
|
||||
calcSlices(widget, arrowStyle,
|
||||
topLeft, center, bottomRight);
|
||||
|
||||
gfx::Rect clip, rc(0, 0,
|
||||
topLeft.w+center.w+bottomRight.w,
|
||||
topLeft.h+center.h+bottomRight.h);
|
||||
|
||||
if (arrowAlign & LEFT) {
|
||||
clip.w = topLeft.w;
|
||||
clip.x = bounds.x;
|
||||
rc.x = bounds.x;
|
||||
}
|
||||
else if (arrowAlign & RIGHT) {
|
||||
clip.w = bottomRight.w;
|
||||
clip.x = bounds.x+bounds.w-clip.w;
|
||||
rc.x = bounds.x2()-rc.w;
|
||||
}
|
||||
else {
|
||||
clip.w = center.w;
|
||||
clip.x = target.x+target.w/2-clip.w/2;
|
||||
rc.x = clip.x - topLeft.w;
|
||||
}
|
||||
|
||||
if (arrowAlign & TOP) {
|
||||
clip.h = topLeft.h;
|
||||
clip.y = bounds.y;
|
||||
rc.y = bounds.y;
|
||||
}
|
||||
else if (arrowAlign & BOTTOM) {
|
||||
clip.h = bottomRight.h;
|
||||
clip.y = bounds.y+bounds.h-clip.h;
|
||||
rc.y = bounds.y2()-rc.h;
|
||||
}
|
||||
else {
|
||||
clip.h = center.h;
|
||||
clip.y = target.y+target.h/2-clip.h/2;
|
||||
rc.y = clip.y - topLeft.h;
|
||||
}
|
||||
|
||||
IntersectClip intClip(g, clip);
|
||||
if (intClip)
|
||||
paintWidget(g, widget, arrowStyle, rc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Theme::paintLayer(Graphics* g,
|
||||
const Widget* widget,
|
||||
const Style::Layer& layer,
|
||||
@ -133,16 +236,26 @@ void Theme::paintLayer(Graphics* g,
|
||||
}
|
||||
|
||||
if (layer.spriteSheet() &&
|
||||
!layer.spriteBounds().isEmpty() &&
|
||||
!layer.slicesBounds().isEmpty()) {
|
||||
Theme::drawSlices(g, layer.spriteSheet(), rc,
|
||||
layer.spriteBounds(),
|
||||
layer.slicesBounds(), true);
|
||||
!layer.spriteBounds().isEmpty()) {
|
||||
if (!layer.slicesBounds().isEmpty()) {
|
||||
Theme::drawSlices(g, layer.spriteSheet(), rc,
|
||||
layer.spriteBounds(),
|
||||
layer.slicesBounds(), true);
|
||||
|
||||
rc.x += layer.slicesBounds().x;
|
||||
rc.y += layer.slicesBounds().y;
|
||||
rc.w -= layer.spriteBounds().w - layer.slicesBounds().w;
|
||||
rc.h -= layer.spriteBounds().h - layer.slicesBounds().h;
|
||||
rc.x += layer.slicesBounds().x;
|
||||
rc.y += layer.slicesBounds().y;
|
||||
rc.w -= layer.spriteBounds().w - layer.slicesBounds().w;
|
||||
rc.h -= layer.spriteBounds().h - layer.slicesBounds().h;
|
||||
}
|
||||
// Draw background as a solid piece
|
||||
else {
|
||||
g->drawRgbaSurface(layer.spriteSheet(),
|
||||
layer.spriteBounds().x,
|
||||
layer.spriteBounds().y,
|
||||
rc.x, rc.y,
|
||||
layer.spriteBounds().w,
|
||||
layer.spriteBounds().h);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -197,8 +310,9 @@ void Theme::paintLayer(Graphics* g,
|
||||
gfx::Size iconSize(icon->width(), icon->height());
|
||||
gfx::Point pt;
|
||||
|
||||
if (layer.align() & LEFT)
|
||||
if (layer.align() & LEFT) {
|
||||
pt.x = rc.x;
|
||||
}
|
||||
else if (layer.align() & RIGHT)
|
||||
pt.x = rc.x+rc.w-iconSize.w;
|
||||
else
|
||||
@ -242,12 +356,17 @@ void Theme::measureLayer(const Widget* widget,
|
||||
case Style::Layer::Type::kBackground:
|
||||
case Style::Layer::Type::kBorder:
|
||||
if (layer.spriteSheet() &&
|
||||
!layer.spriteBounds().isEmpty() &&
|
||||
!layer.slicesBounds().isEmpty()) {
|
||||
borderHint.left(std::max(borderHint.left(), layer.slicesBounds().x));
|
||||
borderHint.top(std::max(borderHint.top(), layer.slicesBounds().y));
|
||||
borderHint.right(std::max(borderHint.right(), layer.spriteBounds().w - layer.slicesBounds().x2()));
|
||||
borderHint.bottom(std::max(borderHint.bottom(), layer.spriteBounds().h - layer.slicesBounds().y2()));
|
||||
!layer.spriteBounds().isEmpty()) {
|
||||
if (!layer.slicesBounds().isEmpty()) {
|
||||
borderHint.left(std::max(borderHint.left(), layer.slicesBounds().x));
|
||||
borderHint.top(std::max(borderHint.top(), layer.slicesBounds().y));
|
||||
borderHint.right(std::max(borderHint.right(), layer.spriteBounds().w - layer.slicesBounds().x2()));
|
||||
borderHint.bottom(std::max(borderHint.bottom(), layer.spriteBounds().h - layer.slicesBounds().y2()));
|
||||
}
|
||||
else {
|
||||
iconHint.w = std::max(iconHint.w, layer.spriteBounds().w);
|
||||
iconHint.h = std::max(iconHint.h, layer.spriteBounds().h);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -284,6 +403,53 @@ gfx::Border Theme::calcBorder(const Widget* widget,
|
||||
return borderHint;
|
||||
}
|
||||
|
||||
void Theme::calcSlices(const Widget* widget,
|
||||
const Style* style,
|
||||
gfx::Size& topLeft,
|
||||
gfx::Size& center,
|
||||
gfx::Size& bottomRight)
|
||||
{
|
||||
ASSERT(widget);
|
||||
ASSERT(style);
|
||||
|
||||
for_each_layer(
|
||||
widget, style,
|
||||
[&topLeft, ¢er, &bottomRight]
|
||||
(const Style::Layer& layer) {
|
||||
if (layer.spriteSheet() &&
|
||||
!layer.spriteBounds().isEmpty() &&
|
||||
!layer.slicesBounds().isEmpty()) {
|
||||
gfx::Rect sprite = layer.spriteBounds();
|
||||
gfx::Rect slices = layer.slicesBounds();
|
||||
topLeft.w = MAX(topLeft.w, slices.x);
|
||||
topLeft.h = MAX(topLeft.h, slices.y);
|
||||
center.w = MAX(center.w, slices.w);
|
||||
center.h = MAX(center.h, slices.h);
|
||||
bottomRight.w = MAX(bottomRight.w, sprite.w - slices.x2());
|
||||
bottomRight.h = MAX(bottomRight.h, sprite.h - slices.y2());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
gfx::Color Theme::calcBgColor(const Widget* widget,
|
||||
const Style* style)
|
||||
{
|
||||
ASSERT(widget);
|
||||
ASSERT(style);
|
||||
|
||||
gfx::Color bgColor = gfx::ColorNone;
|
||||
|
||||
for_each_layer(
|
||||
widget, style,
|
||||
[&bgColor]
|
||||
(const Style::Layer& layer) {
|
||||
if (layer.type() == Style::Layer::Type::kBackground)
|
||||
bgColor = layer.color();
|
||||
});
|
||||
|
||||
return bgColor;
|
||||
}
|
||||
|
||||
void Theme::calcWidgetMetrics(const Widget* widget,
|
||||
const Style* style,
|
||||
gfx::Size& sizeHint,
|
||||
@ -309,15 +475,17 @@ void Theme::calcWidgetMetrics(const Widget* widget,
|
||||
iconHint, iconAlign);
|
||||
});
|
||||
|
||||
if (style->border().left() >= 0) borderHint.left(style->border().left());
|
||||
if (style->border().top() >= 0) borderHint.top(style->border().top());
|
||||
if (style->border().right() >= 0) borderHint.right(style->border().right());
|
||||
if (style->border().bottom() >= 0) borderHint.bottom(style->border().bottom());
|
||||
gfx::Border undef = Style::UndefinedBorder();
|
||||
|
||||
if (style->padding().left() >= 0) paddingHint.left(style->padding().left());
|
||||
if (style->padding().top() >= 0) paddingHint.top(style->padding().top());
|
||||
if (style->padding().right() >= 0) paddingHint.right(style->padding().right());
|
||||
if (style->padding().bottom() >= 0) paddingHint.bottom(style->padding().bottom());
|
||||
if (style->border().left() != undef.left()) borderHint.left(style->border().left());
|
||||
if (style->border().top() != undef.top()) borderHint.top(style->border().top());
|
||||
if (style->border().right() != undef.right()) borderHint.right(style->border().right());
|
||||
if (style->border().bottom() != undef.bottom()) borderHint.bottom(style->border().bottom());
|
||||
|
||||
if (style->padding().left() != undef.left()) paddingHint.left(style->padding().left());
|
||||
if (style->padding().top() != undef.top()) paddingHint.top(style->padding().top());
|
||||
if (style->padding().right() != undef.right()) paddingHint.right(style->padding().right());
|
||||
if (style->padding().bottom() != undef.bottom()) paddingHint.bottom(style->padding().bottom());
|
||||
|
||||
sizeHint = gfx::Size(borderHint.width() + paddingHint.width(),
|
||||
borderHint.height() + paddingHint.height());
|
||||
|
@ -49,7 +49,7 @@ namespace ui {
|
||||
virtual Cursor* getCursor(CursorType type) = 0;
|
||||
virtual void initWidget(Widget* widget) = 0;
|
||||
virtual void getWindowMask(Widget* widget, gfx::Region& region) = 0;
|
||||
virtual void setDecorativeWidgetBounds(Widget* widget) = 0;
|
||||
virtual void setDecorativeWidgetBounds(Widget* widget);
|
||||
virtual int getScrollbarSize() = 0;
|
||||
virtual gfx::Size getEntryCaretSize(Widget* widget) = 0;
|
||||
|
||||
@ -70,19 +70,32 @@ namespace ui {
|
||||
virtual void paintTextBox(PaintEvent& ev) = 0;
|
||||
virtual void paintViewScrollbar(PaintEvent& ev) = 0;
|
||||
virtual void paintViewViewport(PaintEvent& ev) = 0;
|
||||
virtual void paintWindow(PaintEvent& ev) = 0;
|
||||
virtual void paintPopupWindow(PaintEvent& ev) = 0;
|
||||
virtual void paintTooltip(PaintEvent& ev) = 0;
|
||||
|
||||
// Default implementation to draw widgets with new ui::Styles
|
||||
virtual void paintWidget(Graphics* g,
|
||||
const Widget* widget,
|
||||
const Style* style,
|
||||
gfx::Rect rc);
|
||||
const gfx::Rect& bounds);
|
||||
|
||||
virtual void paintTooltip(Graphics* g,
|
||||
const Widget* widget,
|
||||
const Style* style,
|
||||
const Style* arrowStyle,
|
||||
const gfx::Rect& bounds,
|
||||
const int arrowAlign,
|
||||
const gfx::Rect& target);
|
||||
|
||||
virtual gfx::Size calcSizeHint(const Widget* widget,
|
||||
const Style* style);
|
||||
virtual gfx::Border calcBorder(const Widget* widget,
|
||||
const Style* style);
|
||||
virtual void calcSlices(const Widget* widget,
|
||||
const Style* style,
|
||||
gfx::Size& topLeft,
|
||||
gfx::Size& center,
|
||||
gfx::Size& bottomRight);
|
||||
virtual gfx::Color calcBgColor(const Widget* widget,
|
||||
const Style* style);
|
||||
|
||||
static void drawSlices(Graphics* g,
|
||||
she::Surface* sheet,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -19,6 +19,7 @@
|
||||
#include "ui/paint_event.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/textbox.h"
|
||||
#include "ui/theme.h"
|
||||
|
||||
#include <string>
|
||||
@ -123,12 +124,20 @@ void TooltipManager::onTick()
|
||||
// TipWindow
|
||||
|
||||
TipWindow::TipWindow(const std::string& text)
|
||||
: PopupWindow(text, ClickBehavior::CloseOnClickInOtherWindow)
|
||||
// Put an empty string in the ctor so the window label isn't build
|
||||
: PopupWindow("", ClickBehavior::CloseOnClickInOtherWindow)
|
||||
, m_arrowStyle(nullptr)
|
||||
, m_arrowAlign(0)
|
||||
, m_closeOnKeyDown(true)
|
||||
, m_textBox(new TextBox("", LEFT | TOP))
|
||||
{
|
||||
setTransparent(true);
|
||||
|
||||
// Here we build our own custimized label for the window
|
||||
// (a text box).
|
||||
addChild(m_textBox);
|
||||
setText(text);
|
||||
|
||||
makeFixed();
|
||||
initTheme();
|
||||
}
|
||||
@ -232,50 +241,17 @@ bool TipWindow::onProcessMessage(Message* msg)
|
||||
return PopupWindow::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void TipWindow::onSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
ScreenGraphics g;
|
||||
g.setFont(font());
|
||||
Size resultSize =
|
||||
g.fitString(text(),
|
||||
(clientBounds() - border()).w,
|
||||
align());
|
||||
|
||||
resultSize.w += border().width();
|
||||
resultSize.h += border().height();
|
||||
|
||||
if (!children().empty()) {
|
||||
Size maxSize(0, 0);
|
||||
Size reqSize;
|
||||
|
||||
for (auto child : children()) {
|
||||
reqSize = child->sizeHint();
|
||||
|
||||
maxSize.w = MAX(maxSize.w, reqSize.w);
|
||||
maxSize.h = MAX(maxSize.h, reqSize.h);
|
||||
}
|
||||
|
||||
resultSize.w = MAX(resultSize.w, maxSize.w + border().width());
|
||||
resultSize.h += maxSize.h;
|
||||
}
|
||||
|
||||
ev.setSizeHint(resultSize);
|
||||
}
|
||||
|
||||
void TipWindow::onInitTheme(InitThemeEvent& ev)
|
||||
{
|
||||
Window::onInitTheme(ev);
|
||||
|
||||
setBorder(
|
||||
gfx::Border(6 * guiscale(),
|
||||
6 * guiscale(),
|
||||
6 * guiscale(),
|
||||
7 * guiscale()));
|
||||
}
|
||||
|
||||
void TipWindow::onPaint(PaintEvent& ev)
|
||||
{
|
||||
theme()->paintTooltip(ev);
|
||||
theme()->paintTooltip(
|
||||
ev.graphics(), this, style(), arrowStyle(),
|
||||
clientBounds(), arrowAlign(),
|
||||
gfx::Rect(target()).offset(-bounds().origin()));
|
||||
}
|
||||
|
||||
void TipWindow::onBuildTitleLabel()
|
||||
{
|
||||
m_textBox->setText(text());
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2001-2013, 2015 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
class TextBox;
|
||||
class TipWindow;
|
||||
|
||||
class TooltipManager : public Widget {
|
||||
@ -58,6 +59,9 @@ namespace ui {
|
||||
public:
|
||||
TipWindow(const std::string& text = "");
|
||||
|
||||
Style* arrowStyle() { return m_arrowStyle; }
|
||||
void setArrowStyle(Style* style) { m_arrowStyle = style; }
|
||||
|
||||
int arrowAlign() const { return m_arrowAlign; }
|
||||
const gfx::Rect& target() const { return m_target; }
|
||||
|
||||
@ -67,16 +71,19 @@ namespace ui {
|
||||
// window.
|
||||
bool pointAt(int arrowAlign, const gfx::Rect& target);
|
||||
|
||||
TextBox* textBox() const { return m_textBox; }
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(Message* msg) override;
|
||||
void onSizeHint(SizeHintEvent& ev) override;
|
||||
void onInitTheme(InitThemeEvent& ev) override;
|
||||
void onPaint(PaintEvent& ev) override;
|
||||
void onBuildTitleLabel() override;
|
||||
|
||||
private:
|
||||
Style* m_arrowStyle;
|
||||
int m_arrowAlign;
|
||||
gfx::Rect m_target;
|
||||
bool m_closeOnKeyDown;
|
||||
TextBox* m_textBox;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "ui/hit_test_event.h"
|
||||
#include "ui/image_view.h"
|
||||
#include "ui/init_theme_event.h"
|
||||
#include "ui/int_entry.h"
|
||||
#include "ui/keys.h"
|
||||
#include "ui/label.h"
|
||||
#include "ui/layout_io.h"
|
||||
|
@ -176,6 +176,10 @@ void Widget::setBgColor(gfx::Color color)
|
||||
{
|
||||
m_bgColor = color;
|
||||
onSetBgColor();
|
||||
|
||||
if (m_style) {
|
||||
LOG(WARNING) << "Warning setting bgColor to a widget with style\n";
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setTheme(Theme* theme)
|
||||
@ -188,6 +192,7 @@ void Widget::setStyle(Style* style)
|
||||
{
|
||||
m_style = style;
|
||||
m_border = m_theme->calcBorder(this, style);
|
||||
m_bgColor = m_theme->calcBgColor(this, m_style);
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
@ -645,6 +650,7 @@ void Widget::setBoundsQuietly(const gfx::Rect& rc)
|
||||
void Widget::setBorder(const Border& br)
|
||||
{
|
||||
m_border = br;
|
||||
|
||||
if (m_style) {
|
||||
LOG(WARNING) << "Warning setting border to a widget with style\n";
|
||||
}
|
||||
@ -1484,9 +1490,8 @@ void Widget::onInitTheme(InitThemeEvent& ev)
|
||||
|
||||
void Widget::onSetDecorativeWidgetBounds()
|
||||
{
|
||||
if (m_theme) {
|
||||
if (m_theme)
|
||||
m_theme->setDecorativeWidgetBounds(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::onVisible(bool visible)
|
||||
|
@ -42,6 +42,8 @@ namespace ui {
|
||||
kViewViewportWidget,
|
||||
kViewWidget,
|
||||
kWindowWidget,
|
||||
kWindowTitleLabelWidget,
|
||||
kWindowCloseButtonWidget,
|
||||
|
||||
// User widgets.
|
||||
kFirstUserWidget,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -11,14 +11,16 @@
|
||||
#include "ui/window.h"
|
||||
|
||||
#include "gfx/size.h"
|
||||
#include "ui/button.h"
|
||||
#include "ui/graphics.h"
|
||||
#include "ui/intern.h"
|
||||
#include "ui/label.h"
|
||||
#include "ui/manager.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/message_loop.h"
|
||||
#include "ui/move_region.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/resize_event.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/theme.h"
|
||||
|
||||
@ -26,6 +28,8 @@ namespace ui {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
namespace {
|
||||
|
||||
enum {
|
||||
WINDOW_NONE = 0,
|
||||
WINDOW_MOVE = 1,
|
||||
@ -35,25 +39,88 @@ enum {
|
||||
WINDOW_RESIZE_BOTTOM = 16,
|
||||
};
|
||||
|
||||
static gfx::Point clickedMousePos;
|
||||
static gfx::Rect* clickedWindowPos = NULL;
|
||||
gfx::Point clickedMousePos;
|
||||
gfx::Rect* clickedWindowPos = nullptr;
|
||||
|
||||
class WindowTitleLabel : public Label {
|
||||
public:
|
||||
WindowTitleLabel(const std::string& text) : Label(text) {
|
||||
setDecorative(true);
|
||||
setType(kWindowTitleLabelWidget);
|
||||
initTheme();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Controls the "X" button in a window to close it.
|
||||
class WindowCloseButton : public ButtonBase {
|
||||
public:
|
||||
WindowCloseButton()
|
||||
: ButtonBase("", kWindowCloseButtonWidget,
|
||||
kButtonWidget, kButtonWidget) {
|
||||
setDecorative(true);
|
||||
initTheme();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void onClick(Event& ev) override {
|
||||
ButtonBase::onClick(ev);
|
||||
closeWindow();
|
||||
}
|
||||
|
||||
bool onProcessMessage(Message* msg) override {
|
||||
switch (msg->type()) {
|
||||
|
||||
case kSetCursorMessage:
|
||||
ui::set_mouse_cursor(kArrowCursor);
|
||||
return true;
|
||||
|
||||
case kKeyDownMessage:
|
||||
if (window()->isForeground() &&
|
||||
static_cast<KeyMessage*>(msg)->scancode() == kKeyEsc) {
|
||||
setSelected(true);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case kKeyUpMessage:
|
||||
if (window()->isForeground() &&
|
||||
static_cast<KeyMessage*>(msg)->scancode() == kKeyEsc) {
|
||||
if (isSelected()) {
|
||||
setSelected(false);
|
||||
closeWindow();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ButtonBase::onProcessMessage(msg);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
Window::Window(Type type, const std::string& text)
|
||||
: Widget(kWindowWidget)
|
||||
, m_closer(nullptr)
|
||||
, m_titleLabel(nullptr)
|
||||
, m_closeButton(nullptr)
|
||||
, m_isDesktop(type == DesktopWindow)
|
||||
, m_isMoveable(!m_isDesktop)
|
||||
, m_isSizeable(!m_isDesktop)
|
||||
, m_isOnTop(false)
|
||||
, m_isWantFocus(true)
|
||||
, m_isForeground(false)
|
||||
, m_isAutoRemap(true)
|
||||
{
|
||||
m_closer = NULL;
|
||||
m_isDesktop = (type == DesktopWindow);
|
||||
m_isMoveable = !m_isDesktop;
|
||||
m_isSizeable = !m_isDesktop;
|
||||
m_isOnTop = false;
|
||||
m_isWantFocus = true;
|
||||
m_isForeground = false;
|
||||
m_isAutoRemap = true;
|
||||
|
||||
setVisible(false);
|
||||
setAlign(LEFT | MIDDLE);
|
||||
if (type == WithTitleBar)
|
||||
if (type == WithTitleBar) {
|
||||
setText(text);
|
||||
addChild(m_closeButton = new WindowCloseButton);
|
||||
}
|
||||
|
||||
initTheme();
|
||||
}
|
||||
@ -95,12 +162,6 @@ HitTest Window::hitTest(const gfx::Point& point)
|
||||
return ev.hit();
|
||||
}
|
||||
|
||||
void Window::removeDecorativeWidgets()
|
||||
{
|
||||
while (!children().empty())
|
||||
delete children().front();
|
||||
}
|
||||
|
||||
void Window::onClose(CloseEvent& ev)
|
||||
{
|
||||
// Fire Close signal
|
||||
@ -112,11 +173,18 @@ void Window::onHitTest(HitTestEvent& ev)
|
||||
HitTest ht = HitTestNowhere;
|
||||
|
||||
// If this window is not movable or we are not completely visible.
|
||||
if (!m_isMoveable ||
|
||||
// TODO check why this is necessary, there should be a bug in
|
||||
// the manager where we are receiving mouse events and are not
|
||||
// the top most window.
|
||||
this->manager()->pick(ev.point()) != this) {
|
||||
if (!m_isMoveable) {
|
||||
ev.setHit(ht);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO check why this is necessary, there should be a bug in
|
||||
// the manager where we are receiving mouse events and are not
|
||||
// the top most window.
|
||||
Widget* picked = manager()->pick(ev.point());
|
||||
if (picked &&
|
||||
picked != this &&
|
||||
picked->type() != kWindowTitleLabelWidget) {
|
||||
ev.setHit(ht);
|
||||
return;
|
||||
}
|
||||
@ -444,19 +512,14 @@ void Window::onSizeHint(SizeHintEvent& ev)
|
||||
}
|
||||
}
|
||||
|
||||
if (hasText())
|
||||
maxSize.w = MAX(maxSize.w, textWidth());
|
||||
if (m_titleLabel)
|
||||
maxSize.w = MAX(maxSize.w, m_titleLabel->sizeHint().w);
|
||||
|
||||
ev.setSizeHint(maxSize.w + border().width(),
|
||||
maxSize.h + border().height());
|
||||
}
|
||||
}
|
||||
|
||||
void Window::onPaint(PaintEvent& ev)
|
||||
{
|
||||
theme()->paintWindow(ev);
|
||||
}
|
||||
|
||||
void Window::onBroadcastMouseMessage(WidgetsList& targets)
|
||||
{
|
||||
targets.push_back(this);
|
||||
@ -473,10 +536,30 @@ void Window::onBroadcastMouseMessage(WidgetsList& targets)
|
||||
|
||||
void Window::onSetText()
|
||||
{
|
||||
onBuildTitleLabel();
|
||||
Widget::onSetText();
|
||||
initTheme();
|
||||
}
|
||||
|
||||
void Window::onBuildTitleLabel()
|
||||
{
|
||||
if (text().empty()) {
|
||||
if (m_titleLabel) {
|
||||
removeChild(m_titleLabel);
|
||||
delete m_titleLabel;
|
||||
m_titleLabel = nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!m_titleLabel) {
|
||||
m_titleLabel = new WindowTitleLabel(text());
|
||||
addChild(m_titleLabel);
|
||||
}
|
||||
else
|
||||
m_titleLabel->setText(text());
|
||||
}
|
||||
}
|
||||
|
||||
void Window::windowSetPosition(const gfx::Rect& rect)
|
||||
{
|
||||
// Copy the new position rectangle
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -17,6 +17,9 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
class ButtonBase;
|
||||
class Label;
|
||||
|
||||
class Window : public Widget {
|
||||
public:
|
||||
enum Type { DesktopWindow, WithTitleBar, WithoutTitleBar };
|
||||
@ -51,8 +54,6 @@ namespace ui {
|
||||
|
||||
HitTest hitTest(const gfx::Point& point);
|
||||
|
||||
void removeDecorativeWidgets();
|
||||
|
||||
// Signals
|
||||
obs::signal<void (CloseEvent&)> Close;
|
||||
|
||||
@ -60,7 +61,6 @@ namespace ui {
|
||||
virtual bool onProcessMessage(Message* msg) override;
|
||||
virtual void onResize(ResizeEvent& ev) override;
|
||||
virtual void onSizeHint(SizeHintEvent& ev) override;
|
||||
virtual void onPaint(PaintEvent& ev) override;
|
||||
virtual void onBroadcastMouseMessage(WidgetsList& targets) override;
|
||||
virtual void onSetText() override;
|
||||
|
||||
@ -69,6 +69,7 @@ namespace ui {
|
||||
virtual void onHitTest(HitTestEvent& ev);
|
||||
virtual void onWindowResize();
|
||||
virtual void onWindowMovement();
|
||||
virtual void onBuildTitleLabel();
|
||||
|
||||
private:
|
||||
void windowSetPosition(const gfx::Rect& rect);
|
||||
@ -77,6 +78,8 @@ namespace ui {
|
||||
void moveWindow(const gfx::Rect& rect, bool use_blit);
|
||||
|
||||
Widget* m_closer;
|
||||
Label* m_titleLabel;
|
||||
ButtonBase* m_closeButton;
|
||||
bool m_isDesktop : 1;
|
||||
bool m_isMoveable : 1;
|
||||
bool m_isSizeable : 1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user