1// Aseprite
2// Copyright (c) 2020-2022 Igara Studio S.A.
3//
4// This program is distributed under the terms of
5// the End-User License Agreement for Aseprite.
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif
10
11#include "app/ui/tile_button.h"
12
13#include "app/modules/gfx.h"
14#include "app/ui/skin/skin_theme.h"
15#include "app/ui/status_bar.h"
16#include "app/ui_context.h"
17#include "fmt/format.h"
18#include "ui/graphics.h"
19#include "ui/message.h"
20#include "ui/paint_event.h"
21#include "ui/size_hint_event.h"
22#include "ui/system.h"
23#include "ui/window.h"
24
25namespace app {
26
27using namespace app::skin;
28using namespace ui;
29
30static WidgetType tilebutton_type()
31{
32 static WidgetType type = kGenericWidget;
33 if (type == kGenericWidget)
34 type = register_widget_type();
35 return type;
36}
37
38TileButton::TileButton()
39 : ButtonBase("", tilebutton_type(), kButtonWidget, kButtonWidget)
40{
41 setFocusStop(true);
42 initTheme();
43
44 UIContext::instance()->add_observer(this);
45}
46
47TileButton::~TileButton()
48{
49 UIContext::instance()->remove_observer(this);
50}
51
52doc::tile_t TileButton::getTile() const
53{
54 return m_tile;
55}
56
57void TileButton::setTile(doc::tile_t origTile)
58{
59 // Before change (this signal can modify the color)
60 doc::tile_t tile = origTile;
61 BeforeChange(tile);
62 m_tile = tile;
63 Change(tile);
64 invalidate();
65}
66
67doc::tile_t TileButton::getTileByPosition(const gfx::Point& pos)
68{
69 // Ignore the position
70 return m_tile;
71}
72
73void TileButton::onInitTheme(InitThemeEvent& ev)
74{
75 ButtonBase::onInitTheme(ev);
76 setStyle(SkinTheme::get(this)->styles.colorButton());
77}
78
79bool TileButton::onProcessMessage(Message* msg)
80{
81 switch (msg->type()) {
82
83 case kMouseEnterMessage:
84 StatusBar::instance()->showTile(0, m_tile);
85 break;
86
87 case kMouseLeaveMessage:
88 StatusBar::instance()->showDefaultText();
89 break;
90
91 case kMouseMoveMessage:
92 // TODO code similar to ColorButton::onProcessMessage()
93 if (hasCapture()) {
94 gfx::Point mousePos = static_cast<MouseMessage*>(msg)->position();
95 doc::tile_t tile = m_tile;
96
97 // Pick a tile from a ITileSource
98 Widget* picked = window()->pick(mousePos);
99 if (picked == this) {
100 // Do nothing
101 break;
102 }
103
104 ITileSource* tileSource = dynamic_cast<ITileSource*>(picked);
105
106 // If there is no tile source in this window, try to get the
107 // tile from other display, i.e. and editor in other native
108 // window.
109 if (!tileSource && get_multiple_displays()) {
110 os::Window* nativeWindow = display()->nativeWindow();
111 gfx::Point screenPos = nativeWindow->pointToScreen(mousePos);
112
113 picked = manager()->pickFromScreenPos(screenPos);
114 tileSource = (picked != this ? dynamic_cast<ITileSource*>(picked): nullptr);
115 if (tileSource) {
116 nativeWindow = picked->display()->nativeWindow();
117 mousePos = nativeWindow->pointFromScreen(screenPos);
118 }
119 }
120
121 if (tileSource) {
122 tile = tileSource->getTileByPosition(mousePos);
123 }
124
125 // Did the tile change?
126 if (tile != m_tile) {
127 setTile(tile);
128 }
129 }
130 break;
131
132 case kSetCursorMessage:
133 if (hasCapture()) {
134 auto theme = SkinTheme::get(this);
135 ui::set_mouse_cursor(kCustomCursor, theme->cursors.eyedropper());
136 return true;
137 }
138 break;
139
140 }
141
142 return ButtonBase::onProcessMessage(msg);
143}
144
145void TileButton::onSizeHint(SizeHintEvent& ev)
146{
147 ButtonBase::onSizeHint(ev);
148 gfx::Size sz(32*guiscale(),
149 32*guiscale());
150 ev.setSizeHint(sz);
151}
152
153void TileButton::onPaint(PaintEvent& ev)
154{
155 Graphics* g = ev.graphics();
156 SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
157 gfx::Rect rc = clientBounds();
158
159 gfx::Color bg = bgColor();
160 if (gfx::is_transparent(bg))
161 bg = theme->colors.face();
162 g->fillRect(bg, rc);
163
164 Site site = UIContext::instance()->activeSite();
165 draw_tile_button(g, rc,
166 site, m_tile,
167 hasMouseOver(), false);
168
169 // Draw text
170 if (m_tile != doc::notile) {
171 int baseIndex = 1;
172 if (site.tileset())
173 baseIndex = site.tileset()->baseIndex();
174
175 std::string str = fmt::format(
176 "{}", int(doc::tile_geti(m_tile)) + baseIndex - 1);
177 setTextQuiet(str.c_str());
178
179 // TODO calc a proper color for the text
180 gfx::Color textcolor = gfx::rgba(0, 0, 0);
181 gfx::Rect textrc;
182 getTextIconInfo(NULL, &textrc);
183 g->drawUIText(text(), textcolor, gfx::ColorNone, textrc.origin(), 0);
184 }
185}
186
187void TileButton::onActiveSiteChange(const Site& site)
188{
189 invalidate();
190}
191
192} // namespace app
193