WIP: Added font controller

This enables font packages: packages can now provide fonts by
featuring a "fonts" directory with the font layouts.

This commit also adds the capability to dynamically add fonts.
The Glyphs system is decoupled from the application's system
path and the BASIC.TEXT PCell parameters are non-cached to
enable dynamic updates.
This commit is contained in:
Matthias Koefferlein 2017-04-22 00:03:58 +02:00
parent a7038282ce
commit 6ba251cf2a
12 changed files with 392 additions and 27 deletions

View File

@ -230,6 +230,9 @@ HEADERS = \
dbGlyphs.h \
dbCommon.h
RESOURCES = \
dbResources.qrc
INCLUDEPATH += ../tl ../gsi
DEPENDPATH += ../tl ../gsi
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_gsi

View File

@ -299,12 +299,25 @@ TextGenerator::default_generator ()
return fonts.empty () ? 0 : &fonts [0];
}
static std::vector<std::string> s_font_paths;
static std::vector<TextGenerator> s_fonts;
static bool s_fonts_loaded = false;
void
TextGenerator::set_font_paths (const std::vector<std::string> &paths)
{
s_font_paths = paths;
s_fonts.clear ();
s_fonts_loaded = false;
}
const std::vector<TextGenerator> &
TextGenerator::generators ()
{
static std::vector<TextGenerator> m_fonts;
if (! s_fonts_loaded) {
if (m_fonts.empty ()) {
s_fonts.clear ();
const char *resources[] = {
":/fonts/std_font.gds"
@ -312,42 +325,47 @@ TextGenerator::generators ()
for (size_t i = 0 ; i < sizeof (resources) / sizeof (resources [0]); ++i) {
try {
m_fonts.push_back (TextGenerator ());
m_fonts.back ().load_from_resource (resources [i]);
tl::log << "Loading font from resource " << resources [i] << " ..";
s_fonts.push_back (TextGenerator ());
s_fonts.back ().load_from_resource (resources [i]);
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
m_fonts.pop_back ();
s_fonts.pop_back ();
}
}
std::vector<std::string> system_path = tl::get_klayout_path ();
// scan for font files
for (std::vector<std::string>::const_iterator p = system_path.begin (); p != system_path.end (); ++p) {
for (std::vector<std::string>::const_iterator p = s_font_paths.begin (); p != s_font_paths.end (); ++p) {
QDir fp = QDir (tl::to_qstring (*p)).filePath (tl::to_qstring ("fonts"));
QDir fp = QDir (tl::to_qstring (*p));
if (fp.exists ()) {
QStringList name_filters;
name_filters << QString::fromUtf8 ("*");
QStringList name_filters;
name_filters << QString::fromUtf8 ("*");
QStringList font_files = fp.entryList (name_filters, QDir::Files);
for (QStringList::const_iterator ff = font_files.begin (); ff != font_files.end (); ++ff) {
QStringList font_files = fp.entryList (name_filters, QDir::Files);
for (QStringList::const_iterator ff = font_files.begin (); ff != font_files.end (); ++ff) {
try {
tl::log << "Loading font from " << tl::to_string (fp.filePath (*ff)) << " ..";
s_fonts.push_back (TextGenerator ());
s_fonts.back ().load_from_file (tl::to_string (fp.filePath (*ff)));
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
s_fonts.pop_back ();
}
try {
m_fonts.push_back (TextGenerator ());
m_fonts.back ().load_from_file (tl::to_string (fp.filePath (*ff)));
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
m_fonts.pop_back ();
}
}
}
s_fonts_loaded = true;
}
return m_fonts;
return s_fonts;
}
}

View File

@ -188,6 +188,12 @@ public:
*/
static const std::vector<TextGenerator> &generators ();
/**
* @brief Sets the search path for font files
* The given folders are scanned for font files.
*/
static void set_font_paths (const std::vector<std::string> &paths);
/**
* @brief Returns the font with the given name
* If no font with that name exsist, 0 is returned.

View File

@ -453,7 +453,7 @@ public:
*/
const std::vector<PCellParameterDeclaration> &parameter_declarations () const
{
if (! m_has_parameter_declarations) {
if (! m_has_parameter_declarations || ! wants_parameter_declaration_caching ()) {
m_parameter_declarations = get_parameter_declarations ();
m_has_parameter_declarations = true;
}
@ -495,6 +495,18 @@ public:
*/
pcell_parameters_type map_parameters (const std::map<std::string, tl::Variant> &named_parameters) const;
protected:
/**
* @brief Gets a value indicating whether the PCell wants caching of the parameter declarations
*
* Some PCells with a dynamic parameter definition may not want paramater declaration caching. These
* PCells can override this method and return false.
*/
virtual bool wants_parameter_declaration_caching () const
{
return true;
}
private:
int m_ref_count;
pcell_id_type m_id;

5
src/db/dbResources.qrc Normal file
View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/fonts">
<file>std_font.gds</file>
</qresource>
</RCC>

View File

@ -58,7 +58,8 @@ HEADERS = \
laySaltModel.h \
laySaltController.h \
laySignalHandler.h \
layLibraryController.h
layLibraryController.h \
layFontController.h
FORMS = \
ClipDialog.ui \
@ -162,7 +163,8 @@ SOURCES = \
laySaltModel.cc \
laySaltController.cc \
laySignalHandler.cc \
layLibraryController.cc
layLibraryController.cc \
layFontController.cc
RESOURCES = layBuildInMacros.qrc \
layHelpResources.qrc \

View File

@ -0,0 +1,180 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "layFontController.h"
#include "layApplication.h"
#include "laySaltController.h"
#include "layConfig.h"
#include "layMainWindow.h"
#include "dbGlyphs.h"
#include "tlLog.h"
#include <QDir>
namespace lay
{
FontController::FontController ()
: m_file_watcher (0),
dm_sync_dirs (this, &FontController::sync_dirs)
{
}
void
FontController::initialize (lay::PluginRoot * /*root*/)
{
// NOTE: we initialize the dirs in the stage once to have them available for the autorun
// macros. We'll do that later again in order to pull in the dirs from the packages.
sync_dirs ();
}
void
FontController::initialized (lay::PluginRoot * /*root*/)
{
if (lay::SaltController::instance ()) {
connect (lay::SaltController::instance (), SIGNAL (salt_changed ()), this, SLOT (sync_with_external_sources ()));
}
if (! m_file_watcher) {
m_file_watcher = new tl::FileSystemWatcher (this);
connect (m_file_watcher, SIGNAL (fileChanged (const QString &)), this, SLOT (file_watcher_triggered ()));
connect (m_file_watcher, SIGNAL (fileRemoved (const QString &)), this, SLOT (file_watcher_triggered ()));
}
sync_dirs ();
}
void
FontController::uninitialize (lay::PluginRoot * /*root*/)
{
if (m_file_watcher) {
disconnect (m_file_watcher, SIGNAL (fileChanged (const QString &)), this, SLOT (file_watcher_triggered ()));
disconnect (m_file_watcher, SIGNAL (fileRemoved (const QString &)), this, SLOT (file_watcher_triggered ()));
delete m_file_watcher;
m_file_watcher = 0;
}
if (lay::SaltController::instance ()) {
disconnect (lay::SaltController::instance (), SIGNAL (salt_changed ()), this, SLOT (sync_with_external_sources ()));
}
}
void
FontController::get_options (std::vector < std::pair<std::string, std::string> > & /*options*/) const
{
// .. nothing yet ..
}
void
FontController::get_menu_entries (std::vector<lay::MenuEntry> & /*menu_entries*/) const
{
// .. nothing yet ..
}
bool
FontController::configure (const std::string & /*name*/, const std::string & /*value*/)
{
return false;
}
void
FontController::config_finalize()
{
// .. nothing yet ..
}
bool
FontController::can_exit (lay::PluginRoot * /*root*/) const
{
// .. nothing yet ..
return true;
}
void
FontController::sync_dirs ()
{
if (! m_file_watcher) {
return;
}
m_file_watcher->clear ();
m_file_watcher->enable (false);
std::vector<std::string> paths = lay::Application::instance ()->klayout_path ();
// add the salt grains as potential sources for library definitions
lay::SaltController *sc = lay::SaltController::instance ();
if (sc) {
for (lay::Salt::flat_iterator g = sc->salt ().begin_flat (); g != sc->salt ().end_flat (); ++g) {
paths.push_back ((*g)->path ());
}
}
// scan for font directories
std::vector<std::string> font_paths;
for (std::vector <std::string>::const_iterator p = paths.begin (); p != paths.end (); ++p) {
QDir fp = QDir (tl::to_qstring (*p)).filePath (tl::to_qstring ("fonts"));
if (fp.exists ()) {
m_file_watcher->add_file (tl::to_string (fp.absolutePath ()));
font_paths.push_back (tl::to_string (fp.absolutePath ()));
}
}
db::TextGenerator::set_font_paths (font_paths);
m_file_watcher->enable (true);
}
void
FontController::sync_with_external_sources ()
{
tl::log << tl::to_string (tr ("Package updates - updating fonts"));
dm_sync_dirs ();
}
void
FontController::file_watcher_triggered ()
{
tl::log << tl::to_string (tr ("Detected file system change in fonts - updating"));
dm_sync_dirs ();
}
FontController *
FontController::instance ()
{
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
FontController *sc = dynamic_cast <FontController *> (cls.operator-> ());
if (sc) {
return sc;
}
}
return 0;
}
// The singleton instance of the library controller
static tl::RegisteredClass<lay::PluginDeclaration> font_controller_decl (new lay::FontController (), 160, "FontController");
}

131
src/lay/layFontController.h Normal file
View File

@ -0,0 +1,131 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_layFontController
#define HDR_layFontController
#include "layCommon.h"
#include "layPlugin.h"
#include "tlFileSystemWatcher.h"
#include "tlDeferredExecution.h"
#include <vector>
#include <string>
#include <QObject>
namespace lay
{
class FontManagerDialog;
class MainWindow;
/**
* @brief A controller for the fonts
*
* This object is a singleton that acts as a controller
* for the font management for the Glyphs. The controller is responsible
* to managing the fonts and notifying library consumers
* of changes.
*
* By making the controller a PluginDeclaration it will receive
* initialization and configuration calls.
*/
class FontController
: public lay::PluginDeclaration, public tl::Object
{
Q_OBJECT
public:
/**
* @brief Default constructor
*/
FontController ();
/**
* @brief Reimplementation of the PluginDeclaration interface
*/
virtual void initialize (lay::PluginRoot *root);
/**
* @brief Reimplementation of the PluginDeclaration interface
*/
virtual void initialized (lay::PluginRoot *root);
/**
* @brief Reimplementation of the PluginDeclaration interface
*/
virtual void uninitialize (lay::PluginRoot *root);
/**
* @brief Reimplementation of the PluginDeclaration interface
*/
void get_options (std::vector < std::pair<std::string, std::string> > &options) const;
/**
* @brief Reimplementation of the PluginDeclaration interface
*/
void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const;
/**
* @brief Reimplementation of the PluginDeclaration interface
*/
bool configure (const std::string &key, const std::string &value);
/**
* @brief Reimplementation of the PluginDeclaration interface
*/
void config_finalize();
/**
* @brief Reimplementation of the PluginDeclaration interface
*/
bool can_exit (lay::PluginRoot *root) const;
/**
* @brief Gets the singleton instance for this object
*/
static FontController *instance ();
private slots:
/**
* @brief Called when the file watcher detects a change in the file system
*/
void file_watcher_triggered ();
/**
* @brief Called when the salt (packages) has changed
*/
void sync_with_external_sources ();
private:
tl::FileSystemWatcher *m_file_watcher;
tl::DeferredMethod<FontController> dm_sync_dirs;
void sync_dirs ();
};
}
#endif

View File

@ -255,7 +255,7 @@ LibraryController::instance ()
}
// The singleton instance of the library controller
static tl::RegisteredClass<lay::PluginDeclaration> salt_controller_decl (new lay::LibraryController (), 150, "LibraryController");
static tl::RegisteredClass<lay::PluginDeclaration> library_controller_decl (new lay::LibraryController (), 150, "LibraryController");
}

View File

@ -83,6 +83,17 @@ public:
*/
virtual std::vector<db::PCellParameterDeclaration> get_parameter_declarations () const;
protected:
/**
* @brief Returns a value indicating that this PCell wants to update it's parameter declarations dynamically
*
* This is be required because the fonts can be updated dynamically when new packages are installed.
*/
virtual bool wants_parameter_declaration_caching () const
{
return false;
}
public:
int get_font_index (const db::pcell_parameters_type &parameters) const;
};

View File

@ -1,5 +1,2 @@
<RCC>
<qresource prefix="/fonts" >
<file>std_font.gds</file>
</qresource>
</RCC>