ad7b2a4937
[GB.GTK] * NEW: Automatically set Paint.FontScale when painting on a printer, so that font size is actually the same as on the screen. [GB.GTK3] * NEW: Automatically set Paint.FontScale when painting on a printer, so that font size is actually the same as on the screen. [GB.QT4] * NEW: Automatically set Paint.FontScale when painting on a printer, so that font size is actually the same as on the screen. * BUG: Fix rich text size margins between paragraphs and titles. * BUG: Fix rich text size computation. [GB.QT5] * NEW: Automatically set Paint.FontScale when painting on a printer, so that font size is actually the same as on the screen. * BUG: Fix rich text size margins between paragraphs and titles. * BUG: Fix rich text size computation.
654 lines
12 KiB
C++
654 lines
12 KiB
C++
/***************************************************************************
|
|
|
|
CFont.cpp
|
|
|
|
(c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>
|
|
|
|
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, 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 Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA.
|
|
|
|
***************************************************************************/
|
|
|
|
#define __CFONT_CPP
|
|
|
|
#include "gambas.h"
|
|
#include "main.h"
|
|
|
|
#include <math.h>
|
|
|
|
#include <QApplication>
|
|
#include <QStringList>
|
|
#include <QFontMetrics>
|
|
#include <QFontDatabase>
|
|
#include <QTextDocument>
|
|
|
|
#include "CWidget.h"
|
|
#include "CDraw.h"
|
|
#include "CFont.h"
|
|
|
|
#include "gb.form.font.h"
|
|
|
|
#ifdef USE_DPI
|
|
int CFONT_dpi = 96;
|
|
#endif
|
|
|
|
static GB_CLASS CLASS_Font;
|
|
|
|
static QStringList _families;
|
|
static QFontDatabase *_info = 0;
|
|
|
|
static void init_font_database()
|
|
{
|
|
if (_info)
|
|
return;
|
|
|
|
_info = new QFontDatabase();
|
|
_families = _info->families();
|
|
}
|
|
|
|
static void exit_font_database()
|
|
{
|
|
if (_info)
|
|
delete _info;
|
|
}
|
|
|
|
|
|
CFONT *CFONT_create(const QFont &font, FONT_FUNC func, void *object)
|
|
{
|
|
CFONT *_object = (CFONT *)GB.New(CLASS_Font, NULL, NULL);
|
|
|
|
*(THIS->font) = font;
|
|
THIS->func = func;
|
|
THIS->object = object;
|
|
if (object)
|
|
GB.Ref(object);
|
|
|
|
return THIS;
|
|
}
|
|
|
|
void CFONT_set(FONT_FUNC func, void *font, void *object)
|
|
{
|
|
if (!font)
|
|
{
|
|
QFont f;
|
|
(*func)(f, object);
|
|
}
|
|
else
|
|
(*func)(*(((CFONT *)font)->font), object);
|
|
}
|
|
|
|
|
|
double CFONT_size_real_to_virtual(double size)
|
|
{
|
|
#ifdef USE_DPI
|
|
return size * (double)QPaintDevice::x11AppDpiY() / CFONT_dpi;
|
|
#else
|
|
return size;
|
|
#endif
|
|
}
|
|
|
|
double CFONT_size_virtual_to_real(double size)
|
|
{
|
|
#ifdef USE_DPI
|
|
return size * CFONT_dpi / (double)QPaintDevice::x11AppDpiY();
|
|
#else
|
|
return size;
|
|
#endif
|
|
}
|
|
|
|
|
|
static void set_font_from_string(CFONT *_object, QString &str)
|
|
{
|
|
QStringList list;
|
|
QString name, elt, flag;
|
|
double size = 0;
|
|
bool number;
|
|
QFont f;
|
|
|
|
// (!) Remove this test later, it is for backward compatibility
|
|
|
|
if (str.length())
|
|
{
|
|
list = str.split(",");
|
|
|
|
for (QStringList::Iterator it = list.begin(); it != list.end(); ++it )
|
|
{
|
|
elt = (*it);
|
|
elt = elt.trimmed();
|
|
flag = elt.toUpper();
|
|
size = elt.toDouble(&number);
|
|
|
|
if (flag == "BOLD")
|
|
{
|
|
f.setBold(true);
|
|
#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
|
|
f.setStyleName("Bold");
|
|
#endif
|
|
}
|
|
else if (flag == "ITALIC")
|
|
f.setItalic(true);
|
|
else if (flag == "UNDERLINE")
|
|
f.setUnderline(true);
|
|
else if (flag == "STRIKEOUT")
|
|
f.setStrikeOut(true);
|
|
else if (flag[0] == '+' || flag[0] == '-' || flag[0] == '0')
|
|
{
|
|
//f.setPointSizeFloat((int)(powf(qApp->font().pointSizeFloat(), 1.0 + ((int)size / 10.0)) + 0.5));
|
|
f.setPointSizeF(GRADE_TO_SIZE(size, qApp->font().pointSizeF()));
|
|
}
|
|
else if (number && size > 0.0)
|
|
f.setPointSizeF(SIZE_VIRTUAL_TO_REAL(size));
|
|
else if (elt.length())
|
|
{
|
|
f.setBold(false);
|
|
f.setItalic(false);
|
|
f.setUnderline(false);
|
|
f.setStrikeOut(false);
|
|
f.setFamily(elt);
|
|
#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
|
|
f.setStyleName("");
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
*(THIS->font) = f;
|
|
}
|
|
|
|
|
|
BEGIN_METHOD_VOID(Font_init)
|
|
|
|
CLASS_Font = GB.FindClass("Font");
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD_VOID(Font_exit)
|
|
|
|
exit_font_database();
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD(Font_new, GB_STRING font)
|
|
|
|
QString s;
|
|
|
|
THIS->font = new QFont;
|
|
THIS->func = 0;
|
|
THIS->object = 0;
|
|
|
|
if (!MISSING(font))
|
|
QString s = QSTRING_ARG(font);
|
|
|
|
set_font_from_string(THIS, s);
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD_VOID(Font_free)
|
|
|
|
if (THIS->object)
|
|
GB.Unref(POINTER(&THIS->object));
|
|
delete THIS->font;
|
|
|
|
END_METHOD
|
|
|
|
|
|
static void CFONT_manage(int prop, CFONT *_object, void *_param)
|
|
{
|
|
bool noResize = false;
|
|
QFont *f = THIS->font;
|
|
double size;
|
|
|
|
noResize = true; //((long)THIS->control == CFONT_DRAW && !DRAW_must_resize_font());
|
|
|
|
if (READ_PROPERTY)
|
|
{
|
|
switch(prop)
|
|
{
|
|
case CFONT::Name: GB.ReturnNewZeroString(f->family().toUtf8()); break;
|
|
case CFONT::Size:
|
|
if (noResize)
|
|
GB.ReturnFloat(f->pointSizeF());
|
|
else
|
|
GB.ReturnFloat(SIZE_REAL_TO_VIRTUAL(f->pointSizeF()));
|
|
break;
|
|
case CFONT::Grade:
|
|
GB.ReturnInteger(SIZE_TO_GRADE(f->pointSizeF(), qApp->font().pointSizeF()));
|
|
break;
|
|
case CFONT::Bold: GB.ReturnBoolean(f->bold()); break;
|
|
case CFONT::Italic: GB.ReturnBoolean(f->italic()); break;
|
|
case CFONT::Underline: GB.ReturnBoolean(f->underline()); break;
|
|
case CFONT::Strikeout: GB.ReturnBoolean(f->strikeOut()); break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (prop)
|
|
{
|
|
case CFONT::Name: f->setFamily(GB.ToZeroString(PROP(GB_STRING))); break;
|
|
case CFONT::Size:
|
|
if (noResize)
|
|
size = VPROP(GB_FLOAT);
|
|
else
|
|
size = SIZE_VIRTUAL_TO_REAL(VPROP(GB_FLOAT));
|
|
|
|
if (size <= 0)
|
|
{
|
|
GB.Error("Bad font size");
|
|
return;
|
|
}
|
|
|
|
f->setPointSizeF(size);
|
|
break;
|
|
case CFONT::Grade:
|
|
{
|
|
int g = VPROP(GB_INTEGER);
|
|
if (g < FONT_GRADE_MIN)
|
|
g = FONT_GRADE_MIN;
|
|
else if (g > FONT_GRADE_MAX)
|
|
g = FONT_GRADE_MAX;
|
|
f->setPointSizeF(GRADE_TO_SIZE(g, qApp->font().pointSizeF()));
|
|
}
|
|
break;
|
|
case CFONT::Bold: f->setBold(VPROP(GB_BOOLEAN)); break;
|
|
case CFONT::Italic: f->setItalic(VPROP(GB_BOOLEAN)); break;
|
|
case CFONT::Underline: f->setUnderline(VPROP(GB_BOOLEAN)); break;
|
|
case CFONT::Strikeout: f->setStrikeOut(VPROP(GB_BOOLEAN)); break;
|
|
}
|
|
|
|
if (THIS->func)
|
|
(*(THIS->func))(*f, THIS->object);
|
|
else if (THIS->object)
|
|
{
|
|
GB_VALUE value;
|
|
value.type = GB_T_OBJECT;
|
|
value._object.value = THIS;
|
|
GB.SetProperty(THIS->object, "Font", &value);
|
|
}
|
|
|
|
THIS->modified = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
BEGIN_PROPERTY(Font_Name)
|
|
|
|
CFONT_manage(CFONT::Name, OBJECT(CFONT), _param);
|
|
|
|
END_PROPERTY
|
|
|
|
BEGIN_PROPERTY(Font_Size)
|
|
|
|
CFONT_manage(CFONT::Size, OBJECT(CFONT), _param);
|
|
|
|
END_PROPERTY
|
|
|
|
BEGIN_PROPERTY(Font_Grade)
|
|
|
|
CFONT_manage(CFONT::Grade, OBJECT(CFONT), _param);
|
|
|
|
END_PROPERTY
|
|
|
|
BEGIN_PROPERTY(Font_Bold)
|
|
|
|
CFONT_manage(CFONT::Bold, OBJECT(CFONT), _param);
|
|
|
|
END_PROPERTY
|
|
|
|
BEGIN_PROPERTY(Font_Italic)
|
|
|
|
CFONT_manage(CFONT::Italic, OBJECT(CFONT), _param);
|
|
|
|
END_PROPERTY
|
|
|
|
BEGIN_PROPERTY(Font_Underline)
|
|
|
|
CFONT_manage(CFONT::Underline, OBJECT(CFONT), _param);
|
|
|
|
END_PROPERTY
|
|
|
|
BEGIN_PROPERTY(Font_Strikeout)
|
|
|
|
CFONT_manage(CFONT::Strikeout, OBJECT(CFONT), _param);
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
static void add(QString &str, const QString& data)
|
|
{
|
|
if (str.length())
|
|
str += ',';
|
|
|
|
str += data;
|
|
}
|
|
|
|
BEGIN_METHOD_VOID(Font_ToString)
|
|
|
|
QFont *f = THIS->font;
|
|
QString str;
|
|
double size;
|
|
|
|
//str = qfont.family().left(1).upper() + qfont.family().mid(1).lower() + " " + QString::number(qfont.pointSize());
|
|
add(str, f->family());
|
|
size = SIZE_REAL_TO_VIRTUAL(f->pointSizeF());
|
|
size = (double)((int)(size * 10 + 0.5)) / 10;
|
|
add(str, QString::number(size));
|
|
if (f->bold())
|
|
add(str, "Bold");
|
|
if (f->italic())
|
|
add(str, "Italic");
|
|
if (f->underline())
|
|
add(str, "Underline");
|
|
if (f->strikeOut())
|
|
add(str, "StrikeOut");
|
|
|
|
RETURN_NEW_STRING(str);
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD(Font_get, GB_STRING str)
|
|
|
|
CFONT *font;
|
|
QString s = QSTRING_ARG(str);
|
|
|
|
//qDebug(">> Font_get: %s", s.latin1());
|
|
|
|
font = (CFONT *)GB.New(CLASS_Font, NULL, NULL);
|
|
set_font_from_string(font, s);
|
|
|
|
GB.ReturnObject(font);
|
|
|
|
//qDebug("<< Font_get");
|
|
|
|
END_METHOD
|
|
|
|
BEGIN_METHOD_VOID(Font_Copy)
|
|
|
|
GB.ReturnObject(CFONT_create(*THIS->font));
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_PROPERTY(Font_Ascent)
|
|
|
|
QFontMetrics fm(*(THIS->font));
|
|
|
|
GB.ReturnInteger(fm.ascent());
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(Font_Descent)
|
|
|
|
QFontMetrics fm(*(THIS->font));
|
|
|
|
GB.ReturnInteger(fm.descent());
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(Font_Height)
|
|
|
|
QFontMetrics fm(*(THIS->font));
|
|
|
|
GB.ReturnInteger(fm.height() + fm.leading());
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_METHOD(Font_TextHeight, GB_STRING text)
|
|
|
|
QFontMetrics fm(*(THIS->font));
|
|
QString s;
|
|
int nl;
|
|
|
|
if (!MISSING(text))
|
|
s = QSTRING_ARG(text);
|
|
nl = s.count('\n');
|
|
|
|
GB.ReturnInteger(fm.height() * (1 + nl) + fm.leading() * nl);
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD(Font_TextWidth, GB_STRING text)
|
|
|
|
QFontMetricsF fm(*(THIS->font));
|
|
QStringList sl;
|
|
qreal w, width = 0;
|
|
int i;
|
|
|
|
QString str = QSTRING_ARG(text);
|
|
|
|
sl = str.split('\n');
|
|
|
|
for (i = 0; i < (int)sl.count(); i++)
|
|
{
|
|
w = fm.width(sl[i]);
|
|
if (w > width) width = w;
|
|
}
|
|
|
|
GB.ReturnInteger((int)(width + 0.5));
|
|
|
|
END_METHOD
|
|
|
|
|
|
static void rich_text_size(CFONT *_object, char *text, int len, int sw, int *w, int *h)
|
|
{
|
|
QTextDocument rt;
|
|
|
|
DRAW_init_rich_text(&rt, *(THIS->font));
|
|
|
|
rt.setHtml(QString::fromUtf8((const char *)text, len));
|
|
|
|
if (sw > 0)
|
|
rt.setTextWidth(sw);
|
|
|
|
if (w) *w = rt.idealWidth();
|
|
if (h) *h = rt.size().height();
|
|
}
|
|
|
|
|
|
BEGIN_METHOD(Font_RichTextWidth, GB_STRING text)
|
|
|
|
int w;
|
|
|
|
rich_text_size(THIS, STRING(text), LENGTH(text), -1, &w, NULL);
|
|
GB.ReturnInteger(w);
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD(Font_RichTextHeight, GB_STRING text; GB_INTEGER width)
|
|
|
|
int h;
|
|
|
|
rich_text_size(THIS, STRING(text), LENGTH(text), VARGOPT(width, -1), NULL, &h);
|
|
GB.ReturnInteger(h);
|
|
|
|
END_METHOD
|
|
|
|
|
|
#ifdef USE_DPI
|
|
BEGIN_PROPERTY(Font_Resolution)
|
|
|
|
if (READ_PROPERTY)
|
|
GB.ReturnInteger(CFONT_dpi);
|
|
else
|
|
{
|
|
CFONT_dpi = VPROP(GB_INTEGER);
|
|
if (CFONT_dpi < 1)
|
|
CFONT_dpi = 96;
|
|
}
|
|
|
|
END_PROPERTY
|
|
#endif
|
|
|
|
BEGIN_METHOD_VOID(Fonts_next)
|
|
|
|
QString s;
|
|
int *index = (int *)GB.GetEnum();
|
|
|
|
if (*index == 0)
|
|
init_font_database();
|
|
|
|
if (*index >= _families.count())
|
|
GB.StopEnum();
|
|
else
|
|
{
|
|
s = _families[*index];
|
|
RETURN_NEW_STRING(s);
|
|
(*index)++;
|
|
}
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD(Fonts_Exist, GB_STRING family)
|
|
|
|
int i;
|
|
char *family = GB.ToZeroString(ARG(family));
|
|
|
|
init_font_database();
|
|
|
|
for (i = 0; i < _families.count(); i++)
|
|
{
|
|
if (_families[i] == family)
|
|
{
|
|
GB.ReturnBoolean(true);
|
|
return;
|
|
}
|
|
}
|
|
|
|
GB.ReturnBoolean(false);
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_PROPERTY(Fonts_Count)
|
|
|
|
init_font_database();
|
|
GB.ReturnInteger(_families.count());
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(Font_Fixed)
|
|
|
|
init_font_database();
|
|
GB.ReturnBoolean(_info->isFixedPitch(THIS->font->family()));
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(Font_Scalable)
|
|
|
|
init_font_database();
|
|
GB.ReturnBoolean(_info->isSmoothlyScalable(THIS->font->family()));
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(Font_Styles)
|
|
|
|
QStringList styles;
|
|
GB_ARRAY array;
|
|
int i;
|
|
|
|
init_font_database();
|
|
styles = _info->styles(THIS->font->family());
|
|
|
|
GB.Array.New(&array, GB_T_STRING, styles.count());
|
|
for (i = 0; i < styles.count(); i++)
|
|
*(char **)GB.Array.Get(array, i) = NEW_STRING(styles[i]);
|
|
|
|
GB.ReturnObject(array);
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(Font_Modified)
|
|
|
|
if (READ_PROPERTY)
|
|
GB.ReturnBoolean(THIS->modified);
|
|
else
|
|
THIS->modified = VPROP(GB_BOOLEAN);
|
|
|
|
END_PROPERTY
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
GB_DESC CFontsDesc[] =
|
|
{
|
|
GB_DECLARE_STATIC("Fonts"),
|
|
|
|
GB_STATIC_METHOD("Exist", "b", Fonts_Exist, "(Family)s"),
|
|
GB_STATIC_METHOD("_next", "s", Fonts_next, NULL),
|
|
GB_STATIC_PROPERTY_READ("Count", "i", Fonts_Count),
|
|
|
|
GB_END_DECLARE
|
|
};
|
|
|
|
|
|
GB_DESC CFontDesc[] =
|
|
{
|
|
GB_DECLARE("Font", sizeof(CFONT)),
|
|
//GB_NOT_CREATABLE(),
|
|
|
|
GB_STATIC_METHOD("_init", NULL, Font_init, NULL),
|
|
GB_STATIC_METHOD("_exit", NULL, Font_exit, NULL),
|
|
GB_METHOD("_new", NULL, Font_new, "[(Font)s]"),
|
|
GB_METHOD("_free", NULL, Font_free, NULL),
|
|
GB_METHOD("Copy", "Font", Font_Copy, NULL),
|
|
|
|
GB_PROPERTY("Name", "s", Font_Name),
|
|
GB_PROPERTY("Size", "f", Font_Size),
|
|
GB_PROPERTY("Grade", "i", Font_Grade),
|
|
GB_PROPERTY("Bold", "b", Font_Bold),
|
|
GB_PROPERTY("Italic", "b", Font_Italic),
|
|
GB_PROPERTY("Underline", "b", Font_Underline),
|
|
GB_PROPERTY("Strikeout", "b", Font_Strikeout),
|
|
GB_PROPERTY("Modified", "b", Font_Modified),
|
|
|
|
GB_METHOD("ToString", "s", Font_ToString, NULL),
|
|
|
|
GB_METHOD("TextWidth", "i", Font_TextWidth, "(Text)s"),
|
|
GB_METHOD("TextHeight", "i", Font_TextHeight, "(Text)s"),
|
|
|
|
GB_METHOD("RichTextWidth", "i", Font_RichTextWidth, "(Text)s"),
|
|
GB_METHOD("RichTextHeight", "i", Font_RichTextHeight, "(Text)s[(Width)i]"),
|
|
|
|
GB_STATIC_METHOD("_get", "Font", Font_get, "(Font)s"),
|
|
|
|
#ifdef USE_DPI
|
|
GB_STATIC_PROPERTY("Resolution", "i", Font_Resolution),
|
|
#endif
|
|
|
|
GB_PROPERTY_READ("Ascent", "i", Font_Ascent),
|
|
GB_PROPERTY_READ("Descent", "i", Font_Descent),
|
|
GB_PROPERTY_READ("Height", "i", Font_Height),
|
|
GB_PROPERTY_READ("H", "i", Font_Height),
|
|
|
|
GB_PROPERTY_READ("Fixed", "b", Font_Fixed),
|
|
GB_PROPERTY_READ("Scalable", "b", Font_Scalable),
|
|
GB_PROPERTY_READ("Styles", "String[]", Font_Styles),
|
|
|
|
GB_END_DECLARE
|
|
};
|
|
|
|
|