diff --git a/src/include/font_browser.h b/src/include/font_browser.h index dce704a..1d112d2 100644 --- a/src/include/font_browser.h +++ b/src/include/font_browser.h @@ -37,65 +37,102 @@ #include #include "flslider2.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#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 +struct font_pair { + int nbr; + std::string name; + font_pair() { + nbr = 0; + name.clear(); + } + ~font_pair() { + } +}; + class Font_Browser : public Fl_Window { public: - enum filter_t { FIXED_WIDTH, VARIABLE_WIDTH, ALL_TYPES }; +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 int *fixed; + static std::list font_list; + font_pair nufont; + 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 = 430, 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; diff --git a/src/widgets/font_browser.cxx b/src/widgets/font_browser.cxx index 6abd115..f25ca8a 100644 --- a/src/widgets/font_browser.cxx +++ b/src/widgets/font_browser.cxx @@ -41,307 +41,389 @@ #include "font_browser.h" #include "flslider2.h" #include "gettext.h" +#include "util.h" +#include "debug.h" + +void find_fonts(); Font_Browser* font_browser; +//====================================================================== +// static members +int Font_Browser::instance = 0; +int *Font_Browser::fixed = 0; +int Font_Browser::numfonts = 100; +std::list Font_Browser::font_list; +//====================================================================== + +static inline std::string uucase(std::string s) { + for (size_t n = 0; n < s.length(); n++) s[n] = toupper(s[n]); + return s; +} + +static bool font_compare(font_pair &p1, font_pair &p2) +{ + if (uucase(p1.name) > uucase(p2.name)) return false; + return true; +} + // 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(arg); + Font_Browser* fb = reinterpret_cast(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(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(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(lst_Font->data(fn)); + fontnbr = (Fl_Font)reinterpret_cast(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(sizes[i])); + lst_Size->add(buf, reinterpret_cast(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(i)); + snprintf(buf, sizeof(buf), "%d", i); + lst_Size->add(buf, reinterpret_cast(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); - 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, 80, 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, 80, 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, 80, 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, 420, 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(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("*"); // Nr of fonts available on the server - xclass(PACKAGE_NAME); + font_list.clear(); + + fixed = new int[numfonts]; + + 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) { + nufont.name = fntname; + nufont.nbr = i; + font_list.push_back(nufont); + j++; + } + } + + numfonts = j; + + font_list.sort(font_compare); + + std::list temp_list = font_list; + + int i = 0; + while (!temp_list.empty()) { + nufont = temp_list.front(); + lst_Font->add( nufont.name.c_str(), reinterpret_cast(nufont.nbr) ); + temp_list.pop_front(); + fixed[i++] = 0; + } + find_fonts(); + + } else { + ++instance; + std::list temp_list = font_list; + while (!temp_list.empty()) { + nufont = temp_list.front(); + lst_Font->add( nufont.name.c_str(), reinterpret_cast(nufont.nbr) ); + temp_list.pop_front(); + } + } + + 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; + font_list.clear(); + } } 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(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(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; + +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 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) { fl_font(f, FL_NORMAL_SIZE); - return fl_width('X') == fl_width('i'); + return fl_width(".") == fl_width("W"); } -#include -#include -#include - -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 std::vector 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(); }