mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-30 15:32:38 +00:00
Add way to mix spritesheet+truetype fonts
This commit is contained in:
parent
776566463b
commit
867ab891bf
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
data/fonts/aseprite_font.png
Normal file
BIN
data/fonts/aseprite_font.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
26
data/fonts/fonts.xml
Normal file
26
data/fonts/fonts.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<fonts>
|
||||
<!-- Preset fonts that can be used by all themes -->
|
||||
|
||||
<font name="Arial"
|
||||
type="truetype"
|
||||
file="Arial.ttf" />
|
||||
|
||||
<font name="Arial Unicode"
|
||||
type="truetype"
|
||||
file_win="ARIALUNI.TTF"
|
||||
file_mac="Arial Unicode.ttf" />
|
||||
|
||||
<font name="Aseprite"
|
||||
type="spritesheet"
|
||||
file="aseprite_font.png">
|
||||
<fallback font="Arial Unicode" size="8" />
|
||||
</font>
|
||||
|
||||
<font name="Aseprite Mini"
|
||||
type="spritesheet"
|
||||
file="aseprite_mini.png">
|
||||
<fallback font="Arial Unicode" size="6" />
|
||||
</font>
|
||||
|
||||
</fonts>
|
Binary file not shown.
Before Width: | Height: | Size: 9.6 KiB |
@ -3,6 +3,11 @@
|
||||
author="Ilija Melentijevic & David Capello"
|
||||
url="http://ilkke.blogspot.com/">
|
||||
|
||||
<fonts>
|
||||
<font id="default" font="Aseprite" />
|
||||
<font id="mini" font="Aseprite Mini" />
|
||||
</fonts>
|
||||
|
||||
<dimensions>
|
||||
<dim id="scrollbar_size" value="12" />
|
||||
<dim id="mini_scrollbar_size" value="6" />
|
||||
|
@ -89,6 +89,20 @@ include_directories(${CMAKE_BINARY_DIR}/third_party/cmark)
|
||||
######################################################################
|
||||
# app-lib target
|
||||
|
||||
# These specific-platform files should be in an external library
|
||||
# (e.g. "base" or "she").
|
||||
set(app_platform_files)
|
||||
if(WIN32)
|
||||
set(app_platform_files
|
||||
font_path_win32.cpp)
|
||||
elseif(APPLE)
|
||||
set(app_platform_files
|
||||
font_path_osx.mm)
|
||||
else()
|
||||
set(app_platform_files
|
||||
font_path_linux.cpp)
|
||||
endif()
|
||||
|
||||
set(data_recovery_files)
|
||||
if(NOT ENABLE_TRIAL_MODE)
|
||||
set(data_recovery_files
|
||||
@ -356,6 +370,7 @@ add_library(app-lib
|
||||
file_system.cpp
|
||||
filename_formatter.cpp
|
||||
flatten.cpp
|
||||
font_path.cpp
|
||||
gui_xml.cpp
|
||||
i18n/strings.cpp
|
||||
ini_file.cpp
|
||||
@ -455,6 +470,7 @@ add_library(app-lib
|
||||
ui/search_entry.cpp
|
||||
ui/select_accelerator.cpp
|
||||
ui/skin/button_icon_impl.cpp
|
||||
ui/skin/font_data.cpp
|
||||
ui/skin/skin_part.cpp
|
||||
ui/skin/skin_property.cpp
|
||||
ui/skin/skin_slider_property.cpp
|
||||
@ -490,6 +506,7 @@ add_library(app-lib
|
||||
widget_loader.cpp
|
||||
xml_document.cpp
|
||||
xml_exception.cpp
|
||||
${app_platform_files}
|
||||
${data_recovery_files}
|
||||
${scripting_files}
|
||||
${generated_files})
|
||||
|
32
src/app/font_path.cpp
Normal file
32
src/app/font_path.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// 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/font_path.h"
|
||||
|
||||
#include "base/fs.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
std::string find_font(const std::string& filename)
|
||||
{
|
||||
std::vector<std::string> fontDirs;
|
||||
get_font_dirs(fontDirs);
|
||||
|
||||
std::string fn;
|
||||
for (const std::string& dir : fontDirs) {
|
||||
fn = base::join_path(dir, filename);
|
||||
if (base::is_file(fn))
|
||||
return fn;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
} // namespace app
|
21
src/app/font_path.h
Normal file
21
src/app/font_path.h
Normal file
@ -0,0 +1,21 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_FONT_PATH_H_INCLUDED
|
||||
#define APP_FONT_PATH_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace app {
|
||||
|
||||
void get_font_dirs(std::vector<std::string>& fontDirs);
|
||||
std::string find_font(const std::string& filename);
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
23
src/app/font_path_osx.mm
Normal file
23
src/app/font_path_osx.mm
Normal file
@ -0,0 +1,23 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// 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/font_path.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
void get_font_dirs(std::vector<std::string>& fontDirs)
|
||||
{
|
||||
// TODO use a Cocoa API to get the list of paths
|
||||
fontDirs.push_back("~/Library/Fonts");
|
||||
fontDirs.push_back("/Library/Fonts");
|
||||
fontDirs.push_back("/System/Library/Fonts/");
|
||||
}
|
||||
|
||||
} // namespace app
|
49
src/app/font_path_unix.cpp
Normal file
49
src/app/font_path_unix.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// 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/font_path.h"
|
||||
|
||||
#include "base/fs.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
namespace app {
|
||||
|
||||
std::vector<std::string> g_cache;
|
||||
|
||||
void get_font_dirs(std::vector<std::string>& fontDirs)
|
||||
{
|
||||
if (!g_cache.empty()) {
|
||||
fontDirs = g_cache;
|
||||
return;
|
||||
}
|
||||
|
||||
std::queue<std::string> q;
|
||||
q.push("~/.fonts");
|
||||
q.push("/usr/local/share/fonts");
|
||||
q.push("/usr/share/fonts");
|
||||
|
||||
while (!q.empty()) {
|
||||
std::string fontDir = q.front();
|
||||
q.pop();
|
||||
|
||||
fontDirs.push_back(fontDir);
|
||||
|
||||
for (const auto& file : base::list_files(fontDir)) {
|
||||
std::string fullpath = base::join_path(fontDir, file);
|
||||
if (base::is_directory(fullpath))
|
||||
q.push_back(fontDir); // Add subdirectory in the queue
|
||||
}
|
||||
}
|
||||
|
||||
g_cache = fontDirs;
|
||||
}
|
||||
|
||||
} // namespace app
|
31
src/app/font_path_win.cpp
Normal file
31
src/app/font_path_win.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// 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/font_path.h"
|
||||
|
||||
#include "base/string.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
namespace app {
|
||||
|
||||
void get_font_dirs(std::vector<std::string>& fontDirs)
|
||||
{
|
||||
std::vector<wchar_t> buf(MAX_PATH+1);
|
||||
HRESULT hr = SHGetFolderPath(
|
||||
nullptr, CSIDL_FONTS, nullptr,
|
||||
SHGFP_TYPE_DEFAULT, &buf[0]);
|
||||
if (hr == S_OK)
|
||||
fontDirs.push_back(base::to_utf8(&buf[0]));
|
||||
}
|
||||
|
||||
} // namespace app
|
@ -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.
|
||||
@ -13,6 +13,7 @@
|
||||
#include "app/commands/cmd_set_palette.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/console.h"
|
||||
#include "app/font_path.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "app/util/freetype_utils.h"
|
||||
@ -38,7 +39,6 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <queue>
|
||||
#include <map>
|
||||
|
||||
namespace app {
|
||||
@ -144,43 +144,16 @@ FontPopup::FontPopup()
|
||||
|
||||
m_popup->view()->attachToView(&m_listBox);
|
||||
|
||||
std::queue<std::string> fontDirs;
|
||||
#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) {
|
||||
fontDirs.push(base::to_utf8(&buf[0]));
|
||||
}
|
||||
}
|
||||
#elif __APPLE__
|
||||
{
|
||||
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");
|
||||
}
|
||||
#endif
|
||||
std::vector<std::string> fontDirs;
|
||||
get_font_dirs(fontDirs);
|
||||
|
||||
// Create a list of fullpaths to every font found in all font
|
||||
// directories (fontDirs)
|
||||
std::vector<std::string> files;
|
||||
while (!fontDirs.empty()) {
|
||||
std::string fontDir = fontDirs.front();
|
||||
fontDirs.pop();
|
||||
|
||||
auto fontDirFiles = base::list_files(fontDir);
|
||||
for (const auto& file : fontDirFiles) {
|
||||
for (const auto& fontDir : fontDirs) {
|
||||
for (const auto& file : base::list_files(fontDir)) {
|
||||
std::string fullpath = base::join_path(fontDir, file);
|
||||
if (base::is_directory(fullpath))
|
||||
fontDirs.push(fullpath); // Add subdirectory
|
||||
else
|
||||
if (base::is_file(fullpath))
|
||||
files.push_back(fullpath);
|
||||
}
|
||||
}
|
||||
|
63
src/app/ui/skin/font_data.cpp
Normal file
63
src/app/ui/skin/font_data.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// 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/skin/font_data.h"
|
||||
|
||||
#include "she/font.h"
|
||||
#include "she/system.h"
|
||||
|
||||
namespace app {
|
||||
namespace skin {
|
||||
|
||||
FontData::FontData(she::FontType type)
|
||||
: m_type(type)
|
||||
, m_antialias(false)
|
||||
, m_fallback(nullptr)
|
||||
, m_fallbackSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
FontData::~FontData()
|
||||
{
|
||||
// Destroy all fonts
|
||||
for (auto& it : m_fonts)
|
||||
it.second->dispose();
|
||||
}
|
||||
|
||||
she::Font* FontData::getFont(int size)
|
||||
{
|
||||
if (m_type == she::FontType::kSpriteSheet)
|
||||
size = 0; // Same size always
|
||||
|
||||
auto it = m_fonts.find(size);
|
||||
if (it != m_fonts.end())
|
||||
return it->second;
|
||||
|
||||
she::Font* font = nullptr;
|
||||
|
||||
switch (m_type) {
|
||||
case she::FontType::kSpriteSheet:
|
||||
font = she::instance()->loadSpriteSheetFont(m_filename.c_str());
|
||||
break;
|
||||
case she::FontType::kTrueType:
|
||||
font = she::instance()->loadTrueTypeFont(m_filename.c_str(), size);
|
||||
if (font)
|
||||
font->setAntialias(m_antialias);
|
||||
break;
|
||||
}
|
||||
|
||||
if (font && m_fallback)
|
||||
font->setFallback(m_fallback->getFont(m_fallbackSize));
|
||||
|
||||
return m_fonts[size] = font;
|
||||
}
|
||||
|
||||
} // namespace skin
|
||||
} // namespace app
|
47
src/app/ui/skin/font_data.h
Normal file
47
src/app/ui/skin/font_data.h
Normal file
@ -0,0 +1,47 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UI_SKIN_FONT_DATA_H_INCLUDED
|
||||
#define APP_UI_SKIN_FONT_DATA_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
#include "she/font.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace app {
|
||||
namespace skin {
|
||||
|
||||
class FontData {
|
||||
public:
|
||||
FontData(she::FontType type);
|
||||
~FontData();
|
||||
|
||||
void setFilename(const std::string& filename) { m_filename = filename; }
|
||||
void setAntialias(bool antialias) { m_antialias = antialias; }
|
||||
void setFallback(FontData* fallback, int fallbackSize) {
|
||||
m_fallback = fallback;
|
||||
m_fallbackSize = fallbackSize;
|
||||
}
|
||||
|
||||
she::Font* getFont(int size);
|
||||
|
||||
private:
|
||||
she::FontType m_type;
|
||||
std::string m_filename;
|
||||
bool m_antialias;
|
||||
std::map<int, she::Font*> m_fonts; // key=font size, value=real font
|
||||
FontData* m_fallback;
|
||||
int m_fallbackSize;
|
||||
|
||||
DISABLE_COPYING(FontData);
|
||||
};
|
||||
|
||||
} // namespace skin
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -9,12 +9,14 @@
|
||||
#endif
|
||||
|
||||
#include "app/console.h"
|
||||
#include "app/font_path.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/resource_finder.h"
|
||||
#include "app/ui/app_menuitem.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/skin/button_icon_impl.h"
|
||||
#include "app/ui/skin/font_data.h"
|
||||
#include "app/ui/skin/skin_property.h"
|
||||
#include "app/ui/skin/skin_slider_property.h"
|
||||
#include "app/ui/skin/skin_style_property.h"
|
||||
@ -94,6 +96,104 @@ static css::Value value_or_none(const char* valueStr)
|
||||
return css::Value(valueStr);
|
||||
}
|
||||
|
||||
static FontData* load_font(std::map<std::string, FontData*>& fonts,
|
||||
const TiXmlElement* xmlFont,
|
||||
const std::string& xmlFilename)
|
||||
{
|
||||
const char* fontRef = xmlFont->Attribute("font");
|
||||
if (fontRef) {
|
||||
auto it = fonts.find(fontRef);
|
||||
if (it == fonts.end())
|
||||
throw base::Exception("Font named '%s' not found\n", fontRef);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const char* nameStr = xmlFont->Attribute("name");
|
||||
if (!nameStr)
|
||||
throw base::Exception("No \"name\" or \"font\" attributes specified on <font>");
|
||||
|
||||
std::string name(nameStr);
|
||||
LOG(VERBOSE) << "SKIN: Loading font '" << name << "'\n";
|
||||
|
||||
const char* typeStr = xmlFont->Attribute("type");
|
||||
if (!typeStr)
|
||||
throw base::Exception("<font> without 'type' attribute in '%s'\n",
|
||||
xmlFilename.c_str());
|
||||
|
||||
std::string type(typeStr);
|
||||
base::UniquePtr<FontData> font(nullptr);
|
||||
|
||||
if (type == "spritesheet") {
|
||||
const char* fileStr = xmlFont->Attribute("file");
|
||||
if (fileStr) {
|
||||
font.reset(new FontData(she::FontType::kSpriteSheet));
|
||||
font->setFilename(
|
||||
base::join_path(
|
||||
base::get_file_path(xmlFilename),
|
||||
fileStr));
|
||||
}
|
||||
}
|
||||
else if (type == "truetype") {
|
||||
const char* platformFileAttrName =
|
||||
#ifdef _WIN32
|
||||
"file_win"
|
||||
#elif defined __APPLE__
|
||||
"file_mac"
|
||||
#else
|
||||
"file_linux"
|
||||
#endif
|
||||
;
|
||||
|
||||
const char* platformFileStr = xmlFont->Attribute(platformFileAttrName);
|
||||
const char* fileStr = xmlFont->Attribute("file");
|
||||
bool antialias = true;
|
||||
if (xmlFont->Attribute("antialias"))
|
||||
antialias = bool_attr_is_true(xmlFont, "antialias");
|
||||
|
||||
std::string fontFilename;
|
||||
if (platformFileStr)
|
||||
fontFilename = app::find_font(platformFileStr);
|
||||
if (fileStr && fontFilename.empty())
|
||||
fontFilename = app::find_font(fileStr);
|
||||
|
||||
if (!fontFilename.empty()) {
|
||||
font.reset(new FontData(she::FontType::kTrueType));
|
||||
font->setFilename(fontFilename);
|
||||
font->setAntialias(antialias);
|
||||
}
|
||||
else {
|
||||
throw base::Exception("Invalid file for <font name=\"%s\" ...> in '%s'\n",
|
||||
name.c_str(), xmlFilename.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw base::Exception("Invalid type=\"%s\" in '%s' for <font name=\"%s\" ...>\n",
|
||||
type.c_str(), xmlFilename.c_str(), name.c_str());
|
||||
}
|
||||
|
||||
FontData* result = nullptr;
|
||||
if (font) {
|
||||
fonts[name] = result = font.get();
|
||||
font.release();
|
||||
|
||||
// Fallback font
|
||||
const TiXmlElement* xmlFallback =
|
||||
(const TiXmlElement*)xmlFont->FirstChild("fallback");
|
||||
if (xmlFallback) {
|
||||
FontData* fallback = load_font(fonts, xmlFallback, xmlFilename);
|
||||
if (fallback) {
|
||||
int size = 10;
|
||||
const char* sizeStr = xmlFont->Attribute("size");
|
||||
if (sizeStr)
|
||||
size = std::strtol(sizeStr, nullptr, 10);
|
||||
|
||||
result->setFallback(fallback, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
SkinTheme* SkinTheme::instance()
|
||||
{
|
||||
@ -101,13 +201,11 @@ SkinTheme* SkinTheme::instance()
|
||||
}
|
||||
|
||||
SkinTheme::SkinTheme()
|
||||
: m_cursors(ui::kCursorTypes, NULL)
|
||||
: m_sheet(nullptr)
|
||||
, m_cursors(ui::kCursorTypes, nullptr)
|
||||
, m_defaultFont(nullptr)
|
||||
, m_miniFont(nullptr)
|
||||
{
|
||||
m_defaultFont = nullptr;
|
||||
m_miniFont = nullptr;
|
||||
|
||||
// Initialize all graphics in NULL (these bitmaps are loaded from the skin)
|
||||
m_sheet = NULL;
|
||||
}
|
||||
|
||||
SkinTheme::~SkinTheme()
|
||||
@ -127,11 +225,8 @@ SkinTheme::~SkinTheme()
|
||||
m_parts_by_id.clear();
|
||||
|
||||
// Destroy fonts
|
||||
if (m_defaultFont)
|
||||
m_defaultFont->dispose();
|
||||
|
||||
if (m_miniFont)
|
||||
m_miniFont->dispose();
|
||||
for (auto kv : m_fonts)
|
||||
delete kv.second; // Delete all FontDatas
|
||||
}
|
||||
|
||||
void SkinTheme::onRegenerate()
|
||||
@ -160,12 +255,37 @@ void SkinTheme::onRegenerate()
|
||||
}
|
||||
}
|
||||
|
||||
void SkinTheme::loadFontData()
|
||||
{
|
||||
LOG("SKIN: Loading fonts\n");
|
||||
|
||||
std::string fonstFilename("fonts/fonts.xml");
|
||||
|
||||
ResourceFinder rf;
|
||||
rf.includeDataDir(fonstFilename.c_str());
|
||||
if (!rf.findFirst())
|
||||
throw base::Exception("File %s not found", fonstFilename.c_str());
|
||||
|
||||
XmlDocumentRef doc = open_xml(rf.filename());
|
||||
TiXmlHandle handle(doc.get());
|
||||
|
||||
TiXmlElement* xmlFont = handle
|
||||
.FirstChild("fonts")
|
||||
.FirstChild("font").ToElement();
|
||||
while (xmlFont) {
|
||||
load_font(m_fonts, xmlFont, rf.filename());
|
||||
xmlFont = xmlFont->NextSiblingElement();
|
||||
}
|
||||
}
|
||||
|
||||
void SkinTheme::loadAll(const std::string& skinId)
|
||||
{
|
||||
LOG("SKIN: Loading theme %s\n", skinId.c_str());
|
||||
|
||||
if (m_fonts.empty())
|
||||
loadFontData();
|
||||
|
||||
loadSheet(skinId);
|
||||
loadFonts(skinId);
|
||||
loadXml(skinId);
|
||||
}
|
||||
|
||||
@ -190,17 +310,6 @@ void SkinTheme::loadSheet(const std::string& skinId)
|
||||
}
|
||||
}
|
||||
|
||||
void SkinTheme::loadFonts(const std::string& skinId)
|
||||
{
|
||||
if (m_defaultFont) m_defaultFont->dispose();
|
||||
if (m_miniFont) m_miniFont->dispose();
|
||||
|
||||
Preferences& pref = Preferences::instance();
|
||||
|
||||
m_defaultFont = loadFont(pref.theme.font(), themeFileName(skinId, "font.png"));
|
||||
m_miniFont = loadFont(pref.theme.miniFont(), themeFileName(skinId, "minifont.png"));
|
||||
}
|
||||
|
||||
void SkinTheme::loadXml(const std::string& skinId)
|
||||
{
|
||||
// Load the skin XML
|
||||
@ -213,6 +322,42 @@ void SkinTheme::loadXml(const std::string& skinId)
|
||||
XmlDocumentRef doc = open_xml(rf.filename());
|
||||
TiXmlHandle handle(doc.get());
|
||||
|
||||
// Load fonts
|
||||
{
|
||||
TiXmlElement* xmlFont = handle
|
||||
.FirstChild("theme")
|
||||
.FirstChild("fonts")
|
||||
.FirstChild("font").ToElement();
|
||||
while (xmlFont) {
|
||||
const char* idStr = xmlFont->Attribute("id");
|
||||
FontData* fontData = load_font(m_fonts, xmlFont, rf.filename());
|
||||
if (idStr && fontData) {
|
||||
std::string id(idStr);
|
||||
LOG(VERBOSE) << "SKIN: Loading theme font '" << id << "\n";
|
||||
|
||||
int size = 10;
|
||||
const char* sizeStr = xmlFont->Attribute("size");
|
||||
if (sizeStr)
|
||||
size = std::strtol(sizeStr, nullptr, 10);
|
||||
|
||||
if (id == "default") {
|
||||
m_defaultFont = fontData->getFont(size);
|
||||
}
|
||||
else if (id == "mini") {
|
||||
m_miniFont = fontData->getFont(size);
|
||||
}
|
||||
}
|
||||
|
||||
xmlFont = xmlFont->NextSiblingElement();
|
||||
}
|
||||
}
|
||||
|
||||
// No available font to run the program
|
||||
if (!m_defaultFont)
|
||||
throw base::Exception("There is no default font");
|
||||
if (!m_miniFont)
|
||||
m_miniFont = m_defaultFont;
|
||||
|
||||
// Load dimension
|
||||
{
|
||||
TiXmlElement* xmlDim = handle
|
||||
@ -1778,30 +1923,6 @@ void SkinTheme::paintIcon(Widget* widget, Graphics* g, IButtonIcon* iconInterfac
|
||||
g->drawRgbaSurface(icon_bmp, x, y);
|
||||
}
|
||||
|
||||
she::Font* SkinTheme::loadFont(const std::string& userFont, const std::string& themeFont)
|
||||
{
|
||||
// Directories to find the font
|
||||
ResourceFinder rf;
|
||||
if (!userFont.empty())
|
||||
rf.addPath(userFont.c_str());
|
||||
rf.includeDataDir(themeFont.c_str());
|
||||
|
||||
// Try to load the font
|
||||
while (rf.next()) {
|
||||
try {
|
||||
she::Font* f = she::instance()->loadSpriteSheetFont(rf.filename().c_str(), guiscale());
|
||||
if (f->isScalable())
|
||||
f->setSize(8);
|
||||
return f;
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string SkinTheme::themeFileName(const std::string& skinId,
|
||||
const std::string& fileName) const
|
||||
{
|
||||
|
@ -33,6 +33,8 @@ namespace she {
|
||||
namespace app {
|
||||
namespace skin {
|
||||
|
||||
class FontData;
|
||||
|
||||
// This is the GUI theme used by Aseprite (which use images from
|
||||
// data/skins directory).
|
||||
class SkinTheme : public ui::Theme
|
||||
@ -114,9 +116,9 @@ namespace app {
|
||||
void onRegenerate() override;
|
||||
|
||||
private:
|
||||
void loadFontData();
|
||||
void loadAll(const std::string& skinId);
|
||||
void loadSheet(const std::string& skinId);
|
||||
void loadFonts(const std::string& skinId);
|
||||
void loadXml(const std::string& skinId);
|
||||
|
||||
she::Surface* sliceSheet(she::Surface* sur, const gfx::Rect& bounds);
|
||||
@ -128,7 +130,6 @@ namespace app {
|
||||
|
||||
void paintIcon(ui::Widget* widget, ui::Graphics* g, ui::IButtonIcon* iconInterface, int x, int y);
|
||||
|
||||
she::Font* loadFont(const std::string& userFont, const std::string& themeFont);
|
||||
std::string themeFileName(const std::string& skinId,
|
||||
const std::string& fileName) const;
|
||||
|
||||
@ -140,6 +141,7 @@ namespace app {
|
||||
std::vector<ui::Cursor*> m_cursors;
|
||||
StyleSheet m_stylesheet;
|
||||
std::map<std::string, ui::Style*> m_styles;
|
||||
std::map<std::string, FontData*> m_fonts;
|
||||
she::Font* m_defaultFont;
|
||||
she::Font* m_miniFont;
|
||||
};
|
||||
|
@ -69,6 +69,11 @@ void FreeTypeFont::setAntialias(bool antialias)
|
||||
m_face.setAntialias(antialias);
|
||||
}
|
||||
|
||||
bool FreeTypeFont::hasCodePoint(int codepoint) const
|
||||
{
|
||||
return true; // TODO
|
||||
}
|
||||
|
||||
FreeTypeFont* loadFreeTypeFont(const char* filename, int height)
|
||||
{
|
||||
FreeTypeFont* font = new FreeTypeFont(filename, height);
|
||||
|
@ -30,6 +30,7 @@ namespace she {
|
||||
bool isScalable() const override;
|
||||
void setSize(int size) override;
|
||||
void setAntialias(bool antialias) override;
|
||||
bool hasCodePoint(int codepoint) const override;
|
||||
|
||||
Face& face() { return m_face; }
|
||||
|
||||
|
@ -63,6 +63,11 @@ public:
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
bool hasCodePoint(int codepoint) const override {
|
||||
codepoint -= (int)' ';
|
||||
return (codepoint >= 0 && codepoint < (int)m_chars.size());
|
||||
}
|
||||
|
||||
Surface* getSurfaceSheet() const {
|
||||
return m_sheet;
|
||||
}
|
||||
|
@ -29,6 +29,24 @@ gfx::Rect draw_text(Surface* surface, Font* font,
|
||||
base::utf8_const_iterator it = begin;
|
||||
gfx::Rect textBounds;
|
||||
|
||||
retry:;
|
||||
// Check if this font is enough to draw the given string or we will
|
||||
// need the fallback for some special Unicode chars
|
||||
if (font->fallback()) {
|
||||
// TODO compose unicode characters and check those codepoints, the
|
||||
// same in the drawing code of sprite sheet font
|
||||
for (auto it=begin; it!=end; ++it) {
|
||||
uint32_t code = *it;
|
||||
if (code && !font->hasCodePoint(code)) {
|
||||
Font* newFont = font->fallback();
|
||||
y += font->height()/2 - newFont->height()/2;
|
||||
|
||||
font = newFont;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (font->type()) {
|
||||
|
||||
case FontType::kSpriteSheet: {
|
||||
|
@ -20,6 +20,7 @@ namespace she {
|
||||
|
||||
class Font {
|
||||
public:
|
||||
Font() : m_fallback(nullptr) { }
|
||||
virtual ~Font() { }
|
||||
virtual void dispose() = 0;
|
||||
virtual FontType type() = 0;
|
||||
@ -28,6 +29,17 @@ namespace she {
|
||||
virtual bool isScalable() const = 0;
|
||||
virtual void setSize(int size) = 0;
|
||||
virtual void setAntialias(bool antialias) = 0;
|
||||
virtual bool hasCodePoint(int codepoint) const = 0;
|
||||
|
||||
she::Font* fallback() const {
|
||||
return m_fallback;
|
||||
}
|
||||
void setFallback(she::Font* font) {
|
||||
m_fallback = font;
|
||||
}
|
||||
|
||||
private:
|
||||
she::Font* m_fallback;
|
||||
};
|
||||
|
||||
} // namespace she
|
||||
|
Loading…
x
Reference in New Issue
Block a user