Dillo v3.2.0-170-gacf511bb
Loading...
Searching...
No Matches
fltkplatform.cc
Go to the documentation of this file.
1/*
2 * Dillo Widget
3 *
4 * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
5 * Copyright 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <stdio.h>
22
23#include "dlib/dlib.h"
24#include "../lout/msg.h"
25#include "../lout/debug.hh"
26#include "fltkcore.hh"
27
28#include <FL/fl_draw.H>
29#include <FL/Fl_Box.H>
30#include <FL/Fl_Tooltip.H>
31#include <FL/Fl_Menu_Window.H>
32#include <FL/Fl_Paged_Device.H>
33
34/*
35 * Local data
36 */
37
38/* Tooltips */
39static Fl_Menu_Window *tt_window = NULL;
40static int in_tooltip = 0, req_tooltip = 0;
41
42namespace dw {
43namespace fltk {
44
45using namespace lout;
46
52 FltkFont> *FltkFont::fontsTable =
54 FltkFont> (false, false);
55
57 FltkFont::FontFamily> *FltkFont::systemFonts =
58 NULL;
59
60FltkFont::FontFamily FltkFont::standardFontFamily (FL_HELVETICA,
61 FL_HELVETICA_BOLD,
62 FL_HELVETICA_ITALIC,
63 FL_HELVETICA_BOLD_ITALIC);
64
65FltkFont::FontFamily::FontFamily (Fl_Font fontNormal, Fl_Font fontBold,
66 Fl_Font fontItalic, Fl_Font fontBoldItalic)
67{
68 font[0] = fontNormal;
69 font[1] = fontBold;
70 font[2] = fontItalic;
71 font[3] = fontBoldItalic;
72}
73
74void FltkFont::FontFamily::set (Fl_Font f, int attrs)
75{
76 int idx = 0;
77 if (attrs & FL_BOLD)
78 idx += 1;
79 if (attrs & FL_ITALIC)
80 idx += 2;
81 font[idx] = f;
82}
83
84Fl_Font FltkFont::FontFamily::get (int attrs)
85{
86 int idx = 0;
87 if (attrs & FL_BOLD)
88 idx += 1;
89 if (attrs & FL_ITALIC)
90 idx += 2;
91
92 // should the desired font style not exist, we
93 // return the normal font of the fontFamily
94 return font[idx] >= 0 ? font[idx] : font[0];
95}
96
97
98
100{
101 if (!systemFonts)
103
104 copyAttrs (attrs);
105
106 int fa = 0;
107 if (weight >= 500)
108 fa |= FL_BOLD;
110 fa |= FL_ITALIC;
111
112 object::ConstString nameString (name);
113 FontFamily *family = systemFonts->get (&nameString);
114 if (!family)
115 family = &standardFontFamily;
116
117 font = family->get (fa);
118
119 fl_font(font, size);
120 // WORKAROUND: A bug with fl_width(uint_t) on non-xft X was present in
121 // 1.3.0 (STR #2688).
122 spaceWidth = misc::max(0, (int)fl_width(" ") + letterSpacing);
123 int xx, xy, xw, xh;
124 fl_text_extents("x", xx, xy, xw, xh);
125 xHeight = xh;
126 zeroWidth = (int) fl_width("0");
127 descent = fl_descent();
128 ascent = fl_height() - descent;
129}
130
132{
133 fontsTable->remove (this);
134}
135
136static void strstrip(char *big, const char *little)
137{
138 if (strlen(big) >= strlen(little) &&
139 misc::AsciiStrcasecmp(big + strlen(big) - strlen(little), little) == 0)
140 *(big + strlen(big) - strlen(little)) = '\0';
141}
142
144{
147
148 int k = Fl::set_fonts ("-*-iso10646-1");
149 for (int i = 0; i < k; i++) {
150 int t;
151 char *name = dStrdup (Fl::get_font_name ((Fl_Font) i, &t));
152
153 // normalize font family names (strip off "bold", "italic")
154 if (t & FL_ITALIC) {
155 strstrip(name, " oblique");
156 strstrip(name, " italic");
157 }
158
159 if (t & FL_BOLD)
160 strstrip(name, " bold");
161
162 /* Always strip Book, similar to Regular */
163 strstrip(name, " book");
164
165 _MSG("Found font: %s%s%s\n", name, t & FL_BOLD ? " Bold" : "",
166 t & FL_ITALIC ? " Italic" : "");
167
168 object::String *familyName = new object::String(name);
169 free (name);
170 FontFamily *family = systemFonts->get (familyName);
171
172 if (family) {
173 family->set ((Fl_Font) i, t);
174 delete familyName;
175 } else {
176 // set first font of family also as normal font in case there
177 // is no normal (non-bold, non-italic) font
178 family = new FontFamily ((Fl_Font) i, -1, -1, -1);
179 family->set ((Fl_Font) i, t);
180 systemFonts->put (familyName, family);
181 }
182 }
183}
184
185bool
187{
188 if (!systemFonts)
190 object::ConstString familyName (name);
191 return systemFonts->get (&familyName) != NULL;
192}
193
194Fl_Font
195FltkFont::get (const char *name, int attrs)
196{
197 if (!systemFonts)
199 object::ConstString familyName (name);
200 FontFamily *family = systemFonts->get (&familyName);
201 if (family)
202 return family->get (attrs);
203 else
204 return FL_HELVETICA;
205}
206
207bool
209{
210 return FltkFont::fontExists (name);
211}
212
215{
216 FltkFont *font = fontsTable->get (attrs);
217
218 if (font == NULL) {
219 font = new FltkFont (attrs);
220 fontsTable->put (font, font);
221 }
222
223 return font;
224}
225
227 FltkColor>
230 FltkColor> (false, false);
231
232FltkColor::FltkColor (int color): Color (color)
233{
234 this->color = color;
235
237 colors[SHADING_NORMAL] = FL_BLACK;
239 colors[SHADING_INVERSE] = FL_BLACK;
241 colors[SHADING_DARK] = FL_BLACK;
243 colors[SHADING_LIGHT] = FL_BLACK;
244}
245
247{
248 colorsTable->remove (this);
249}
250
252{
253 ColorAttrs attrs(col);
254 FltkColor *color = colorsTable->get (&attrs);
255
256 if (color == NULL) {
257 color = new FltkColor (col);
258 colorsTable->put (color, color);
259 }
260
261 return color;
262}
263
264FltkTooltip::FltkTooltip (const char *text) : Tooltip(text)
265{
266}
267
269{
270 if (in_tooltip || req_tooltip)
271 cancel(); /* cancel tooltip window */
272}
273
275{
276 return new FltkTooltip(text);
277}
278
279/*
280 * Tooltip callback: used to delay it a bit
281 * INVARIANT: Only one instance of this function is requested.
282 */
283static void tooltip_tcb(void *data)
284{
285 req_tooltip = 2;
286 ((FltkTooltip *)data)->onEnter();
287 req_tooltip = 0;
288}
289
291{
292 _MSG("FltkTooltip::onEnter\n");
293 if (!str || !*str)
294 return;
295 if (req_tooltip == 0) {
296 Fl::remove_timeout(tooltip_tcb);
297 Fl::add_timeout(1.0, tooltip_tcb, this);
298 req_tooltip = 1;
299 return;
300 }
301
302 if (!tt_window) {
303 tt_window = new Fl_Menu_Window(0,0,100,24);
304 tt_window->set_override();
305 tt_window->box(FL_NO_BOX);
306 Fl_Box *b = new Fl_Box(0,0,100,24);
307 b->box(FL_BORDER_BOX);
308 b->color(fl_color_cube(FL_NUM_RED-1, FL_NUM_GREEN-1, FL_NUM_BLUE-2));
309 b->labelcolor(FL_BLACK);
310 b->labelfont(FL_HELVETICA);
311 b->labelsize(14);
312 b->align(FL_ALIGN_WRAP|FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
313 tt_window->resizable(b);
314 tt_window->end();
315 }
316
317 /* prepare tooltip window */
318 int x, y;
319 Fl_Box *box = (Fl_Box*)tt_window->child(0);
320 box->label(str);
321 Fl::get_mouse(x,y); y += 6;
322 /* calculate window size */
323 int ww, hh;
324 ww = 800; // max width;
325 box->measure_label(ww, hh);
326 ww += 6 + 2 * Fl::box_dx(box->box());
327 hh += 6 + 2 * Fl::box_dy(box->box());
328 tt_window->resize(x,y,ww,hh);
329 tt_window->show();
330 in_tooltip = 1;
331}
332
333/*
334 * Leaving the widget cancels the tooltip
335 */
337{
338 _MSG(" FltkTooltip::onLeave in_tooltip=%d\n", in_tooltip);
339 cancel();
340}
341
346
347/*
348 * Remove a shown tooltip or cancel a pending one
349 */
351{
352 if (req_tooltip) {
353 Fl::remove_timeout(tooltip_tcb);
354 req_tooltip = 0;
355 }
356 if (!in_tooltip) return;
357 in_tooltip = 0;
358 tt_window->hide();
359
360 /* WORKAROUND: (Black magic here)
361 * Hiding a tooltip with the keyboard or mousewheel doesn't work.
362 * The code below "fixes" the problem */
363 Fl_Widget *widget = Fl::belowmouse();
364 if (widget && widget->window()) {
365 widget->window()->damage(FL_DAMAGE_EXPOSE,0,0,1,1);
366 }
367}
368
370{
371}
372
373void FltkView::addFltkWidget (Fl_Widget *widget,
374 core::Allocation *allocation)
375{
376}
377
378void FltkView::removeFltkWidget (Fl_Widget *widget)
379{
380}
381
382void FltkView::allocateFltkWidget (Fl_Widget *widget,
383 core::Allocation *allocation)
384{
385}
386
387void FltkView::drawFltkWidget (Fl_Widget *widget, core::Rectangle *area)
388{
389}
390
391
398
401 *widget,
402 bool relief)
403{
404 return new ui::FltkComplexButtonResource (platform, widget, relief);
405}
406
409 ::ListResource
410 ::SelectionMode
411 selectionMode, int rows)
412{
413 return new ui::FltkListResource (platform, selectionMode, rows);
414}
415
421
424 bool password,
425 const char *label,
426 const char *placeholder)
427{
428 return new ui::FltkEntryResource (platform, size, password, label,
429 placeholder);
430}
431
434 int rows,
435 const char *placeholder)
436{
437 return new ui::FltkMultiLineTextResource (platform, cols, rows,placeholder);
438}
439
445
448(core::ui::RadioButtonResource *groupedWith, bool activated)
449{
450 return
453 groupedWith,
454 activated);
455}
456
457// ----------------------------------------------------------------------
458
460{
461 DBG_OBJ_CREATE ("dw::fltk::FltkPlatform");
462
463 layout = NULL;
464 idleQueue = new container::typed::List <IdleFunc> (true);
465 idleFuncRunning = false;
466 idleFuncId = 0;
467
468 view = NULL;
469 resources = new container::typed::List <ui::FltkResource> (false);
470
472}
473
475{
476 if (idleFuncRunning)
477 Fl::remove_idle (generalStaticIdle, (void*)this);
478 delete idleQueue;
479 delete resources;
480
482}
483
485{
486 this->layout = layout;
488}
489
490
492{
493 if (this->view)
494 MSG_ERR("FltkPlatform::attachView: multiple views!\n");
495 this->view = (FltkView*)view;
496
497 for (container::typed::Iterator <ui::FltkResource> it =
498 resources->iterator (); it.hasNext (); ) {
499 ui::FltkResource *resource = it.getNext ();
500 resource->attachView (this->view);
501 }
502}
503
504
506{
507 if (this->view != view)
508 MSG_ERR("FltkPlatform::detachView: this->view: %p view: %p\n",
509 (void *) this->view, (void *) view);
510
511 for (container::typed::Iterator <ui::FltkResource> it =
512 resources->iterator (); it.hasNext (); ) {
513 ui::FltkResource *resource = it.getNext ();
514 resource->detachView ((FltkView*)view);
515 }
516 this->view = NULL;
517}
518
519
520int FltkPlatform::textWidth (core::style::Font *font, const char *text,
521 int len)
522{
523 char chbuf[4];
524 int c, cu;
525 int width = 0;
526 FltkFont *ff = (FltkFont*) font;
527 int curr = 0, next = 0, nb;
528
530 int sc_fontsize = lout::misc::roundInt(ff->size * 0.78);
531 for (curr = 0; next < len; curr = next) {
532 next = nextGlyph(text, curr);
533 c = fl_utf8decode(text + curr, text + next, &nb);
534 if ((cu = fl_toupper(c)) == c) {
535 /* already uppercase, just draw the character */
536 fl_font(ff->font, ff->size);
537 if (fl_nonspacing(cu) == 0) {
538 width += font->letterSpacing;
539 width += (int)fl_width(text + curr, next - curr);
540 }
541 } else {
542 /* make utf8 string for converted char */
543 nb = fl_utf8encode(cu, chbuf);
544 fl_font(ff->font, sc_fontsize);
545 if (fl_nonspacing(cu) == 0) {
546 width += font->letterSpacing;
547 width += (int)fl_width(chbuf, nb);
548 }
549 }
550 }
551 } else {
552 fl_font (ff->font, ff->size);
553 width = (int) fl_width (text, len);
554
555 if (font->letterSpacing) {
556 int curr = 0, next = 0;
557
558 while (next < len) {
559 next = nextGlyph(text, curr);
560 c = fl_utf8decode(text + curr, text + next, &nb);
561 if (fl_nonspacing(c) == 0)
562 width += font->letterSpacing;
563 curr = next;
564 }
565 }
566 }
567
568 return width;
569}
570
571char *FltkPlatform::textToUpper (const char *text, int len)
572{
573 char *newstr = NULL;
574
575 if (len > 0) {
576 int newlen;
577
578 newstr = (char*) malloc(3 * len + 1);
579 newlen = fl_utf_toupper((const unsigned char*)text, len, newstr);
580 assert(newlen <= 3 * len);
581 newstr[newlen] = '\0';
582 }
583 return newstr;
584}
585
586char *FltkPlatform::textToLower (const char *text, int len)
587{
588 char *newstr = NULL;
589
590 if (len > 0) {
591 int newlen;
592
593 newstr = (char*) malloc(3 * len + 1);
594 newlen = fl_utf_tolower((const unsigned char*)text, len, newstr);
595 assert(newlen <= 3 * len);
596 newstr[newlen] = '\0';
597 }
598 return newstr;
599}
600
601int FltkPlatform::nextGlyph (const char *text, int idx)
602{
603 return fl_utf8fwd (&text[idx + 1], text, &text[strlen (text)]) - text;
604}
605
606int FltkPlatform::prevGlyph (const char *text, int idx)
607{
608 return fl_utf8back (&text[idx - 1], text, &text[strlen (text)]) - text;
609}
610
612{
613 float horizontal, vertical;
614
615 Fl::screen_dpi(horizontal, vertical);
616 return horizontal;
617}
618
620{
621 float horizontal, vertical;
622
623 Fl::screen_dpi(horizontal, vertical);
624 return vertical;
625}
626
628{
629 ((FltkPlatform*)data)->generalIdle();
630}
631
633{
634 IdleFunc *idleFunc;
635
636 if (!idleQueue->isEmpty ()) {
637 /* Execute the first function in the list. */
638 idleFunc = idleQueue->getFirst ();
639 (layout->*(idleFunc->func)) ();
640
641 /* Remove this function. */
642 idleQueue->removeRef(idleFunc);
643 }
644
645 if (idleQueue->isEmpty()) {
646 idleFuncRunning = false;
647 Fl::remove_idle (generalStaticIdle, (void*)this);
648 }
649}
650
655{
656 /*
657 * Since ... (todo) we have to wrap around fltk_add_idle. There is only one
658 * idle function, the passed idle function is put into a queue.
659 */
660 if (!idleFuncRunning) {
661 Fl::add_idle (generalStaticIdle, (void*)this);
662 idleFuncRunning = true;
663 }
664
665 idleFuncId++;
666
667 IdleFunc *idleFunc = new IdleFunc();
668 idleFunc->id = idleFuncId;
669 idleFunc->func = func;
670 idleQueue->append (idleFunc);
671
672 return idleFuncId;
673}
674
676{
677 bool found;
678 container::typed::Iterator <IdleFunc> it;
679 IdleFunc *idleFunc;
680
681 for (found = false, it = idleQueue->iterator(); !found && it.hasNext(); ) {
682 idleFunc = it.getNext();
683 if (idleFunc->id == idleId) {
684 idleQueue->removeRef (idleFunc);
685 found = true;
686 }
687 }
688
689 if (idleFuncRunning && idleQueue->isEmpty())
690 Fl::remove_idle (generalStaticIdle, (void*)this);
691}
692
694 *attrs,
695 bool tryEverything)
696{
697 return FltkFont::create (attrs);
698}
699
701{
702 return FltkColor::create (color);
703}
704
706{
707 return FltkTooltip::create (text);
708}
709
710void FltkPlatform::copySelection(const char *text, int destination)
711{
712 Fl::copy(text, strlen(text), destination);
713}
714
716 int width, int height, double gamma)
717{
718 return new FltkImgbuf (type, width, height, gamma);
719}
720
725
726
728{
729 resources->append (resource);
730 resource->attachView (view);
731}
732
734{
735 resources->removeRef (resource);
736}
737
738} // namespace fltk
739} // namespace dw
#define _MSG(...)
Definition bookmarks.c:44
The platform independent interface for image buffers.
Definition imgbuf.hh:162
The central class for managing and drawing a widget tree.
Definition layout.hh:37
dw::core::Shape implementation for simple rectangles.
Definition types.hh:70
An interface to encapsulate platform dependent drawing.
Definition view.hh:17
The base class of all dillo widgets.
Definition widget.hh:44
int shadeColor(int color, int d)
Definition style.cc:471
FontVariant fontVariant
Definition style.hh:688
void copyAttrs(FontAttrs *attrs)
Definition style.cc:427
Interface for labelled buttons resources.
Definition ui.hh:400
A factory for the common resource.
Definition ui.hh:581
static FltkColor * create(int color)
static lout::container::typed::HashTable< dw::core::style::ColorAttrs, FltkColor > * colorsTable
int colors[SHADING_NUM]
FontFamily(Fl_Font fontNormal, Fl_Font fontBold, Fl_Font fontItalic, Fl_Font fontBoldItalic)
void set(Fl_Font, int attrs)
FltkFont(core::style::FontAttrs *attrs)
static FontFamily standardFontFamily
static bool fontExists(const char *name)
static FltkFont * create(core::style::FontAttrs *attrs)
static lout::container::typed::HashTable< lout::object::ConstString, FontFamily > * systemFonts
static Fl_Font get(const char *name, int attrs)
static void initSystemFonts()
static lout::container::typed::HashTable< dw::core::style::FontAttrs, FltkFont > * fontsTable
core::ui::LabelButtonResource * createLabelButtonResource(const char *label)
core::ui::OptionMenuResource * createOptionMenuResource()
core::ui::ComplexButtonResource * createComplexButtonResource(core::Widget *widget, bool relief)
core::ui::RadioButtonResource * createRadioButtonResource(core::ui::RadioButtonResource *groupedWith, bool activated)
core::ui::MultiLineTextResource * createMultiLineTextResource(int cols, int rows, const char *placeholder)
core::ui::ListResource * createListResource(core::ui::ListResource::SelectionMode selectionMode, int rows)
void setPlatform(FltkPlatform *platform)
core::ui::EntryResource * createEntryResource(int size, bool password, const char *label, const char *placeholder)
core::ui::CheckButtonResource * createCheckButtonResource(bool activated)
void(core::Layout::* func)()
static void generalStaticIdle(void *data)
float dpiX()
Return screen resolution in x-direction.
int nextGlyph(const char *text, int idx)
Return the index of the next glyph in string text.
int addIdle(void(core::Layout::*func)())
core::Imgbuf * createImgbuf(core::Imgbuf::Type type, int width, int height, double gamma)
Create a (platform specific) image buffer.
int prevGlyph(const char *text, int idx)
Return the index of the previous glyph in string text.
void copySelection(const char *text, int destination)
Copy selected text (0-terminated).
void setLayout(core::Layout *layout)
This methods notifies the platform, that it has been attached to a layout.
bool fontExists(const char *name)
void removeIdle(int idleId)
Remove an idle function, which has not been processed yet.
core::style::Color * createColor(int color)
Create a color resource for a given 0xrrggbb value.
FltkResourceFactory resourceFactory
lout::container::typed::List< ui::FltkResource > * resources
float dpiY()
Return screen resolution in y-direction.
void attachResource(ui::FltkResource *resource)
lout::container::typed::List< IdleFunc > * idleQueue
char * textToLower(const char *text, int len)
Return the string resulting from transforming text to lowercase.
core::style::Tooltip * createTooltip(const char *text)
Create a tooltip.
core::ui::ResourceFactory * getResourceFactory()
...
void detachResource(ui::FltkResource *resource)
void detachView(core::View *view)
This methods notifies the platform, that a view has been detached from the related layout.
core::style::Font * createFont(core::style::FontAttrs *attrs, bool tryEverything)
Create a (platform dependent) font.
int textWidth(core::style::Font *font, const char *text, int len)
Return the width of a text, with a given length and font.
void attachView(core::View *view)
This methods notifies the platform, that a view has been attached to the related layout.
void cancelTooltip()
Cancel a tooltip (either shown or requested)
char * textToUpper(const char *text, int len)
Return the string resulting from transforming text to uppercase.
static FltkTooltip * create(const char *text)
FltkTooltip(const char *text)
This interface adds some more methods for all flkt-based views.
virtual void drawFltkWidget(Fl_Widget *widget, core::Rectangle *area)
virtual void removeFltkWidget(Fl_Widget *widget)
virtual void addFltkWidget(Fl_Widget *widget, core::Allocation *allocation)
virtual void allocateFltkWidget(Fl_Widget *widget, core::Allocation *allocation)
virtual void detachView(FltkView *view)
Definition fltkui.cc:483
virtual void attachView(FltkView *view)
Definition fltkui.cc:466
Typed version of container::untyped::HashTable.
Definition container.hh:536
An object::Object wrapper for constant strings (char*).
Definition object.hh:183
An object::Object wrapper for strings (char*).
Definition object.hh:206
#define DBG_OBJ_DELETE()
#define DBG_OBJ_CREATE(klass)
#define DBG_OBJ_ASSOC_CHILD(child)
char * dStrdup(const char *s)
Definition dlib.c:76
#define MSG_ERR(...)
Definition dpid_common.h:23
static FltkPlatform * platform
static Fl_Menu_Window * tt_window
static int in_tooltip
static int req_tooltip
@ FONT_VARIANT_SMALL_CAPS
Definition style.hh:334
static void strstrip(char *big, const char *little)
static void tooltip_tcb(void *data)
Dw is in this namespace, or sub namespaces of this one.
T max(T a, T b)
Definition misc.hh:41
int AsciiStrcasecmp(const char *s1, const char *s2)
Definition misc.hh:97
int roundInt(double d)
Definition misc.hh:82
Represents the allocation, i.e.
Definition types.hh:164