* fix slow start caused by font fixed/proportional enumeration
    - fixed point evaluator moved to separate thread during first
      instantiation of Font_Browser class.  Actual time to enumerate
      2650 fonts on an i5 3.2 GHz system is approximately 25
      seconds.  Background process does not effect UI, but selection
      of fixed fonts in font browser dialog may not show all of the
      fixed fonts until the evaluator thread exits.
This commit is contained in:
David Freese 2020-10-27 06:58:09 -05:00
parent e95333b9bf
commit c735fb253d
2 changed files with 384 additions and 267 deletions

View file

@ -1,10 +1,16 @@
// ----------------------------------------------------------------------------
// based on similar widget by Mariwan Jalal, in FLTK source
// Font_Browser.h v 0.0.1 2005-10-17
//
// for the Fast Light Tool Kit (FLTK) 1.1.x .
//
// David Freese, w1hkj@w1hkj.com
// based on similar widget by Mariwan Jalal
//
// ----------------------------------------------------------------------------
// Copyright (C) 2014
// Copyright (C) 2014-2020
// David Freese, W1HKJ
//
// This file is part of flrig.
// This file is part of flrig
//
// flrig is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -23,73 +29,101 @@
#ifndef FONTBROWSER_H
#define FONTBROWSER_H
#include <string>
#include <FL/Enumerations.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Widget.H>
#include <FL/Fl_Browser.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Return_Button.H>
#include <FL/Fl_Check_Button.H>
#include "flslider2.h"
// Preview box for showing font
class Preview_Box : public Fl_Widget
{
private:
int fontName;
int fontSize;
Fl_Color fontColor;
int fontName;
int fontSize;
Fl_Color fontColor;
void draw();
void draw();
public:
Preview_Box(int x, int y, int w, int h, const char* l);
void SetFont( int fontname, int fontsize, Fl_Color c);
Preview_Box(int x, int y, int w, int h, const char* l);
void SetFont( int fontname, int fontsize, Fl_Color c);
};
// Font browser widget
class Font_Browser : public Fl_Window
{
friend void *find_fixed_fonts(void *);
public:
enum filter_t { FIXED_WIDTH, VARIABLE_WIDTH, ALL_TYPES };
struct font_pair {
int nbr;
std::string *name;
font_pair() {
nbr = 0;
name = 0;
}
~font_pair() {
if (name) delete name;
}
};
enum filter_t { FIXED_WIDTH, VARIABLE_WIDTH, ALL_TYPES };
// these are shared by all instances of Font_Browser
// created for instance 1 and deleted for instance 0
static int *fixed;
static font_pair *font_pairs;
static int instance;
static int numfonts;
private:
int numfonts;
Fl_Font fontnbr;
int fontsize;
Fl_Color fontcolor;
filter_t filter;
void *data_;
Fl_Browser *lst_Font;
Fl_Browser *lst_Size;
Fl_Value_Input2 *txt_Size;
Fl_Return_Button *btn_OK;
Fl_Button *btn_Cancel;
Fl_Button *btn_Color;
Preview_Box *box_Example;
Fl_Font fontnbr;
int fontsize;
Fl_Color fontcolor;
filter_t filter;
void *data_;
void FontSort();
Fl_Callback* callback_;
Fl_Browser *lst_Font;
Fl_Browser *lst_Size;
Fl_Value_Input2 *txt_Size;
Fl_Return_Button *btn_OK;
Fl_Button *btn_Cancel;
Fl_Button *btn_Color;
Fl_Check_Button *btn_fixed;
Preview_Box *box_Example;
Fl_Callback* callback_;
public:
Font_Browser(int x = 100, int y = 100, int w = 400, int h = 225, const char *lbl = "Font Browser");
void callback(Fl_Callback* cb, void *d = 0) { callback_ = cb; data_ = d; }
static void fb_callback(Fl_Widget* w, void* arg);
void FontNameSelect();
void ColorSelect();
Font_Browser(int x = 100, int y = 100, int w = 430, int h = 225, const char *lbl = "Font Browser");
~Font_Browser();
int numFonts() { return numfonts; }
void fontNumber(Fl_Font n);
Fl_Font fontNumber() { return fontnbr; }
void fontSize(int s);
int fontSize() { return fontsize; }
void fontColor(Fl_Color c);
Fl_Color fontColor() { return fontcolor; };
void callback(Fl_Callback* cb, void *d = 0) { callback_ = cb; data_ = d; }
static void fb_callback(Fl_Widget* w, void* arg);
void FontNameSelect();
void ColorSelect();
const char *fontName() { return lst_Font->text(lst_Font->value()); }
void fontName(const char* n);
int numFonts() { return numfonts; }
void fontNumber(Fl_Font n);
Fl_Font fontNumber() { return fontnbr; }
void fontSize(int s);
int fontSize() { return fontsize; }
void fontColor(Fl_Color c);
Fl_Color fontColor() { return fontcolor; };
static bool fixed_width(Fl_Font f);
void fontFilter(filter_t filter);
const char *fontName() { return lst_Font->text(lst_Font->value()); }
void fontName(const char* n);
static bool fixed_width(Fl_Font f);
void fontFilter(filter_t filter);
};
extern Font_Browser* font_browser;

View file

@ -1,10 +1,8 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2014
// Copyright (C) 2014-2020
// David Freese, W1HKJ
//
// based on similar widget by Mariwan Jalal and distributed with fltk
//
// This file is part of flrig.
// This file is part of flrig
//
// flrig is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -26,7 +24,12 @@
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <list>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <FL/Fl.H>
#include <FL/Fl_Color_Chooser.H>
@ -36,308 +39,388 @@
#include "flslider2.h"
#include "gettext.h"
#include "threads.h"
#include "debug.h"
using namespace std;
void find_fonts();
Font_Browser* font_browser;
int Font_Browser::instance = 0;
int *Font_Browser::fixed = 0;
int Font_Browser::numfonts = 0;
Font_Browser::font_pair *Font_Browser::font_pairs = 0;
static int font_compare(const void *p1, const void *p2)
{
std::string s1 = *((const Font_Browser::font_pair *)p1)->name;
std::string s2 = *((const Font_Browser::font_pair *)p2)->name;
return strcasecmp( s1.c_str(), s2.c_str() );
}
// Font Color selected
void Font_Browser::ColorSelect()
{
unsigned char r, g, b;
Fl::get_color(fontcolor, r, g, b);
if (fl_color_chooser(_("Font color"), r, g, b) == 0)
return;
fontcolor = fl_rgb_color(r, g, b);
btn_Color->color(fontcolor);
unsigned char r, g, b;
Fl::get_color(fontcolor, r, g, b);
if (fl_color_chooser(_("Font color"), r, g, b) == 0)
return;
fontcolor = fl_rgb_color(r, g, b);
btn_Color->color(fontcolor);
btn_Color->labelcolor( fl_contrast(FL_BLACK, fontcolor));
}
void Font_Browser::fb_callback(Fl_Widget* w, void* arg)
{
Font_Browser* fb = reinterpret_cast<Font_Browser*>(arg);
Font_Browser* fb = reinterpret_cast<Font_Browser*>(arg);
if (w == fb->btn_Cancel)
if (w == fb->btn_fixed) {
if (fb->btn_fixed->value())
fb->fontFilter(FIXED_WIDTH);
else
fb->fontFilter(ALL_TYPES);
return;
}
if (w == fb->btn_Cancel)
fb->hide();
else if (w == fb->btn_OK) {
if (fb->callback_)
(*fb->callback_)(fb, fb->data_);
}
else if (w == fb->btn_Color)
fb->ColorSelect();
else if (w == fb->lst_Font)
fb->FontNameSelect();
else {
if (w == fb->lst_Size)
fb->txt_Size->value(strtol(fb->lst_Size->text(fb->lst_Size->value()), NULL, 10));
fb->fontsize = static_cast<int>(fb->txt_Size->value());
}
fb->box_Example->SetFont(fb->fontnbr, fb->fontsize, fb->fontcolor);
}
// Sort the font list
void Font_Browser::FontSort()
{
int size = lst_Font->size();
for ( int t = 1; t <= size - 1; t++ )
for ( int r = t+1; r <= size; r++ )
if ( strcasecmp(lst_Font->text(t), lst_Font->text(r)) > 0 )
lst_Font->swap(t,r);
else if (w == fb->btn_OK) {
if (fb->callback_)
(*fb->callback_)(fb, fb->data_);
}
else if (w == fb->btn_Color)
fb->ColorSelect();
else if (w == fb->lst_Font)
fb->FontNameSelect();
else {
if (w == fb->lst_Size)
fb->txt_Size->value(strtol(fb->lst_Size->text(fb->lst_Size->value()), NULL, 10));
fb->fontsize = static_cast<int>(fb->txt_Size->value());
}
fb->box_Example->SetFont(fb->fontnbr, fb->fontsize, fb->fontcolor);
}
// Font Name changed callback
void Font_Browser::FontNameSelect()
{
int fn = lst_Font->value();
if (!fn)
return;
int fn = lst_Font->value();
if (!fn)
return;
fontnbr = (Fl_Font)reinterpret_cast<intptr_t>(lst_Font->data(fn));
fontnbr = (Fl_Font)reinterpret_cast<intptr_t>(lst_Font->data(fn));
// get sizes and fill browser; skip first element if it is zero
lst_Size->clear();
int nsizes, *sizes;
char buf[4];
nsizes = Fl::get_font_sizes(fontnbr, sizes);
//
for (int i = !*sizes; i < nsizes; i++)
// get sizes and fill browser; skip first element if it is zero
lst_Size->clear();
int nsizes, *sizes;
char buf[4];
nsizes = Fl::get_font_sizes(fontnbr, sizes);
//
for (int i = !*sizes; i < nsizes; i++)
if ((size_t)snprintf(buf, sizeof(buf), "%d", sizes[i]) < sizeof(buf))
lst_Size->add(buf, reinterpret_cast<void*>(sizes[i]));
lst_Size->add(buf, reinterpret_cast<void*>(sizes[i]));
// scalable font with no suggested sizes
if (!lst_Size->size()) {
// scalable font with no suggested sizes
if (!lst_Size->size()) {
for (int i = 1; i <= 48; i++) {
snprintf(buf, sizeof(buf), "%d", i);
lst_Size->add(buf, reinterpret_cast<void*>(i));
snprintf(buf, sizeof(buf), "%d", i);
lst_Size->add(buf, reinterpret_cast<void*>(i));
}
}
fontSize(fontsize);
}
fontSize(fontsize);
}
Font_Browser::Font_Browser(int x, int y, int w, int h, const char *lbl )
: Fl_Window(x, y, w, h, lbl)
: Fl_Window(x, y, w, h, lbl)
{
lst_Font = new Fl_Browser(5, 15, 280, 125, _("Font:"));
lst_Font->align(FL_ALIGN_TOP_LEFT);
lst_Font->type(FL_HOLD_BROWSER);
lst_Font->callback(fb_callback, this);
lst_Font = new Fl_Browser(5, 15, 280, 125, _("Font:"));
lst_Font->align(FL_ALIGN_TOP_LEFT);
lst_Font->type(FL_HOLD_BROWSER);
lst_Font->callback(fb_callback, this);
fixed = 0;
txt_Size = new Fl_Value_Input2(290, 15, 50, 22, _("Size:"));
txt_Size->align(FL_ALIGN_TOP_LEFT);
txt_Size->range(1.0, 48.0);
txt_Size->step(1.0);
txt_Size->callback(fb_callback, this);
txt_Size = new Fl_Value_Input2(290, 15, 50, 22, _("Size:"));
txt_Size->align(FL_ALIGN_TOP_LEFT);
txt_Size->range(1.0, 48.0);
txt_Size->step(1.0);
txt_Size->callback(fb_callback, this);
lst_Size = new Fl_Browser(290, 40, 50, 100);
lst_Size->type(FL_HOLD_BROWSER);
lst_Size->callback(fb_callback, this);
lst_Size = new Fl_Browser(290, 40, 50, 100);
lst_Size->type(FL_HOLD_BROWSER);
lst_Size->callback(fb_callback, this);
btn_OK = new Fl_Return_Button(345, 40, 50, 25, _("&OK"));
btn_OK->shortcut(0x8006f);
btn_OK->callback(fb_callback, this);
btn_fixed = new Fl_Check_Button(345, 15, 18, 18, _("Fixed"));
btn_fixed->callback(fb_callback, this);
btn_fixed->value(0);
btn_Cancel = new Fl_Button(345, 70, 50, 25, _("Cancel"));
btn_Cancel->labelsize(12);
btn_Cancel->callback(fb_callback, this);
btn_OK = new Fl_Return_Button(345, 40, 80, 25, _("&OK"));
btn_OK->shortcut(0x8006f);
btn_OK->callback(fb_callback, this);
btn_Color = new Fl_Button(345, 100, 50, 25, _("Color"));
btn_Color->down_box(FL_BORDER_BOX);
btn_Color->color(FL_FOREGROUND_COLOR);
btn_Color->callback(fb_callback, this);
btn_Cancel = new Fl_Button(345, 70, 80, 25, _("Cancel"));
btn_Cancel->labelsize(12);
btn_Cancel->callback(fb_callback, this);
box_Example = new Preview_Box(5, 145, 390, 75, _("That crazy fox jumped over the dog again!\n"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789\n"
"!\"#$%&'()*+,-./:;<=>?@@[\\]^_`{|}~"));
box_Example->box(FL_DOWN_BOX);
box_Example->align(FL_ALIGN_WRAP|FL_ALIGN_CLIP|FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
resizable(box_Example);
btn_Color = new Fl_Button(345, 100, 80, 25, _("Color"));
btn_Color->down_box(FL_BORDER_BOX);
btn_Color->color(FL_FOREGROUND_COLOR);
btn_Color->labelcolor( fl_contrast(FL_BLACK, FL_FOREGROUND_COLOR));
btn_Color->callback(fb_callback, this);
set_modal();
end();
box_Example = new Preview_Box(5, 145, 420, 75,
_("\
abcdefghijklmnopqrstuvwxyz\n\
ABCDEFGHIJKLMNOPQRSTUVWXYZ\n\
0123456789"
) );
box_Example->box(FL_DOWN_BOX);
box_Example->align(FL_ALIGN_WRAP|FL_ALIGN_CLIP|FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
resizable(box_Example);
// Initializations
set_modal();
end();
this->callback_ = 0; // Initialize Widgets callback
this->data_ = 0; // And the data
// Initializations
numfonts = Fl::set_fonts(0); // Nr of fonts available on the server
this->callback_ = 0; // Initialize Widgets callback
this->data_ = 0; // And the data
const char* name;
for(int i = 0; i < numfonts; i++) {
name = Fl::get_font_name((Fl_Font)i);
if (isalpha(*name))
lst_Font->add(name, reinterpret_cast<void*>(i));
}
FontSort();
std::string fntname;
bool ok = true;
fontnbr = FL_HELVETICA;;
fontsize = FL_NORMAL_SIZE; // Font Size to be used
fontcolor = FL_FOREGROUND_COLOR;
filter = ALL_TYPES;
if (instance == 0) {
lst_Font->value(1);
FontNameSelect();
++instance;
//! Fl::focus(lst_Font);
numfonts = Fl::set_fonts(0); // Nr of fonts available on the server
font_pairs = new font_pair[numfonts];
fixed = new int[numfonts];
xclass(PACKAGE_NAME);
int j = 0;
for (int i = 0; i < numfonts; i++) {
fntname = Fl::get_font_name((Fl_Font)i);
ok = true;
for (size_t k = 0; k < fntname.length(); k++) {
if (fntname[k] < ' ' || fntname[k] > 'z' ||
fntname[k] == '\\' || fntname[k] == '@') { // disallowed chars in browser widget
ok = false;
break;
}
}
if (fntname.empty()) ok = false;
if (ok) {
font_pairs[j].name = new std::string;
*(font_pairs[j].name) = fntname;
font_pairs[j].nbr = i;
j++;
}
}
numfonts = j;
qsort(&font_pairs[0], numfonts, sizeof(font_pair), font_compare);
for (int i = 0; i < numfonts; i++) {
lst_Font->add((*(font_pairs[i].name)).c_str(), reinterpret_cast<void *>(font_pairs[i].nbr));
fixed[i] = 0;
}
find_fonts();
} else {
++instance;
for (int i = 0; i < numfonts; i++) {
lst_Font->add((*(font_pairs[i].name)).c_str(), reinterpret_cast<void *>(font_pairs[i].nbr));
}
}
fontnbr = FL_HELVETICA;;
fontsize = FL_NORMAL_SIZE;
fontcolor = FL_FOREGROUND_COLOR;
filter = ALL_TYPES;
lst_Font->value(1);
FontNameSelect();
xclass(PACKAGE_NAME);
}
Font_Browser::~Font_Browser()
{
--instance;
if (instance == 0) {
delete [] fixed;
fixed = 0;
delete [] font_pairs;
font_pairs = 0;
}
}
void Font_Browser::fontNumber(Fl_Font n)
{
fontnbr = n;
lst_Font->value(1);
int s = lst_Font->size();
for (int i = 1; i < s; i++ ) {
if ((Fl_Font)reinterpret_cast<intptr_t>(lst_Font->data(i)) == n) {
lst_Font->value(i);
FontNameSelect();
break;
}
}
fontnbr = n;
lst_Font->value(1);
int s = lst_Font->size();
for (int i = 1; i < s; i++ ) {
if ((Fl_Font)reinterpret_cast<intptr_t>(lst_Font->data(i)) == n) {
lst_Font->value(i);
FontNameSelect();
break;
}
}
}
void Font_Browser::fontSize(int s)
{
fontsize = s;
int n = lst_Size->size();
for (int i = 1; i < n; i++) {
fontsize = s;
int n = lst_Size->size();
for (int i = 1; i < n; i++) {
if ((intptr_t)lst_Size->data(i) == fontsize) {
lst_Size->value(i);
break;
lst_Size->value(i);
break;
}
}
txt_Size->value(s);
}
txt_Size->value(s);
}
void Font_Browser::fontColor(Fl_Color c)
{
btn_Color->color(fontcolor = c);
box_Example->SetFont(fontnbr, fontsize, fontcolor);
box_Example->redraw();
btn_Color->color(fontcolor = c);
box_Example->SetFont(fontnbr, fontsize, fontcolor);
box_Example->redraw();
}
void Font_Browser::fontName(const char* n)
{
int s = lst_Font->size();
for (int i = 1; i < s; i++) {
if (!strcmp(lst_Font->text(i), n)) {
lst_Font->value(i);
FontNameSelect();
}
}
int s = lst_Font->size();
for (int i = 1; i < s; i++) {
if (!strcmp(lst_Font->text(i), n)) {
lst_Font->value(i);
FontNameSelect();
}
}
}
void Font_Browser::fontFilter(filter_t filter)
{
int s = lst_Font->size();
switch (filter) {
case FIXED_WIDTH:
for (int i = 0; i < s; i++) {
if (fixed[i])
lst_Font->show(i + 1);
else
lst_Font->hide(i + 1);
}
btn_fixed->value(1);
break;
case VARIABLE_WIDTH:
for (int i = 0; i < s; i++) {
if (!fixed[i])
lst_Font->show(i + 1);
else
lst_Font->hide(i + 1);
}
btn_fixed->value(0);
break;
case ALL_TYPES:
for (int i = 0; i < s; i++)
lst_Font->show(i + 1);
btn_fixed->value(0);
break;
}
lst_Font->redraw();
lst_Font->topline(lst_Font->value());
}
// separate thread used to evaluate fixed / proportional fonts
// friend of Font_Browser
// launched by Font_Browser instance 1
static pthread_t find_font_thread;
//#define FBDEBUG 1
static int is_fixed;
Fl_Font test_font;
void font_test(void *)
{
fl_font(test_font, FL_NORMAL_SIZE);
is_fixed = (fl_width(".") == fl_width("W"));
}
void *find_fixed_fonts(void *)
{
#ifdef FBDEBUG
FILE *sys_fonts = fopen("fonts.txt", "w");
fprintf(sys_fonts, "Font #, Type, Name\n");
#endif
for (int i = 0; i < Font_Browser::numfonts; i++) {
test_font = Font_Browser::font_pairs[i].nbr;
is_fixed = -1;
Fl::awake(font_test);
while (is_fixed == -1) MilliSleep(10);
Font_Browser::fixed[i] = is_fixed;
#ifdef FBDEBUG
fprintf(
sys_fonts,
"%d, %c, %s\n",
Font_Browser::font_pairs[i].nbr,
Font_Browser::fixed[i] ? 'F' : 'P',
(*(Font_Browser::font_pairs[i].name)).c_str());
#endif
}
#ifdef FBDEBUG
fclose(sys_fonts);
#endif
return NULL;
}
void find_fonts()
{
if (pthread_create(&find_font_thread, NULL, find_fixed_fonts, NULL) < 0) {
LOG_ERROR("%s", "pthread_create find_fixed_fonts failed");
}
return;
}
bool Font_Browser::fixed_width(Fl_Font f)
{
fl_font(f, FL_NORMAL_SIZE);
return fl_width('X') == fl_width('i');
return fl_width(".") == fl_width("W");
}
#include <vector>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Progress.H>
class Progress_Window : public Fl_Double_Window
{
public:
Progress_Window(float min = 0.0f, float max = 100.0f, const char* l = 0)
: Fl_Double_Window(200, 34), ps(5, 5, 190, 24, l)
{
end();
range(min, max);
ps.align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
ps.selection_color(FL_SELECTION_COLOR);
set_modal();
callback(nop);
if (l && *l) {
fl_font(FL_HELVETICA, FL_NORMAL_SIZE);
int s = (int)(fl_width(l) + fl_width('W'));
if (s > ps.w()) {
ps.size(s, ps.h());
size(ps.w() + 10, h());
}
}
position(Fl::event_x_root() - w() / 2, Fl::event_y_root() - h());
xclass(PACKAGE_TARNAME);
show();
}
void range(float min, float max) { ps.minimum(min); ps.maximum(max); }
void value(float val) { ps.value(val); }
static void nop(Fl_Widget*, void*) { }
private:
Fl_Progress ps;
};
void Font_Browser::fontFilter(filter_t filter)
{
if (this->filter == filter)
return;
int s = lst_Font->size();
static vector<bool> fixed;
if (fixed.empty()) {
Progress_Window pw(1, s, _("Reading fonts..."));
fixed.resize(s);
for (int i = 1; i < s; i++) {
fixed[i] = fixed_width((Fl_Font)(intptr_t)(lst_Font->data(i)));
pw.value(i);
Fl::check();
}
}
switch (this->filter = filter) {
case FIXED_WIDTH:
for (int i = 1; i < s; i++) {
if (fixed[i])
lst_Font->show(i);
else
lst_Font->hide(i);
}
break;
case VARIABLE_WIDTH:
for (int i = 1; i < s; i++) {
if (!fixed[i])
lst_Font->show(i);
else
lst_Font->hide(i);
}
break;
case ALL_TYPES:
for (int i = 1; i < s; i++)
lst_Font->show(i);
break;
}
lst_Font->topline(lst_Font->value());
}
//////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------
Preview_Box::Preview_Box(int x, int y, int w, int h, const char* l)
: Fl_Widget(x, y, w, h, l)
{
fontName = 1;
fontSize = FL_NORMAL_SIZE;
box(FL_DOWN_BOX);
color(FL_BACKGROUND2_COLOR);
fontColor = FL_FOREGROUND_COLOR;
fontName = 1;
fontSize = FL_NORMAL_SIZE;
box(FL_DOWN_BOX);
color(FL_BACKGROUND2_COLOR);
fontColor = FL_FOREGROUND_COLOR;
}
void Preview_Box::draw()
{
draw_box();
fl_font((Fl_Font)fontName, fontSize);
fl_color(fontColor);
fl_draw(label(), x()+3, y()+3, w()-6, h()-6, align());
draw_box();
fl_font((Fl_Font)fontName, fontSize);
fl_color(fontColor);
fl_draw(label(), x()+3, y()+3, w()-6, h()-6, align());
}
void Preview_Box::SetFont(int fontname, int fontsize, Fl_Color c)
{
fontName = fontname;
fontSize = fontsize;
fontColor = c;
redraw();
fontName = fontname;
fontSize = fontsize;
fontColor = c;
redraw();
}