mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-29 10:20:48 +00:00
Merge branches
This commit is contained in:
commit
7c57ec40fc
@ -20,7 +20,7 @@ features are:
|
||||
* Real-time **animation preview**.
|
||||
* [**Multiple editors**](http://www.aseprite.org/docs/workspace/#drag-and-drop-tabs) support.
|
||||
* Pixel-art specific tools like filled **Contour**, **Polygon**, [**Shading**](http://www.aseprite.org/docs/shading/) mode, etc.
|
||||
* **Onion skinning**
|
||||
* [**Onion skinning**](https://www.aseprite.org/docs/animation/#onion-skinning)
|
||||
|
||||
## Issues
|
||||
|
||||
|
@ -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.
|
||||
@ -211,7 +211,7 @@ private:
|
||||
g->fillRect(bg, bounds);
|
||||
|
||||
bounds.shrink(border());
|
||||
g->drawUIString(text(), fg, bg,
|
||||
g->drawUIText(text(), fg, bg,
|
||||
gfx::Point(
|
||||
bounds.x + m_level*16 * guiscale(),
|
||||
bounds.y + 2*guiscale()));
|
||||
@ -224,7 +224,7 @@ private:
|
||||
|
||||
for (const Accelerator& accel : m_key->accels()) {
|
||||
if (i != m_hotAccel || !m_changeButton) {
|
||||
g->drawString(accel.toString(), fg, bg,
|
||||
g->drawText(accel.toString(), fg, bg,
|
||||
gfx::Point(bounds.x + g_sep, y + 2*guiscale()));
|
||||
}
|
||||
|
||||
@ -258,7 +258,7 @@ private:
|
||||
int maxi = (accels && accels->size() > 1 ? accels->size(): 1);
|
||||
|
||||
for (int i=0; i<maxi; ++i, y += dh) {
|
||||
int w = Graphics::measureUIStringLength(
|
||||
int w = Graphics::measureUITextLength(
|
||||
(accels && i < (int)accels->size() ? (*accels)[i].toString().c_str(): ""),
|
||||
font());
|
||||
gfx::Rect itemBounds(bounds.x + g_sep, y, w, dh);
|
||||
@ -295,7 +295,7 @@ private:
|
||||
m_deleteButton->setBounds(gfx::Rect(
|
||||
itemBounds.x + itemBounds.w + 2*guiscale(),
|
||||
itemBounds.y,
|
||||
Graphics::measureUIStringLength(
|
||||
Graphics::measureUITextLength(
|
||||
label, font()) + 4*guiscale(),
|
||||
itemBounds.h));
|
||||
m_deleteButton->setText(label);
|
||||
@ -312,7 +312,7 @@ private:
|
||||
setup_mini_look(m_addButton.get());
|
||||
addChild(m_addButton.get());
|
||||
|
||||
itemBounds.w = 8*guiscale() + Graphics::measureUIStringLength("Add", font());
|
||||
itemBounds.w = 8*guiscale() + Graphics::measureUITextLength("Add", font());
|
||||
itemBounds.x -= itemBounds.w + 2*guiscale();
|
||||
|
||||
m_addButton->setBgColor(gfx::ColorNone);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -99,7 +99,7 @@ void AppMenuItem::onSizeHint(SizeHintEvent& ev)
|
||||
+ border().height();
|
||||
|
||||
if (m_key && !m_key->accels().empty()) {
|
||||
size.w += Graphics::measureUIStringLength(
|
||||
size.w += Graphics::measureUITextLength(
|
||||
m_key->accels().front().toString().c_str(), font());
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
@ -141,8 +141,8 @@ void ButtonSet::Item::onPaint(ui::PaintEvent& ev)
|
||||
|
||||
if (hasText()) {
|
||||
g->setFont(font());
|
||||
g->drawUIString(text(), fg, gfx::ColorNone, textRc.origin(),
|
||||
false);
|
||||
g->drawUIText(text(), fg, gfx::ColorNone, textRc.origin(),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
@ -226,7 +226,7 @@ void ColorButton::onPaint(PaintEvent& ev)
|
||||
|
||||
gfx::Rect textrc;
|
||||
getTextIconInfo(NULL, &textrc);
|
||||
g->drawUIString(text(), textcolor, gfx::ColorNone, textrc.origin());
|
||||
g->drawUIText(text(), textcolor, gfx::ColorNone, textrc.origin());
|
||||
}
|
||||
|
||||
void ColorButton::onClick(Event& ev)
|
||||
|
@ -715,8 +715,8 @@ class ContextBar::InkShadesField : public HBox {
|
||||
}
|
||||
else {
|
||||
g->fillRect(theme->colors.editorFace(), bounds);
|
||||
g->drawAlignedUIString(text(), theme->colors.face(), gfx::ColorNone, bounds,
|
||||
ui::CENTER | ui::MIDDLE);
|
||||
g->drawAlignedUIText(text(), theme->colors.face(), gfx::ColorNone, bounds,
|
||||
ui::CENTER | ui::MIDDLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1521,7 +1521,7 @@ void Editor::onPaint(ui::PaintEvent& ev)
|
||||
gfx::Rect vp = view->viewportBounds();
|
||||
char buf[128];
|
||||
sprintf(buf, "%.3f", renderElapsed);
|
||||
g->drawString(
|
||||
g->drawText(
|
||||
buf,
|
||||
gfx::rgba(255, 255, 255, 255),
|
||||
gfx::rgba(0, 0, 0, 255),
|
||||
|
@ -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.
|
||||
@ -362,12 +362,12 @@ void FileList::onPaint(ui::PaintEvent& ev)
|
||||
if (fi->isFolder()) {
|
||||
int icon_w = font()->textLength("[+]");
|
||||
|
||||
g->drawString("[+]", fgcolor, bgcolor, gfx::Point(x, y+2*guiscale()));
|
||||
g->drawText("[+]", fgcolor, bgcolor, gfx::Point(x, y+2*guiscale()));
|
||||
x += icon_w+2*guiscale();
|
||||
}
|
||||
|
||||
// item name
|
||||
g->drawString(
|
||||
g->drawText(
|
||||
fi->displayName().c_str(),
|
||||
fgcolor, bgcolor, gfx::Point(x, y+2*guiscale()));
|
||||
|
||||
|
@ -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.
|
||||
@ -546,9 +546,9 @@ void PaletteView::onPaint(ui::PaintEvent& ev)
|
||||
she::Font* minifont = theme->getMiniFont();
|
||||
std::string text = base::convert_to<std::string>(k);
|
||||
g->setFont(minifont);
|
||||
g->drawString(text, neg, gfx::ColorNone,
|
||||
gfx::Point(box2.x + box2.w/2 - minifont->textLength(text)/2,
|
||||
box2.y + box2.h/2 - minifont->height()/2));
|
||||
g->drawText(text, neg, gfx::ColorNone,
|
||||
gfx::Point(box2.x + box2.w/2 - minifont->textLength(text)/2,
|
||||
box2.y + box2.h/2 - minifont->height()/2));
|
||||
}
|
||||
|
||||
// Draw outlines
|
||||
|
@ -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.
|
||||
@ -65,10 +65,10 @@ void ResourceListItem::onPaint(PaintEvent& ev)
|
||||
static_cast<ResourcesListBox*>(parent())->
|
||||
paintResource(g, bounds, m_resource);
|
||||
|
||||
g->drawString(text(), fgcolor, gfx::ColorNone,
|
||||
gfx::Point(
|
||||
bounds.x + 2*guiscale(),
|
||||
bounds.y + bounds.h/2 - g->measureUIString(text()).h/2));
|
||||
g->drawText(text(), fgcolor, gfx::ColorNone,
|
||||
gfx::Point(
|
||||
bounds.x + 2*guiscale(),
|
||||
bounds.y + bounds.h/2 - g->measureUIText(text()).h/2));
|
||||
}
|
||||
|
||||
void ResourceListItem::onSizeHint(SizeHintEvent& ev)
|
||||
|
@ -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.
|
||||
@ -32,6 +32,7 @@
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "gfx/size.h"
|
||||
#include "she/draw_text.h"
|
||||
#include "she/font.h"
|
||||
#include "she/surface.h"
|
||||
#include "she/system.h"
|
||||
@ -769,6 +770,14 @@ int SkinTheme::getScrollbarSize()
|
||||
return dimensions.scrollbarSize();
|
||||
}
|
||||
|
||||
gfx::Size SkinTheme::getEntryCaretSize(Widget* widget)
|
||||
{
|
||||
if (widget->font()->type() == she::FontType::kTrueType)
|
||||
return gfx::Size(2*guiscale(), widget->textHeight());
|
||||
else
|
||||
return gfx::Size(2*guiscale(), widget->textHeight()+2*guiscale());
|
||||
}
|
||||
|
||||
void SkinTheme::paintDesktop(PaintEvent& ev)
|
||||
{
|
||||
Graphics* g = ev.graphics();
|
||||
@ -850,8 +859,8 @@ void SkinTheme::paintButton(PaintEvent& ev)
|
||||
drawRect(g, widget->clientBounds(), part_nw.get(), bg);
|
||||
|
||||
// text
|
||||
drawTextString(g, NULL, fg, ColorNone, widget,
|
||||
widget->clientChildrenBounds(), get_button_selected_offset());
|
||||
drawText(g, NULL, fg, ColorNone, widget,
|
||||
widget->clientChildrenBounds(), get_button_selected_offset());
|
||||
|
||||
// Paint the icon
|
||||
if (iconInterface) {
|
||||
@ -895,7 +904,7 @@ void SkinTheme::paintCheckBox(PaintEvent& ev)
|
||||
}
|
||||
|
||||
// Text
|
||||
drawTextString(g, NULL, ColorNone, ColorNone, widget, text, 0);
|
||||
drawText(g, NULL, ColorNone, ColorNone, widget, text, 0);
|
||||
|
||||
// Paint the icon
|
||||
if (iconInterface)
|
||||
@ -924,13 +933,6 @@ void SkinTheme::paintEntry(PaintEvent& ev)
|
||||
Graphics* g = ev.graphics();
|
||||
Entry* widget = static_cast<Entry*>(ev.getSource());
|
||||
gfx::Rect bounds = widget->clientBounds();
|
||||
bool password = widget->isPassword();
|
||||
int scroll, caret, state, selbeg, selend;
|
||||
const std::string& textString = widget->text();
|
||||
int c, ch, x, y, w;
|
||||
int caret_x;
|
||||
|
||||
widget->getEntryThemeInfo(&scroll, &caret, &state, &selbeg, &selend);
|
||||
|
||||
// Outside borders
|
||||
g->fillRect(BGCOLOR, bounds);
|
||||
@ -947,26 +949,49 @@ void SkinTheme::paintEntry(PaintEvent& ev)
|
||||
(isMiniLook ? parts.sunkenMiniNormal().get() : parts.sunkenNormal().get())),
|
||||
bg);
|
||||
|
||||
// Draw the text
|
||||
bounds = widget->getEntryTextBounds();
|
||||
x = bounds.x;
|
||||
y = bounds.y;
|
||||
drawEntryText(g, widget);
|
||||
}
|
||||
|
||||
base::utf8_const_iterator utf8_it = base::utf8_const_iterator(textString.begin());
|
||||
int textlen = base::utf8_length(textString);
|
||||
if (scroll < textlen)
|
||||
utf8_it += scroll;
|
||||
namespace {
|
||||
|
||||
for (c=scroll; c<textlen; ++c, ++utf8_it) {
|
||||
ch = password ? '*': *utf8_it;
|
||||
class DrawEntryTextDelegate : public she::DrawTextDelegate {
|
||||
public:
|
||||
DrawEntryTextDelegate(Entry* widget, Graphics* graphics,
|
||||
const gfx::Point& pos, const int h)
|
||||
: m_widget(widget)
|
||||
, m_graphics(graphics)
|
||||
, m_caretDrawn(false)
|
||||
// m_lastX is an absolute position on screen
|
||||
, m_lastX(pos.x+m_widget->bounds().x)
|
||||
, m_y(pos.y)
|
||||
, m_h(h)
|
||||
{
|
||||
m_widget->getEntryThemeInfo(&m_index, &m_caret, &m_state, &m_selbeg, &m_selend);
|
||||
}
|
||||
|
||||
int index() const { return m_index; }
|
||||
bool caretDrawn() const { return m_caretDrawn; }
|
||||
const gfx::Rect& textBounds() const { return m_textBounds; }
|
||||
|
||||
void preProcessChar(const base::utf8_const_iterator& it,
|
||||
const base::utf8_const_iterator& end,
|
||||
int& chr,
|
||||
gfx::Color& fg,
|
||||
gfx::Color& bg,
|
||||
bool& drawChar,
|
||||
bool& moveCaret) override {
|
||||
if (m_widget->isPassword())
|
||||
chr = '*';
|
||||
|
||||
// Normal text
|
||||
auto& colors = SkinTheme::instance()->colors;
|
||||
bg = ColorNone;
|
||||
gfx::Color fg = colors.text();
|
||||
fg = colors.text();
|
||||
|
||||
// Selected
|
||||
if ((c >= selbeg) && (c <= selend)) {
|
||||
if (widget->hasFocus())
|
||||
if ((m_index >= m_selbeg) &&
|
||||
(m_index <= m_selend)) {
|
||||
if (m_widget->hasFocus())
|
||||
bg = colors.selected();
|
||||
else
|
||||
bg = colors.disabled();
|
||||
@ -974,43 +999,112 @@ void SkinTheme::paintEntry(PaintEvent& ev)
|
||||
}
|
||||
|
||||
// Disabled
|
||||
if (!widget->isEnabled()) {
|
||||
if (!m_widget->isEnabled()) {
|
||||
bg = ColorNone;
|
||||
fg = colors.disabled();
|
||||
}
|
||||
|
||||
w = g->measureChar(ch).w;
|
||||
if (x+w > bounds.x2())
|
||||
return;
|
||||
|
||||
caret_x = x;
|
||||
g->drawChar(ch, fg, bg, x, y);
|
||||
x += w;
|
||||
|
||||
// Caret
|
||||
if ((c == caret) && (state) && (widget->hasFocus()))
|
||||
drawEntryCaret(g, widget, caret_x, y);
|
||||
drawChar = true;
|
||||
moveCaret = true;
|
||||
m_bg = bg;
|
||||
}
|
||||
|
||||
bool preDrawChar(const gfx::Rect& charBounds) override {
|
||||
m_textBounds |= charBounds;
|
||||
m_charStartX = charBounds.x;
|
||||
|
||||
if (charBounds.x2()-m_widget->bounds().x < m_widget->clientBounds().x2()) {
|
||||
if (m_bg != ColorNone) {
|
||||
// Fill background e.g. needed for selected/highlighted
|
||||
// regions with TTF fonts where the char is smaller than the
|
||||
// text bounds [m_y,m_y+m_h)
|
||||
gfx::Rect fillThisRect(m_lastX-m_widget->bounds().x,
|
||||
m_y, charBounds.x2()-m_lastX, m_h);
|
||||
if (charBounds != fillThisRect)
|
||||
m_graphics->fillRect(m_bg, fillThisRect);
|
||||
}
|
||||
m_lastX = charBounds.x2();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void postDrawChar(const gfx::Rect& charBounds) override {
|
||||
// Caret
|
||||
if (m_state &&
|
||||
m_index == m_caret &&
|
||||
m_widget->hasFocus() &&
|
||||
m_widget->isEnabled()) {
|
||||
SkinTheme::instance()->drawEntryCaret(
|
||||
m_graphics, m_widget,
|
||||
m_charStartX-m_widget->bounds().x, m_y);
|
||||
m_caretDrawn = true;
|
||||
}
|
||||
|
||||
++m_index;
|
||||
}
|
||||
|
||||
private:
|
||||
Entry* m_widget;
|
||||
Graphics* m_graphics;
|
||||
int m_index;
|
||||
int m_caret;
|
||||
int m_state;
|
||||
int m_selbeg;
|
||||
int m_selend;
|
||||
gfx::Rect m_textBounds;
|
||||
bool m_caretDrawn;
|
||||
gfx::Color m_bg;
|
||||
int m_lastX; // Last position used to fill the background
|
||||
int m_y, m_h;
|
||||
int m_charStartX;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void SkinTheme::drawEntryText(ui::Graphics* g, ui::Entry* widget)
|
||||
{
|
||||
// Draw the text
|
||||
gfx::Rect bounds = widget->getEntryTextBounds();
|
||||
|
||||
DrawEntryTextDelegate delegate(widget, g, bounds.origin(), widget->textHeight());
|
||||
int scroll = delegate.index();
|
||||
|
||||
const std::string& textString = widget->text();
|
||||
base::utf8_const_iterator utf8_it((textString.begin()));
|
||||
int textlen = base::utf8_length(textString);
|
||||
scroll = MIN(scroll, textlen);
|
||||
if (scroll)
|
||||
utf8_it += scroll;
|
||||
|
||||
g->drawText(utf8_it,
|
||||
base::utf8_const_iterator(textString.end()),
|
||||
colors.text(), ColorNone,
|
||||
bounds.origin(), &delegate);
|
||||
|
||||
bounds.x += delegate.textBounds().w;
|
||||
|
||||
// Draw suffix if there is enough space
|
||||
if (!widget->getSuffix().empty()) {
|
||||
Rect sufBounds(x, y,
|
||||
bounds.x2()-widget->childSpacing()*guiscale()-x,
|
||||
Rect sufBounds(bounds.x, bounds.y,
|
||||
bounds.x2()-widget->childSpacing()*guiscale()-bounds.x,
|
||||
widget->textHeight());
|
||||
IntersectClip clip(g, sufBounds);
|
||||
IntersectClip clip(g, sufBounds & widget->clientChildrenBounds());
|
||||
if (clip) {
|
||||
drawTextString(
|
||||
drawText(
|
||||
g, widget->getSuffix().c_str(),
|
||||
colors.entrySuffix(), ColorNone,
|
||||
widget, sufBounds, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the caret if it is next of the last character
|
||||
if ((c == caret) && (state) &&
|
||||
(widget->hasFocus()) &&
|
||||
(widget->isEnabled())) {
|
||||
drawEntryCaret(g, widget, x, y);
|
||||
// Draw caret at the end of the text
|
||||
if (!delegate.caretDrawn()) {
|
||||
gfx::Rect charBounds(bounds.x+widget->bounds().x,
|
||||
bounds.y+widget->bounds().y, 0, widget->textHeight());
|
||||
delegate.preDrawChar(charBounds);
|
||||
delegate.postDrawChar(charBounds);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1092,7 +1186,7 @@ void SkinTheme::paintListItem(ui::PaintEvent& ev)
|
||||
|
||||
if (widget->hasText()) {
|
||||
bounds.shrink(widget->border());
|
||||
drawTextString(g, NULL, fg, bg, widget, bounds, 0);
|
||||
drawText(g, NULL, fg, bg, widget, bounds, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1163,7 +1257,7 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
|
||||
Rect pos = bounds;
|
||||
if (!bar)
|
||||
pos.offset(widget->childSpacing()/2, 0);
|
||||
drawTextString(g, NULL, fg, ColorNone, widget, pos, 0);
|
||||
drawText(g, NULL, fg, ColorNone, widget, pos, 0);
|
||||
|
||||
// For menu-box
|
||||
if (!bar) {
|
||||
@ -1200,7 +1294,7 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
|
||||
std::string buf = appMenuItem->key()->accels().front().toString();
|
||||
|
||||
widget->setAlign(RIGHT | MIDDLE);
|
||||
drawTextString(g, buf.c_str(), fg, ColorNone, widget, pos, 0);
|
||||
drawText(g, buf.c_str(), fg, ColorNone, widget, pos, 0);
|
||||
widget->setAlign(old_align);
|
||||
}
|
||||
}
|
||||
@ -1240,7 +1334,7 @@ void SkinTheme::paintRadioButton(PaintEvent& ev)
|
||||
}
|
||||
|
||||
// Text
|
||||
drawTextString(g, NULL, ColorNone, ColorNone, widget, text, 0);
|
||||
drawText(g, NULL, ColorNone, ColorNone, widget, text, 0);
|
||||
|
||||
// Icon
|
||||
if (iconInterface)
|
||||
@ -1282,7 +1376,7 @@ void SkinTheme::paintSeparator(ui::PaintEvent& ev)
|
||||
bounds.y + bounds.h/2 - h/2,
|
||||
widget->textWidth(), h);
|
||||
|
||||
drawTextString(g, NULL,
|
||||
drawText(g, NULL,
|
||||
colors.separatorLabel(), BGCOLOR,
|
||||
widget, r, 0);
|
||||
}
|
||||
@ -1389,7 +1483,7 @@ void SkinTheme::paintSlider(PaintEvent& ev)
|
||||
{
|
||||
IntersectClip clip(g, Rect(rc.x, rc.y, x-rc.x, rc.h));
|
||||
if (clip) {
|
||||
drawTextString(g, NULL,
|
||||
drawText(g, NULL,
|
||||
colors.sliderFullText(), ColorNone,
|
||||
widget, rc, 0);
|
||||
}
|
||||
@ -1398,7 +1492,7 @@ void SkinTheme::paintSlider(PaintEvent& ev)
|
||||
{
|
||||
IntersectClip clip(g, Rect(x+1, rc.y, rc.w-(x-rc.x+1), rc.h));
|
||||
if (clip) {
|
||||
drawTextString(g, NULL,
|
||||
drawText(g, NULL,
|
||||
colors.sliderEmptyText(),
|
||||
ColorNone, widget, rc, 0);
|
||||
}
|
||||
@ -1413,75 +1507,18 @@ void SkinTheme::paintComboBoxEntry(ui::PaintEvent& ev)
|
||||
Graphics* g = ev.graphics();
|
||||
Entry* widget = static_cast<Entry*>(ev.getSource());
|
||||
gfx::Rect bounds = widget->clientBounds();
|
||||
bool password = widget->isPassword();
|
||||
int scroll, caret, state, selbeg, selend;
|
||||
const std::string& textString = widget->text();
|
||||
int c, ch, x, y, w;
|
||||
int caret_x;
|
||||
|
||||
widget->getEntryThemeInfo(&scroll, &caret, &state, &selbeg, &selend);
|
||||
|
||||
// Outside borders
|
||||
g->fillRect(BGCOLOR, bounds);
|
||||
|
||||
gfx::Color fg, bg = colors.background();
|
||||
gfx::Color bg = colors.background();
|
||||
|
||||
drawRect(g, bounds,
|
||||
(widget->hasFocus() ?
|
||||
parts.sunken2Focused().get():
|
||||
parts.sunken2Normal().get()), bg);
|
||||
|
||||
// Draw the text
|
||||
x = bounds.x + widget->border().left();
|
||||
y = bounds.y + bounds.h/2 - widget->textHeight()/2;
|
||||
|
||||
base::utf8_const_iterator utf8_it = base::utf8_const_iterator(textString.begin());
|
||||
int textlen = base::utf8_length(textString);
|
||||
|
||||
if (scroll < textlen)
|
||||
utf8_it += scroll;
|
||||
|
||||
for (c=scroll; c<textlen; ++c, ++utf8_it) {
|
||||
ch = password ? '*': *utf8_it;
|
||||
|
||||
// Normal text
|
||||
bg = ColorNone;
|
||||
fg = colors.text();
|
||||
|
||||
// Selected
|
||||
if ((c >= selbeg) && (c <= selend)) {
|
||||
if (widget->hasFocus())
|
||||
bg = colors.selected();
|
||||
else
|
||||
bg = colors.disabled();
|
||||
fg = colors.background();
|
||||
}
|
||||
|
||||
// Disabled
|
||||
if (!widget->isEnabled()) {
|
||||
bg = ColorNone;
|
||||
fg = colors.disabled();
|
||||
}
|
||||
|
||||
w = g->measureChar(ch).w;
|
||||
if (x+w > bounds.x2()-3)
|
||||
return;
|
||||
|
||||
caret_x = x;
|
||||
g->drawChar(ch, fg, bg, x, y);
|
||||
x += w;
|
||||
|
||||
// Caret
|
||||
if ((c == caret) && (state) && (widget->hasFocus()))
|
||||
drawEntryCaret(g, widget, caret_x, y);
|
||||
}
|
||||
|
||||
// Draw the caret if it is next of the last character
|
||||
if ((c == caret) && (state) &&
|
||||
(widget->hasFocus()) &&
|
||||
(widget->isEnabled())) {
|
||||
drawEntryCaret(g, widget, x, y);
|
||||
}
|
||||
drawEntryText(g, widget);
|
||||
}
|
||||
|
||||
void SkinTheme::paintComboBoxButton(PaintEvent& ev)
|
||||
@ -1653,7 +1690,7 @@ void SkinTheme::paintPopupWindow(PaintEvent& ev)
|
||||
|
||||
pos.shrink(window->border());
|
||||
|
||||
g->drawAlignedUIString(window->text(),
|
||||
g->drawAlignedUIText(window->text(),
|
||||
colors.text(),
|
||||
window->bgColor(), pos,
|
||||
window->align());
|
||||
@ -1749,7 +1786,7 @@ void SkinTheme::paintTooltip(PaintEvent& ev)
|
||||
|
||||
rc.shrink(widget->border());
|
||||
|
||||
g->drawAlignedUIString(widget->text(), fg, bg, rc, widget->align());
|
||||
g->drawAlignedUIText(widget->text(), fg, bg, rc, widget->align());
|
||||
}
|
||||
|
||||
gfx::Color SkinTheme::getWidgetBgColor(Widget* widget)
|
||||
@ -1765,9 +1802,9 @@ gfx::Color SkinTheme::getWidgetBgColor(Widget* widget)
|
||||
return colors.face();
|
||||
}
|
||||
|
||||
void SkinTheme::drawTextString(Graphics* g, const char *t, gfx::Color fg_color, gfx::Color bg_color,
|
||||
Widget* widget, const Rect& rc,
|
||||
int selected_offset)
|
||||
void SkinTheme::drawText(Graphics* g, const char *t, gfx::Color fg_color, gfx::Color bg_color,
|
||||
Widget* widget, const Rect& rc,
|
||||
int selected_offset)
|
||||
{
|
||||
if (t || widget->hasText()) {
|
||||
Rect textrc;
|
||||
@ -1777,7 +1814,7 @@ void SkinTheme::drawTextString(Graphics* g, const char *t, gfx::Color fg_color,
|
||||
if (!t)
|
||||
t = widget->text().c_str();
|
||||
|
||||
textrc.setSize(g->measureUIString(t));
|
||||
textrc.setSize(g->measureUIText(t));
|
||||
|
||||
// Horizontally text alignment
|
||||
|
||||
@ -1820,13 +1857,13 @@ void SkinTheme::drawTextString(Graphics* g, const char *t, gfx::Color fg_color,
|
||||
if (clip) {
|
||||
if (!widget->isEnabled()) {
|
||||
// Draw white part
|
||||
g->drawUIString(t,
|
||||
g->drawUIText(t,
|
||||
colors.background(),
|
||||
gfx::ColorNone,
|
||||
textrc.origin() + Point(guiscale(), guiscale()));
|
||||
}
|
||||
|
||||
g->drawUIString(t,
|
||||
g->drawUIText(t,
|
||||
(!widget->isEnabled() ?
|
||||
colors.disabled():
|
||||
(gfx::geta(fg_color) > 0 ? fg_color :
|
||||
@ -1839,10 +1876,11 @@ void SkinTheme::drawTextString(Graphics* g, const char *t, gfx::Color fg_color,
|
||||
void SkinTheme::drawEntryCaret(ui::Graphics* g, Entry* widget, int x, int y)
|
||||
{
|
||||
gfx::Color color = colors.text();
|
||||
int h = widget->textHeight();
|
||||
int textHeight = widget->textHeight();
|
||||
gfx::Size caretSize = getEntryCaretSize(widget);
|
||||
|
||||
for (int u=x; u<x+2*guiscale(); ++u)
|
||||
g->drawVLine(color, u, y-1, h+2);
|
||||
for (int u=x; u<x+caretSize.w; ++u)
|
||||
g->drawVLine(color, u, y+textHeight/2-caretSize.h/2, caretSize.h);
|
||||
}
|
||||
|
||||
she::Surface* SkinTheme::getToolIcon(const char* toolId) const
|
||||
|
@ -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.
|
||||
@ -54,6 +54,7 @@ namespace app {
|
||||
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;
|
||||
|
||||
void paintDesktop(ui::PaintEvent& ev) override;
|
||||
void paintBox(ui::PaintEvent& ev) override;
|
||||
@ -116,6 +117,8 @@ namespace app {
|
||||
return m_colors_by_id[id];
|
||||
}
|
||||
|
||||
void drawEntryCaret(ui::Graphics* g, ui::Entry* widget, int x, int y);
|
||||
|
||||
protected:
|
||||
void onRegenerate() override;
|
||||
|
||||
@ -127,10 +130,10 @@ namespace app {
|
||||
|
||||
she::Surface* sliceSheet(she::Surface* sur, const gfx::Rect& bounds);
|
||||
gfx::Color getWidgetBgColor(ui::Widget* widget);
|
||||
void drawTextString(ui::Graphics* g, const char *t, gfx::Color fg_color, gfx::Color bg_color,
|
||||
ui::Widget* widget, const gfx::Rect& rc,
|
||||
int selected_offset);
|
||||
void drawEntryCaret(ui::Graphics* g, ui::Entry* widget, int x, int y);
|
||||
void drawText(ui::Graphics* g, const char *t, gfx::Color fg_color, gfx::Color bg_color,
|
||||
ui::Widget* widget, const gfx::Rect& rc,
|
||||
int selected_offset);
|
||||
void drawEntryText(ui::Graphics* g, ui::Entry* widget);
|
||||
|
||||
void paintIcon(ui::Widget* widget, ui::Graphics* g, ui::IButtonIcon* iconInterface, int x, int y);
|
||||
|
||||
|
@ -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.
|
||||
@ -79,7 +79,7 @@ void TextRule::onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* tex
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(ui::CurrentTheme::get());
|
||||
|
||||
if (text) {
|
||||
g->drawAlignedUIString(text,
|
||||
g->drawAlignedUIText(text,
|
||||
(gfx::is_transparent(m_color) ?
|
||||
theme->colors.text():
|
||||
m_color),
|
||||
|
@ -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.
|
||||
@ -101,8 +101,8 @@ class StatusBar::Indicators : public HBox {
|
||||
|
||||
g->fillRect(bgColor(), rc);
|
||||
if (textLength() > 0) {
|
||||
g->drawString(text(), textColor, ColorNone,
|
||||
Point(rc.x, rc.y + rc.h/2 - font()->height()/2));
|
||||
g->drawText(text(), textColor, ColorNone,
|
||||
Point(rc.x, rc.y + rc.h/2 - font()->height()/2));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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.
|
||||
@ -2032,7 +2032,7 @@ void Timeline::drawFrameTags(ui::Graphics* g)
|
||||
|
||||
bounds.y += 2*ui::guiscale();
|
||||
bounds.x += 2*ui::guiscale();
|
||||
g->drawString(
|
||||
g->drawText(
|
||||
frameTag->name(),
|
||||
color_utils::blackandwhite_neg(bg),
|
||||
gfx::ColorNone,
|
||||
|
@ -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.
|
||||
@ -38,54 +38,61 @@ doc::Image* render_text(const std::string& fontfile, int fontsize,
|
||||
face.setAntialias(antialias);
|
||||
|
||||
// Calculate text size
|
||||
gfx::Rect bounds = face.calcTextBounds(text);
|
||||
gfx::Rect bounds = ft::calc_text_bounds(face, text);
|
||||
|
||||
// Render the image and copy it to the clipboard
|
||||
if (!bounds.isEmpty()) {
|
||||
image.reset(doc::Image::create(doc::IMAGE_RGB, bounds.w, bounds.h));
|
||||
doc::clear_image(image, 0);
|
||||
|
||||
face.forEachGlyph(
|
||||
text,
|
||||
[&bounds, &image, color, antialias](const ft::Glyph& glyph) {
|
||||
int t, yimg = - bounds.y + int(glyph.y);
|
||||
ft::ForEachGlyph<ft::Face> feg(face);
|
||||
auto it = base::utf8_const_iterator(text.begin());
|
||||
auto end = base::utf8_const_iterator(text.end());
|
||||
while (it != end) {
|
||||
feg.processChar(
|
||||
*it,
|
||||
[&bounds, &image, color, antialias](const ft::Glyph& glyph) {
|
||||
int t, yimg = - bounds.y + int(glyph.y);
|
||||
|
||||
for (int v=0; v<int(glyph.bitmap->rows); ++v, ++yimg) {
|
||||
const uint8_t* p = glyph.bitmap->buffer + v*glyph.bitmap->pitch;
|
||||
int ximg = - bounds.x + int(glyph.x);
|
||||
int bit = 0;
|
||||
for (int v=0; v<int(glyph.bitmap->rows); ++v, ++yimg) {
|
||||
const uint8_t* p = glyph.bitmap->buffer + v*glyph.bitmap->pitch;
|
||||
int ximg = - bounds.x + int(glyph.x);
|
||||
int bit = 0;
|
||||
|
||||
for (int u=0; u<int(glyph.bitmap->width); ++u, ++ximg) {
|
||||
int alpha;
|
||||
for (int u=0; u<int(glyph.bitmap->width); ++u, ++ximg) {
|
||||
int alpha;
|
||||
|
||||
if (antialias) {
|
||||
alpha = *(p++);
|
||||
}
|
||||
else {
|
||||
alpha = ((*p) & (1 << (7 - (bit++))) ? 255: 0);
|
||||
if (bit == 8) {
|
||||
bit = 0;
|
||||
++p;
|
||||
if (antialias) {
|
||||
alpha = *(p++);
|
||||
}
|
||||
else {
|
||||
alpha = ((*p) & (1 << (7 - (bit++))) ? 255: 0);
|
||||
if (bit == 8) {
|
||||
bit = 0;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
int output_alpha = MUL_UN8(doc::rgba_geta(color), alpha, t);
|
||||
if (output_alpha) {
|
||||
doc::color_t output_color =
|
||||
doc::rgba(doc::rgba_getr(color),
|
||||
doc::rgba_getg(color),
|
||||
doc::rgba_getb(color),
|
||||
output_alpha);
|
||||
|
||||
doc::put_pixel(
|
||||
image, ximg, yimg,
|
||||
doc::rgba_blender_normal(
|
||||
doc::get_pixel(image, ximg, yimg),
|
||||
output_color));
|
||||
}
|
||||
}
|
||||
|
||||
int output_alpha = MUL_UN8(doc::rgba_geta(color), alpha, t);
|
||||
if (output_alpha) {
|
||||
doc::color_t output_color =
|
||||
doc::rgba(doc::rgba_getr(color),
|
||||
doc::rgba_getg(color),
|
||||
doc::rgba_getb(color),
|
||||
output_alpha);
|
||||
|
||||
doc::put_pixel(
|
||||
image, ximg, yimg,
|
||||
doc::rgba_blender_normal(
|
||||
doc::get_pixel(image, ximg, yimg),
|
||||
output_color));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("There is no text");
|
||||
|
124
src/ft/face.h
124
src/ft/face.h
@ -1,5 +1,5 @@
|
||||
// Aseprite FreeType Wrapper
|
||||
// Copyright (c) 2016 David Capello
|
||||
// Copyright (c) 2016-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -22,6 +22,8 @@ namespace ft {
|
||||
FT_UInt glyph_index;
|
||||
FT_Glyph ft_glyph;
|
||||
FT_Bitmap* bitmap;
|
||||
double startX;
|
||||
double endX;
|
||||
double bearingX;
|
||||
double bearingY;
|
||||
double x;
|
||||
@ -29,12 +31,12 @@ namespace ft {
|
||||
};
|
||||
|
||||
template<typename Cache>
|
||||
class FaceBase {
|
||||
class FaceFT {
|
||||
public:
|
||||
FaceBase(FT_Face face) : m_face(face) {
|
||||
FaceFT(FT_Face face) : m_face(face) {
|
||||
}
|
||||
|
||||
~FaceBase() {
|
||||
~FaceFT() {
|
||||
if (m_face)
|
||||
FT_Done_Face(m_face);
|
||||
}
|
||||
@ -81,81 +83,89 @@ namespace ft {
|
||||
return int(m_face->descender * y_scale);
|
||||
}
|
||||
|
||||
Cache& cache() { return m_cache; }
|
||||
|
||||
protected:
|
||||
FT_Face m_face;
|
||||
bool m_antialias;
|
||||
Cache m_cache;
|
||||
|
||||
private:
|
||||
DISABLE_COPYING(FaceBase);
|
||||
DISABLE_COPYING(FaceFT);
|
||||
};
|
||||
|
||||
template<typename Cache>
|
||||
class FaceFT : public FaceBase<Cache> {
|
||||
template<typename FaceFT>
|
||||
class ForEachGlyph {
|
||||
public:
|
||||
using FaceBase<Cache>::m_face;
|
||||
using FaceBase<Cache>::m_cache;
|
||||
|
||||
FaceFT(FT_Face face)
|
||||
: FaceBase<Cache>(face) {
|
||||
ForEachGlyph(FaceFT& face)
|
||||
: m_face(face)
|
||||
, m_useKerning(FT_HAS_KERNING((FT_Face)face) ? true: false)
|
||||
, m_prevGlyph(0)
|
||||
, m_x(0.0), m_y(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
void forEachGlyph(const std::string& str, Callback callback) {
|
||||
bool use_kerning = (FT_HAS_KERNING(this->m_face) ? true: false);
|
||||
FT_UInt prev_glyph = 0;
|
||||
double x = 0, y = 0;
|
||||
template<typename ProcessGlyph>
|
||||
void processChar(const int chr, ProcessGlyph processGlyph) {
|
||||
FT_UInt glyphIndex = m_face.cache().getGlyphIndex(m_face, chr);
|
||||
double initialX = m_x;
|
||||
|
||||
auto it = base::utf8_const_iterator(str.begin());
|
||||
auto end = base::utf8_const_iterator(str.end());
|
||||
for (; it != end; ++it) {
|
||||
FT_UInt glyph_index = this->m_cache.getGlyphIndex(
|
||||
this->m_face, *it);
|
||||
|
||||
if (use_kerning && prev_glyph && glyph_index) {
|
||||
FT_Vector kerning;
|
||||
FT_Get_Kerning(this->m_face, prev_glyph, glyph_index,
|
||||
FT_KERNING_DEFAULT, &kerning);
|
||||
x += kerning.x / 64.0;
|
||||
}
|
||||
|
||||
Glyph* glyph = this->m_cache.loadGlyph(
|
||||
this->m_face, glyph_index, this->m_antialias);
|
||||
if (glyph) {
|
||||
glyph->bitmap = &FT_BitmapGlyph(glyph->ft_glyph)->bitmap;
|
||||
glyph->x = x + glyph->bearingX;
|
||||
glyph->y = y
|
||||
+ this->height()
|
||||
+ this->descender() // descender is negative
|
||||
- glyph->bearingY;
|
||||
|
||||
callback(*glyph);
|
||||
|
||||
x += glyph->ft_glyph->advance.x / double(1 << 16);
|
||||
y += glyph->ft_glyph->advance.y / double(1 << 16);
|
||||
|
||||
this->m_cache.doneGlyph(glyph);
|
||||
}
|
||||
|
||||
prev_glyph = glyph_index;
|
||||
if (m_useKerning && m_prevGlyph && glyphIndex) {
|
||||
FT_Vector kerning;
|
||||
FT_Get_Kerning(m_face, m_prevGlyph, glyphIndex,
|
||||
FT_KERNING_DEFAULT, &kerning);
|
||||
m_x += kerning.x / 64.0;
|
||||
}
|
||||
|
||||
Glyph* glyph = m_face.cache().loadGlyph(
|
||||
m_face, glyphIndex, m_face.antialias());
|
||||
if (glyph) {
|
||||
glyph->bitmap = &FT_BitmapGlyph(glyph->ft_glyph)->bitmap;
|
||||
glyph->x = m_x + glyph->bearingX;
|
||||
glyph->y = m_y
|
||||
+ m_face.height()
|
||||
+ m_face.descender() // descender is negative
|
||||
- glyph->bearingY;
|
||||
|
||||
m_x += glyph->ft_glyph->advance.x / double(1 << 16);
|
||||
m_y += glyph->ft_glyph->advance.y / double(1 << 16);
|
||||
|
||||
glyph->startX = initialX;
|
||||
glyph->endX = m_x;
|
||||
|
||||
processGlyph(*glyph);
|
||||
|
||||
m_face.cache().doneGlyph(glyph);
|
||||
}
|
||||
|
||||
m_prevGlyph = glyphIndex;
|
||||
}
|
||||
|
||||
gfx::Rect calcTextBounds(const std::string& str) {
|
||||
gfx::Rect bounds(0, 0, 0, 0);
|
||||
private:
|
||||
FaceFT& m_face;
|
||||
bool m_useKerning;
|
||||
FT_UInt m_prevGlyph;
|
||||
double m_x, m_y;
|
||||
};
|
||||
|
||||
forEachGlyph(
|
||||
str,
|
||||
[&bounds, this](Glyph& glyph) {
|
||||
template<typename FaceFT>
|
||||
gfx::Rect calc_text_bounds(FaceFT& face, const std::string& str) {
|
||||
gfx::Rect bounds(0, 0, 0, 0);
|
||||
auto it = base::utf8_const_iterator(str.begin());
|
||||
auto end = base::utf8_const_iterator(str.end());
|
||||
ForEachGlyph<FaceFT> feg(face);
|
||||
for (; it != end; ++it) {
|
||||
feg.processChar(
|
||||
*it,
|
||||
[&bounds](Glyph& glyph) {
|
||||
bounds |= gfx::Rect(int(glyph.x),
|
||||
int(glyph.y),
|
||||
glyph.bitmap->width,
|
||||
glyph.bitmap->rows);
|
||||
});
|
||||
|
||||
return bounds;
|
||||
}
|
||||
};
|
||||
return bounds;
|
||||
}
|
||||
|
||||
class NoCache {
|
||||
public:
|
||||
|
@ -1,8 +1,9 @@
|
||||
# SHE
|
||||
# Copyright (C) 2012-2016 David Capello
|
||||
# Copyright (C) 2012-2017 David Capello
|
||||
|
||||
set(SHE_SOURCES
|
||||
common/freetype_font.cpp
|
||||
draw_text.cpp
|
||||
system.cpp)
|
||||
|
||||
######################################################################
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SHE library
|
||||
// Copyright (C) 2012-2016 David Capello
|
||||
// Copyright (C) 2012-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
namespace she {
|
||||
|
||||
class Alleg4Surface : public GenericDrawTextSurface<GenericDrawColoredRgbaSurface<Surface> > {
|
||||
class Alleg4Surface : public GenericDrawColoredRgbaSurface<Surface> {
|
||||
public:
|
||||
enum DestroyFlag {
|
||||
None = 0,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SHE library
|
||||
// Copyright (C) 2016 David Capello
|
||||
// Copyright (C) 2016-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -48,17 +48,9 @@ int FreeTypeFont::height() const
|
||||
return int(m_face.height());
|
||||
}
|
||||
|
||||
int FreeTypeFont::charWidth(int chr) const
|
||||
{
|
||||
// TODO avoid creating a temporary string
|
||||
std::wstring tmp;
|
||||
tmp.push_back(chr);
|
||||
return m_face.calcTextBounds(base::to_utf8(tmp)).w;
|
||||
}
|
||||
|
||||
int FreeTypeFont::textLength(const std::string& str) const
|
||||
{
|
||||
return m_face.calcTextBounds(str).w;
|
||||
return ft::calc_text_bounds(m_face, str).w;
|
||||
}
|
||||
|
||||
bool FreeTypeFont::isScalable() const
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SHE library
|
||||
// Copyright (C) 2016 David Capello
|
||||
// Copyright (C) 2016-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -24,7 +24,6 @@ namespace she {
|
||||
void dispose() override;
|
||||
FontType type() override;
|
||||
int height() const override;
|
||||
int charWidth(int chr) const override;
|
||||
int textLength(const std::string& str) const override;
|
||||
bool isScalable() const override;
|
||||
void setSize(int size) override;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SHE library
|
||||
// Copyright (C) 2012-2016 David Capello
|
||||
// Copyright (C) 2012-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -9,8 +9,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "gfx/clip.h"
|
||||
#include "she/common/freetype_font.h"
|
||||
#include "she/common/sprite_sheet_font.h"
|
||||
#include "gfx/color.h"
|
||||
#include "she/surface.h"
|
||||
|
||||
namespace she {
|
||||
|
||||
@ -19,7 +19,7 @@ namespace {
|
||||
#define MUL_UN8(a, b, t) \
|
||||
((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
|
||||
|
||||
gfx::Color blend(const gfx::Color backdrop, gfx::Color src)
|
||||
inline gfx::Color blend(const gfx::Color backdrop, gfx::Color src)
|
||||
{
|
||||
if (gfx::geta(backdrop) == 0)
|
||||
return src;
|
||||
@ -92,145 +92,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Base>
|
||||
class GenericDrawTextSurface : public Base {
|
||||
public:
|
||||
|
||||
void drawChar(Font* font, gfx::Color fg, gfx::Color bg, int x, int y, int chr) override {
|
||||
switch (font->type()) {
|
||||
|
||||
case FontType::kSpriteSheet: {
|
||||
SpriteSheetFont* ssFont = static_cast<SpriteSheetFont*>(font);
|
||||
|
||||
gfx::Rect charBounds = ssFont->getCharBounds(chr);
|
||||
if (!charBounds.isEmpty()) {
|
||||
Surface* sheet = ssFont->getSurfaceSheet();
|
||||
SurfaceLock lock(sheet);
|
||||
this->drawColoredRgbaSurface(sheet, fg, bg, gfx::Clip(x, y, charBounds));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FontType::kTrueType: {
|
||||
// TODO avoid a temporary string
|
||||
std::wstring str;
|
||||
str.push_back(chr);
|
||||
drawString(font, fg, bg, x, y, base::to_utf8(str).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void drawString(Font* font, gfx::Color fg, gfx::Color bg, int x, int y, const std::string& str) override {
|
||||
switch (font->type()) {
|
||||
|
||||
case FontType::kSpriteSheet: {
|
||||
base::utf8_const_iterator it(str.begin()), end(str.end());
|
||||
while (it != end) {
|
||||
drawChar(font, fg, bg, x, y, *it);
|
||||
x += font->charWidth(*it);
|
||||
++it;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FontType::kTrueType: {
|
||||
FreeTypeFont* ttFont = static_cast<FreeTypeFont*>(font);
|
||||
bool antialias = ttFont->face().antialias();
|
||||
int fg_alpha = gfx::geta(fg);
|
||||
|
||||
gfx::Rect clipBounds = this->getClipBounds();
|
||||
|
||||
she::SurfaceFormatData fd;
|
||||
this->getFormat(&fd);
|
||||
|
||||
ttFont->face().forEachGlyph(
|
||||
str,
|
||||
[this, x, y, fg, fg_alpha, bg, antialias, &clipBounds, &fd](const ft::Glyph& glyph) {
|
||||
gfx::Rect origDstBounds(x + int(glyph.x),
|
||||
y + int(glyph.y),
|
||||
int(glyph.bitmap->width),
|
||||
int(glyph.bitmap->rows));
|
||||
gfx::Rect dstBounds = origDstBounds;
|
||||
dstBounds &= clipBounds;
|
||||
if (dstBounds.isEmpty())
|
||||
return;
|
||||
|
||||
int clippedRows = dstBounds.y - origDstBounds.y;
|
||||
int dst_y = dstBounds.y;
|
||||
int t;
|
||||
for (int v=0; v<dstBounds.h; ++v, ++dst_y) {
|
||||
int bit = 0;
|
||||
const uint8_t* p = glyph.bitmap->buffer
|
||||
+ (v+clippedRows)*glyph.bitmap->pitch;
|
||||
int dst_x = dstBounds.x;
|
||||
uint32_t* dst_address =
|
||||
(uint32_t*)this->getData(dst_x, dst_y);
|
||||
|
||||
// Skip first clipped pixels
|
||||
for (int u=0; u<dstBounds.x-origDstBounds.x; ++u) {
|
||||
if (antialias) {
|
||||
++p;
|
||||
}
|
||||
else {
|
||||
if (bit == 8) {
|
||||
bit = 0;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int u=0; u<dstBounds.w; ++u, ++dst_x) {
|
||||
ASSERT(clipBounds.contains(gfx::Point(dst_x, dst_y)));
|
||||
|
||||
int alpha;
|
||||
if (antialias) {
|
||||
alpha = *(p++);
|
||||
}
|
||||
else {
|
||||
alpha = ((*p) & (1 << (7 - (bit++))) ? 255: 0);
|
||||
if (bit == 8) {
|
||||
bit = 0;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t backdrop = *dst_address;
|
||||
gfx::Color backdropColor =
|
||||
gfx::rgba(
|
||||
((backdrop & fd.redMask) >> fd.redShift),
|
||||
((backdrop & fd.greenMask) >> fd.greenShift),
|
||||
((backdrop & fd.blueMask) >> fd.blueShift),
|
||||
((backdrop & fd.alphaMask) >> fd.alphaShift));
|
||||
|
||||
gfx::Color output = gfx::rgba(gfx::getr(fg),
|
||||
gfx::getg(fg),
|
||||
gfx::getb(fg),
|
||||
MUL_UN8(fg_alpha, alpha, t));
|
||||
if (gfx::geta(bg) > 0)
|
||||
output = blend(blend(backdropColor, bg), output);
|
||||
else
|
||||
output = blend(backdropColor, output);
|
||||
|
||||
*dst_address =
|
||||
((gfx::getr(output) << fd.redShift ) & fd.redMask ) |
|
||||
((gfx::getg(output) << fd.greenShift) & fd.greenMask) |
|
||||
((gfx::getb(output) << fd.blueShift ) & fd.blueMask ) |
|
||||
((gfx::geta(output) << fd.alphaShift) & fd.alphaMask);
|
||||
|
||||
++dst_address;
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace she
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SHE library
|
||||
// Copyright (C) 2012-2016 David Capello
|
||||
// Copyright (C) 2012-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -41,15 +41,11 @@ public:
|
||||
return getCharBounds(' ').h;
|
||||
}
|
||||
|
||||
int charWidth(int chr) const override {
|
||||
return getCharBounds(chr).w;
|
||||
}
|
||||
|
||||
int textLength(const std::string& str) const override {
|
||||
base::utf8_const_iterator it(str.begin()), end(str.end());
|
||||
int x = 0;
|
||||
while (it != end) {
|
||||
x += charWidth(*it);
|
||||
x += getCharBounds(*it).w;
|
||||
++it;
|
||||
}
|
||||
return x;
|
||||
|
201
src/she/draw_text.cpp
Normal file
201
src/she/draw_text.cpp
Normal file
@ -0,0 +1,201 @@
|
||||
// SHE library
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "she/draw_text.h"
|
||||
|
||||
#include "gfx/clip.h"
|
||||
#include "she/common/freetype_font.h"
|
||||
#include "she/common/generic_surface.h"
|
||||
#include "she/common/sprite_sheet_font.h"
|
||||
|
||||
namespace she {
|
||||
|
||||
gfx::Rect draw_text(Surface* surface, Font* font,
|
||||
base::utf8_const_iterator it,
|
||||
const base::utf8_const_iterator& end,
|
||||
gfx::Color fg, gfx::Color bg,
|
||||
int x, int y,
|
||||
DrawTextDelegate* delegate)
|
||||
{
|
||||
gfx::Rect textBounds;
|
||||
bool drawChar = true;
|
||||
bool moveCaret = true;
|
||||
|
||||
switch (font->type()) {
|
||||
|
||||
case FontType::kSpriteSheet: {
|
||||
SpriteSheetFont* ssFont = static_cast<SpriteSheetFont*>(font);
|
||||
while (it != end) {
|
||||
int chr = *it;
|
||||
if (delegate)
|
||||
delegate->preProcessChar(it, end, chr, fg, bg, drawChar, moveCaret);
|
||||
|
||||
if (moveCaret) {
|
||||
gfx::Rect charBounds = ssFont->getCharBounds(chr);
|
||||
gfx::Rect outCharBounds(x, y, charBounds.w, charBounds.h);
|
||||
if (delegate && !delegate->preDrawChar(outCharBounds))
|
||||
break;
|
||||
|
||||
if (!charBounds.isEmpty()) {
|
||||
if (surface && drawChar) {
|
||||
Surface* sheet = ssFont->getSurfaceSheet();
|
||||
SurfaceLock lock(sheet);
|
||||
surface->drawColoredRgbaSurface(sheet, fg, bg, gfx::Clip(x, y, charBounds));
|
||||
}
|
||||
}
|
||||
|
||||
textBounds |= outCharBounds;
|
||||
if (delegate)
|
||||
delegate->postDrawChar(outCharBounds);
|
||||
|
||||
x += charBounds.w;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FontType::kTrueType: {
|
||||
FreeTypeFont* ttFont = static_cast<FreeTypeFont*>(font);
|
||||
bool antialias = ttFont->face().antialias();
|
||||
bool done = false;
|
||||
int fg_alpha = gfx::geta(fg);
|
||||
|
||||
gfx::Rect clipBounds;
|
||||
she::SurfaceFormatData fd;
|
||||
if (surface) {
|
||||
clipBounds = surface->getClipBounds();
|
||||
surface->getFormat(&fd);
|
||||
}
|
||||
|
||||
ft::ForEachGlyph<ft::Face> feg(ttFont->face());
|
||||
while (it != end) {
|
||||
int chr = *it;
|
||||
if (delegate)
|
||||
delegate->preProcessChar(it, end, chr, fg, bg, drawChar, moveCaret);
|
||||
|
||||
if (!moveCaret) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
feg.processChar(
|
||||
chr,
|
||||
[x, y, fg, fg_alpha, bg, antialias, surface,
|
||||
&clipBounds, &textBounds, &fd, &done, delegate, drawChar]
|
||||
(const ft::Glyph& glyph) {
|
||||
gfx::Rect origDstBounds(
|
||||
x + int(glyph.startX),
|
||||
y + int(glyph.y),
|
||||
int(glyph.endX) - int(glyph.startX),
|
||||
int(glyph.bitmap->rows) ? int(glyph.bitmap->rows): 1);
|
||||
|
||||
if (delegate && !delegate->preDrawChar(origDstBounds)) {
|
||||
done = true;
|
||||
return;
|
||||
}
|
||||
origDstBounds.x = x + int(glyph.x);
|
||||
origDstBounds.w = int(glyph.bitmap->width);
|
||||
origDstBounds.h = int(glyph.bitmap->rows);
|
||||
|
||||
gfx::Rect dstBounds = origDstBounds;
|
||||
if (surface)
|
||||
dstBounds &= clipBounds;
|
||||
|
||||
if (surface && drawChar && !dstBounds.isEmpty()) {
|
||||
int clippedRows = dstBounds.y - origDstBounds.y;
|
||||
int dst_y = dstBounds.y;
|
||||
int t;
|
||||
for (int v=0; v<dstBounds.h; ++v, ++dst_y) {
|
||||
int bit = 0;
|
||||
const uint8_t* p = glyph.bitmap->buffer
|
||||
+ (v+clippedRows)*glyph.bitmap->pitch;
|
||||
int dst_x = dstBounds.x;
|
||||
uint32_t* dst_address =
|
||||
(uint32_t*)surface->getData(dst_x, dst_y);
|
||||
|
||||
// Skip first clipped pixels
|
||||
for (int u=0; u<dstBounds.x-origDstBounds.x; ++u) {
|
||||
if (antialias) {
|
||||
++p;
|
||||
}
|
||||
else {
|
||||
if (bit == 8) {
|
||||
bit = 0;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int u=0; u<dstBounds.w; ++u, ++dst_x) {
|
||||
ASSERT(clipBounds.contains(gfx::Point(dst_x, dst_y)));
|
||||
|
||||
int alpha;
|
||||
if (antialias) {
|
||||
alpha = *(p++);
|
||||
}
|
||||
else {
|
||||
alpha = ((*p) & (1 << (7 - (bit++))) ? 255: 0);
|
||||
if (bit == 8) {
|
||||
bit = 0;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t backdrop = *dst_address;
|
||||
gfx::Color backdropColor =
|
||||
gfx::rgba(
|
||||
((backdrop & fd.redMask) >> fd.redShift),
|
||||
((backdrop & fd.greenMask) >> fd.greenShift),
|
||||
((backdrop & fd.blueMask) >> fd.blueShift),
|
||||
((backdrop & fd.alphaMask) >> fd.alphaShift));
|
||||
|
||||
gfx::Color output = gfx::rgba(gfx::getr(fg),
|
||||
gfx::getg(fg),
|
||||
gfx::getb(fg),
|
||||
MUL_UN8(fg_alpha, alpha, t));
|
||||
if (gfx::geta(bg) > 0)
|
||||
output = blend(blend(backdropColor, bg), output);
|
||||
else
|
||||
output = blend(backdropColor, output);
|
||||
|
||||
*dst_address =
|
||||
((gfx::getr(output) << fd.redShift ) & fd.redMask ) |
|
||||
((gfx::getg(output) << fd.greenShift) & fd.greenMask) |
|
||||
((gfx::getb(output) << fd.blueShift ) & fd.blueMask ) |
|
||||
((gfx::geta(output) << fd.alphaShift) & fd.alphaMask);
|
||||
|
||||
++dst_address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!origDstBounds.w) origDstBounds.w = 1;
|
||||
if (!origDstBounds.h) origDstBounds.h = 1;
|
||||
textBounds |= origDstBounds;
|
||||
if (delegate)
|
||||
delegate->postDrawChar(origDstBounds);
|
||||
});
|
||||
|
||||
if (done)
|
||||
break;
|
||||
|
||||
++it;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return textBounds;
|
||||
}
|
||||
|
||||
} // namespace she
|
62
src/she/draw_text.h
Normal file
62
src/she/draw_text.h
Normal file
@ -0,0 +1,62 @@
|
||||
// SHE library
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef SHE_DRAW_TEXT_H_INCLUDED
|
||||
#define SHE_DRAW_TEXT_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/string.h"
|
||||
#include "gfx/color.h"
|
||||
#include "gfx/fwd.h"
|
||||
|
||||
namespace she {
|
||||
|
||||
class Font;
|
||||
class Surface;
|
||||
class SurfaceLock;
|
||||
|
||||
class DrawTextDelegate {
|
||||
public:
|
||||
virtual ~DrawTextDelegate() { }
|
||||
|
||||
// This is called before drawing the character. Here you can
|
||||
// modify the final painted character (e.g. for passwords you can
|
||||
// modify chr='*') and change the specific fg/bg color for this
|
||||
// char (e.g. to change the color depending if is a
|
||||
// selected/highlighted portion of text).
|
||||
virtual void preProcessChar(const base::utf8_const_iterator& it,
|
||||
const base::utf8_const_iterator& end,
|
||||
int& chr,
|
||||
gfx::Color& fg,
|
||||
gfx::Color& bg,
|
||||
bool& drawChar,
|
||||
bool& moveCaret) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
virtual bool preDrawChar(const gfx::Rect& charBounds) {
|
||||
// Returns false if the process should stop here.
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void postDrawChar(const gfx::Rect& charBounds) {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
|
||||
// The surface can be nullptr just to process the string
|
||||
// (e.g. measure how much space will use the text without drawing
|
||||
// it).
|
||||
gfx::Rect draw_text(Surface* surface, Font* font,
|
||||
base::utf8_const_iterator it,
|
||||
const base::utf8_const_iterator& end,
|
||||
gfx::Color fg, gfx::Color bg,
|
||||
int x, int y,
|
||||
DrawTextDelegate* delegate);
|
||||
|
||||
} // namespace she
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
// SHE library
|
||||
// Copyright (C) 2012-2016 David Capello
|
||||
// Copyright (C) 2012-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -24,7 +24,6 @@ namespace she {
|
||||
virtual void dispose() = 0;
|
||||
virtual FontType type() = 0;
|
||||
virtual int height() const = 0;
|
||||
virtual int charWidth(int chr) const = 0;
|
||||
virtual int textLength(const std::string& str) const = 0;
|
||||
virtual bool isScalable() const = 0;
|
||||
virtual void setSize(int size) = 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SHE library
|
||||
// Copyright (C) 2012-2016 David Capello
|
||||
// Copyright (C) 2012-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -31,7 +31,7 @@ inline SkIRect to_skia(const gfx::Rect& rc) {
|
||||
return SkIRect::MakeXYWH(rc.x, rc.y, rc.w, rc.h);
|
||||
}
|
||||
|
||||
class SkiaSurface : public GenericDrawTextSurface<Surface> {
|
||||
class SkiaSurface : public Surface {
|
||||
public:
|
||||
SkiaSurface() : m_surface(nullptr)
|
||||
, m_canvas(nullptr)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SHE library
|
||||
// Copyright (C) 2012-2016 David Capello
|
||||
// Copyright (C) 2012-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -8,6 +8,7 @@
|
||||
#define SHE_SURFACE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/string.h"
|
||||
#include "gfx/color.h"
|
||||
#include "gfx/fwd.h"
|
||||
#include "she/surface_format.h"
|
||||
@ -63,9 +64,6 @@ namespace she {
|
||||
virtual void drawRgbaSurface(const Surface* src, int dstx, int dsty) = 0;
|
||||
virtual void drawColoredRgbaSurface(const Surface* src, gfx::Color fg, gfx::Color bg, const gfx::Clip& clip) = 0;
|
||||
|
||||
virtual void drawChar(Font* font, gfx::Color fg, gfx::Color bg, int x, int y, int chr) = 0;
|
||||
virtual void drawString(Font* font, gfx::Color fg, gfx::Color bg, int x, int y, const std::string& str) = 0;
|
||||
|
||||
virtual void applyScale(int scaleFactor) = 0;
|
||||
virtual void* nativeHandle() = 0;
|
||||
};
|
||||
|
181
src/ui/entry.cpp
181
src/ui/entry.cpp
@ -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.
|
||||
@ -13,6 +13,7 @@
|
||||
#include "base/bind.h"
|
||||
#include "base/string.h"
|
||||
#include "clip/clip.h"
|
||||
#include "she/draw_text.h"
|
||||
#include "she/font.h"
|
||||
#include "she/system.h"
|
||||
#include "ui/manager.h"
|
||||
@ -29,6 +30,25 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
namespace {
|
||||
|
||||
class MeasureTextDelegate : public she::DrawTextDelegate {
|
||||
public:
|
||||
MeasureTextDelegate() { }
|
||||
|
||||
gfx::Rect bounds() const { return m_bounds; }
|
||||
|
||||
bool preDrawChar(const gfx::Rect& charBounds) override {
|
||||
m_bounds |= charBounds;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
gfx::Rect m_bounds;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Entry::Entry(const std::size_t maxsize, const char* format, ...)
|
||||
: Widget(kEntryWidget)
|
||||
, m_timer(500, this)
|
||||
@ -110,32 +130,32 @@ void Entry::hideCaret()
|
||||
|
||||
void Entry::setCaretPos(int pos)
|
||||
{
|
||||
auto utf8_begin = base::utf8_const_iterator(text().begin());
|
||||
auto utf8_end = base::utf8_const_iterator(text().end());
|
||||
gfx::Size caretSize = theme()->getEntryCaretSize(this);
|
||||
int textlen = base::utf8_length(text());
|
||||
|
||||
m_caret = MID(0, pos, textlen);
|
||||
m_scroll = MID(0, m_scroll, textlen);
|
||||
|
||||
// Backward scroll
|
||||
if (m_scroll > m_caret)
|
||||
if (m_caret < m_scroll)
|
||||
m_scroll = m_caret;
|
||||
|
||||
// Forward scroll
|
||||
--m_scroll;
|
||||
int c;
|
||||
while (true) {
|
||||
c = ++m_scroll;
|
||||
auto utf8_it = utf8_begin + MID(0, c, textlen);
|
||||
int x = bounds().x + border().left()
|
||||
- font()->charWidth(' '); // Space for the carret
|
||||
for (; utf8_it != utf8_end; ++c, ++utf8_it) {
|
||||
int ch = *utf8_it;
|
||||
x += font()->charWidth(ch);
|
||||
if (x >= bounds().x2()-border().right())
|
||||
else if (m_caret > m_scroll) {
|
||||
auto it = base::utf8_const_iterator(text().begin()) + m_scroll;
|
||||
while (m_caret > m_scroll) {
|
||||
MeasureTextDelegate delegate;
|
||||
she::draw_text(nullptr, font(), it, it+(m_caret-m_scroll),
|
||||
gfx::ColorNone, gfx::ColorNone, 0, 0,
|
||||
&delegate);
|
||||
|
||||
int x = bounds().x + border().left()
|
||||
+ delegate.bounds().w + caretSize.w;
|
||||
if (x < bounds().x2() - border().right())
|
||||
break;
|
||||
else {
|
||||
++it;
|
||||
++m_scroll;
|
||||
}
|
||||
}
|
||||
if (m_caret < c || utf8_it == utf8_end)
|
||||
break;
|
||||
}
|
||||
|
||||
m_timer.start();
|
||||
@ -356,58 +376,15 @@ bool Entry::onProcessMessage(Message* msg)
|
||||
|
||||
case kMouseMoveMessage:
|
||||
if (hasCapture()) {
|
||||
gfx::Point mousePos = static_cast<MouseMessage*>(msg)->position();
|
||||
auto utf8_begin = base::utf8_const_iterator(text().begin());
|
||||
auto utf8_end = base::utf8_const_iterator(text().end());
|
||||
int textlen = base::utf8_length(text());
|
||||
int c, x;
|
||||
|
||||
bool move = true;
|
||||
bool is_dirty = false;
|
||||
int c = getCaretFromMouse(static_cast<MouseMessage*>(msg));
|
||||
|
||||
// Backward scroll
|
||||
if (mousePos.x < bounds().x) {
|
||||
if (m_scroll > 0) {
|
||||
m_caret = --m_scroll;
|
||||
move = false;
|
||||
is_dirty = true;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
// Forward scroll
|
||||
else if (mousePos.x >= bounds().x2()) {
|
||||
if (m_scroll < textlen - getAvailableTextLength()) {
|
||||
++m_scroll;
|
||||
x = bounds().x + border().left();
|
||||
|
||||
auto utf8_it = utf8_begin + MID(0, m_scroll, textlen);
|
||||
for (c=m_scroll; utf8_it != utf8_end; ++c, ++utf8_it) {
|
||||
int ch = (c < textlen ? *utf8_it: ' ');
|
||||
|
||||
x += font()->charWidth(ch);
|
||||
if (x > bounds().x2()-border().right()) {
|
||||
c--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_caret = MID(0, c, textlen);
|
||||
move = false;
|
||||
is_dirty = true;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
c = getCaretFromMouse(static_cast<MouseMessage*>(msg));
|
||||
|
||||
if (static_cast<MouseMessage*>(msg)->left() ||
|
||||
(move && !isPosInSelection(c))) {
|
||||
if (static_cast<MouseMessage*>(msg)->left() || !isPosInSelection(c)) {
|
||||
// Move caret
|
||||
if (move) {
|
||||
if (m_caret != c) {
|
||||
m_caret = c;
|
||||
is_dirty = true;
|
||||
invalidate();
|
||||
}
|
||||
if (m_caret != c) {
|
||||
setCaretPos(c);
|
||||
is_dirty = true;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// Move selection
|
||||
@ -465,7 +442,7 @@ bool Entry::onProcessMessage(Message* msg)
|
||||
void Entry::onSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
int w =
|
||||
+ font()->charWidth('w') * MIN(m_maxsize, 6)
|
||||
+ font()->textLength("w") * MIN(m_maxsize, 6)
|
||||
+ 2*guiscale()
|
||||
+ border().width();
|
||||
|
||||
@ -509,37 +486,40 @@ gfx::Rect Entry::onGetEntryTextBounds() const
|
||||
|
||||
int Entry::getCaretFromMouse(MouseMessage* mousemsg)
|
||||
{
|
||||
base::utf8_const_iterator utf8_begin = base::utf8_const_iterator(text().begin());
|
||||
base::utf8_const_iterator utf8_end = base::utf8_const_iterator(text().end());
|
||||
int caret = m_caret;
|
||||
int mouseX = mousemsg->position().x;
|
||||
if (mouseX < bounds().x+border().left()) {
|
||||
// Scroll to the left
|
||||
return MAX(0, m_scroll-1);
|
||||
}
|
||||
|
||||
int textlen = base::utf8_length(text());
|
||||
gfx::Rect bounds = getEntryTextBounds().offset(this->bounds().origin());
|
||||
auto it = base::utf8_const_iterator(text().begin()) + m_scroll;
|
||||
int i = MIN(m_scroll, textlen);
|
||||
for (; i<textlen; ++i) {
|
||||
MeasureTextDelegate delegate;
|
||||
she::draw_text(nullptr, font(), it, it+(i-m_scroll),
|
||||
gfx::ColorNone, gfx::ColorNone, 0, 0,
|
||||
&delegate);
|
||||
|
||||
int mx = mousemsg->position().x;
|
||||
mx = MID(bounds.x, mx, bounds.x2()-1);
|
||||
int x = bounds().x + border().left() + delegate.bounds().w;
|
||||
|
||||
int x = bounds.x;
|
||||
|
||||
auto utf8_it = utf8_begin + MID(0, m_scroll, textlen);
|
||||
int c = m_scroll;
|
||||
for (; utf8_it != utf8_end; ++c, ++utf8_it) {
|
||||
int w = font()->charWidth(*utf8_it);
|
||||
if (x+w >= bounds.x2()-border().right())
|
||||
break;
|
||||
if ((mx >= x) && (mx < x+w)) {
|
||||
caret = c;
|
||||
break;
|
||||
if (mouseX > bounds().x2() - border().right()) {
|
||||
if (x >= bounds().x2() - border().right()) {
|
||||
// Scroll to the right
|
||||
break;
|
||||
}
|
||||
}
|
||||
x += w;
|
||||
}
|
||||
|
||||
if (utf8_it == utf8_end) {
|
||||
if ((mx >= x) && (mx < bounds.x2())) {
|
||||
caret = c;
|
||||
else {
|
||||
if (x > mouseX) {
|
||||
// Previous char is the selected one
|
||||
if (i > m_scroll)
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MID(0, caret, textlen);
|
||||
return MID(0, i, textlen);
|
||||
}
|
||||
|
||||
void Entry::executeCmd(EntryCmd cmd, int unicodeChar, bool shift_pressed)
|
||||
@ -560,6 +540,16 @@ void Entry::executeCmd(EntryCmd cmd, int unicodeChar, bool shift_pressed)
|
||||
text.erase(selbeg, selend-selbeg+1);
|
||||
|
||||
m_caret = selbeg;
|
||||
|
||||
// We set the caret to the beginning of the erased selection,
|
||||
// needed to show the first inserted character in case
|
||||
// m_scroll > m_caret. E.g. we select all text and insert a
|
||||
// new character to replace the whole text, the new inserted
|
||||
// character makes m_caret=1, so m_scroll will be 1 too, but
|
||||
// we need to make m_scroll=0 to show the new inserted char.)
|
||||
// In this way, we first ensure a m_scroll value enough to
|
||||
// show the new inserted character.
|
||||
setCaretPos(m_caret);
|
||||
}
|
||||
|
||||
// put the character
|
||||
@ -782,11 +772,6 @@ void Entry::backwardWord()
|
||||
m_caret = 0;
|
||||
}
|
||||
|
||||
int Entry::getAvailableTextLength()
|
||||
{
|
||||
return clientChildrenBounds().w / font()->charWidth('w');
|
||||
}
|
||||
|
||||
bool Entry::isPosInSelection(int pos)
|
||||
{
|
||||
return (pos >= MIN(m_caret, m_select) && pos <= MAX(m_caret, m_select));
|
||||
|
@ -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.
|
||||
@ -84,7 +84,6 @@ namespace ui {
|
||||
void executeCmd(EntryCmd cmd, int ascii, bool shift_pressed);
|
||||
void forwardWord();
|
||||
void backwardWord();
|
||||
int getAvailableTextLength();
|
||||
bool isPosInSelection(int pos);
|
||||
void showEditPopupMenu(const gfx::Point& pt);
|
||||
|
||||
|
@ -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,7 @@
|
||||
#include "gfx/region.h"
|
||||
#include "gfx/size.h"
|
||||
#include "she/display.h"
|
||||
#include "she/draw_text.h"
|
||||
#include "she/font.h"
|
||||
#include "she/surface.h"
|
||||
#include "she/system.h"
|
||||
@ -200,95 +201,142 @@ void Graphics::setFont(she::Font* font)
|
||||
m_font = font;
|
||||
}
|
||||
|
||||
void Graphics::drawChar(int chr, gfx::Color fg, gfx::Color bg, int x, int y)
|
||||
void Graphics::drawText(base::utf8_const_iterator it,
|
||||
const base::utf8_const_iterator& end,
|
||||
gfx::Color fg, gfx::Color bg,
|
||||
const gfx::Point& origPt,
|
||||
she::DrawTextDelegate* delegate)
|
||||
{
|
||||
dirty(gfx::Rect(gfx::Point(m_dx+x, m_dy+y), measureChar(chr)));
|
||||
gfx::Point pt(m_dx+origPt.x, m_dy+origPt.y);
|
||||
|
||||
she::SurfaceLock lock(m_surface);
|
||||
m_surface->drawChar(m_font, fg, bg, m_dx+x, m_dy+y, chr);
|
||||
gfx::Rect textBounds =
|
||||
she::draw_text(m_surface, m_font, it, end, fg, bg, pt.x, pt.y, delegate);
|
||||
|
||||
dirty(gfx::Rect(pt.x, pt.y, textBounds.w, textBounds.h));
|
||||
}
|
||||
|
||||
void Graphics::drawString(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& ptOrig)
|
||||
void Graphics::drawText(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& pt)
|
||||
{
|
||||
gfx::Point pt(m_dx+ptOrig.x, m_dy+ptOrig.y);
|
||||
dirty(gfx::Rect(pt.x, pt.y, m_font->textLength(str), m_font->height()));
|
||||
|
||||
she::SurfaceLock lock(m_surface);
|
||||
m_surface->drawString(m_font, fg, bg, pt.x, pt.y, str);
|
||||
drawText(base::utf8_const_iterator(str.begin()),
|
||||
base::utf8_const_iterator(str.end()),
|
||||
fg, bg, pt, nullptr);
|
||||
}
|
||||
|
||||
void Graphics::drawUIString(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& pt,
|
||||
bool drawUnderscore)
|
||||
{
|
||||
she::SurfaceLock lock(m_surface);
|
||||
base::utf8_const_iterator it(str.begin()), end(str.end());
|
||||
int x = m_dx+pt.x;
|
||||
int y = m_dy+pt.y;
|
||||
int underscored_x = 0;
|
||||
int underscored_w = -1;
|
||||
namespace {
|
||||
|
||||
while (it != end) {
|
||||
if (*it == '&') {
|
||||
++it;
|
||||
if (it != end && *it != '&') {
|
||||
underscored_x = x;
|
||||
underscored_w = m_font->charWidth(*it);
|
||||
class DrawUITextDelegate : public she::DrawTextDelegate {
|
||||
public:
|
||||
DrawUITextDelegate(she::Surface* surface,
|
||||
she::Font* font, const bool drawUnderscore)
|
||||
: m_surface(surface)
|
||||
, m_font(font)
|
||||
, m_drawUnderscore(drawUnderscore)
|
||||
, m_underscoreNext(false) {
|
||||
}
|
||||
|
||||
gfx::Rect bounds() const { return m_bounds; }
|
||||
|
||||
void preProcessChar(const base::utf8_const_iterator& it,
|
||||
const base::utf8_const_iterator& end,
|
||||
int& chr,
|
||||
gfx::Color& fg,
|
||||
gfx::Color& bg,
|
||||
bool& drawChar,
|
||||
bool& moveCaret) override {
|
||||
if (m_underscoreNext)
|
||||
m_underscoreColor = fg;
|
||||
|
||||
if (!m_surface)
|
||||
drawChar = false;
|
||||
|
||||
moveCaret = true;
|
||||
if (chr == '&') { // TODO change this with other character, maybe '_' or configurable
|
||||
auto it2 = it;
|
||||
++it2;
|
||||
if (it2 != end && *it2 != '&') {
|
||||
m_underscoreNext = true;
|
||||
moveCaret = false;
|
||||
}
|
||||
}
|
||||
m_surface->drawChar(m_font, fg, bg, x, y, *it);
|
||||
x += m_font->charWidth(*it);
|
||||
++it;
|
||||
}
|
||||
|
||||
y += m_font->height();
|
||||
if (drawUnderscore && underscored_w > 0) {
|
||||
m_surface->fillRect(fg,
|
||||
gfx::Rect(underscored_x, y, underscored_w, guiscale()));
|
||||
y += guiscale();
|
||||
bool preDrawChar(const gfx::Rect& charBounds) override {
|
||||
m_bounds |= charBounds;
|
||||
return true;
|
||||
}
|
||||
|
||||
dirty(gfx::Rect(pt, gfx::Point(x, y)));
|
||||
void postDrawChar(const gfx::Rect& charBounds) override {
|
||||
if (m_underscoreNext) {
|
||||
m_underscoreNext = false;
|
||||
if (m_drawUnderscore) {
|
||||
// TODO underscore height = guiscale() should be configurable from ui::Theme
|
||||
int dy = 0;
|
||||
if (m_font->type() == she::FontType::kTrueType) // TODO use other method to locate the underline
|
||||
dy += guiscale();
|
||||
gfx::Rect underscoreBounds(charBounds.x, charBounds.y+charBounds.h+dy,
|
||||
charBounds.w, guiscale());
|
||||
m_surface->fillRect(m_underscoreColor, underscoreBounds);
|
||||
m_bounds |= underscoreBounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
she::Surface* m_surface;
|
||||
she::Font* m_font;
|
||||
bool m_drawUnderscore;
|
||||
bool m_underscoreNext;
|
||||
gfx::Color m_underscoreColor;
|
||||
gfx::Rect m_bounds;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void Graphics::drawAlignedUIString(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Rect& rc, int align)
|
||||
void Graphics::drawUIText(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& pt,
|
||||
bool drawUnderscore)
|
||||
{
|
||||
she::SurfaceLock lock(m_surface);
|
||||
int x = m_dx+pt.x;
|
||||
int y = m_dy+pt.y;
|
||||
|
||||
DrawUITextDelegate delegate(m_surface, m_font, drawUnderscore);
|
||||
she::draw_text(m_surface, m_font,
|
||||
base::utf8_const_iterator(str.begin()),
|
||||
base::utf8_const_iterator(str.end()),
|
||||
fg, bg, x, y, &delegate);
|
||||
|
||||
dirty(delegate.bounds());
|
||||
}
|
||||
|
||||
void Graphics::drawAlignedUIText(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Rect& rc, int align)
|
||||
{
|
||||
doUIStringAlgorithm(str, fg, bg, rc, align, true);
|
||||
}
|
||||
|
||||
gfx::Size Graphics::measureChar(int chr)
|
||||
gfx::Size Graphics::measureUIText(const std::string& str)
|
||||
{
|
||||
return gfx::Size(
|
||||
m_font->charWidth(chr),
|
||||
m_font->height());
|
||||
}
|
||||
|
||||
gfx::Size Graphics::measureUIString(const std::string& str)
|
||||
{
|
||||
return gfx::Size(
|
||||
Graphics::measureUIStringLength(str, m_font),
|
||||
Graphics::measureUITextLength(str, m_font),
|
||||
m_font->height());
|
||||
}
|
||||
|
||||
// static
|
||||
int Graphics::measureUIStringLength(const std::string& str, she::Font* font)
|
||||
int Graphics::measureUITextLength(const std::string& str, she::Font* font)
|
||||
{
|
||||
base::utf8_const_iterator it(str.begin()), end(str.end());
|
||||
int length = 0;
|
||||
|
||||
while (it != end) {
|
||||
if (*it == '&')
|
||||
++it;
|
||||
|
||||
length += font->charWidth(*it);
|
||||
++it;
|
||||
}
|
||||
|
||||
return length;
|
||||
DrawUITextDelegate delegate(nullptr, font, false);
|
||||
she::draw_text(nullptr, font,
|
||||
base::utf8_const_iterator(str.begin()),
|
||||
base::utf8_const_iterator(str.end()),
|
||||
gfx::ColorNone, gfx::ColorNone, 0, 0,
|
||||
&delegate);
|
||||
return delegate.bounds().w;
|
||||
}
|
||||
|
||||
gfx::Size Graphics::fitString(const std::string& str, int maxWidth, int align)
|
||||
{
|
||||
return doUIStringAlgorithm(str, gfx::ColorNone, gfx::ColorNone, gfx::Rect(0, 0, maxWidth, 0), align, false);
|
||||
return doUIStringAlgorithm(str, gfx::ColorNone, gfx::ColorNone,
|
||||
gfx::Rect(0, 0, maxWidth, 0), align, false);
|
||||
}
|
||||
|
||||
gfx::Size Graphics::doUIStringAlgorithm(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Rect& rc, int align, bool draw)
|
||||
@ -366,7 +414,7 @@ gfx::Size Graphics::doUIStringAlgorithm(const std::string& str, gfx::Color fg, g
|
||||
else
|
||||
xout = pt.x;
|
||||
|
||||
drawString(line, fg, bg, gfx::Point(xout, pt.y));
|
||||
drawText(line, fg, bg, gfx::Point(xout, pt.y));
|
||||
|
||||
if (!gfx::is_transparent(bg))
|
||||
fillAreaBetweenRects(bg,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2001-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.
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
#include "base/shared_ptr.h"
|
||||
#include "base/string.h"
|
||||
#include "gfx/color.h"
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/rect.h"
|
||||
@ -22,6 +23,7 @@ namespace gfx {
|
||||
}
|
||||
|
||||
namespace she {
|
||||
class DrawTextDelegate;
|
||||
class Font;
|
||||
class Surface;
|
||||
}
|
||||
@ -79,14 +81,20 @@ namespace ui {
|
||||
she::Font* font() { return m_font; }
|
||||
void setFont(she::Font* font);
|
||||
|
||||
void drawChar(int chr, gfx::Color fg, gfx::Color bg, int x, int y);
|
||||
void drawString(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& pt);
|
||||
void drawUIString(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& pt, bool drawUnderscore = true);
|
||||
void drawAlignedUIString(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Rect& rc, int align);
|
||||
void drawText(base::utf8_const_iterator it,
|
||||
const base::utf8_const_iterator& end,
|
||||
gfx::Color fg, gfx::Color bg, const gfx::Point& pt,
|
||||
she::DrawTextDelegate* delegate);
|
||||
|
||||
gfx::Size measureChar(int chr);
|
||||
gfx::Size measureUIString(const std::string& str);
|
||||
static int measureUIStringLength(const std::string& str, she::Font* font);
|
||||
void drawText(const std::string& str, gfx::Color fg, gfx::Color bg,
|
||||
const gfx::Point& pt);
|
||||
void drawUIText(const std::string& str, gfx::Color fg, gfx::Color bg,
|
||||
const gfx::Point& pt, bool drawUnderscore = true);
|
||||
void drawAlignedUIText(const std::string& str, gfx::Color fg, gfx::Color bg,
|
||||
const gfx::Rect& rc, int align);
|
||||
|
||||
gfx::Size measureUIText(const std::string& str);
|
||||
static int measureUITextLength(const std::string& str, she::Font* font);
|
||||
gfx::Size fitString(const std::string& str, int maxWidth, int align);
|
||||
|
||||
private:
|
||||
|
@ -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.
|
||||
@ -133,10 +133,10 @@ bool IntEntry::onProcessMessage(Message* msg)
|
||||
|
||||
void IntEntry::onSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
int min_w = font()->textLength(m_slider.convertValueToText(m_min));
|
||||
int min_w = font()->textLength(m_slider.convertValueToText(m_min) + "%");
|
||||
int max_w = font()->textLength(m_slider.convertValueToText(m_max));
|
||||
|
||||
int w = MAX(min_w, max_w) + font()->charWidth('%');
|
||||
int w = MAX(min_w, max_w);
|
||||
int h = textHeight();
|
||||
|
||||
w += border().width();
|
||||
|
@ -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.
|
||||
@ -203,7 +203,7 @@ void drawTextBox(Graphics* g, Widget* widget,
|
||||
else // Left align
|
||||
xout = x;
|
||||
|
||||
g->drawString(beg, fg, gfx::ColorNone, gfx::Point(xout, y));
|
||||
g->drawText(beg, fg, gfx::ColorNone, gfx::Point(xout, y));
|
||||
}
|
||||
|
||||
if (w)
|
||||
|
@ -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.
|
||||
@ -8,6 +8,7 @@
|
||||
#define UI_THEME_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "gfx/size.h"
|
||||
#include "ui/base.h"
|
||||
#include "ui/cursor_type.h"
|
||||
|
||||
@ -43,6 +44,7 @@ namespace ui {
|
||||
virtual void getWindowMask(Widget* widget, gfx::Region& region) = 0;
|
||||
virtual void setDecorativeWidgetBounds(Widget* widget) = 0;
|
||||
virtual int getScrollbarSize() = 0;
|
||||
virtual gfx::Size getEntryCaretSize(Widget* widget) = 0;
|
||||
|
||||
virtual void paintDesktop(PaintEvent& ev) = 0;
|
||||
virtual void paintBox(PaintEvent& ev) = 0;
|
||||
|
@ -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.
|
||||
@ -754,7 +754,7 @@ void Widget::getDrawableRegion(gfx::Region& region, DrawableRegionFlags flags)
|
||||
|
||||
int Widget::textWidth() const
|
||||
{
|
||||
return Graphics::measureUIStringLength(text().c_str(), font());
|
||||
return Graphics::measureUITextLength(text().c_str(), font());
|
||||
}
|
||||
|
||||
int Widget::textHeight() const
|
||||
|
Loading…
x
Reference in New Issue
Block a user