ede/pekwm/FontHandler.cc

279 lines
7.4 KiB
C++

//
// FontHandler.cc for pekwm
// Copyright © 2004-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <cctype>
#include <iostream>
#include "PScreen.hh"
#include "ColorHandler.hh"
#include "FontHandler.hh"
#include "Util.hh"
using std::cerr;
using std::endl;
using std::map;
using std::list;
using std::vector;
using std::string;
FontHandler* FontHandler::_instance = 0;
//! @brief FontHandler constructor
FontHandler::FontHandler(void)
{
#ifdef DEBUG
if (_instance) {
cerr << __FILE__ << "@" << __LINE__ << ": "
<< "FontHandler(" << this << ")::FontHandler()"
<< endl << " *** _instance already set" << endl;
}
#endif // DEBUG
if (_map_justify.size() == 0) {
_map_justify[""] = FONT_JUSTIFY_NO;
_map_justify["LEFT"] = FONT_JUSTIFY_LEFT;
_map_justify["CENTER"] = FONT_JUSTIFY_CENTER;
_map_justify["RIGHT"] = FONT_JUSTIFY_RIGHT;
}
if (_map_type.size() == 0) {
_map_type[""] = PFont::FONT_TYPE_NO;
_map_type["X11"] = PFont::FONT_TYPE_X11;
_map_type["XFT"] = PFont::FONT_TYPE_XFT;
_map_type["XMB"] = PFont::FONT_TYPE_XMB;
}
_instance = this;
}
//! @brief FontHandler destructor
FontHandler::~FontHandler(void)
{
list<HandlerEntry<PFont*> >::iterator it_f(_font_list.begin());
for (; it_f != _font_list.end(); ++it_f) {
delete it_f->getData();
}
list<HandlerEntry<PFont::Color*> >::iterator it_c(_color_list.begin());
for (; it_c != _color_list.end(); ++it_c) {
delete it_c->getData();
}
}
//! @brief Gets or allocs a font
//!
//! Syntax of font specification goes as follows:
//! "Font Name#Justify#Offset#Type" ex "Vera#Center#1 1#XFT"
//! where only the first field is obligatory and type needs to be the last
//!
PFont*
FontHandler::getFont(const std::string &font)
{
// Check cache
list<HandlerEntry<PFont*> >::iterator it(_font_list.begin());
for (; it != _font_list.end(); ++it) {
if (*it == font) {
it->incRef();
return it->getData();
}
}
// create new
PFont *pfont = 0;
vector<string> tok;
vector<string>::iterator tok_it; // old gcc doesn't like --tok.end()
if ((Util::splitString(font, tok, "#", 0, true)) > 1) {
// Try getting the font type from the first paramter, if that
// doesn't work fall back to the last. This is to backwards
// compatible.
tok_it = tok.begin();
uint type = ParseUtil::getValue<PFont::Type>(*tok_it, _map_type);
if (type == PFont::FONT_TYPE_NO) {
tok_it = tok.end() - 1;
type = ParseUtil::getValue<PFont::Type>(*tok_it, _map_type);
}
switch (type) {
case PFont::FONT_TYPE_XMB:
pfont = new PFontXmb(PScreen::instance());
tok.erase(tok_it);
break;
#ifdef HAVE_XFT
case PFont::FONT_TYPE_XFT:
pfont = new PFontXft(PScreen::instance());
tok.erase(tok_it);
break;
#endif // HAVE_XFT
case PFont::FONT_TYPE_X11:
pfont = new PFontX11(PScreen::instance());
tok.erase(tok_it);
break;
default:
pfont = new PFontXmb(PScreen::instance());
break;
};
pfont->load(tok.front());
// Remove used fields, type and
tok.erase(tok.begin());
// fields left for justify and offset
vector<string>::iterator s_it(tok.begin());
for (; s_it != tok.end(); ++s_it) {
if (isdigit((*s_it)[0])) { // number
vector<string> tok_2;
if (Util::splitString(*s_it, tok_2, " \t", 2) == 2) {
pfont->setOffset(strtol(tok_2[0].c_str(), 0, 10),
strtol(tok_2[1].c_str(), 0, 10));
}
} else { // justify
uint justify = ParseUtil::getValue<FontJustify>(*s_it, _map_justify);
if (justify == FONT_JUSTIFY_NO) {
justify = FONT_JUSTIFY_LEFT;
}
pfont->setJustify(justify);
}
}
} else {
pfont = new PFontXmb(PScreen::instance());
pfont->load(font);
}
// create new entry
HandlerEntry<PFont*> entry(font);
entry.incRef();
entry.setData(pfont);
_font_list.push_back(entry);
return pfont;
}
//! @brief Returns a font
void
FontHandler::returnFont(PFont *font)
{
list<HandlerEntry<PFont*> >::iterator it(_font_list.begin());
for (; it != _font_list.begin(); ++it) {
if (it->getData() == font) {
it->decRef();
if (! it->getRef()) {
delete it->getData();
_font_list.erase(it);
}
break;
}
}
}
//! @brief Gets or allocs a color
PFont::Color*
FontHandler::getColor(const std::string &color)
{
// check cache
list<HandlerEntry<PFont::Color*> >::iterator it(_color_list.begin());
for (; it != _color_list.end(); ++it) {
if (*it == color) {
it->incRef();
return it->getData();
}
}
// create new
PFont::Color *font_color = new PFont::Color();
font_color->setHasFg(true);
vector<string> tok;
if (Util::splitString(color, tok, " \t", 2) == 2) {
loadColor(tok[0], font_color, true);
loadColor(tok[1], font_color, false);
font_color->setHasBg(true);
} else {
loadColor(color, font_color, true);
}
// create new entry
HandlerEntry<PFont::Color*> entry(color);
entry.incRef();
entry.setData(font_color);
_color_list.push_back(entry);
return font_color;
}
//! @brief Returns a color
void
FontHandler::returnColor(PFont::Color *color)
{
list<HandlerEntry<PFont::Color*> >::iterator it(_color_list.begin());
for (; it != _color_list.begin(); ++it) {
if (it->getData() == color) {
it->decRef();
if (! it->getRef()) {
delete it->getData();
_color_list.erase(it);
}
break;
}
}
}
//! @brief Helper loader of font colors ( main and offset color )
void
FontHandler::loadColor(const std::string &color, PFont::Color *font_color, bool fg)
{
XColor *xc;
vector<string> tok;
if (Util::splitString(color, tok, ",", 2, true) == 2) {
uint alpha = static_cast<uint>(strtol(tok[1].c_str(), 0, 10));
if (alpha > 100) {
cerr << " *** WARNING: Alpha for font color greater than 100%" << endl;
alpha = 100;
}
alpha = static_cast<uint>(65535 * (static_cast<float>(alpha) / 100));
if (fg) {
font_color->setFgAlpha(alpha);
} else {
font_color->setBgAlpha(alpha);
}
xc = ColorHandler::instance()->getColor(tok[0]);
} else {
xc = ColorHandler::instance()->getColor(color);
}
if (fg) {
font_color->setFg(xc);
} else {
font_color->setBg(xc);
}
}
//! @brief Helper unloader of font colors
void
FontHandler::freeColor(PFont::Color *font_color)
{
if (font_color->hasFg()) {
ColorHandler::instance()->returnColor(font_color->getFg());
}
if (font_color->hasBg()) {
ColorHandler::instance()->returnColor(font_color->getBg());
}
delete font_color;
}