diff options
-rw-r--r-- | graphics/font.cpp | 511 | ||||
-rw-r--r-- | graphics/font.h | 13 | ||||
-rw-r--r-- | graphics/fontman.cpp | 7 | ||||
-rw-r--r-- | graphics/fontman.h | 21 | ||||
-rw-r--r-- | gui/EditTextWidget.cpp | 2 | ||||
-rw-r--r-- | gui/ThemeClassic.cpp | 2 | ||||
-rw-r--r-- | gui/ThemeNew.cpp | 145 | ||||
-rw-r--r-- | gui/eval.cpp | 4 | ||||
-rw-r--r-- | gui/newgui.h | 8 | ||||
-rw-r--r-- | gui/theme.h | 46 |
10 files changed, 713 insertions, 46 deletions
diff --git a/graphics/font.cpp b/graphics/font.cpp index c55ce4232f..40a53a3179 100644 --- a/graphics/font.cpp +++ b/graphics/font.cpp @@ -20,10 +20,19 @@ */ #include "common/stdafx.h" +#include "common/stream.h" #include "graphics/font.h" namespace Graphics { +void free_font(NewFontData* pf); + +NewFont::~NewFont() { + if (font) { + free_font(font); + } +} + int NewFont::getCharWidth(byte chr) const { // If no width table is specified, return the maximum width if (!desc.width) @@ -73,6 +82,508 @@ void NewFont::drawChar(Surface *dst, byte chr, int tx, int ty, uint32 color) con #pragma mark - +/* BEGIN font.h*/ +/* bitmap_t helper macros*/ +#define BITMAP_WORDS(x) (((x)+15)/16) /* image size in words*/ +#define BITMAP_BYTES(x) (BITMAP_WORDS(x)*sizeof(bitmap_t)) +#define BITMAP_BITSPERIMAGE (sizeof(bitmap_t) * 8) +#define BITMAP_BITVALUE(n) ((bitmap_t) (((bitmap_t) 1) << (n))) +#define BITMAP_FIRSTBIT (BITMAP_BITVALUE(BITMAP_BITSPERIMAGE - 1)) +#define BITMAP_TESTBIT(m) ((m) & BITMAP_FIRSTBIT) +#define BITMAP_SHIFTBIT(m) ((bitmap_t) ((m) << 1)) + +typedef unsigned short bitmap_t; /* bitmap image unit size*/ + +/* builtin C-based proportional/fixed font structure */ +/* based on The Microwindows Project http://microwindows.org */ +struct NewFontData { + char * name; /* font name*/ + int maxwidth; /* max width in pixels*/ + int height; /* height in pixels*/ + int ascent; /* ascent (baseline) height*/ + int firstchar; /* first character in bitmap*/ + int size; /* font size in glyphs*/ + bitmap_t* bits; /* 16-bit right-padded bitmap data*/ + unsigned long* offset; /* offsets into bitmap data*/ + unsigned char* width; /* character widths or NULL if fixed*/ + int defaultchar; /* default char (not glyph index)*/ + long bits_size; /* # words of bitmap_t bits*/ + + /* unused by runtime system, read in by convbdf*/ + char * facename; /* facename of font*/ + char * copyright; /* copyright info for loadable fonts*/ + int pixel_size; + int descent; + int fbbw, fbbh, fbbx, fbby; +}; +/* END font.h*/ + +#define isprefix(buf,str) (!strncmp(buf, str, strlen(str))) +#define strequal(s1,s2) (!strcmp(s1, s2)) + +#define EXTRA 300 + +int start_char = 0; +int limit_char = 255; + +NewFontData* bdf_read_font(Common::SeekableReadStream &fp); +int bdf_read_header(Common::SeekableReadStream &fp, NewFontData* pf); +int bdf_read_bitmaps(Common::SeekableReadStream &fp, NewFontData* pf); +char * bdf_getline(Common::SeekableReadStream &fp, char *buf, int len); +bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2); + +void free_font(NewFontData* pf) { + if (!pf) + return; + free(pf->name); + free(pf->facename); + free(pf->bits); + free(pf->offset); + free(pf->width); + free(pf); +} + +/* build incore structure from .bdf file*/ +NewFontData* bdf_read_font(Common::SeekableReadStream &fp) { + NewFontData* pf; + + pf = (NewFontData*)calloc(1, sizeof(NewFontData)); + if (!pf) + goto errout; + + if (!bdf_read_header(fp, pf)) { + fprintf(stderr, "Error reading font header\n"); + goto errout; + } + + if (!bdf_read_bitmaps(fp, pf)) { + fprintf(stderr, "Error reading font bitmaps\n"); + goto errout; + } + + return pf; + + errout: + free_font(pf); + return NULL; +} + +/* read bdf font header information, return 0 on error*/ +int bdf_read_header(Common::SeekableReadStream &fp, NewFontData* pf) { + int encoding; + int nchars, maxwidth; + int firstchar = 65535; + int lastchar = -1; + char buf[256]; + char facename[256]; + char copyright[256]; + + /* set certain values to errors for later error checking*/ + pf->defaultchar = -1; + pf->ascent = -1; + pf->descent = -1; + + for (;;) { + if (!bdf_getline(fp, buf, sizeof(buf))) { + fprintf(stderr, "Error: EOF on file\n"); + return 0; + } + if (isprefix(buf, "FONT ")) { /* not required*/ + if (sscanf(buf, "FONT %[^\n]", facename) != 1) { + fprintf(stderr, "Error: bad 'FONT'\n"); + return 0; + } + pf->facename = strdup(facename); + continue; + } + if (isprefix(buf, "COPYRIGHT ")) { /* not required*/ + if (sscanf(buf, "COPYRIGHT \"%[^\"]", copyright) != 1) { + fprintf(stderr, "Error: bad 'COPYRIGHT'\n"); + return 0; + } + pf->copyright = strdup(copyright); + continue; + } + if (isprefix(buf, "DEFAULT_CHAR ")) { /* not required*/ + if (sscanf(buf, "DEFAULT_CHAR %d", &pf->defaultchar) != 1) { + fprintf(stderr, "Error: bad 'DEFAULT_CHAR'\n"); + return 0; + } + } + if (isprefix(buf, "FONT_DESCENT ")) { + if (sscanf(buf, "FONT_DESCENT %d", &pf->descent) != 1) { + fprintf(stderr, "Error: bad 'FONT_DESCENT'\n"); + return 0; + } + continue; + } + if (isprefix(buf, "FONT_ASCENT ")) { + if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent) != 1) { + fprintf(stderr, "Error: bad 'FONT_ASCENT'\n"); + return 0; + } + continue; + } + if (isprefix(buf, "FONTBOUNDINGBOX ")) { + if (sscanf(buf, "FONTBOUNDINGBOX %d %d %d %d", + &pf->fbbw, &pf->fbbh, &pf->fbbx, &pf->fbby) != 4) { + fprintf(stderr, "Error: bad 'FONTBOUNDINGBOX'\n"); + return 0; + } + continue; + } + if (isprefix(buf, "CHARS ")) { + if (sscanf(buf, "CHARS %d", &nchars) != 1) { + fprintf(stderr, "Error: bad 'CHARS'\n"); + return 0; + } + continue; + } + + /* + * Reading ENCODING is necessary to get firstchar/lastchar + * which is needed to pre-calculate our offset and widths + * array sizes. + */ + if (isprefix(buf, "ENCODING ")) { + if (sscanf(buf, "ENCODING %d", &encoding) != 1) { + fprintf(stderr, "Error: bad 'ENCODING'\n"); + return 0; + } + if (encoding >= 0 && + encoding <= limit_char && + encoding >= start_char) { + + if (firstchar > encoding) + firstchar = encoding; + if (lastchar < encoding) + lastchar = encoding; + } + continue; + } + if (strequal(buf, "ENDFONT")) + break; + } + + /* calc font height*/ + if (pf->ascent < 0 || pf->descent < 0 || firstchar < 0) { + fprintf(stderr, "Error: Invalid BDF file, requires FONT_ASCENT/FONT_DESCENT/ENCODING\n"); + return 0; + } + pf->height = pf->ascent + pf->descent; + + /* calc default char*/ + if (pf->defaultchar < 0 || + pf->defaultchar < firstchar || + pf->defaultchar > limit_char ) + pf->defaultchar = firstchar; + + /* calc font size (offset/width entries)*/ + pf->firstchar = firstchar; + pf->size = lastchar - firstchar + 1; + + /* use the font boundingbox to get initial maxwidth*/ + /*maxwidth = pf->fbbw - pf->fbbx;*/ + maxwidth = pf->fbbw; + + /* initially use font maxwidth * height for bits allocation*/ + pf->bits_size = nchars * BITMAP_WORDS(maxwidth) * pf->height; + + /* allocate bits, offset, and width arrays*/ + pf->bits = (bitmap_t *)malloc(pf->bits_size * sizeof(bitmap_t) + EXTRA); + pf->offset = (unsigned long *)malloc(pf->size * sizeof(unsigned long)); + pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char)); + + if (!pf->bits || !pf->offset || !pf->width) { + fprintf(stderr, "Error: no memory for font load\n"); + return 0; + } + + return 1; +} + +/* read bdf font bitmaps, return 0 on error*/ +int bdf_read_bitmaps(Common::SeekableReadStream &fp, NewFontData* pf) { + long ofs = 0; + int maxwidth = 0; + int i, k, encoding, width; + int bbw, bbh, bbx, bby; + int proportional = 0; + int encodetable = 0; + long l; + char buf[256]; + + /* reset file pointer*/ + fp.seek(0, SEEK_SET); + + /* initially mark offsets as not used*/ + for (i = 0; i < pf->size; ++i) + pf->offset[i] = (unsigned long)-1; + + for (;;) { + if (!bdf_getline(fp, buf, sizeof(buf))) { + fprintf(stderr, "Error: EOF on file\n"); + return 0; + } + if (isprefix(buf, "STARTCHAR")) { + encoding = width = bbw = bbh = bbx = bby = -1; + continue; + } + if (isprefix(buf, "ENCODING ")) { + if (sscanf(buf, "ENCODING %d", &encoding) != 1) { + fprintf(stderr, "Error: bad 'ENCODING'\n"); + return 0; + } + if (encoding < start_char || encoding > limit_char) + encoding = -1; + continue; + } + if (isprefix(buf, "DWIDTH ")) { + if (sscanf(buf, "DWIDTH %d", &width) != 1) { + fprintf(stderr, "Error: bad 'DWIDTH'\n"); + return 0; + } + /* use font boundingbox width if DWIDTH <= 0*/ + if (width <= 0) + width = pf->fbbw - pf->fbbx; + continue; + } + if (isprefix(buf, "BBX ")) { + if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) { + fprintf(stderr, "Error: bad 'BBX'\n"); + return 0; + } + continue; + } + if (strequal(buf, "BITMAP")) { + bitmap_t *ch_bitmap = pf->bits + ofs; + int ch_words; + + if (encoding < 0) + continue; + + /* set bits offset in encode map*/ + if (pf->offset[encoding-pf->firstchar] != (unsigned long)-1) { + fprintf(stderr, "Error: duplicate encoding for character %d (0x%02x), ignoring duplicate\n", + encoding, encoding); + continue; + } + pf->offset[encoding-pf->firstchar] = ofs; + + /* calc char width*/ + if (bbx < 0) { + width -= bbx; + /*if (width > maxwidth) + width = maxwidth;*/ + bbx = 0; + } + if (width > maxwidth) + maxwidth = width; + pf->width[encoding-pf->firstchar] = width; + + /* clear bitmap*/ + memset(ch_bitmap, 0, BITMAP_BYTES(width) * pf->height); + + ch_words = BITMAP_WORDS(width); +#define BM(row,col) (*(ch_bitmap + ((row)*ch_words) + (col))) +#define BITMAP_NIBBLES (BITMAP_BITSPERIMAGE/4) + + /* read bitmaps*/ + for (i = 0; ; ++i) { + int hexnibbles; + + if (!bdf_getline(fp, buf, sizeof(buf))) { + fprintf(stderr, "Error: EOF reading BITMAP data\n"); + return 0; + } + if (isprefix(buf, "ENDCHAR")) + break; + + hexnibbles = strlen(buf); + for (k = 0; k < ch_words; ++k) { + int ndx = k * BITMAP_NIBBLES; + uint padnibbles = hexnibbles - ndx; + bitmap_t value; + + if (padnibbles <= 0) + break; + if (padnibbles >= BITMAP_NIBBLES) + padnibbles = 0; + + value = bdf_hexval((unsigned char *)buf, + ndx, ndx+BITMAP_NIBBLES-1-padnibbles); + value <<= padnibbles * BITMAP_NIBBLES; + + BM(pf->height - pf->descent - bby - bbh + i, k) |= + value >> bbx; + /* handle overflow into next image word*/ + if (bbx) { + BM(pf->height - pf->descent - bby - bbh + i, k+1) = + value << (BITMAP_BITSPERIMAGE - bbx); + } + } + } + + ofs += BITMAP_WORDS(width) * pf->height; + + continue; + } + if (strequal(buf, "ENDFONT")) + break; + } + + /* set max width*/ + pf->maxwidth = maxwidth; + + /* change unused offset/width values to default char values*/ + for (i = 0; i < pf->size; ++i) { + int defchar = pf->defaultchar - pf->firstchar; + + if (pf->offset[i] == (unsigned long)-1) { + pf->offset[i] = pf->offset[defchar]; + pf->width[i] = pf->width[defchar]; + } + } + + /* determine whether font doesn't require encode table*/ + l = 0; + for (i = 0; i < pf->size; ++i) { + if (pf->offset[i] != (unsigned long)l) { + encodetable = 1; + break; + } + l += BITMAP_WORDS(pf->width[i]) * pf->height; + } + if (!encodetable) { + free(pf->offset); + pf->offset = NULL; + } + + /* determine whether font is fixed-width*/ + for (i = 0; i < pf->size; ++i) { + if (pf->width[i] != maxwidth) { + proportional = 1; + break; + } + } + if (!proportional) { + free(pf->width); + pf->width = NULL; + } + + /* reallocate bits array to actual bits used*/ + if (ofs < pf->bits_size) { + pf->bits = (bitmap_t *)realloc(pf->bits, ofs * sizeof(bitmap_t)); + pf->bits_size = ofs; + } + else { + if (ofs > pf->bits_size) { + fprintf(stderr, "Warning: DWIDTH spec > max FONTBOUNDINGBOX\n"); + if (ofs > pf->bits_size+EXTRA) { + fprintf(stderr, "Error: Not enough bits initially allocated\n"); + return 0; + } + pf->bits_size = ofs; + } + } + + return 1; +} + +/* read the next non-comment line, returns buf or NULL if EOF*/ +char *bdf_getline(Common::SeekableReadStream &fp, char *buf, int len) { + int c; + char *b; + + for (;;) { + b = buf; + while (!fp.eos()) { + c = fp.readByte(); + if (c == '\r') + continue; + if (c == '\n') + break; + if (b - buf >= (len - 1)) + break; + *b++ = c; + } + *b = '\0'; + if (fp.eos() && b == buf) + return NULL; + if (b != buf && !isprefix(buf, "COMMENT")) + break; + } + return buf; +} + +/* return hex value of portion of buffer*/ +bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2) { + bitmap_t val = 0; + int i, c; + + for (i = ndx1; i <= ndx2; ++i) { + c = buf[i]; + if (c >= '0' && c <= '9') + c -= '0'; + else + if (c >= 'A' && c <= 'F') + c = c - 'A' + 10; + else + if (c >= 'a' && c <= 'f') + c = c - 'a' + 10; + else + c = 0; + val = (val << 4) | c; + } + return val; +} + +NewFont *loadFont(Common::SeekableReadStream &stream) { + NewFontData *data = bdf_read_font(stream); + if (!data) + return 0; + + FontDesc desc; + desc.name = data->name; + desc.maxwidth = data->maxwidth; + desc.height = data->height; + desc.ascent = data->ascent; + desc.firstchar = data->firstchar; + desc.size = data->size; + desc.bits = data->bits; + desc.offset = data->offset; + desc.width = data->width; + desc.defaultchar = data->defaultchar; + desc.bits_size = data->bits_size; + + return new NewFont(desc, data); +} + +NewFont *loadFont(const byte *src, uint32 size) { + Common::MemoryReadStream stream(src, size); + + NewFontData *data = bdf_read_font(stream); + if (!data) + return 0; + + FontDesc desc; + desc.name = data->name; + desc.maxwidth = data->maxwidth; + desc.height = data->height; + desc.ascent = data->ascent; + desc.firstchar = data->firstchar; + desc.size = data->size; + desc.bits = data->bits; + desc.offset = data->offset; + desc.width = data->width; + desc.defaultchar = data->defaultchar; + desc.bits_size = data->bits_size; + + return new NewFont(desc, data); +} + +#pragma mark - + int Font::getStringWidth(const Common::String &str) const { int space = 0; diff --git a/graphics/font.h b/graphics/font.h index b3ed02c3b4..f9d0cb6033 100644 --- a/graphics/font.h +++ b/graphics/font.h @@ -25,6 +25,10 @@ #include "common/str.h" #include "graphics/surface.h" +namespace Common { +class SeekableReadStream; +} + namespace Graphics { // Text alignment modes for drawString() @@ -103,12 +107,16 @@ struct FontDesc { long bits_size; /* # words of bitmap_t bits*/ }; +struct NewFontData; + class NewFont : public Font { protected: FontDesc desc; + NewFontData *font; public: - NewFont(const FontDesc &d) : desc(d) {} + NewFont(const FontDesc &d, NewFontData *font_ = 0) : desc(d), font(font_) {} + ~NewFont(); virtual int getFontHeight() const { return desc.height; } virtual int getMaxCharWidth() const { return desc.maxwidth; }; @@ -117,6 +125,9 @@ public: virtual void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const; }; +NewFont *loadFont(Common::SeekableReadStream &stream); +NewFont *loadFont(const byte *src, uint32 size); + #if (defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__)) # define DEFINE_FONT(n) \ const NewFont *n; \ diff --git a/graphics/fontman.cpp b/graphics/fontman.cpp index d38201ace4..9b567c0be8 100644 --- a/graphics/fontman.cpp +++ b/graphics/fontman.cpp @@ -58,8 +58,11 @@ FontManager::FontManager() { } #endif -//const Font *FontManager::getFontByName(const Common::String &name) const { -//} +const Font *FontManager::getFontByName(const Common::String &name) const { + if (!_fontMap.contains(name)) + return 0; + return _fontMap[name]; +} const Font *FontManager::getFontByUsage(FontUsage usage) const { switch (usage) { diff --git a/graphics/fontman.h b/graphics/fontman.h index ba5939940c..6d214657b9 100644 --- a/graphics/fontman.h +++ b/graphics/fontman.h @@ -26,6 +26,7 @@ #include "common/scummsys.h" #include "common/singleton.h" #include "common/str.h" +#include "common/hashmap.h" #include "graphics/font.h" @@ -46,7 +47,23 @@ public: * @param name the name of the font to be retrieved. * @return a pointer to a font, or 0 if no suitable font was found. */ - //const Font *getFontByName(const Common::String &name) const; + const Font *getFontByName(const Common::String &name) const; + + /** + * Associates a font object with an 'name' + * + * @param name the name of the font + * @param font the font object + * @return true on success, false on failure + */ + bool assignFontToName(const Common::String &name, const Font *font) { _fontMap[name] = font; return true; } + + /** + * Removes binding from name to font + * + * @param name name which should be removed + */ + void removeFontName(const Common::String &name) { _fontMap.erase(name); } /** * Retrieve a font object based on what it is supposed @@ -63,6 +80,8 @@ public: private: friend class Common::Singleton<SingletonBaseType>; FontManager(); + + Common::HashMap<Common::String, const Font *> _fontMap; }; diff --git a/gui/EditTextWidget.cpp b/gui/EditTextWidget.cpp index de54e46048..fa5bdfdca8 100644 --- a/gui/EditTextWidget.cpp +++ b/gui/EditTextWidget.cpp @@ -72,7 +72,7 @@ void EditTextWidget::drawWidget(bool hilite) { // Draw the text adjustOffset(); - g_gui.theme()->drawText(Common::Rect(_x+2,_y+2, _x+getEditRect().width()-2, _y+_h-2), _editString, Theme::kStateEnabled, Theme::kTextAlignLeft, false, -_editScrollOffset, false); + g_gui.theme()->drawText(Common::Rect(_x+2,_y+2, _x+getEditRect().width()-2, _y+_h-2), _editString, Theme::kStateEnabled, Theme::kTextAlignLeft, false, -_editScrollOffset, false, Theme::kFontStyleNormal); } Common::Rect EditTextWidget::getEditRect() const { diff --git a/gui/ThemeClassic.cpp b/gui/ThemeClassic.cpp index 47cb4c6122..d33897774d 100644 --- a/gui/ThemeClassic.cpp +++ b/gui/ThemeClassic.cpp @@ -149,7 +149,7 @@ void ThemeClassic::drawDialogBackground(const Common::Rect &r, uint16 hints, kSt addDirtyRect(r, (hints & THEME_HINT_SAVE_BACKGROUND) != 0); } -void ThemeClassic::drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis) { +void ThemeClassic::drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis, kFontStyle font) { if (!_initOk) return; diff --git a/gui/ThemeNew.cpp b/gui/ThemeNew.cpp index d6ab1666e7..0f064baa29 100644 --- a/gui/ThemeNew.cpp +++ b/gui/ThemeNew.cpp @@ -119,7 +119,8 @@ OverlayColor calcGradient(OverlayColor start, OverlayColor end, int pos, int max #pragma mark - ThemeNew::ThemeNew(OSystem *system, Common::String stylefile) : Theme(), _system(system), _screen(), _initOk(false), -_lastUsedBitMask(0), _forceRedraw(false), _font(0), _imageHandles(0), _images(0), _colors(), _gradientFactors() { +_lastUsedBitMask(0), _forceRedraw(false), _fonts(), _imageHandles(0), _images(0), _colors(), _gradientFactors() { + _stylefile = stylefile; _initOk = false; memset(&_screen, 0, sizeof(_screen)); memset(&_dialog, 0, sizeof(_dialog)); @@ -130,11 +131,6 @@ _lastUsedBitMask(0), _forceRedraw(false), _font(0), _imageHandles(0), _images(0) if (_screen.pixels) { _initOk = true; clearAll(); - if (_screen.w >= 400 && _screen.h >= 300) { - _font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont); - } else { - _font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont); - } } if (ConfMan.hasKey("extrapath")) @@ -167,6 +163,7 @@ _lastUsedBitMask(0), _forceRedraw(false), _font(0), _imageHandles(0), _images(0) delete [] buffer; buffer = 0; } else { + unzClose(zipFile); warning("Can not find theme config file '%s'", (stylefile + ".ini").c_str()); return; } @@ -296,6 +293,9 @@ _lastUsedBitMask(0), _forceRedraw(false), _font(0), _imageHandles(0), _images(0) warning("no valid 'inactive_dialog_shading' specified"); } } + + // load up all fonts + setupFonts(); // load the colors from the config file setupColors(); @@ -314,6 +314,7 @@ _lastUsedBitMask(0), _forceRedraw(false), _font(0), _imageHandles(0), _images(0) } ThemeNew::~ThemeNew() { + deleteFonts(); deinit(); delete [] _images; _images = 0; @@ -338,11 +339,7 @@ bool ThemeNew::init() { if (_screen.pixels) { _initOk = true; clearAll(); - if (_screen.w >= 400 && _screen.h >= 300) { - _font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont); - } else { - _font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont); - } + setupFonts(); } if (isThemeLoadingRequired()) { @@ -471,10 +468,10 @@ void ThemeNew::drawDialogBackground(const Common::Rect &r, uint16 hints, kState addDirtyRect(r2, (hints & THEME_HINT_SAVE_BACKGROUND) != 0, true); } -void ThemeNew::drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis) { +void ThemeNew::drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis, kFontStyle font) { if (!_initOk) return; - Common::Rect r2(r.left, r.top, r.right, r.top+_font->getFontHeight()); + Common::Rect r2(r.left, r.top, r.right, r.top+getFontHeight(font)); uint32 color; restoreBackground(r2); @@ -487,7 +484,7 @@ void ThemeNew::drawText(const Common::Rect &r, const Common::String &str, kState color = getColor(state); } - _font->drawString(&_screen, str, r.left, r.top, r.width(), color, convertAligment(align), deltax, useEllipsis); + getFont(font)->drawString(&_screen, str, r.left, r.top, r.width(), color, convertAligment(align), deltax, useEllipsis); addDirtyRect(r2); } @@ -559,7 +556,7 @@ void ThemeNew::drawButton(const Common::Rect &r, const Common::String &str, kSta _gradientFactors[kButtonFactor]); } - const int off = (r.height() - _font->getFontHeight()) / 2; + const int off = (r.height() - getFontHeight()) / 2; OverlayColor col = 0; switch (state) { @@ -576,7 +573,7 @@ void ThemeNew::drawButton(const Common::Rect &r, const Common::String &str, kSta break; }; - _font->drawString(&_screen, str, r.left, r.top + off, r.width(), col, Graphics::kTextAlignCenter, 0, true); + getFont()->drawString(&_screen, str, r.left, r.top + off, r.width(), col, Graphics::kTextAlignCenter, 0, true); addDirtyRect(r2); } @@ -657,7 +654,7 @@ void ThemeNew::drawCheckbox(const Common::Rect &r, const Common::String &str, bo drawSurface(Common::Rect(r.left, r.top, r.left+checkBox->w, r.top+checkBox->h), checkBox, false, false, (state == kStateDisabled) ? 128 : 256); r2.left += checkBoxSize + 5; - _font->drawString(&_screen, str, r2.left, r2.top, r2.width(), getColor(state), Graphics::kTextAlignLeft, 0, false); + getFont()->drawString(&_screen, str, r2.left, r2.top, r2.width(), getColor(state), Graphics::kTextAlignLeft, 0, false); addDirtyRect(r); } @@ -679,7 +676,7 @@ void ThemeNew::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const drawRectMasked(tabRect, surface(kTabBkgdCorner), surface(kTabBkgdTop), surface(kTabBkgdLeft), surface(kTabBkgd), 128, _colors[kTabBackgroundStart], tabEnd, _gradientFactors[kTabFactor], true); - _font->drawString(&_screen, tabs[i], tabRect.left, tabRect.top+2, tabRect.width(), getColor(kStateEnabled), Graphics::kTextAlignCenter, 0, true); + getFont()->drawString(&_screen, tabs[i], tabRect.left, tabRect.top+2, tabRect.width(), getColor(kStateEnabled), Graphics::kTextAlignCenter, 0, true); } Common::Rect widgetBackground = Common::Rect(r.left, r.top + tabHeight, r.right, r.bottom); @@ -692,7 +689,7 @@ void ThemeNew::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const drawRectMasked(tabRect, surface(kTabBkgdCorner), surface(kTabBkgdTop), surface(kTabBkgdLeft), surface(kTabBkgd), 256, _colors[kTabBackgroundStart], tabEnd, _gradientFactors[kTabFactor], true); - _font->drawString(&_screen, tabs[active], tabRect.left, tabRect.top+2, tabRect.width(), getColor(kStateHighlight), Graphics::kTextAlignCenter, 0, true); + getFont()->drawString(&_screen, tabs[active], tabRect.left, tabRect.top+2, tabRect.width(), getColor(kStateHighlight), Graphics::kTextAlignCenter, 0, true); addDirtyRect(r); } @@ -1266,6 +1263,116 @@ void ThemeNew::setupColors() { getColorFromConfig(_configFile, "caret_color", _colors[kCaretColor]); } +#define FONT_NAME_NORMAL "newgui_normal" +#define FONT_NAME_BOLD "newgui_bold" +#define FONT_NAME_ITALIC "newgui_italic" + +void ThemeNew::setupFonts() { + if (_screen.w >= 400 && _screen.h >= 300) { + if (_configFile.hasKey("fontfile_bold", "extra")) { + _fonts[kFontStyleBold] = FontMan.getFontByName(FONT_NAME_BOLD); + + if (!_fonts[kFontStyleBold]) { + Common::String temp; + _configFile.getKey("fontfile_bold", "extra", temp); + + _fonts[kFontStyleBold] = loadFont(temp.c_str()); + if (!_fonts[kFontStyleBold]) + error("Couldn't load bold font '%s'", temp.c_str()); + + FontMan.assignFontToName(FONT_NAME_BOLD, _fonts[kFontStyleBold]); + } + } else { + _fonts[kFontStyleBold] = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont); + } + + if (_configFile.hasKey("fontfile_normal", "extra")) { + _fonts[kFontStyleNormal] = FontMan.getFontByName(FONT_NAME_NORMAL); + + if (!_fonts[kFontStyleNormal]) { + Common::String temp; + _configFile.getKey("fontfile_normal", "extra", temp); + + _fonts[kFontStyleNormal] = loadFont(temp.c_str()); + if (!_fonts[kFontStyleNormal]) + error("Couldn't load normal font '%s'", temp.c_str()); + + FontMan.assignFontToName(FONT_NAME_NORMAL, _fonts[kFontStyleNormal]); + } + } else { + _fonts[kFontStyleNormal] = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont); + } + + if (_configFile.hasKey("fontfile_italic", "extra")) { + _fonts[kFontStyleItalic] = FontMan.getFontByName(FONT_NAME_ITALIC); + + if (!_fonts[kFontStyleItalic]) { + Common::String temp; + _configFile.getKey("fontfile_italic", "extra", temp); + + _fonts[kFontStyleNormal] = loadFont(temp.c_str()); + if (!_fonts[kFontStyleItalic]) + error("Couldn't load italic font '%s'", temp.c_str()); + + FontMan.assignFontToName(FONT_NAME_ITALIC, _fonts[kFontStyleItalic]); + } + } else { + _fonts[kFontStyleItalic] = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont); + } + } else { + _fonts[kFontStyleBold] = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont); + _fonts[kFontStyleNormal] = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont); + _fonts[kFontStyleItalic] = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont); + } +} + +void ThemeNew::deleteFonts() { + const Graphics::Font *normal = FontMan.getFontByName(FONT_NAME_NORMAL); + const Graphics::Font *bold = FontMan.getFontByName(FONT_NAME_BOLD); + const Graphics::Font *italic = FontMan.getFontByName(FONT_NAME_ITALIC); + + delete normal; + delete bold; + delete italic; + + FontMan.removeFontName(FONT_NAME_NORMAL); + FontMan.removeFontName(FONT_NAME_BOLD); + FontMan.removeFontName(FONT_NAME_ITALIC); +} + +const Graphics::Font *ThemeNew::loadFont(const char *filename) { + const Graphics::Font *font = 0; + + Common::File fontFile; + if (fontFile.open(filename)) { + font = Graphics::loadFont(fontFile); + if (font) + return font; + } + +#ifdef USE_ZLIB + unzFile zipFile = unzOpen((_stylefile + ".zip").c_str()); + if (zipFile && unzLocateFile(zipFile, filename, 2) == UNZ_OK) { + unz_file_info fileInfo; + unzOpenCurrentFile(zipFile); + unzGetCurrentFileInfo(zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0); + uint8 *buffer = new uint8[fileInfo.uncompressed_size+1]; + assert(buffer); + memset(buffer, 0, (fileInfo.uncompressed_size+1)*sizeof(uint8)); + unzReadCurrentFile(zipFile, buffer, fileInfo.uncompressed_size); + unzCloseCurrentFile(zipFile); + Common::MemoryReadStream stream(buffer, fileInfo.uncompressed_size+1); + + font = Graphics::loadFont(stream); + + delete [] buffer; + buffer = 0; + } + unzClose(zipFile); +#endif + return font; +} + #pragma mark - OverlayColor ThemeNew::calcLuminance(OverlayColor col) { diff --git a/gui/eval.cpp b/gui/eval.cpp index 5d661cc9cf..61f5307355 100644 --- a/gui/eval.cpp +++ b/gui/eval.cpp @@ -250,6 +250,10 @@ static const BuiltinConsts builtinConsts[] = { {"kTextAlignRight", kTextAlignRight}, {"kTextAlignCenter", kTextAlignCenter}, + {"kFontStyleBold", Theme::kFontStyleBold}, + {"kFontStyleNormal", Theme::kFontStyleNormal}, + {"kFontStyleItalic", Theme::kFontStyleItalic}, + {"false", 0}, {"true", 1}, {NULL, 0} diff --git a/gui/newgui.h b/gui/newgui.h index 8b8babe27c..9e46738162 100644 --- a/gui/newgui.h +++ b/gui/newgui.h @@ -73,10 +73,10 @@ public: Theme *theme() { return _theme; } Eval *evaluator() { return _theme->_evaluator; } - const Graphics::Font &getFont() const { return *(_theme->getFont()); } - int getFontHeight() const { return _theme->getFontHeight(); } - int getStringWidth(const Common::String &str) const { return _theme->getStringWidth(str); } - int getCharWidth(byte c) const { return _theme->getCharWidth(c); } + const Graphics::Font &getFont(Theme::kFontStyle style = Theme::kFontStyleBold) const { return *(_theme->getFont(style)); } + int getFontHeight(Theme::kFontStyle style = Theme::kFontStyleBold) const { return _theme->getFontHeight(style); } + int getStringWidth(const Common::String &str, Theme::kFontStyle style = Theme::kFontStyleBold) const { return _theme->getStringWidth(str, style); } + int getCharWidth(byte c, Theme::kFontStyle style = Theme::kFontStyleBold) const { return _theme->getCharWidth(c, style); } WidgetSize getWidgetSize(); diff --git a/gui/theme.h b/gui/theme.h index 9c3bcf95d4..734ff3c37a 100644 --- a/gui/theme.h +++ b/gui/theme.h @@ -94,6 +94,13 @@ public: kScrollbarStateSinglePage }; + enum kFontStyle { + kFontStyleBold = 0, // standard font + kFontStyleNormal = 1, + kFontStyleItalic = 2, + kFontStyleMax + }; + virtual bool init() = 0; virtual void deinit() = 0; @@ -114,13 +121,13 @@ public: virtual const Common::ConfigFile &getConfigFile() { return _configFile; } - virtual const Graphics::Font *getFont() const = 0; - virtual int getFontHeight() const = 0; - virtual int getStringWidth(const Common::String &str) const = 0; - virtual int getCharWidth(byte c) const = 0; + virtual const Graphics::Font *getFont(kFontStyle font = kFontStyleBold) const = 0; + virtual int getFontHeight(kFontStyle font = kFontStyleBold) const = 0; + virtual int getStringWidth(const Common::String &str, kFontStyle font = kFontStyleBold) const = 0; + virtual int getCharWidth(byte c, kFontStyle font = kFontStyleBold) const = 0; virtual void drawDialogBackground(const Common::Rect &r, uint16 hints, kState state = kStateEnabled) = 0; - virtual void drawText(const Common::Rect &r, const Common::String &str, kState state = kStateEnabled, kTextAlign align = kTextAlignCenter, bool inverted = false, int deltax = 0, bool useEllipsis = true) = 0; + virtual void drawText(const Common::Rect &r, const Common::String &str, kState state = kStateEnabled, kTextAlign align = kTextAlignCenter, bool inverted = false, int deltax = 0, bool useEllipsis = true, kFontStyle font = kFontStyleBold) = 0; // this should ONLY be used by the debugger until we get a nicer solution virtual void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state = kStateEnabled) = 0; @@ -211,13 +218,13 @@ public: typedef Common::String String; - const Graphics::Font *getFont() const { return _font; } - int getFontHeight() const { if (_initOk) return _font->getFontHeight(); return 0; } - int getStringWidth(const String &str) const { if (_initOk) return _font->getStringWidth(str); return 0; } - int getCharWidth(byte c) const { if (_initOk) return _font->getCharWidth(c); return 0; } + const Graphics::Font *getFont(kFontStyle font) const { return _font; } + int getFontHeight(kFontStyle font = kFontStyleBold) const { if (_initOk) return _font->getFontHeight(); return 0; } + int getStringWidth(const String &str, kFontStyle font) const { if (_initOk) return _font->getStringWidth(str); return 0; } + int getCharWidth(byte c, kFontStyle font) const { if (_initOk) return _font->getCharWidth(c); return 0; } void drawDialogBackground(const Common::Rect &r, uint16 hints, kState state); - void drawText(const Common::Rect &r, const String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis); + void drawText(const Common::Rect &r, const String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis, kFontStyle font); void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state); void drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state); @@ -284,13 +291,13 @@ public: void setDrawArea(const Common::Rect &r); void resetDrawArea(); - const Graphics::Font *getFont() const { return _font; } - int getFontHeight() const { if (_font) return _font->getFontHeight(); return 0; } - int getStringWidth(const String &str) const { if (_font) return _font->getStringWidth(str); return 0; } - int getCharWidth(byte c) const { if (_font) return _font->getCharWidth(c); return 0; } + const Graphics::Font *getFont(kFontStyle font = kFontStyleBold) const { return _fonts[font]; } + int getFontHeight(kFontStyle font = kFontStyleBold) const { if (_fonts[font]) return _fonts[font]->getFontHeight(); return 0; } + int getStringWidth(const String &str, kFontStyle font = kFontStyleBold) const { if (_fonts[font]) return _fonts[font]->getStringWidth(str); return 0; } + int getCharWidth(byte c, kFontStyle font = kFontStyleBold) const { if (_fonts[font]) return _fonts[font]->getCharWidth(c); return 0; } void drawDialogBackground(const Common::Rect &r, uint16 hints, kState state); - void drawText(const Common::Rect &r, const String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis); + void drawText(const Common::Rect &r, const String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis, kFontStyle font); void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state); void drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state); @@ -338,9 +345,11 @@ private: Graphics::Surface _screen; Common::Rect _shadowDrawArea; + Common::String _stylefile; + bool _initOk; bool _forceRedraw; - + int _lastUsedBitMask; void resetupGuiRenderer(); void setupColors(); @@ -352,7 +361,10 @@ private: Graphics::Surface screen; } *_dialog; - const Graphics::Font *_font; + void setupFonts(); + void deleteFonts(); + const Graphics::Font *loadFont(const char *filename); + const Graphics::Font *_fonts[kFontStyleMax]; public: enum kImageHandles { |