aseprite/src/app/ui/font_popup.cpp

234 lines
5.7 KiB
C++
Raw Normal View History

// Aseprite
// Copyright (C) 2001-2018 David Capello
//
2016-08-27 04:02:58 +08:00
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/font_popup.h"
#include "app/commands/cmd_set_palette.h"
#include "app/commands/commands.h"
#include "app/console.h"
#include "app/font_path.h"
#include "app/match_words.h"
#include "app/ui/search_entry.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui_context.h"
#include "app/util/freetype_utils.h"
#include "base/bind.h"
#include "base/fs.h"
#include "base/string.h"
2018-08-09 23:58:43 +08:00
#include "doc/conversion_to_surface.h"
#include "doc/image.h"
2015-11-04 23:17:30 +08:00
#include "doc/image_ref.h"
2018-08-09 23:58:43 +08:00
#include "os/surface.h"
#include "os/system.h"
#include "ui/box.h"
#include "ui/button.h"
#include "ui/graphics.h"
#include "ui/listitem.h"
#include "ui/paint_event.h"
2015-12-04 08:50:05 +08:00
#include "ui/size_hint_event.h"
#include "ui/theme.h"
#include "ui/view.h"
#include "font_popup.xml.h"
#ifdef _WIN32
#include <shlobj.h>
#include <windows.h>
#endif
2015-11-04 23:17:30 +08:00
#include <map>
namespace app {
using namespace ui;
2015-11-04 23:17:30 +08:00
static std::map<std::string, doc::ImageRef> g_thumbnails;
class FontItem : public ListItem {
public:
2015-10-17 04:00:10 +08:00
FontItem(const std::string& fn)
: ListItem(base::get_file_title(fn))
2015-11-04 23:17:30 +08:00
, m_image(g_thumbnails[fn])
, m_filename(fn) {
2015-10-17 04:00:10 +08:00
}
const std::string& filename() const {
return m_filename;
}
private:
void onPaint(PaintEvent& ev) override {
ListItem::onPaint(ev);
if (m_image) {
Graphics* g = ev.graphics();
2018-08-09 23:58:43 +08:00
os::Surface* sur = os::instance()->createRgbaSurface(m_image->width(),
m_image->height());
convert_image_to_surface(
m_image.get(), nullptr, sur,
0, 0, 0, 0, m_image->width(), m_image->height());
g->drawRgbaSurface(sur, textWidth()+4, 0);
sur->dispose();
}
}
2015-12-04 08:50:05 +08:00
void onSizeHint(SizeHintEvent& ev) override {
ListItem::onSizeHint(ev);
if (m_image) {
2015-12-04 08:50:05 +08:00
gfx::Size sz = ev.sizeHint();
ev.setSizeHint(
sz.w + 4 + m_image->width(),
MAX(sz.h, m_image->height()));
}
}
void onSelect(bool selected) override {
if (!selected || m_image)
2015-11-04 23:17:30 +08:00
return;
ListBox* listbox = static_cast<ListBox*>(parent());
if (!listbox)
return;
app::skin::SkinTheme* theme = app::skin::SkinTheme::instance();
gfx::Color color = theme->colors.text();
try {
m_image.reset(
render_text(
2015-10-17 04:00:10 +08:00
m_filename, 16,
"ABCDEabcde", // TODO custom text
doc::rgba(gfx::getr(color),
gfx::getg(color),
gfx::getb(color),
gfx::geta(color)),
true)); // antialias
View* view = View::getView(listbox);
view->updateView();
listbox->makeChildVisible(this);
2015-11-04 23:17:30 +08:00
// Save the thumbnail for future FontPopups
g_thumbnails[m_filename] = m_image;
}
catch (const std::exception&) {
// Ignore errors
}
}
private:
2015-11-04 23:17:30 +08:00
doc::ImageRef m_image;
2015-10-17 04:00:10 +08:00
std::string m_filename;
};
FontPopup::FontPopup()
: PopupWindow("Fonts",
2015-12-06 02:56:32 +08:00
ClickBehavior::CloseOnClickInOtherWindow,
EnterBehavior::DoNothingOnEnter)
, m_popup(new gen::FontPopup())
{
setAutoRemap(false);
setBorder(gfx::Border(4*guiscale()));
addChild(m_popup);
m_popup->search()->Change.connect(base::Bind<void>(&FontPopup::onSearchChange, this));
m_popup->loadFont()->Click.connect(base::Bind<void>(&FontPopup::onLoadFont, this));
m_listBox.setFocusMagnet(true);
m_listBox.Change.connect(base::Bind<void>(&FontPopup::onChangeFont, this));
m_listBox.DoubleClickItem.connect(base::Bind<void>(&FontPopup::onLoadFont, this));
m_popup->view()->attachToView(&m_listBox);
base::paths fontDirs;
get_font_dirs(fontDirs);
2015-10-17 04:00:10 +08:00
// Create a list of fullpaths to every font found in all font
// directories (fontDirs)
base::paths files;
for (const auto& fontDir : fontDirs) {
for (const auto& file : base::list_files(fontDir)) {
std::string fullpath = base::join_path(fontDir, file);
if (base::is_file(fullpath))
files.push_back(fullpath);
}
2015-10-17 04:00:10 +08:00
}
// Sort all files by "file title"
std::sort(
files.begin(), files.end(),
[](const std::string& a, const std::string& b){
return base::utf8_icmp(base::get_file_title(a), base::get_file_title(b)) < 0;
});
// Create one FontItem for each font
for (auto& file : files) {
2017-03-15 22:41:10 +08:00
std::string ext = base::string_to_lower(base::get_file_extension(file));
if (ext == "ttf" || ext == "ttc" ||
ext == "otf" || ext == "dfont")
2015-10-17 04:00:10 +08:00
m_listBox.addChild(new FontItem(file));
}
if (m_listBox.children().empty())
m_listBox.addChild(new ListItem("No system fonts were found"));
}
void FontPopup::showPopup(const gfx::Rect& bounds)
{
m_popup->loadFont()->setEnabled(false);
m_listBox.selectChild(NULL);
moveWindow(bounds);
// Setup the hot-region
setHotRegion(gfx::Region(gfx::Rect(bounds).enlarge(32 * guiscale())));
openWindow();
}
void FontPopup::onSearchChange()
{
std::string searchText = m_popup->search()->text();
Widget* firstItem = nullptr;
MatchWords match(searchText);
for (auto child : m_listBox.children()) {
bool visible = match(child->text());
if (visible && !firstItem)
firstItem = child;
child->setVisible(visible);
}
m_listBox.selectChild(firstItem);
layout();
}
void FontPopup::onChangeFont()
{
m_popup->loadFont()->setEnabled(true);
}
void FontPopup::onLoadFont()
{
2015-10-17 04:00:10 +08:00
FontItem* child = dynamic_cast<FontItem*>(m_listBox.getSelectedChild());
if (!child)
return;
2015-10-17 04:00:10 +08:00
std::string filename = child->filename();
if (base::is_file(filename))
Load(filename); // Fire Load signal
closeWindow(nullptr);
}
} // namespace app