mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-12 16:14:10 +00:00
Add canvas autoScaling feature (fix #3748)
This commit is contained in:
parent
067309f776
commit
0958573cac
@ -18,18 +18,74 @@ namespace script {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Theme { };
|
||||
struct ThemeDimension { };
|
||||
class Theme {
|
||||
public:
|
||||
Theme(int uiscale) : m_uiscale(uiscale) { }
|
||||
|
||||
gfx::Border styleMetrics(const std::string& id) const {
|
||||
auto theme = skin::SkinTheme::instance();
|
||||
if (!theme) return gfx::Border(0);
|
||||
|
||||
ui::Style* style = theme->getStyleById(id);
|
||||
if (!style) return gfx::Border(0);
|
||||
|
||||
ui::Widget widget(ui::kGenericWidget);
|
||||
auto border = theme->calcBorder(&widget, style);
|
||||
if (m_uiscale > 1)
|
||||
border /= m_uiscale;
|
||||
|
||||
return border;
|
||||
}
|
||||
|
||||
int getDimensionById(const std::string& id) const {
|
||||
int value = skin::SkinTheme::instance()->getDimensionById(id);
|
||||
if (m_uiscale > 1)
|
||||
value /= m_uiscale;
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_uiscale;
|
||||
};
|
||||
|
||||
struct ThemeDimension {
|
||||
Theme* theme;
|
||||
|
||||
ThemeDimension(Theme* theme) : theme(theme) { }
|
||||
|
||||
int getById(const std::string& id) const {
|
||||
return theme->getDimensionById(id);
|
||||
}
|
||||
};
|
||||
|
||||
struct ThemeColor { };
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
void push_border_as_table(lua_State* L, const gfx::Border& border)
|
||||
{
|
||||
lua_newtable(L);
|
||||
{
|
||||
lua_newtable(L);
|
||||
setfield_integer(L, "left", border.left());
|
||||
setfield_integer(L, "top", border.top());
|
||||
setfield_integer(L, "right", border.right());
|
||||
setfield_integer(L, "bottom", border.bottom());
|
||||
}
|
||||
lua_setfield(L, -2, "border");
|
||||
}
|
||||
#endif
|
||||
|
||||
int ThemeDimension_index(lua_State* L)
|
||||
{
|
||||
[[maybe_unused]]
|
||||
auto themeDimension = get_obj<ThemeDimension>(L, 1);
|
||||
|
||||
const char* id = lua_tostring(L, 2);
|
||||
if (!id)
|
||||
return luaL_error(L, "id in app.theme.dimension.id must be a string");
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
const int value = skin::SkinTheme::instance()->getDimensionById(id);
|
||||
const int value = themeDimension->getById(id);
|
||||
lua_pushinteger(L, value);
|
||||
#else
|
||||
lua_pushinteger(L, 0);
|
||||
@ -55,38 +111,15 @@ int ThemeColor_index(lua_State* L)
|
||||
int Theme_styleMetrics(lua_State* L)
|
||||
{
|
||||
[[maybe_unused]]
|
||||
auto t = get_obj<Theme>(L, 1);
|
||||
auto theme = get_obj<Theme>(L, 1);
|
||||
|
||||
const char* id = lua_tostring(L, 2);
|
||||
if (!id)
|
||||
return 0;
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
auto theme = skin::SkinTheme::instance();
|
||||
if (!theme)
|
||||
return 0;
|
||||
|
||||
ui::Style* style = theme->getStyleById(id);
|
||||
if (!style)
|
||||
return 0;
|
||||
|
||||
ui::Widget widget(ui::kGenericWidget);
|
||||
gfx::Border border = theme->calcBorder(&widget, style);
|
||||
|
||||
lua_newtable(L);
|
||||
{
|
||||
lua_newtable(L);
|
||||
lua_pushinteger(L, border.left());
|
||||
lua_setfield(L, -2, "left");
|
||||
lua_pushinteger(L, border.top());
|
||||
lua_setfield(L, -2, "top");
|
||||
lua_pushinteger(L, border.right());
|
||||
lua_setfield(L, -2, "right");
|
||||
lua_pushinteger(L, border.bottom());
|
||||
lua_setfield(L, -2, "bottom");
|
||||
}
|
||||
lua_setfield(L, -2, "border");
|
||||
|
||||
gfx::Border border = theme->styleMetrics(id);
|
||||
push_border_as_table(L, border);
|
||||
return 1;
|
||||
#else // ENABLE_UI
|
||||
return 0;
|
||||
@ -95,7 +128,8 @@ int Theme_styleMetrics(lua_State* L)
|
||||
|
||||
int Theme_get_dimension(lua_State* L)
|
||||
{
|
||||
push_obj<ThemeDimension>(L, ThemeDimension());
|
||||
auto theme = get_obj<Theme>(L, 1);
|
||||
push_new<ThemeDimension>(L, theme);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -140,9 +174,9 @@ void register_theme_classes(lua_State* L)
|
||||
REG_CLASS_PROPERTIES(L, Theme);
|
||||
}
|
||||
|
||||
void push_app_theme(lua_State* L)
|
||||
void push_app_theme(lua_State* L, int uiscale)
|
||||
{
|
||||
push_obj<Theme>(L, Theme());
|
||||
push_new<Theme>(L, uiscale);
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
|
@ -52,8 +52,14 @@ void Canvas::callPaint()
|
||||
m_surface->drawRect(m_surface->bounds(), p);
|
||||
|
||||
// Draw only on resize (onPaint we draw the cached m_surface)
|
||||
GraphicsContext gc(m_surface);
|
||||
gc.font(AddRef(font()));
|
||||
GraphicsContext gc(m_surface, m_autoScaling ? ui::guiscale() : 1);
|
||||
if (m_autoScaling) {
|
||||
auto theme = skin::SkinTheme::get(this);
|
||||
gc.font(AddRef(theme->getUnscaledFont(font())));
|
||||
}
|
||||
else
|
||||
gc.font(AddRef(font()));
|
||||
|
||||
Paint(gc);
|
||||
}
|
||||
|
||||
@ -69,6 +75,16 @@ void Canvas::onInitTheme(ui::InitThemeEvent& ev)
|
||||
setBgColor(bg);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T makeScaled(T* msg, const gfx::Point& offset)
|
||||
{
|
||||
static_assert(std::is_base_of<ui::Message, T>::value, "type parameter must derive from ui::Message");
|
||||
auto result = T(msg->type(), *msg, ((msg->position() - offset) / ui::guiscale()) + offset);
|
||||
result.setRecipient(static_cast<ui::Message*>(msg)->recipient());
|
||||
result.setDisplay(static_cast<ui::Message*>(msg)->display());
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Canvas::onProcessMessage(ui::Message* msg)
|
||||
{
|
||||
switch (msg->type()) {
|
||||
@ -98,8 +114,11 @@ bool Canvas::onProcessMessage(ui::Message* msg)
|
||||
return true;
|
||||
|
||||
case ui::kMouseMoveMessage: {
|
||||
auto mouseMsg = static_cast<ui::MouseMessage*>(msg);
|
||||
MouseMove(mouseMsg);
|
||||
auto mouseMsg = *static_cast<ui::MouseMessage*>(msg);
|
||||
if (m_autoScaling) {
|
||||
mouseMsg = makeScaled(&mouseMsg, bounds().origin());
|
||||
}
|
||||
MouseMove(&mouseMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -110,14 +129,20 @@ bool Canvas::onProcessMessage(ui::Message* msg)
|
||||
if (isFocusStop() && !hasFocus())
|
||||
requestFocus();
|
||||
|
||||
auto mouseMsg = static_cast<ui::MouseMessage*>(msg);
|
||||
MouseDown(mouseMsg);
|
||||
auto mouseMsg = *static_cast<ui::MouseMessage*>(msg);
|
||||
if (m_autoScaling) {
|
||||
mouseMsg = makeScaled(&mouseMsg, bounds().origin());
|
||||
}
|
||||
MouseDown(&mouseMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
case ui::kMouseUpMessage: {
|
||||
auto mouseMsg = static_cast<ui::MouseMessage*>(msg);
|
||||
MouseUp(mouseMsg);
|
||||
auto mouseMsg = *static_cast<ui::MouseMessage*>(msg);
|
||||
if (m_autoScaling) {
|
||||
mouseMsg = makeScaled(&mouseMsg, bounds().origin());
|
||||
}
|
||||
MouseUp(&mouseMsg);
|
||||
|
||||
if (hasCapture())
|
||||
releaseMouse();
|
||||
@ -125,20 +150,29 @@ bool Canvas::onProcessMessage(ui::Message* msg)
|
||||
}
|
||||
|
||||
case ui::kDoubleClickMessage: {
|
||||
auto mouseMsg = static_cast<ui::MouseMessage*>(msg);
|
||||
DoubleClick(mouseMsg);
|
||||
auto mouseMsg = *static_cast<ui::MouseMessage*>(msg);
|
||||
if (m_autoScaling) {
|
||||
mouseMsg = makeScaled(&mouseMsg, bounds().origin());
|
||||
}
|
||||
DoubleClick(&mouseMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
case ui::kMouseWheelMessage: {
|
||||
auto mouseMsg = static_cast<ui::MouseMessage*>(msg);
|
||||
Wheel(mouseMsg);
|
||||
auto mouseMsg = *static_cast<ui::MouseMessage*>(msg);
|
||||
if (m_autoScaling) {
|
||||
mouseMsg = makeScaled(&mouseMsg, bounds().origin());
|
||||
}
|
||||
Wheel(&mouseMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
case ui::kTouchMagnifyMessage: {
|
||||
auto touchMsg = static_cast<ui::TouchMessage*>(msg);
|
||||
TouchMagnify(touchMsg);
|
||||
auto touchMsg = *static_cast<ui::TouchMessage*>(msg);
|
||||
if (m_autoScaling) {
|
||||
touchMsg = makeScaled(&touchMsg, bounds().origin());
|
||||
}
|
||||
TouchMagnify(&touchMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -150,14 +184,18 @@ void Canvas::onResize(ui::ResizeEvent& ev)
|
||||
{
|
||||
Widget::onResize(ev);
|
||||
if (os::instance() && !ev.bounds().isEmpty()) {
|
||||
const int w = ev.bounds().w;
|
||||
const int h = ev.bounds().h;
|
||||
int w = ev.bounds().w;
|
||||
int h = ev.bounds().h;
|
||||
|
||||
if (m_autoScaling) {
|
||||
w = w/ui::guiscale() + (w % ui::guiscale());
|
||||
h = h/ui::guiscale() + (h % ui::guiscale());
|
||||
}
|
||||
|
||||
if (!m_surface ||
|
||||
m_surface->width() != w ||
|
||||
m_surface->height() != h) {
|
||||
m_surface = os::instance()->makeSurface(w, h);
|
||||
|
||||
callPaint();
|
||||
}
|
||||
}
|
||||
@ -168,9 +206,14 @@ void Canvas::onResize(ui::ResizeEvent& ev)
|
||||
void Canvas::onPaint(ui::PaintEvent& ev)
|
||||
{
|
||||
auto g = ev.graphics();
|
||||
const gfx::Rect rc = clientBounds();
|
||||
if (m_surface)
|
||||
g->drawSurface(m_surface.get(), rc.x, rc.y);
|
||||
gfx::Rect rc = clientBounds();
|
||||
if (m_surface) {
|
||||
if (m_autoScaling) {
|
||||
rc.w += (rc.w % ui::guiscale());
|
||||
rc.h += (rc.h % ui::guiscale());
|
||||
}
|
||||
g->drawSurface(m_surface.get(), m_surface->bounds(), rc, os::Sampling(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
|
@ -35,6 +35,14 @@ public:
|
||||
m_cursorType = cursor;
|
||||
}
|
||||
|
||||
void setAutoScaling(const bool v) {
|
||||
m_autoScaling = v;
|
||||
}
|
||||
|
||||
bool isAutoScaling() const {
|
||||
return m_autoScaling;
|
||||
}
|
||||
|
||||
obs::signal<void(GraphicsContext&)> Paint;
|
||||
obs::signal<void(ui::KeyMessage*)> KeyDown;
|
||||
obs::signal<void(ui::KeyMessage*)> KeyUp;
|
||||
@ -57,6 +65,11 @@ private:
|
||||
|
||||
os::SurfaceRef m_surface;
|
||||
ui::CursorType m_cursorType = ui::kArrowCursor;
|
||||
|
||||
// Flag used to indicate that the canvas will scale all the drawing operations
|
||||
// according to the UI scale's preferences setting. So the user doesn't have to
|
||||
// take care about the current scale when writing scripts.
|
||||
bool m_autoScaling = true;
|
||||
};
|
||||
|
||||
} // namespace script
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "ui/manager.h"
|
||||
#include "ui/menu.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/scale.h"
|
||||
#include "ui/separator.h"
|
||||
#include "ui/slider.h"
|
||||
#include "ui/system.h"
|
||||
@ -1103,6 +1104,15 @@ int Dialog_canvas(lua_State* L)
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
type = lua_getfield(L, 2, "autoScaling");
|
||||
if (type != LUA_TNIL) {
|
||||
widget->setAutoScaling(lua_toboolean(L, -1));
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (widget->isAutoScaling())
|
||||
sz *= ui::guiscale();
|
||||
|
||||
widget->setSizeHint(sz);
|
||||
|
||||
bool handleKeyEvents = false;
|
||||
|
@ -139,7 +139,7 @@ namespace app {
|
||||
};
|
||||
|
||||
void push_app_events(lua_State* L);
|
||||
void push_app_theme(lua_State* L);
|
||||
void push_app_theme(lua_State* L, int uiscale = 1);
|
||||
int push_image_iterator_function(lua_State* L, const doc::Image* image, int extraArgIndex);
|
||||
void push_brush(lua_State* L, const doc::BrushRef& brush);
|
||||
void push_cel_image(lua_State* L, doc::Cel* cel);
|
||||
|
@ -84,16 +84,20 @@ void GraphicsContext::drawImage(const doc::Image* img,
|
||||
void GraphicsContext::drawThemeImage(const std::string& partId, const gfx::Point& pt)
|
||||
{
|
||||
if (auto theme = skin::SkinTheme::instance()) {
|
||||
skin::SkinPartPtr part = theme->getPartById(partId);
|
||||
if (part && part->bitmap(0))
|
||||
m_surface->drawRgbaSurface(part->bitmap(0), pt.x, pt.y);
|
||||
skin::SkinPartPtr part = (m_uiscale > 1 ? theme->getUnscaledPartById(partId):
|
||||
theme->getPartById(partId));
|
||||
if (part && part->bitmap(0)) {
|
||||
auto bmp = part->bitmap(0);
|
||||
m_surface->drawRgbaSurface(bmp, pt.x, pt.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsContext::drawThemeRect(const std::string& partId, const gfx::Rect& rc)
|
||||
{
|
||||
if (auto theme = skin::SkinTheme::instance()) {
|
||||
skin::SkinPartPtr part = theme->getPartById(partId);
|
||||
skin::SkinPartPtr part = (m_uiscale > 1 ? theme->getUnscaledPartById(partId):
|
||||
theme->getPartById(partId));
|
||||
if (part && part->bitmap(0)) {
|
||||
ui::Graphics g(nullptr, m_surface, 0, 0);
|
||||
|
||||
@ -101,16 +105,20 @@ void GraphicsContext::drawThemeRect(const std::string& partId, const gfx::Rect&
|
||||
|
||||
// 9-slices
|
||||
if (!part->slicesBounds().isEmpty()) {
|
||||
theme->drawRect(&g, rc, part.get(), true);
|
||||
if (m_uiscale > 1)
|
||||
theme->drawRectUsingUnscaledSheet(&g, rc, part.get(), true);
|
||||
else
|
||||
theme->drawRect(&g, rc, part.get(), true);
|
||||
}
|
||||
else {
|
||||
ui::IntersectClip clip(&g, rc);
|
||||
if (clip) {
|
||||
auto bmp = part->bitmap(0);
|
||||
// Horizontal line
|
||||
if (rc.w > part->spriteBounds().w) {
|
||||
for (int x=rc.x; x<rc.x2(); x+=part->spriteBounds().w) {
|
||||
g.drawRgbaSurface(
|
||||
part->bitmap(0),
|
||||
bmp,
|
||||
x, rc.y+rc.h/2-part->spriteBounds().h/2);
|
||||
}
|
||||
}
|
||||
@ -118,7 +126,7 @@ void GraphicsContext::drawThemeRect(const std::string& partId, const gfx::Rect&
|
||||
else {
|
||||
for (int y=rc.y; y<rc.y2(); y+=part->spriteBounds().h) {
|
||||
g.drawRgbaSurface(
|
||||
part->bitmap(0),
|
||||
bmp,
|
||||
rc.x+rc.w/2-part->spriteBounds().w/2, y);
|
||||
}
|
||||
}
|
||||
@ -236,6 +244,13 @@ int GraphicsContext_drawImage(lua_State* L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GraphicsContext_theme(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
push_app_theme(L, gc->uiscale());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GraphicsContext_drawThemeImage(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
@ -466,6 +481,7 @@ const luaL_Reg GraphicsContext_methods[] = {
|
||||
const Property GraphicsContext_properties[] = {
|
||||
{ "width", GraphicsContext_get_width, nullptr },
|
||||
{ "height", GraphicsContext_get_height, nullptr },
|
||||
{ "theme", GraphicsContext_theme, nullptr },
|
||||
{ "antialias", GraphicsContext_get_antialias, GraphicsContext_set_antialias },
|
||||
{ "color", GraphicsContext_get_color, GraphicsContext_set_color },
|
||||
{ "strokeWidth", GraphicsContext_get_strokeWidth, GraphicsContext_set_strokeWidth },
|
||||
|
@ -26,12 +26,13 @@ namespace script {
|
||||
|
||||
class GraphicsContext {
|
||||
public:
|
||||
GraphicsContext(const os::SurfaceRef& surface) : m_surface(surface) { }
|
||||
GraphicsContext(const os::SurfaceRef& surface, int uiscale) : m_surface(surface), m_uiscale(uiscale) { }
|
||||
GraphicsContext(GraphicsContext&& gc) {
|
||||
std::swap(m_surface, gc.m_surface);
|
||||
std::swap(m_paint, gc.m_paint);
|
||||
std::swap(m_font, gc.m_font);
|
||||
std::swap(m_path, gc.m_path);
|
||||
m_uiscale = gc.m_uiscale;
|
||||
}
|
||||
|
||||
os::FontRef font() const { return m_font; }
|
||||
@ -118,8 +119,14 @@ public:
|
||||
m_surface->clipPath(m_path);
|
||||
}
|
||||
|
||||
int uiscale() const {
|
||||
return m_uiscale;
|
||||
}
|
||||
|
||||
private:
|
||||
os::SurfaceRef m_surface = nullptr;
|
||||
// Keeps the UI Scale currently in use when canvas autoScaling is enabled.
|
||||
int m_uiscale;
|
||||
os::Paint m_paint;
|
||||
os::FontRef m_font;
|
||||
gfx::Path m_path;
|
||||
|
@ -28,13 +28,13 @@ FontData::FontData(os::FontType type)
|
||||
{
|
||||
}
|
||||
|
||||
os::FontRef FontData::getFont(int size)
|
||||
os::FontRef FontData::getFont(int size, int uiscale)
|
||||
{
|
||||
if (m_type == os::FontType::SpriteSheet)
|
||||
if (m_type == os::FontType::SpriteSheet)
|
||||
size = 1; // Same size always
|
||||
|
||||
// Use cache
|
||||
size *= ui::guiscale();
|
||||
size *= uiscale;
|
||||
auto it = m_fonts.find(size);
|
||||
if (it != m_fonts.end())
|
||||
return it->second;
|
||||
@ -66,5 +66,10 @@ os::FontRef FontData::getFont(int size)
|
||||
return font;
|
||||
}
|
||||
|
||||
os::FontRef FontData::getFont(int size)
|
||||
{
|
||||
return getFont(size, ui::guiscale());
|
||||
}
|
||||
|
||||
} // namespace skin
|
||||
} // namespace app
|
||||
|
@ -28,6 +28,7 @@ namespace skin {
|
||||
m_fallbackSize = fallbackSize;
|
||||
}
|
||||
|
||||
os::FontRef getFont(int size, int uiscale);
|
||||
os::FontRef getFont(int size);
|
||||
|
||||
private:
|
||||
|
@ -288,6 +288,7 @@ SkinTheme::~SkinTheme()
|
||||
for (auto& it : m_cursors)
|
||||
delete it.second; // Delete cursor
|
||||
|
||||
m_unscaledSheet.reset();
|
||||
m_sheet.reset();
|
||||
m_parts_by_id.clear();
|
||||
|
||||
@ -337,12 +338,12 @@ void SkinTheme::loadFontData()
|
||||
{
|
||||
LOG("THEME: Loading fonts\n");
|
||||
|
||||
std::string fonstFilename("fonts/fonts.xml");
|
||||
std::string fontsFilename("fonts/fonts.xml");
|
||||
|
||||
ResourceFinder rf;
|
||||
rf.includeDataDir(fonstFilename.c_str());
|
||||
rf.includeDataDir(fontsFilename.c_str());
|
||||
if (!rf.findFirst())
|
||||
throw base::Exception("File %s not found", fonstFilename.c_str());
|
||||
throw base::Exception("File %s not found", fontsFilename.c_str());
|
||||
|
||||
XmlDocumentRef doc = open_xml(rf.filename());
|
||||
TiXmlHandle handle(doc.get());
|
||||
@ -387,6 +388,12 @@ void SkinTheme::loadSheet()
|
||||
if (!newSheet)
|
||||
throw base::Exception("Error loading %s file", sheet_filename.c_str());
|
||||
|
||||
// TODO Change os::Surface::applyScale() to return a new surface,
|
||||
// avoid loading two times the same file (even more, if there
|
||||
// is no scale to apply, m_unscaledSheet must reference the
|
||||
// same m_sheet).
|
||||
m_unscaledSheet = os::instance()->loadRgbaSurface(sheet_filename.c_str());
|
||||
|
||||
// Replace the sprite sheet
|
||||
if (m_sheet)
|
||||
m_sheet.reset();
|
||||
@ -456,6 +463,10 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
|
||||
os::FontRef font = fontData->getFont(size);
|
||||
m_themeFonts[idStr] = ThemeFont(font, mnemonics);
|
||||
|
||||
// Store a unscaled version for using when ui scaling is not desired (i.e. in a Canvas widget with
|
||||
// autoScaling enabled).
|
||||
m_unscaledFonts[font.get()] = fontData->getFont(size, 1);
|
||||
|
||||
if (id == "default")
|
||||
m_defaultFont = font;
|
||||
else if (id == "mini")
|
||||
@ -530,9 +541,15 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
|
||||
if (!part)
|
||||
part = m_parts_by_id[part_id] = SkinPartPtr(new SkinPart);
|
||||
|
||||
SkinPartPtr unscaledPart = m_unscaledParts_by_id[part_id];
|
||||
if (!unscaledPart)
|
||||
unscaledPart = m_unscaledParts_by_id[part_id] = SkinPartPtr(new SkinPart);
|
||||
|
||||
if (w > 0 && h > 0) {
|
||||
part->setSpriteBounds(gfx::Rect(x, y, w, h));
|
||||
part->setBitmap(0, sliceSheet(part->bitmapRef(0), gfx::Rect(x, y, w, h)));
|
||||
unscaledPart->setSpriteBounds(part->spriteBounds()/scale);
|
||||
unscaledPart->setBitmap(0, sliceUnscaledSheet(unscaledPart->bitmapRef(0), unscaledPart->spriteBounds()));
|
||||
}
|
||||
else if (xmlPart->Attribute("w1")) { // 3x3-1 part (NW, N, NE, E, SE, S, SW, W)
|
||||
int w1 = scale*strtol(xmlPart->Attribute("w1"), nullptr, 10);
|
||||
@ -553,6 +570,18 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
|
||||
part->setBitmap(5, sliceSheet(part->bitmapRef(5), gfx::Rect(x+w1, y+h1+h2, w2, h3))); // S
|
||||
part->setBitmap(6, sliceSheet(part->bitmapRef(6), gfx::Rect(x, y+h1+h2, w1, h3))); // SW
|
||||
part->setBitmap(7, sliceSheet(part->bitmapRef(7), gfx::Rect(x, y+h1, w1, h2))); // W
|
||||
|
||||
unscaledPart->setSpriteBounds(part->spriteBounds()/scale);
|
||||
unscaledPart->setSlicesBounds(part->slicesBounds()/scale);
|
||||
|
||||
unscaledPart->setBitmap(0, sliceUnscaledSheet(unscaledPart->bitmapRef(0), gfx::Rect(x, y, w1, h1)/scale));
|
||||
unscaledPart->setBitmap(1, sliceUnscaledSheet(unscaledPart->bitmapRef(1), gfx::Rect(x+w1, y, w2, h1)/scale));
|
||||
unscaledPart->setBitmap(2, sliceUnscaledSheet(unscaledPart->bitmapRef(2), gfx::Rect(x+w1+w2, y, w3, h1)/scale));
|
||||
unscaledPart->setBitmap(3, sliceUnscaledSheet(unscaledPart->bitmapRef(3), gfx::Rect(x+w1+w2, y+h1, w3, h2)/scale));
|
||||
unscaledPart->setBitmap(4, sliceUnscaledSheet(unscaledPart->bitmapRef(4), gfx::Rect(x+w1+w2, y+h1+h2, w3, h3)/scale));
|
||||
unscaledPart->setBitmap(5, sliceUnscaledSheet(unscaledPart->bitmapRef(5), gfx::Rect(x+w1, y+h1+h2, w2, h3)/scale));
|
||||
unscaledPart->setBitmap(6, sliceUnscaledSheet(unscaledPart->bitmapRef(6), gfx::Rect(x, y+h1+h2, w1, h3)/scale));
|
||||
unscaledPart->setBitmap(7, sliceUnscaledSheet(unscaledPart->bitmapRef(7), gfx::Rect(x, y+h1, w1, h2)/scale));
|
||||
}
|
||||
|
||||
// Is it a mouse cursor?
|
||||
@ -847,7 +876,7 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
|
||||
ThemeFile<SkinTheme>::updateInternals();
|
||||
}
|
||||
|
||||
os::SurfaceRef SkinTheme::sliceSheet(os::SurfaceRef sur, const gfx::Rect& bounds)
|
||||
static os::SurfaceRef sliceSheet(os::SurfaceRef sheet, os::SurfaceRef sur, const gfx::Rect& bounds)
|
||||
{
|
||||
if (sur && (sur->width() != bounds.w ||
|
||||
sur->height() != bounds.h)) {
|
||||
@ -858,9 +887,9 @@ os::SurfaceRef SkinTheme::sliceSheet(os::SurfaceRef sur, const gfx::Rect& bounds
|
||||
if (!sur)
|
||||
sur = os::instance()->makeRgbaSurface(bounds.w, bounds.h);
|
||||
|
||||
os::SurfaceLock lockSrc(m_sheet.get());
|
||||
os::SurfaceLock lockSrc(sheet.get());
|
||||
os::SurfaceLock lockDst(sur.get());
|
||||
m_sheet->blitTo(sur.get(), bounds.x, bounds.y, 0, 0, bounds.w, bounds.h);
|
||||
sheet->blitTo(sur.get(), bounds.x, bounds.y, 0, 0, bounds.w, bounds.h);
|
||||
|
||||
// The new surface is immutable because we're going to re-use the
|
||||
// surface if we reload the theme.
|
||||
@ -875,6 +904,16 @@ os::SurfaceRef SkinTheme::sliceSheet(os::SurfaceRef sur, const gfx::Rect& bounds
|
||||
return sur;
|
||||
}
|
||||
|
||||
os::SurfaceRef SkinTheme::sliceSheet(os::SurfaceRef sur, const gfx::Rect& bounds)
|
||||
{
|
||||
return app::skin::sliceSheet(m_sheet, sur, bounds);
|
||||
}
|
||||
|
||||
os::SurfaceRef SkinTheme::sliceUnscaledSheet(os::SurfaceRef sur, const gfx::Rect& bounds)
|
||||
{
|
||||
return app::skin::sliceSheet(m_unscaledSheet, sur, bounds);
|
||||
}
|
||||
|
||||
os::Font* SkinTheme::getWidgetFont(const Widget* widget) const
|
||||
{
|
||||
auto skinPropery = std::static_pointer_cast<SkinProperty>(widget->getProperty(SkinProperty::Name));
|
||||
@ -1712,6 +1751,16 @@ void SkinTheme::drawRect(ui::Graphics* g, const gfx::Rect& rc,
|
||||
drawCenter);
|
||||
}
|
||||
|
||||
void SkinTheme::drawRectUsingUnscaledSheet(ui::Graphics* g, const gfx::Rect& rc,
|
||||
SkinPart* skinPart, const bool drawCenter)
|
||||
{
|
||||
Theme::drawSlices(g, m_unscaledSheet.get(), rc,
|
||||
skinPart->spriteBounds(),
|
||||
skinPart->slicesBounds(),
|
||||
gfx::ColorNone,
|
||||
drawCenter);
|
||||
}
|
||||
|
||||
void SkinTheme::drawRect2(Graphics* g, const Rect& rc, int x_mid,
|
||||
SkinPart* nw1, SkinPart* nw2)
|
||||
{
|
||||
|
@ -65,6 +65,13 @@ namespace app {
|
||||
os::Font* getDefaultFont() const override { return m_defaultFont.get(); }
|
||||
os::Font* getWidgetFont(const ui::Widget* widget) const override;
|
||||
os::Font* getMiniFont() const { return m_miniFont.get(); }
|
||||
os::Font* getUnscaledFont(os::Font* font) const {
|
||||
auto it = m_unscaledFonts.find(font);
|
||||
if (it != m_unscaledFonts.end())
|
||||
return it->second.get();
|
||||
else
|
||||
return font;
|
||||
}
|
||||
|
||||
ui::Cursor* getStandardCursor(ui::CursorType type) override;
|
||||
void initWidget(ui::Widget* widget) override;
|
||||
@ -90,6 +97,7 @@ namespace app {
|
||||
os::Surface* e, os::Surface* se, os::Surface* s,
|
||||
os::Surface* sw, os::Surface* w);
|
||||
void drawRect(ui::Graphics* g, const gfx::Rect& rc, SkinPart* skinPart, const bool drawCenter = true);
|
||||
void drawRectUsingUnscaledSheet(ui::Graphics* g, const gfx::Rect& rc, SkinPart* skinPart, const bool drawCenter = true);
|
||||
void drawRect2(ui::Graphics* g, const gfx::Rect& rc, int x_mid, SkinPart* nw1, SkinPart* nw2);
|
||||
void drawHline(ui::Graphics* g, const gfx::Rect& rc, SkinPart* skinPart);
|
||||
void drawVline(ui::Graphics* g, const gfx::Rect& rc, SkinPart* skinPart);
|
||||
@ -111,6 +119,14 @@ namespace app {
|
||||
return SkinPartPtr(nullptr);
|
||||
}
|
||||
|
||||
SkinPartPtr getUnscaledPartById(const std::string& id) const {
|
||||
auto it = m_unscaledParts_by_id.find(id);
|
||||
if (it != m_unscaledParts_by_id.end())
|
||||
return it->second;
|
||||
else
|
||||
return SkinPartPtr(nullptr);
|
||||
}
|
||||
|
||||
ui::Cursor* getCursorById(const std::string& id) const {
|
||||
auto it = m_cursors.find(id);
|
||||
if (it != m_cursors.end())
|
||||
@ -150,6 +166,7 @@ namespace app {
|
||||
void loadXml(BackwardCompatibility* backward);
|
||||
|
||||
os::SurfaceRef sliceSheet(os::SurfaceRef sur, const gfx::Rect& bounds);
|
||||
os::SurfaceRef sliceUnscaledSheet(os::SurfaceRef sur, const gfx::Rect& bounds);
|
||||
gfx::Color getWidgetBgColor(ui::Widget* widget);
|
||||
void drawText(ui::Graphics* g,
|
||||
const char* t,
|
||||
@ -165,7 +182,11 @@ namespace app {
|
||||
|
||||
std::string m_path;
|
||||
os::SurfaceRef m_sheet;
|
||||
// Contains the sheet surface as is, without any scale.
|
||||
os::SurfaceRef m_unscaledSheet;
|
||||
std::map<std::string, SkinPartPtr> m_parts_by_id;
|
||||
// Stores the same SkinParts as m_parts_by_id but unscaled, using the same keys.
|
||||
std::map<std::string, SkinPartPtr> m_unscaledParts_by_id;
|
||||
std::map<std::string, gfx::Color> m_colors_by_id;
|
||||
std::map<std::string, int> m_dimensions_by_id;
|
||||
std::map<std::string, ui::Cursor*> m_cursors;
|
||||
@ -173,6 +194,8 @@ namespace app {
|
||||
std::map<std::string, ui::Style*> m_styles;
|
||||
std::map<std::string, FontData*> m_fonts;
|
||||
std::map<std::string, ThemeFont> m_themeFonts;
|
||||
// Stores the unscaled font version of the Font pointer used as a key.
|
||||
std::map<os::Font*, os::FontRef> m_unscaledFonts;
|
||||
os::FontRef m_defaultFont;
|
||||
os::FontRef m_miniFont;
|
||||
int m_preferredScreenScaling;
|
||||
|
@ -188,6 +188,15 @@ namespace ui {
|
||||
m_magnification(magnification) {
|
||||
}
|
||||
|
||||
// Copy other TouchMessage converting its type
|
||||
TouchMessage(MessageType type,
|
||||
const TouchMessage& other,
|
||||
const gfx::Point& newPosition)
|
||||
: Message(type, other.modifiers()),
|
||||
m_pos(newPosition),
|
||||
m_magnification(other.magnification()) {
|
||||
}
|
||||
|
||||
const gfx::Point& position() const { return m_pos; }
|
||||
double magnification() const { return m_magnification; }
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user