gambas-source-code/gb.qt4/src/CFont.cpp

655 lines
12 KiB
C++
Raw Normal View History

/***************************************************************************
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);
}
[DEVELOPMENT ENVIRONMENT] * NEW: Use the new TextEditor instead of the old Editor control. Consequently, the 'gb.qt4.ext' component is not needed by the IDE anymore. * NEW: Option dialog: Put the fonts options in their own panel. * NEW: Farm client: Add new categories. [GB.FORM] * NEW: Fix some breeze icons. [GB.FORM.EDITOR] * NEW: TextEditor: Development continues... [GB.GTK] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". * BUG: Remove a GTK+ bug workaround in the Control.Refresh() method. Maybe it is useless now. [GB.GTK3] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". * BUG: Remove a GTK+ bug workaround in the Control.Refresh() method. Maybe it is useless now. [GB.GUI.BASE] * BUG: GridView: Use the new Font.Modified property so that the initial font of a cell is always the font of the GridView, even if it changed after the cell has been filled. [GB.QT4] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". [GB.QT5] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". git-svn-id: svn://localhost/gambas/trunk@7089 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2015-05-20 00:21:22 +02:00
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
[DEVELOPMENT ENVIRONMENT] * NEW: Take property synonymous into account. * BUG: Pasting text as comments correctly converts tabulations into spaces. [INTERPRETER] * NEW: GB.RaiseBegin() and GB.RaiseEnd() are two new intepreter APIs that allow to define a callback that will be called if an exception is raised during a call to GB.Raise(). * BUG: CATCH and FINALLY correctly restore the stack pointer. Without that, it is possible to use more stack than possible and to crash the interpreter. [COMPILER] * NEW: A property now can has up to four different names. The syntax is: "Property Name [ , Synonymous1, ..., Synonymous3 ] As Datatype". [GB.DB] * BUG: Table.Type property now correctly handle null table types. [GB.DB.FORM] * NEW: DataBrowser.Grid is a new property to define the grid visibility. * BUG: The DataBrowser and DataView controls have been fixed. There is only one problem to fix that depends on a gb.gtk bug. [GB.DRAW] * BUG: Setting Draw.Font to NULL does not crash anymore, and raise an error instead. [GB.FORM] * NEW: The new GridView is finished and replaces the old one now. * NEW: GridView.ShowCursor is a new property that displays a light cursor around the current cell when set. [GB.GTK] * NEW: Font.Copy() is a new method to copy a font object. * NEW: GTK+ GridView has been disabled. * NEW: The Container Insert event has been renamed as NewChild. [GB.QT4] * NEW: Font.Copy() is a new method to copy a font object. * NEW: Qt4 GridView has been disabled. * NEW: The Container Insert event has been renamed as NewChild. * BUG: If the DrawingArea Draw event handler raises an error, then the interpreter should not crash anymore. [GB.QT4.EXT] * BUG: Fix an uninitialized field in Editor internal GLine class. git-svn-id: svn://localhost/gambas/trunk@4503 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2012-02-25 02:35:55 +01:00
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
[DEVELOPMENT ENVIRONMENT] * NEW: Use the new TextEditor instead of the old Editor control. Consequently, the 'gb.qt4.ext' component is not needed by the IDE anymore. * NEW: Option dialog: Put the fonts options in their own panel. * NEW: Farm client: Add new categories. [GB.FORM] * NEW: Fix some breeze icons. [GB.FORM.EDITOR] * NEW: TextEditor: Development continues... [GB.GTK] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". * BUG: Remove a GTK+ bug workaround in the Control.Refresh() method. Maybe it is useless now. [GB.GTK3] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". * BUG: Remove a GTK+ bug workaround in the Control.Refresh() method. Maybe it is useless now. [GB.GUI.BASE] * BUG: GridView: Use the new Font.Modified property so that the initial font of a cell is always the font of the GridView, even if it changed after the cell has been filled. [GB.QT4] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". [GB.QT5] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". git-svn-id: svn://localhost/gambas/trunk@7089 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2015-05-20 00:21:22 +02:00
BEGIN_PROPERTY(Font_Modified)
if (READ_PROPERTY)
GB.ReturnBoolean(THIS->modified);
else
THIS->modified = VPROP(GB_BOOLEAN);
END_PROPERTY
//---------------------------------------------------------------------------
GB_DESC CFontsDesc[] =
{
[DEVELOPMENT ENVIRONMENT] * NEW: Use the new TextEditor instead of the old Editor control. Consequently, the 'gb.qt4.ext' component is not needed by the IDE anymore. * NEW: Option dialog: Put the fonts options in their own panel. * NEW: Farm client: Add new categories. [GB.FORM] * NEW: Fix some breeze icons. [GB.FORM.EDITOR] * NEW: TextEditor: Development continues... [GB.GTK] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". * BUG: Remove a GTK+ bug workaround in the Control.Refresh() method. Maybe it is useless now. [GB.GTK3] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". * BUG: Remove a GTK+ bug workaround in the Control.Refresh() method. Maybe it is useless now. [GB.GUI.BASE] * BUG: GridView: Use the new Font.Modified property so that the initial font of a cell is always the font of the GridView, even if it changed after the cell has been filled. [GB.QT4] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". [GB.QT5] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". git-svn-id: svn://localhost/gambas/trunk@7089 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2015-05-20 00:21:22 +02:00
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),
[DEVELOPMENT ENVIRONMENT] * NEW: Use the new TextEditor instead of the old Editor control. Consequently, the 'gb.qt4.ext' component is not needed by the IDE anymore. * NEW: Option dialog: Put the fonts options in their own panel. * NEW: Farm client: Add new categories. [GB.FORM] * NEW: Fix some breeze icons. [GB.FORM.EDITOR] * NEW: TextEditor: Development continues... [GB.GTK] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". * BUG: Remove a GTK+ bug workaround in the Control.Refresh() method. Maybe it is useless now. [GB.GTK3] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". * BUG: Remove a GTK+ bug workaround in the Control.Refresh() method. Maybe it is useless now. [GB.GUI.BASE] * BUG: GridView: Use the new Font.Modified property so that the initial font of a cell is always the font of the GridView, even if it changed after the cell has been filled. [GB.QT4] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". [GB.QT5] * NEW: Font.Modified is a new property that returns if the font has been modified, i.e. if one of its properties has been set. This property can be freely reset. That way, it allows to implement the concept of "default font". git-svn-id: svn://localhost/gambas/trunk@7089 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2015-05-20 00:21:22 +02:00
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
};