2015-10-16 05:16:16 +08:00
|
|
|
// Aseprite
|
|
|
|
// Copyright (C) 2001-2015 David Capello
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License version 2 as
|
|
|
|
// published by the Free Software Foundation.
|
|
|
|
|
|
|
|
#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/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/path.h"
|
|
|
|
#include "base/string.h"
|
|
|
|
#include "base/unique_ptr.h"
|
|
|
|
#include "doc/conversion_she.h"
|
|
|
|
#include "doc/image.h"
|
2015-11-04 23:17:30 +08:00
|
|
|
#include "doc/image_ref.h"
|
2015-10-16 05:16:16 +08:00
|
|
|
#include "she/surface.h"
|
|
|
|
#include "she/system.h"
|
|
|
|
#include "ui/box.h"
|
|
|
|
#include "ui/button.h"
|
|
|
|
#include "ui/preferred_size_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-10-20 03:41:14 +08:00
|
|
|
#include <queue>
|
2015-11-04 23:17:30 +08:00
|
|
|
#include <map>
|
2015-10-20 03:41:14 +08:00
|
|
|
|
2015-10-16 05:16:16 +08:00
|
|
|
namespace app {
|
|
|
|
|
|
|
|
using namespace ui;
|
|
|
|
|
2015-11-04 23:17:30 +08:00
|
|
|
static std::map<std::string, doc::ImageRef> g_thumbnails;
|
|
|
|
|
2015-10-16 05:16:16 +08:00
|
|
|
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;
|
2015-10-16 05:16:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void onPaint(PaintEvent& ev) override {
|
2015-10-17 05:52:52 +08:00
|
|
|
ListItem::onPaint(ev);
|
|
|
|
|
|
|
|
if (m_image) {
|
2015-10-16 05:16:16 +08:00
|
|
|
Graphics* g = ev.getGraphics();
|
|
|
|
she::Surface* sur = she::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());
|
|
|
|
|
2015-10-17 05:52:52 +08:00
|
|
|
g->drawRgbaSurface(sur, getTextWidth()+4, 0);
|
|
|
|
sur->dispose();
|
2015-10-16 05:16:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void onPreferredSize(PreferredSizeEvent& ev) override {
|
2015-10-17 05:52:52 +08:00
|
|
|
ListItem::onPreferredSize(ev);
|
|
|
|
if (m_image) {
|
|
|
|
gfx::Size sz = ev.getPreferredSize();
|
|
|
|
ev.setPreferredSize(
|
|
|
|
sz.w + 4 + m_image->width(),
|
|
|
|
MAX(sz.h, m_image->height()));
|
|
|
|
}
|
2015-10-16 05:16:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void onSelect() override {
|
2015-11-04 23:17:30 +08:00
|
|
|
if (m_image)
|
|
|
|
return;
|
|
|
|
|
2015-10-17 05:51:35 +08:00
|
|
|
ListBox* listbox = static_cast<ListBox*>(getParent());
|
|
|
|
if (!listbox)
|
2015-10-16 05:16:16 +08:00
|
|
|
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,
|
2015-10-17 05:52:52 +08:00
|
|
|
"ABCDEabcde", // TODO custom text
|
2015-10-16 05:16:16 +08:00
|
|
|
doc::rgba(gfx::getr(color),
|
|
|
|
gfx::getg(color),
|
|
|
|
gfx::getb(color),
|
2015-12-02 02:46:21 +08:00
|
|
|
gfx::geta(color)),
|
|
|
|
true)); // antialias
|
2015-10-16 05:16:16 +08:00
|
|
|
|
2015-10-17 05:51:35 +08:00
|
|
|
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;
|
2015-10-16 05:16:16 +08:00
|
|
|
}
|
2015-10-30 03:18:51 +08:00
|
|
|
catch (const std::exception&) {
|
2015-10-17 05:52:52 +08:00
|
|
|
// Ignore errors
|
2015-10-16 05:16:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2015-10-16 05:16:16 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
FontPopup::FontPopup()
|
2015-10-20 02:32:44 +08:00
|
|
|
: PopupWindow("Fonts",
|
|
|
|
kCloseOnClickInOtherWindow,
|
|
|
|
kDoNothingOnEnter)
|
2015-10-16 05:16:16 +08:00
|
|
|
, m_popup(new gen::FontPopup())
|
|
|
|
{
|
|
|
|
setAutoRemap(false);
|
|
|
|
setBorder(gfx::Border(4*guiscale()));
|
|
|
|
|
|
|
|
addChild(m_popup);
|
|
|
|
|
|
|
|
m_popup->loadFont()->Click.connect(Bind<void>(&FontPopup::onLoadFont, this));
|
2015-10-20 02:32:44 +08:00
|
|
|
m_listBox.setFocusMagnet(true);
|
2015-10-16 05:16:16 +08:00
|
|
|
m_listBox.Change.connect(Bind<void>(&FontPopup::onChangeFont, this));
|
|
|
|
m_listBox.DoubleClickItem.connect(Bind<void>(&FontPopup::onLoadFont, this));
|
|
|
|
|
|
|
|
m_popup->view()->attachToView(&m_listBox);
|
|
|
|
|
2015-10-20 03:41:14 +08:00
|
|
|
std::queue<std::string> fontDirs;
|
2015-10-16 05:16:16 +08:00
|
|
|
#if _WIN32
|
|
|
|
{
|
|
|
|
std::vector<wchar_t> buf(MAX_PATH);
|
|
|
|
HRESULT hr = SHGetFolderPath(NULL, CSIDL_FONTS, NULL,
|
|
|
|
SHGFP_TYPE_DEFAULT, &buf[0]);
|
|
|
|
if (hr == S_OK) {
|
2015-10-20 03:41:14 +08:00
|
|
|
fontDirs.push(base::to_utf8(&buf[0]));
|
2015-10-16 05:16:16 +08:00
|
|
|
}
|
|
|
|
}
|
2015-10-16 05:33:13 +08:00
|
|
|
#elif __APPLE__
|
|
|
|
{
|
2015-10-20 03:41:14 +08:00
|
|
|
fontDirs.push("/System/Library/Fonts/");
|
|
|
|
fontDirs.push("/Library/Fonts");
|
|
|
|
fontDirs.push("~/Library/Fonts");
|
|
|
|
}
|
|
|
|
#else // Unix-like
|
|
|
|
{
|
|
|
|
fontDirs.push("/usr/share/fonts");
|
|
|
|
fontDirs.push("/usr/local/share/fonts");
|
|
|
|
fontDirs.push("~/.fonts");
|
2015-10-16 05:33:13 +08:00
|
|
|
}
|
2015-10-16 05:16:16 +08:00
|
|
|
#endif
|
|
|
|
|
2015-10-17 04:00:10 +08:00
|
|
|
// Create a list of fullpaths to every font found in all font
|
|
|
|
// directories (fontDirs)
|
|
|
|
std::vector<std::string> files;
|
2015-10-20 03:41:14 +08:00
|
|
|
while (!fontDirs.empty()) {
|
|
|
|
std::string fontDir = fontDirs.front();
|
|
|
|
fontDirs.pop();
|
|
|
|
|
2015-10-17 04:00:10 +08:00
|
|
|
auto fontDirFiles = base::list_files(fontDir);
|
2015-10-20 03:41:14 +08:00
|
|
|
for (const auto& file : fontDirFiles) {
|
|
|
|
std::string fullpath = base::join_path(fontDir, file);
|
|
|
|
if (base::is_directory(fullpath))
|
|
|
|
fontDirs.push(fullpath); // Add subdirectory
|
|
|
|
else
|
|
|
|
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) {
|
|
|
|
if (base::string_to_lower(base::get_file_extension(file)) == "ttf")
|
|
|
|
m_listBox.addChild(new FontItem(file));
|
2015-10-16 05:16:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m_listBox.getChildren().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::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());
|
2015-10-16 05:16:16 +08:00
|
|
|
if (!child)
|
|
|
|
return;
|
|
|
|
|
2015-10-17 04:00:10 +08:00
|
|
|
std::string filename = child->filename();
|
2015-10-16 05:16:16 +08:00
|
|
|
if (base::is_file(filename))
|
|
|
|
Load(filename); // Fire Load signal
|
|
|
|
|
|
|
|
closeWindow(nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace app
|