mirror of
https://git.code.sf.net/p/fldigi/fldigi
synced 2026-08-13 17:47:54 -04:00
font browser
* update font browser widget class to use std::list
for enumerating fonts
This commit is contained in:
parent
e0f72304d5
commit
19e9811289
2 changed files with 155 additions and 139 deletions
|
|
@ -47,20 +47,25 @@
|
|||
|
||||
void find_fonts();
|
||||
|
||||
Font_Browser* font_browser = 0;
|
||||
Font_Browser* font_browser;
|
||||
|
||||
//======================================================================
|
||||
// static members
|
||||
int Font_Browser::instance = 0;
|
||||
int Font_Browser::numfonts = 0;
|
||||
int *Font_Browser::fixed = 0;
|
||||
int Font_Browser::numfonts = 100;
|
||||
std::list<font_pair> Font_Browser::font_list;
|
||||
//======================================================================
|
||||
|
||||
Font_Browser::font_pair *Font_Browser::font_pairs = 0;
|
||||
static inline std::string ucase(std::string s) {
|
||||
for (size_t n = 0; n < s.length(); n++) s[n] = toupper(s[n]);
|
||||
return s;
|
||||
}
|
||||
|
||||
static int font_compare(const void *p1, const void *p2)
|
||||
static bool font_compare(font_pair &p1, font_pair &p2)
|
||||
{
|
||||
std::string *s1 = ((const Font_Browser::font_pair *)p1)->name;
|
||||
std::string *s2 = ((const Font_Browser::font_pair *)p2)->name;
|
||||
size_t c1 = s1->find("@.");
|
||||
size_t c2 = s2->find("@.");
|
||||
return strcasecmp( &(*s1)[c1+2], &(*s2)[c2+2] );
|
||||
if (ucase(p1.name) > ucase(p2.name)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Font Color selected
|
||||
|
|
@ -80,22 +85,28 @@ void Font_Browser::fb_callback(Fl_Widget* w, void* arg)
|
|||
{
|
||||
Font_Browser* fb = reinterpret_cast<Font_Browser*>(arg);
|
||||
|
||||
if (w == fb->btn_Cancel)
|
||||
fb->hide();
|
||||
else if (w == fb->btn_fixed) {
|
||||
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();
|
||||
fb->ColorSelect();
|
||||
|
||||
else if (w == fb->lst_Font)
|
||||
fb->FontNameSelect();
|
||||
fb->FontNameSelect();
|
||||
|
||||
else {
|
||||
if (w == fb->lst_Size)
|
||||
fb->txt_Size->value(strtol(fb->lst_Size->text(fb->lst_Size->value()), NULL, 10));
|
||||
|
|
@ -133,10 +144,6 @@ void Font_Browser::FontNameSelect()
|
|||
fontSize(fontsize);
|
||||
}
|
||||
|
||||
static long long usec;
|
||||
static long long sec;
|
||||
static double fsec;
|
||||
|
||||
Font_Browser::Font_Browser(int x, int y, int w, int h, const char *lbl )
|
||||
: Fl_Window(x, y, w, h, lbl)
|
||||
{
|
||||
|
|
@ -191,51 +198,71 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ\n\
|
|||
this->callback_ = 0; // Initialize Widgets callback
|
||||
this->data_ = 0; // And the data
|
||||
|
||||
std::string fntname;
|
||||
bool ok = true;
|
||||
|
||||
if (instance == 0) {
|
||||
|
||||
numfonts = Fl::set_fonts(0); // Nr of fonts available on the server
|
||||
font_pairs = new font_pair[numfonts];
|
||||
++instance;
|
||||
|
||||
numfonts = Fl::set_fonts("*"); // Nr of fonts available on the server
|
||||
|
||||
font_list.clear();
|
||||
|
||||
fixed = new int[numfonts];
|
||||
|
||||
int j = 0;
|
||||
std::string fontname = "";
|
||||
int t;
|
||||
|
||||
for (int i = 0; i < numfonts; i++) {
|
||||
fontname = Fl::get_font_name((Fl_Font)i, &t);
|
||||
|
||||
if ( fontname.find("Noto Color Emoji") != std::string::npos )
|
||||
continue;
|
||||
|
||||
if (fontname.length() && isprint(fontname[0])) {
|
||||
// Suppress subsequent formatting - some MS fonts have '@' in their name
|
||||
fontname.insert(0, "@.");
|
||||
if (t) {
|
||||
if (t & FL_BOLD) fontname.insert(0, "@b");
|
||||
if (t & FL_ITALIC) fontname.insert(0, "@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;
|
||||
}
|
||||
font_pairs[j].nbr = i;
|
||||
font_pairs[j].name = new std::string(fontname);
|
||||
++j;
|
||||
}
|
||||
if (fntname.empty()) ok = false;
|
||||
if (ok) {
|
||||
nufont.name = fntname;
|
||||
nufont.nbr = i;
|
||||
font_list.push_back(nufont);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
numfonts = j;
|
||||
|
||||
qsort(&font_pairs[0], numfonts, sizeof(font_pair), font_compare);
|
||||
font_list.sort(font_compare);
|
||||
|
||||
std::list<font_pair> temp_list = font_list;
|
||||
|
||||
int i = 0;
|
||||
while (!temp_list.empty()) {
|
||||
nufont = temp_list.front();
|
||||
lst_Font->add( nufont.name.c_str(), reinterpret_cast<void *>(nufont.nbr) );
|
||||
temp_list.pop_front();
|
||||
fixed[i++] = 0;
|
||||
}
|
||||
find_fonts();
|
||||
|
||||
} else {
|
||||
++instance;
|
||||
std::list<font_pair> temp_list = font_list;
|
||||
while (!temp_list.empty()) {
|
||||
nufont = temp_list.front();
|
||||
lst_Font->add( nufont.name.c_str(), reinterpret_cast<void *>(nufont.nbr) );
|
||||
temp_list.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
++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;
|
||||
|
||||
fontNumber(FL_HELVETICA);
|
||||
box_Example->SetFont(fontnbr, fontsize, fontcolor);
|
||||
lst_Font->value(1);
|
||||
FontNameSelect();
|
||||
|
||||
xclass(PACKAGE_NAME);
|
||||
}
|
||||
|
|
@ -244,8 +271,9 @@ Font_Browser::~Font_Browser()
|
|||
{
|
||||
--instance;
|
||||
if (instance == 0) {
|
||||
delete [] font_pairs;
|
||||
font_pairs = 0;
|
||||
delete [] fixed;
|
||||
fixed = 0;
|
||||
font_list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -257,7 +285,6 @@ void Font_Browser::fontNumber(Fl_Font n)
|
|||
for (int i = 1; i < s; i++ ) {
|
||||
if ((Fl_Font)reinterpret_cast<intptr_t>(lst_Font->data(i)) == n) {
|
||||
lst_Font->value(i);
|
||||
lst_Font->display(i);
|
||||
FontNameSelect();
|
||||
break;
|
||||
}
|
||||
|
|
@ -297,40 +324,75 @@ void Font_Browser::fontName(const char* n)
|
|||
|
||||
void Font_Browser::fontFilter(filter_t filter)
|
||||
{
|
||||
int sel = lst_Font->value();
|
||||
int s = lst_Font->size();
|
||||
|
||||
switch (filter) {
|
||||
case FIXED_WIDTH:
|
||||
for (int i = 0; i < numfonts; i++) {
|
||||
if (font_pairs[i].fixed)
|
||||
lst_Font->show(i + 1);
|
||||
else
|
||||
lst_Font->hide(i + 1);
|
||||
}
|
||||
btn_fixed->value(1);
|
||||
btn_fixed->redraw();
|
||||
break;
|
||||
case VARIABLE_WIDTH:
|
||||
for (int i = 0; i < numfonts; i++) {
|
||||
if (!font_pairs[i].fixed)
|
||||
lst_Font->show(i + 1);
|
||||
else
|
||||
lst_Font->hide(i + 1);
|
||||
}
|
||||
btn_fixed->value(0);
|
||||
btn_fixed->redraw();
|
||||
break;
|
||||
case ALL_TYPES:
|
||||
default:
|
||||
for (int i = 0; i < numfonts; i++)
|
||||
lst_Font->show(i+1);
|
||||
btn_fixed->value(0);
|
||||
btn_fixed->redraw();
|
||||
break;
|
||||
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->make_visible(sel);
|
||||
box_Example->SetFont(fontnbr, fontsize, fontcolor);
|
||||
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;
|
||||
|
||||
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 *)
|
||||
{
|
||||
std::list<font_pair> temp_list = Font_Browser::font_list;
|
||||
int i = 0;
|
||||
while (!temp_list.empty()) {
|
||||
test_font = temp_list.front().nbr;
|
||||
is_fixed = -1;
|
||||
Fl::awake(font_test);
|
||||
while (is_fixed == -1) {
|
||||
MilliSleep(1);
|
||||
}
|
||||
Font_Browser::fixed[i] = is_fixed;
|
||||
i++;
|
||||
temp_list.pop_front();
|
||||
}
|
||||
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)
|
||||
|
|
@ -366,48 +428,3 @@ void Preview_Box::SetFont(int fontname, int fontsize, Fl_Color c)
|
|||
fontColor = c;
|
||||
redraw();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
// separate thread used to evaluate fixed / proportional fonts
|
||||
// friend of Font_Browser
|
||||
// launched by Font_Browser instance 1
|
||||
|
||||
static pthread_t find_font_thread;
|
||||
|
||||
void *find_fixed_fonts(void *)
|
||||
{
|
||||
timeval tv1;
|
||||
timeval tv2;
|
||||
|
||||
gettimeofday(&tv1, NULL);
|
||||
for (int i = 0; i < Font_Browser::numfonts; i++) {
|
||||
Fl::lock();
|
||||
fl_font( Font_Browser::font_pairs[i].nbr, FL_NORMAL_SIZE );
|
||||
Font_Browser::font_pairs[i].fixed = (fl_width('1') == fl_width('9'));
|
||||
Fl::unlock();
|
||||
MilliSleep(2); // don't steal too much time from screen redraw
|
||||
}
|
||||
|
||||
gettimeofday(&tv2, NULL);
|
||||
usec = (tv2.tv_usec - tv1.tv_usec);
|
||||
sec = (tv2.tv_sec - tv1.tv_sec);
|
||||
if (usec < 0) {
|
||||
usec += 1000000;
|
||||
--sec;
|
||||
}
|
||||
fsec = sec + usec / 1000000.0;
|
||||
LOG_INFO("Evaluation of %d fonts took %0.3f seconds", Font_Browser::numfonts, fsec);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#define FONTBROWSER_H
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include <FL/Enumerations.H>
|
||||
#include <FL/Fl_Window.H>
|
||||
|
|
@ -49,38 +50,36 @@ private:
|
|||
Fl_Color fontColor;
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
// Font browser widget
|
||||
struct font_pair {
|
||||
int nbr;
|
||||
std::string name;
|
||||
font_pair() {
|
||||
nbr = 0;
|
||||
name.clear();
|
||||
}
|
||||
~font_pair() {
|
||||
}
|
||||
};
|
||||
|
||||
class Font_Browser : public Fl_Window
|
||||
{
|
||||
friend void *find_fixed_fonts(void *);
|
||||
|
||||
public:
|
||||
struct font_pair {
|
||||
int nbr;
|
||||
std::string *name;
|
||||
bool fixed;
|
||||
font_pair() {
|
||||
nbr = 0;
|
||||
name = 0;
|
||||
fixed = false;
|
||||
}
|
||||
~font_pair() {
|
||||
if (name) delete name;
|
||||
}
|
||||
};
|
||||
friend void *find_fixed_fonts(void *);
|
||||
|
||||
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 font_pair *font_pairs;
|
||||
static int *fixed;
|
||||
static std::list<font_pair> font_list;
|
||||
font_pair nufont;
|
||||
static int instance;
|
||||
static int numfonts;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue