2013-08-09 08:01:20 +08:00
|
|
|
// Aseprite UI Library
|
2019-04-12 09:54:47 +08:00
|
|
|
// Copyright (C) 2019 Igara Studio S.A.
|
2018-06-26 01:05:57 +08:00
|
|
|
// Copyright (C) 2001-2018 David Capello
|
2010-09-28 06:18:17 +08:00
|
|
|
//
|
2014-03-30 07:08:05 +08:00
|
|
|
// This file is released under the terms of the MIT license.
|
|
|
|
// Read LICENSE.txt for more information.
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2009-07-13 04:29:16 +08:00
|
|
|
#include "config.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#endif
|
2009-07-13 04:29:16 +08:00
|
|
|
|
2017-02-14 05:34:23 +08:00
|
|
|
#include "ui/theme.h"
|
|
|
|
|
2011-02-21 05:35:21 +08:00
|
|
|
#include "gfx/point.h"
|
|
|
|
#include "gfx/size.h"
|
2018-08-09 23:58:43 +08:00
|
|
|
#include "os/font.h"
|
|
|
|
#include "os/surface.h"
|
|
|
|
#include "os/system.h"
|
2012-06-18 09:49:58 +08:00
|
|
|
#include "ui/intern.h"
|
|
|
|
#include "ui/manager.h"
|
2017-02-14 05:34:23 +08:00
|
|
|
#include "ui/paint_event.h"
|
2017-08-15 21:39:06 +08:00
|
|
|
#include "ui/scale.h"
|
2017-02-14 05:34:23 +08:00
|
|
|
#include "ui/size_hint_event.h"
|
|
|
|
#include "ui/style.h"
|
2012-06-18 09:49:58 +08:00
|
|
|
#include "ui/system.h"
|
|
|
|
#include "ui/view.h"
|
|
|
|
#include "ui/widget.h"
|
2017-02-18 01:18:47 +08:00
|
|
|
#include "ui/window.h"
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2017-02-14 05:34:23 +08:00
|
|
|
#include <algorithm>
|
2015-03-05 08:35:11 +08:00
|
|
|
#include <cstring>
|
|
|
|
|
2012-06-18 09:02:54 +08:00
|
|
|
namespace ui {
|
|
|
|
|
2017-02-15 01:55:45 +08:00
|
|
|
namespace {
|
|
|
|
|
2017-08-15 21:39:06 +08:00
|
|
|
int current_ui_scale = 1; // Global UI Screen Scaling factor
|
|
|
|
int old_ui_scale = 1; // Add this field in InitThemeEvent
|
|
|
|
Theme* current_theme = nullptr; // Global active theme
|
2017-02-15 01:55:45 +08:00
|
|
|
|
|
|
|
int compare_layer_flags(int a, int b)
|
|
|
|
{
|
|
|
|
// TODO improve this
|
|
|
|
return a - b;
|
|
|
|
}
|
|
|
|
|
2017-03-14 00:47:37 +08:00
|
|
|
void for_each_layer(const int flags,
|
2017-02-15 01:55:45 +08:00
|
|
|
const Style* style,
|
|
|
|
std::function<void(const Style::Layer&)> callback)
|
|
|
|
{
|
2019-09-23 20:03:10 +08:00
|
|
|
ASSERT(style);
|
|
|
|
if (!style)
|
|
|
|
return;
|
|
|
|
|
2017-02-15 01:55:45 +08:00
|
|
|
const Style::Layer* bestLayer = nullptr;
|
|
|
|
|
|
|
|
for (const auto& layer : style->layers()) {
|
|
|
|
if (bestLayer &&
|
|
|
|
bestLayer->type() != layer.type()) {
|
|
|
|
callback(*bestLayer);
|
|
|
|
bestLayer = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((!layer.flags()
|
|
|
|
|| (layer.flags() & flags) == layer.flags())
|
|
|
|
&& (!bestLayer
|
|
|
|
|| (bestLayer && compare_layer_flags(bestLayer->flags(), layer.flags()) <= 0))) {
|
|
|
|
bestLayer = &layer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bestLayer)
|
|
|
|
callback(*bestLayer);
|
|
|
|
}
|
|
|
|
|
2017-03-14 00:47:37 +08:00
|
|
|
void for_each_layer(const Widget* widget,
|
|
|
|
const Style* style,
|
|
|
|
std::function<void(const Style::Layer&)> callback)
|
|
|
|
{
|
|
|
|
for_each_layer(
|
|
|
|
PaintWidgetPartInfo::getStyleFlagsForWidget(widget),
|
|
|
|
style,
|
|
|
|
callback);
|
|
|
|
}
|
|
|
|
|
2017-03-27 23:32:39 +08:00
|
|
|
std::function<void(int srcx, int srcy, int dstx, int dsty, int w, int h)>
|
2018-08-09 23:58:43 +08:00
|
|
|
getDrawSurfaceFunction(Graphics* g, os::Surface* sheet, gfx::Color color)
|
2017-03-27 23:32:39 +08:00
|
|
|
{
|
|
|
|
if (color != gfx::ColorNone)
|
|
|
|
return [g, sheet, color](int srcx, int srcy, int dstx, int dsty, int w, int h) {
|
|
|
|
g->drawColoredRgbaSurface(sheet, color, srcx, srcy, dstx, dsty, w, h);
|
|
|
|
};
|
|
|
|
else
|
|
|
|
return [g, sheet](int srcx, int srcy, int dstx, int dsty, int w, int h) {
|
|
|
|
g->drawRgbaSurface(sheet, srcx, srcy, dstx, dsty, w, h);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-02-15 01:55:45 +08:00
|
|
|
} // anonymous namespace
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2017-03-14 00:47:37 +08:00
|
|
|
PaintWidgetPartInfo::PaintWidgetPartInfo()
|
|
|
|
{
|
|
|
|
bgColor = gfx::ColorNone;
|
|
|
|
styleFlags = 0;
|
|
|
|
text = nullptr;
|
|
|
|
mnemonic = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
PaintWidgetPartInfo::PaintWidgetPartInfo(const Widget* widget)
|
|
|
|
{
|
|
|
|
bgColor = (!widget->isTransparent() ?
|
|
|
|
widget->bgColor():
|
|
|
|
gfx::ColorNone);
|
|
|
|
styleFlags = PaintWidgetPartInfo::getStyleFlagsForWidget(widget);
|
|
|
|
text = &widget->text();
|
|
|
|
mnemonic = widget->mnemonic();
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
int PaintWidgetPartInfo::getStyleFlagsForWidget(const Widget* widget)
|
|
|
|
{
|
|
|
|
return
|
|
|
|
(widget->isEnabled() ? 0: Style::Layer::kDisabled) |
|
|
|
|
(widget->isSelected() ? Style::Layer::kSelected: 0) |
|
|
|
|
(widget->hasMouse() ? Style::Layer::kMouse: 0) |
|
|
|
|
(widget->hasFocus() ? Style::Layer::kFocus: 0);
|
|
|
|
}
|
|
|
|
|
2011-01-22 04:50:04 +08:00
|
|
|
Theme::Theme()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-01-22 04:50:04 +08:00
|
|
|
Theme::~Theme()
|
|
|
|
{
|
|
|
|
if (current_theme == this)
|
2017-08-15 21:39:06 +08:00
|
|
|
set_theme(nullptr, guiscale());
|
2011-01-22 04:50:04 +08:00
|
|
|
}
|
|
|
|
|
2017-08-15 21:39:06 +08:00
|
|
|
void Theme::regenerateTheme()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2014-11-26 08:30:56 +08:00
|
|
|
set_mouse_cursor(kNoCursor);
|
2017-08-15 21:39:06 +08:00
|
|
|
onRegenerateTheme();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2017-02-18 01:18:47 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-14 00:47:37 +08:00
|
|
|
void Theme::paintWidgetPart(Graphics* g,
|
|
|
|
const Style* style,
|
|
|
|
const gfx::Rect& bounds,
|
|
|
|
const PaintWidgetPartInfo& info)
|
2017-02-14 05:34:23 +08:00
|
|
|
{
|
2017-02-15 01:55:45 +08:00
|
|
|
ASSERT(g);
|
|
|
|
ASSERT(style);
|
2017-02-14 05:34:23 +08:00
|
|
|
|
|
|
|
// External background
|
2017-03-14 00:47:37 +08:00
|
|
|
if (!gfx::is_transparent(info.bgColor))
|
|
|
|
g->fillRect(info.bgColor, bounds);
|
2017-02-14 05:34:23 +08:00
|
|
|
|
2017-02-18 01:18:47 +08:00
|
|
|
gfx::Rect rc = bounds;
|
2017-03-14 00:47:37 +08:00
|
|
|
gfx::Color outBgColor = gfx::ColorNone;
|
2017-02-15 01:55:45 +08:00
|
|
|
for_each_layer(
|
2017-03-14 00:47:37 +08:00
|
|
|
info.styleFlags, style,
|
2017-03-14 05:13:38 +08:00
|
|
|
[this, g, style, &info, &rc, &outBgColor]
|
|
|
|
(const Style::Layer& layer) {
|
|
|
|
paintLayer(g, style, layer,
|
2017-03-14 00:47:37 +08:00
|
|
|
(info.text ? *info.text: std::string()),
|
|
|
|
info.mnemonic, rc, outBgColor);
|
2017-02-15 01:55:45 +08:00
|
|
|
});
|
2017-02-14 05:34:23 +08:00
|
|
|
}
|
|
|
|
|
2017-03-14 00:47:37 +08:00
|
|
|
void Theme::paintWidget(Graphics* g,
|
|
|
|
const Widget* widget,
|
|
|
|
const Style* style,
|
|
|
|
const gfx::Rect& bounds)
|
|
|
|
{
|
|
|
|
ASSERT(widget);
|
|
|
|
|
|
|
|
PaintWidgetPartInfo info(widget);
|
|
|
|
paintWidgetPart(g, style, bounds, info);
|
|
|
|
}
|
|
|
|
|
2017-03-11 09:42:15 +08:00
|
|
|
void Theme::paintScrollBar(Graphics* g,
|
|
|
|
const Widget* widget,
|
|
|
|
const Style* style,
|
|
|
|
const Style* thumbStyle,
|
|
|
|
const gfx::Rect& bounds,
|
|
|
|
const gfx::Rect& thumbBounds)
|
|
|
|
{
|
2017-03-14 00:47:37 +08:00
|
|
|
PaintWidgetPartInfo info(widget);
|
|
|
|
paintWidgetPart(g, style, bounds, info);
|
|
|
|
|
|
|
|
// TODO flags for the thumb could have "mouse" only
|
|
|
|
// when the mouse is inside the thumb
|
|
|
|
|
|
|
|
info.bgColor = gfx::ColorNone;
|
|
|
|
paintWidgetPart(g, thumbStyle, thumbBounds, info);
|
2017-03-11 09:42:15 +08:00
|
|
|
}
|
|
|
|
|
2017-02-18 01:18:47 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-15 22:35:11 +08:00
|
|
|
void Theme::paintLayer(Graphics* g,
|
2017-03-14 05:13:38 +08:00
|
|
|
const Style* style,
|
2017-02-14 05:34:23 +08:00
|
|
|
const Style::Layer& layer,
|
2017-03-14 00:47:37 +08:00
|
|
|
const std::string& text,
|
|
|
|
const int mnemonic,
|
2017-02-18 05:00:10 +08:00
|
|
|
gfx::Rect& rc,
|
|
|
|
gfx::Color& bgColor)
|
2017-02-14 05:34:23 +08:00
|
|
|
{
|
2019-09-23 20:03:10 +08:00
|
|
|
ASSERT(style);
|
|
|
|
if (!style)
|
|
|
|
return;
|
|
|
|
|
2017-02-14 05:34:23 +08:00
|
|
|
switch (layer.type()) {
|
|
|
|
|
|
|
|
case Style::Layer::Type::kBackground:
|
2017-03-18 02:43:42 +08:00
|
|
|
case Style::Layer::Type::kBackgroundBorder:
|
2017-02-14 05:34:23 +08:00
|
|
|
if (layer.spriteSheet() &&
|
2017-02-18 01:18:47 +08:00
|
|
|
!layer.spriteBounds().isEmpty()) {
|
|
|
|
if (!layer.slicesBounds().isEmpty()) {
|
|
|
|
Theme::drawSlices(g, layer.spriteSheet(), rc,
|
|
|
|
layer.spriteBounds(),
|
2017-03-27 23:32:39 +08:00
|
|
|
layer.slicesBounds(),
|
|
|
|
layer.color(), true);
|
2017-02-18 01:18:47 +08:00
|
|
|
|
2017-03-18 02:43:42 +08:00
|
|
|
if (layer.type() == Style::Layer::Type::kBackgroundBorder) {
|
|
|
|
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;
|
|
|
|
}
|
2017-02-18 01:18:47 +08:00
|
|
|
}
|
2017-02-18 05:00:10 +08:00
|
|
|
// Draw background using different methods
|
2017-02-18 01:18:47 +08:00
|
|
|
else {
|
2017-02-18 05:00:10 +08:00
|
|
|
IntersectClip clip(g, rc);
|
|
|
|
if (clip) {
|
2017-03-27 23:32:39 +08:00
|
|
|
auto draw = getDrawSurfaceFunction(
|
|
|
|
g, layer.spriteSheet(), layer.color());
|
|
|
|
|
2017-02-18 05:00:10 +08:00
|
|
|
switch (layer.align()) {
|
|
|
|
|
|
|
|
// Horizontal line
|
|
|
|
case MIDDLE:
|
|
|
|
for (int x=rc.x; x<rc.x2(); x+=layer.spriteBounds().w) {
|
2017-03-27 23:32:39 +08:00
|
|
|
draw(layer.spriteBounds().x,
|
|
|
|
layer.spriteBounds().y,
|
|
|
|
x, rc.y+rc.h/2-layer.spriteBounds().h/2,
|
|
|
|
layer.spriteBounds().w,
|
|
|
|
layer.spriteBounds().h);
|
2017-02-18 05:00:10 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Vertical line
|
|
|
|
case CENTER:
|
|
|
|
for (int y=rc.y; y<rc.y2(); y+=layer.spriteBounds().h) {
|
2017-03-27 23:32:39 +08:00
|
|
|
draw(layer.spriteBounds().x,
|
|
|
|
layer.spriteBounds().y,
|
|
|
|
rc.x+rc.w/2-layer.spriteBounds().w/2, y,
|
|
|
|
layer.spriteBounds().w,
|
|
|
|
layer.spriteBounds().h);
|
2017-02-18 05:00:10 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
// One instance
|
|
|
|
case CENTER | MIDDLE:
|
2017-03-27 23:32:39 +08:00
|
|
|
draw(layer.spriteBounds().x,
|
|
|
|
layer.spriteBounds().y,
|
|
|
|
rc.x+rc.w/2-layer.spriteBounds().w/2,
|
|
|
|
rc.y+rc.h/2-layer.spriteBounds().h/2,
|
|
|
|
layer.spriteBounds().w,
|
|
|
|
layer.spriteBounds().h);
|
2017-02-18 05:00:10 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
// Pattern
|
|
|
|
case 0:
|
|
|
|
for (int y=rc.y; y<rc.y2(); y+=layer.spriteBounds().h) {
|
|
|
|
for (int x=rc.x; x<rc.x2(); x+=layer.spriteBounds().w)
|
2017-03-27 23:32:39 +08:00
|
|
|
draw(layer.spriteBounds().x,
|
|
|
|
layer.spriteBounds().y,
|
|
|
|
x, y,
|
|
|
|
layer.spriteBounds().w,
|
|
|
|
layer.spriteBounds().h);
|
2017-02-18 05:00:10 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-02-18 01:18:47 +08:00
|
|
|
}
|
2017-02-14 05:34:23 +08:00
|
|
|
}
|
2017-03-27 23:32:39 +08:00
|
|
|
else if (layer.color() != gfx::ColorNone) {
|
|
|
|
bgColor = layer.color();
|
|
|
|
g->fillRect(layer.color(), rc);
|
|
|
|
}
|
2017-02-14 05:34:23 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Style::Layer::Type::kBorder:
|
|
|
|
if (layer.spriteSheet() &&
|
|
|
|
!layer.spriteBounds().isEmpty() &&
|
|
|
|
!layer.slicesBounds().isEmpty()) {
|
|
|
|
Theme::drawSlices(g, layer.spriteSheet(), rc,
|
|
|
|
layer.spriteBounds(),
|
2017-03-27 23:32:39 +08:00
|
|
|
layer.slicesBounds(),
|
|
|
|
layer.color(), false);
|
2017-02-14 05:34:23 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2017-03-27 23:32:39 +08:00
|
|
|
else if (layer.color() != gfx::ColorNone) {
|
|
|
|
g->drawRect(layer.color(), rc);
|
|
|
|
}
|
2017-02-14 05:34:23 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Style::Layer::Type::kText:
|
|
|
|
if (layer.color() != gfx::ColorNone) {
|
2018-08-09 23:58:43 +08:00
|
|
|
os::Font* oldFont = g->font();
|
2017-03-14 05:13:38 +08:00
|
|
|
if (style->font())
|
|
|
|
g->setFont(style->font());
|
|
|
|
|
2017-03-11 06:23:43 +08:00
|
|
|
if (layer.align() & WORDWRAP) {
|
|
|
|
gfx::Rect textBounds = rc;
|
|
|
|
textBounds.offset(layer.offset());
|
|
|
|
|
2017-03-14 00:47:37 +08:00
|
|
|
g->drawAlignedUIText(text,
|
2017-03-11 06:23:43 +08:00
|
|
|
layer.color(),
|
|
|
|
bgColor,
|
|
|
|
textBounds, layer.align());
|
|
|
|
}
|
|
|
|
else {
|
2017-03-14 00:47:37 +08:00
|
|
|
gfx::Size textSize = g->measureUIText(text);
|
2017-03-11 06:23:43 +08:00
|
|
|
gfx::Point pt;
|
|
|
|
|
|
|
|
if (layer.align() & LEFT)
|
|
|
|
pt.x = rc.x;
|
|
|
|
else if (layer.align() & RIGHT)
|
|
|
|
pt.x = rc.x+rc.w-textSize.w;
|
|
|
|
else
|
|
|
|
pt.x = rc.x+rc.w/2-textSize.w/2;
|
|
|
|
|
|
|
|
if (layer.align() & TOP)
|
|
|
|
pt.y = rc.y;
|
|
|
|
else if (layer.align() & BOTTOM)
|
|
|
|
pt.y = rc.y+rc.h-textSize.h;
|
|
|
|
else
|
|
|
|
pt.y = rc.y+rc.h/2-textSize.h/2;
|
|
|
|
|
|
|
|
pt += layer.offset();
|
|
|
|
|
2017-03-14 00:47:37 +08:00
|
|
|
g->drawUIText(text,
|
2017-03-11 06:23:43 +08:00
|
|
|
layer.color(),
|
|
|
|
bgColor,
|
2017-03-14 00:47:37 +08:00
|
|
|
pt, mnemonic);
|
2017-03-11 06:23:43 +08:00
|
|
|
}
|
2017-03-14 05:13:38 +08:00
|
|
|
|
|
|
|
if (style->font())
|
|
|
|
g->setFont(oldFont);
|
2017-02-14 05:34:23 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Style::Layer::Type::kIcon: {
|
2018-08-09 23:58:43 +08:00
|
|
|
os::Surface* icon = layer.icon();
|
2017-02-14 05:34:23 +08:00
|
|
|
if (icon) {
|
2017-02-15 01:55:45 +08:00
|
|
|
gfx::Size iconSize(icon->width(), icon->height());
|
|
|
|
gfx::Point pt;
|
|
|
|
|
2017-03-14 00:47:37 +08:00
|
|
|
if (layer.align() & LEFT)
|
2017-02-15 01:55:45 +08:00
|
|
|
pt.x = rc.x;
|
|
|
|
else if (layer.align() & RIGHT)
|
|
|
|
pt.x = rc.x+rc.w-iconSize.w;
|
|
|
|
else
|
|
|
|
pt.x = rc.x+rc.w/2-iconSize.w/2;
|
|
|
|
|
|
|
|
if (layer.align() & TOP)
|
|
|
|
pt.y = rc.y;
|
|
|
|
else if (layer.align() & BOTTOM)
|
|
|
|
pt.y = rc.y+rc.h-iconSize.h;
|
|
|
|
else
|
|
|
|
pt.y = rc.y+rc.h/2-iconSize.h/2;
|
|
|
|
|
2017-03-14 00:47:37 +08:00
|
|
|
pt += layer.offset();
|
|
|
|
|
2017-02-15 01:55:45 +08:00
|
|
|
if (layer.color() != gfx::ColorNone)
|
|
|
|
g->drawColoredRgbaSurface(icon, layer.color(), pt.x, pt.y);
|
|
|
|
else
|
|
|
|
g->drawRgbaSurface(icon, pt.x, pt.y);
|
2017-02-14 05:34:23 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-15 22:35:11 +08:00
|
|
|
gfx::Size Theme::calcSizeHint(const Widget* widget,
|
|
|
|
const Style* style)
|
2017-02-14 05:34:23 +08:00
|
|
|
{
|
2017-02-15 01:55:45 +08:00
|
|
|
gfx::Size sizeHint;
|
|
|
|
gfx::Border borderHint;
|
|
|
|
calcWidgetMetrics(widget, style, sizeHint, borderHint);
|
|
|
|
return sizeHint;
|
2017-02-14 05:34:23 +08:00
|
|
|
}
|
|
|
|
|
2017-02-15 22:35:11 +08:00
|
|
|
void Theme::measureLayer(const Widget* widget,
|
2017-03-14 05:13:38 +08:00
|
|
|
const Style* style,
|
2017-02-14 05:34:23 +08:00
|
|
|
const Style::Layer& layer,
|
2017-02-15 01:55:45 +08:00
|
|
|
gfx::Border& borderHint,
|
|
|
|
gfx::Size& textHint, int& textAlign,
|
|
|
|
gfx::Size& iconHint, int& iconAlign)
|
2017-02-14 05:34:23 +08:00
|
|
|
{
|
2019-09-23 20:03:10 +08:00
|
|
|
ASSERT(style);
|
|
|
|
if (!style)
|
|
|
|
return;
|
|
|
|
|
2017-02-14 05:34:23 +08:00
|
|
|
switch (layer.type()) {
|
|
|
|
|
|
|
|
case Style::Layer::Type::kBackground:
|
2017-03-18 02:43:42 +08:00
|
|
|
case Style::Layer::Type::kBackgroundBorder:
|
2017-02-14 05:34:23 +08:00
|
|
|
case Style::Layer::Type::kBorder:
|
|
|
|
if (layer.spriteSheet() &&
|
2017-02-18 01:18:47 +08:00
|
|
|
!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);
|
|
|
|
}
|
2017-02-14 05:34:23 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Style::Layer::Type::kText:
|
|
|
|
if (layer.color() != gfx::ColorNone) {
|
2018-08-09 23:58:43 +08:00
|
|
|
os::Font* font = (style->font() ? style->font(): widget->font());
|
2017-03-14 05:13:38 +08:00
|
|
|
gfx::Size textSize(Graphics::measureUITextLength(widget->text(), font),
|
|
|
|
font->height());
|
2017-03-18 02:43:42 +08:00
|
|
|
|
|
|
|
textHint.w = std::max(textHint.w, textSize.w+ABS(layer.offset().x));
|
|
|
|
textHint.h = std::max(textHint.h, textSize.h+ABS(layer.offset().y));
|
2017-02-15 01:55:45 +08:00
|
|
|
textAlign = layer.align();
|
2017-02-14 05:34:23 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Style::Layer::Type::kIcon: {
|
2018-08-09 23:58:43 +08:00
|
|
|
os::Surface* icon = layer.icon();
|
2017-02-14 05:34:23 +08:00
|
|
|
if (icon) {
|
2017-03-18 02:43:42 +08:00
|
|
|
iconHint.w = std::max(iconHint.w, icon->width()+ABS(layer.offset().x));
|
|
|
|
iconHint.h = std::max(iconHint.h, icon->height()+ABS(layer.offset().y));
|
2017-02-15 01:55:45 +08:00
|
|
|
iconAlign = layer.align();
|
2017-02-14 05:34:23 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-15 22:35:11 +08:00
|
|
|
gfx::Border Theme::calcBorder(const Widget* widget,
|
|
|
|
const Style* style)
|
2017-02-14 05:34:23 +08:00
|
|
|
{
|
2017-02-15 01:55:45 +08:00
|
|
|
gfx::Size sizeHint;
|
|
|
|
gfx::Border borderHint;
|
|
|
|
calcWidgetMetrics(widget, style, sizeHint, borderHint);
|
|
|
|
return borderHint;
|
|
|
|
}
|
|
|
|
|
2017-02-18 01:18:47 +08:00
|
|
|
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();
|
2019-12-21 02:08:34 +08:00
|
|
|
topLeft.w = std::max(topLeft.w, slices.x);
|
|
|
|
topLeft.h = std::max(topLeft.h, slices.y);
|
|
|
|
center.w = std::max(center.w, slices.w);
|
|
|
|
center.h = std::max(center.h, slices.h);
|
|
|
|
bottomRight.w = std::max(bottomRight.w, sprite.w - slices.x2());
|
|
|
|
bottomRight.h = std::max(bottomRight.h, sprite.h - slices.y2());
|
2017-02-18 01:18:47 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2017-03-18 02:43:42 +08:00
|
|
|
if (layer.type() == Style::Layer::Type::kBackground ||
|
|
|
|
layer.type() == Style::Layer::Type::kBackgroundBorder)
|
2017-02-18 01:18:47 +08:00
|
|
|
bgColor = layer.color();
|
|
|
|
});
|
|
|
|
|
|
|
|
return bgColor;
|
|
|
|
}
|
|
|
|
|
2017-02-15 22:35:11 +08:00
|
|
|
void Theme::calcWidgetMetrics(const Widget* widget,
|
2017-02-15 01:55:45 +08:00
|
|
|
const Style* style,
|
|
|
|
gfx::Size& sizeHint,
|
|
|
|
gfx::Border& borderHint)
|
|
|
|
{
|
|
|
|
ASSERT(widget);
|
|
|
|
ASSERT(style);
|
2019-09-23 20:03:10 +08:00
|
|
|
if (!style)
|
|
|
|
return;
|
2017-02-15 01:55:45 +08:00
|
|
|
|
|
|
|
borderHint = gfx::Border(0, 0, 0, 0);
|
|
|
|
gfx::Border paddingHint(0, 0, 0, 0);
|
|
|
|
gfx::Size textHint(0, 0);
|
|
|
|
gfx::Size iconHint(0, 0);
|
|
|
|
int textAlign = CENTER | MIDDLE;
|
|
|
|
int iconAlign = CENTER | MIDDLE;
|
|
|
|
|
|
|
|
for_each_layer(
|
|
|
|
widget, style,
|
2017-03-18 02:43:42 +08:00
|
|
|
[this, widget, style, &borderHint,
|
|
|
|
&textHint, &textAlign, &iconHint, &iconAlign]
|
2017-02-15 01:55:45 +08:00
|
|
|
(const Style::Layer& layer) {
|
2017-03-14 05:13:38 +08:00
|
|
|
measureLayer(widget, style, layer,
|
2017-02-15 01:55:45 +08:00
|
|
|
borderHint,
|
|
|
|
textHint, textAlign,
|
|
|
|
iconHint, iconAlign);
|
|
|
|
});
|
|
|
|
|
2017-02-18 01:18:47 +08:00
|
|
|
gfx::Border undef = Style::UndefinedBorder();
|
|
|
|
|
|
|
|
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());
|
2017-02-15 01:55:45 +08:00
|
|
|
|
2017-02-18 01:18:47 +08:00
|
|
|
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());
|
2017-02-15 01:55:45 +08:00
|
|
|
|
|
|
|
sizeHint = gfx::Size(borderHint.width() + paddingHint.width(),
|
|
|
|
borderHint.height() + paddingHint.height());
|
|
|
|
|
|
|
|
if ((textAlign & (LEFT | CENTER | RIGHT)) == (iconAlign & (LEFT | CENTER | RIGHT)))
|
|
|
|
sizeHint.w += std::max(textHint.w, iconHint.w);
|
|
|
|
else
|
|
|
|
sizeHint.w += textHint.w + iconHint.w;
|
|
|
|
|
|
|
|
if ((textAlign & (TOP | MIDDLE | BOTTOM)) == (iconAlign & (TOP | MIDDLE | BOTTOM)))
|
|
|
|
sizeHint.h += std::max(textHint.h, iconHint.h);
|
|
|
|
else
|
|
|
|
sizeHint.h += textHint.h + iconHint.h;
|
2017-02-14 05:34:23 +08:00
|
|
|
}
|
|
|
|
|
2011-01-22 04:50:04 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2017-08-15 21:39:06 +08:00
|
|
|
void set_theme(Theme* theme, const int uiscale)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2017-08-15 21:39:06 +08:00
|
|
|
old_ui_scale = current_ui_scale;
|
|
|
|
current_ui_scale = uiscale;
|
|
|
|
|
2016-10-27 21:44:31 +08:00
|
|
|
if (theme) {
|
2017-08-15 21:39:06 +08:00
|
|
|
theme->regenerateTheme();
|
2016-10-27 21:44:31 +08:00
|
|
|
|
|
|
|
current_theme = theme;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2017-08-15 21:39:06 +08:00
|
|
|
// Set the theme for all widgets
|
|
|
|
details::reinitThemeForAllWidgets();
|
|
|
|
|
|
|
|
// Reinitialize all widget using the new theme/uiscale
|
2012-06-18 09:02:54 +08:00
|
|
|
Manager* manager = Manager::getDefault();
|
2017-08-15 21:39:06 +08:00
|
|
|
if (manager)
|
|
|
|
manager->initTheme();
|
|
|
|
|
|
|
|
manager->invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2017-08-15 21:39:06 +08:00
|
|
|
|
|
|
|
old_ui_scale = current_ui_scale;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2016-12-12 20:48:58 +08:00
|
|
|
Theme* get_theme()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2011-01-22 04:50:04 +08:00
|
|
|
return current_theme;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2017-08-15 21:39:06 +08:00
|
|
|
int guiscale()
|
|
|
|
{
|
|
|
|
return current_ui_scale;
|
|
|
|
}
|
|
|
|
|
|
|
|
int details::old_guiscale()
|
|
|
|
{
|
|
|
|
return old_ui_scale;
|
|
|
|
}
|
|
|
|
|
2016-12-15 21:50:47 +08:00
|
|
|
// static
|
2018-08-09 23:58:43 +08:00
|
|
|
void Theme::drawSlices(Graphics* g, os::Surface* sheet,
|
2017-02-10 03:51:52 +08:00
|
|
|
const gfx::Rect& rc,
|
|
|
|
const gfx::Rect& sprite,
|
|
|
|
const gfx::Rect& slices,
|
2017-03-27 23:32:39 +08:00
|
|
|
const gfx::Color color,
|
2017-02-10 03:51:52 +08:00
|
|
|
const bool drawCenter)
|
|
|
|
{
|
2019-04-12 09:54:47 +08:00
|
|
|
Paint paint;
|
|
|
|
paint.color(color);
|
|
|
|
if (!drawCenter)
|
|
|
|
paint.setFlags(Paint::kNineWithoutCenter);
|
|
|
|
g->drawSurfaceNine(sheet, sprite, slices, rc, &paint);
|
2017-02-10 03:51:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
2016-12-15 21:50:47 +08:00
|
|
|
void Theme::drawTextBox(Graphics* g, Widget* widget,
|
|
|
|
int* w, int* h, gfx::Color bg, gfx::Color fg)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2011-02-21 05:35:21 +08:00
|
|
|
View* view = View::getView(widget);
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
char* text = const_cast<char*>(widget->text().c_str());
|
2013-10-15 06:58:11 +08:00
|
|
|
char* beg, *end;
|
2016-12-07 08:29:14 +08:00
|
|
|
int x1, y1;
|
2007-09-19 07:57:02 +08:00
|
|
|
int x, y, chr, len;
|
2011-02-21 05:35:21 +08:00
|
|
|
gfx::Point scroll;
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
int textheight = widget->textHeight();
|
2018-08-09 23:58:43 +08:00
|
|
|
os::Font* font = widget->font();
|
2007-09-19 07:57:02 +08:00
|
|
|
char *beg_end, *old_end;
|
|
|
|
int width;
|
2016-11-22 23:47:46 +08:00
|
|
|
gfx::Rect vp;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
|
|
|
if (view) {
|
2016-11-22 23:47:46 +08:00
|
|
|
vp = view->viewportBounds().offset(-widget->bounds().origin());
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
scroll = view->viewScroll();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
else {
|
2016-11-22 23:47:46 +08:00
|
|
|
vp = widget->clientBounds();
|
2011-02-21 05:35:21 +08:00
|
|
|
scroll.x = scroll.y = 0;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2016-12-07 08:29:14 +08:00
|
|
|
x1 = widget->clientBounds().x + widget->border().left();
|
|
|
|
y1 = widget->clientBounds().y + widget->border().top();
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2016-11-23 00:33:01 +08:00
|
|
|
// Fill background
|
|
|
|
if (g)
|
|
|
|
g->fillRect(bg, vp);
|
|
|
|
|
2007-09-19 07:57:02 +08:00
|
|
|
chr = 0;
|
|
|
|
|
2014-04-20 02:18:16 +08:00
|
|
|
// Without word-wrap
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
if (!(widget->align() & WORDWRAP)) {
|
2016-12-07 08:29:14 +08:00
|
|
|
width = widget->clientChildrenBounds().w;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2014-04-20 02:18:16 +08:00
|
|
|
// With word-wrap
|
2007-09-19 07:57:02 +08:00
|
|
|
else {
|
|
|
|
if (w) {
|
|
|
|
width = *w;
|
|
|
|
*w = 0;
|
|
|
|
}
|
|
|
|
else {
|
2016-11-22 23:47:46 +08:00
|
|
|
// TODO modificable option? I don't think so, this is very internal stuff
|
2007-09-19 07:57:02 +08:00
|
|
|
#if 0
|
2016-11-22 23:47:46 +08:00
|
|
|
// Shows more information in x-scroll 0
|
|
|
|
width = vp.w;
|
2007-09-19 07:57:02 +08:00
|
|
|
#else
|
2016-11-22 23:47:46 +08:00
|
|
|
// Make good use of the complete text-box
|
2007-09-19 07:57:02 +08:00
|
|
|
if (view) {
|
2012-01-06 06:45:03 +08:00
|
|
|
gfx::Size maxSize = view->getScrollableSize();
|
2019-12-21 02:08:34 +08:00
|
|
|
width = std::max(vp.w, maxSize.w);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
else {
|
2016-11-22 23:47:46 +08:00
|
|
|
width = vp.w;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2016-12-07 08:29:14 +08:00
|
|
|
width -= widget->border().width();
|
2007-09-19 07:57:02 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-20 02:18:16 +08:00
|
|
|
// Draw line-by-line
|
2016-11-22 23:47:46 +08:00
|
|
|
y = y1;
|
2007-09-19 07:57:02 +08:00
|
|
|
for (beg=end=text; end; ) {
|
2016-11-22 23:47:46 +08:00
|
|
|
x = x1;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-10-15 06:58:11 +08:00
|
|
|
// Without word-wrap
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
if (!(widget->align() & WORDWRAP)) {
|
2015-03-05 08:35:11 +08:00
|
|
|
end = std::strchr(beg, '\n');
|
2007-09-19 07:57:02 +08:00
|
|
|
if (end) {
|
2012-01-06 06:45:03 +08:00
|
|
|
chr = *end;
|
|
|
|
*end = 0;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
// With word-wrap
|
2007-09-19 07:57:02 +08:00
|
|
|
else {
|
|
|
|
old_end = NULL;
|
|
|
|
for (beg_end=beg;;) {
|
2015-03-05 08:35:11 +08:00
|
|
|
end = std::strpbrk(beg_end, " \n");
|
2012-01-06 06:45:03 +08:00
|
|
|
if (end) {
|
|
|
|
chr = *end;
|
|
|
|
*end = 0;
|
|
|
|
}
|
|
|
|
|
2013-10-15 06:58:11 +08:00
|
|
|
// To here we can print
|
2016-12-07 08:29:14 +08:00
|
|
|
if ((old_end) && (x+font->textLength(beg) > x1+width-scroll.x)) {
|
2012-01-06 06:45:03 +08:00
|
|
|
if (end)
|
|
|
|
*end = chr;
|
|
|
|
|
|
|
|
end = old_end;
|
|
|
|
chr = *end;
|
|
|
|
*end = 0;
|
|
|
|
break;
|
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
// We can print one word more
|
2012-01-06 06:45:03 +08:00
|
|
|
else if (end) {
|
2013-10-15 06:58:11 +08:00
|
|
|
// Force break
|
2012-01-06 06:45:03 +08:00
|
|
|
if (chr == '\n')
|
|
|
|
break;
|
|
|
|
|
|
|
|
*end = chr;
|
|
|
|
beg_end = end+1;
|
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
// We are in the end of text
|
2012-01-06 06:45:03 +08:00
|
|
|
else
|
|
|
|
break;
|
|
|
|
|
|
|
|
old_end = end;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-23 05:53:14 +08:00
|
|
|
len = font->textLength(beg);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2014-04-20 02:18:16 +08:00
|
|
|
// Render the text
|
|
|
|
if (g) {
|
2007-09-19 07:57:02 +08:00
|
|
|
int xout;
|
|
|
|
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
if (widget->align() & CENTER)
|
2012-01-06 06:45:03 +08:00
|
|
|
xout = x + width/2 - len/2;
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
else if (widget->align() & RIGHT)
|
2012-01-06 06:45:03 +08:00
|
|
|
xout = x + width - len;
|
2014-04-20 02:18:16 +08:00
|
|
|
else // Left align
|
2012-01-06 06:45:03 +08:00
|
|
|
xout = x;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2017-02-07 04:58:55 +08:00
|
|
|
g->drawText(beg, fg, gfx::ColorNone, gfx::Point(xout, y));
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (w)
|
2019-12-21 02:08:34 +08:00
|
|
|
*w = std::max(*w, len);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
|
|
|
y += textheight;
|
|
|
|
|
|
|
|
if (end) {
|
|
|
|
*end = chr;
|
|
|
|
beg = end+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (h)
|
2014-04-20 02:18:16 +08:00
|
|
|
*h = (y - y1 + scroll.y);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2015-06-24 06:20:49 +08:00
|
|
|
if (w) *w += widget->border().width();
|
|
|
|
if (h) *h += widget->border().height();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2012-06-18 09:02:54 +08:00
|
|
|
|
|
|
|
} // namespace ui
|