From 51389ca460d8533cad790e48aba05648df592360 Mon Sep 17 00:00:00 2001 From: Manolo Gouy Date: Wed, 27 Jun 2018 09:27:04 +0000 Subject: [PATCH] Add examples/SVG_File_Surface.cxx and refer to it in the doc of class Fl_Surface_Device This example code shows how to subclass Fl_Surface_Device and Fl_Graphics_Driver to endow FLTK with a new kind of graphics output. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12980 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- FL/Fl_Device.H | 11 ++ FL/Fl_Graphics_Driver.H | 8 -- examples/SVG_File_Surface.cxx | 234 ++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+), 8 deletions(-) create mode 100644 examples/SVG_File_Surface.cxx diff --git a/FL/Fl_Device.H b/FL/Fl_Device.H index 9162d13b1..5378293f3 100644 --- a/FL/Fl_Device.H +++ b/FL/Fl_Device.H @@ -51,6 +51,17 @@ class Fl_Widget; For back-compatibility, it is also possible to use the Fl_Surface_Device::set_current() member function to change the current drawing surface, once to the new surface, once to the previous one. + + Class Fl_Surface_Device can also be derived to define new kinds of graphical output + usable with FLTK drawing functions. + An example would be to draw to an SVG file. This would require to create a new class, + say SVG_Surface, derived from class Fl_Surface_Device, and another new class, + say SVG_Graphics_Driver, derived from class Fl_Graphics_Driver. + Class SVG_Graphics_Driver should implement all virtual methods of the Fl_Graphics_Driver class + to support all FLTK drawing functions and have them draw into SVG files. Alternatively, + class SVG_Graphics_Driver could implement only some virtual methods, and only part of + the FLTK drawing API would be usable when drawing to SVG files + (see examples/SVG_File_Surface.cxx for a small, working implementation of this procedure). */ class FL_EXPORT Fl_Surface_Device { /** The graphics driver in use by this surface. */ diff --git a/FL/Fl_Graphics_Driver.H b/FL/Fl_Graphics_Driver.H index 0255ae24f..01646b446 100644 --- a/FL/Fl_Graphics_Driver.H +++ b/FL/Fl_Graphics_Driver.H @@ -72,14 +72,6 @@ struct Fl_Fontdesc; drawing operations are directed to another drawing surface by Fl_Surface_Device::push_current() / Fl_Surface_Device::pop_current() / Fl_Surface_Device::set_current(). - The Fl_Graphics_Driver class is of interest if one wants to perform new kinds of drawing operations. - An example would be to draw to an SVG file. This would require to create a new class, - say SVG_Graphics_Driver, derived from class Fl_Graphics_Driver, and another new class, - say SVG_Surface, derived from class Fl_Surface_Device. The new SVG_Graphics_Driver class should - implement all virtual methods of the Fl_Graphics_Driver class to support all FLTK drawing functions - and have them draw into SVG files. Alternatively, class SVG_Graphics_Driver could implement only some - virtual methods, and only part of FLTK drawing functions would be usable when drawing to SVG files. - The Fl_Graphics_Driver class is essential for developers of the FLTK library. Each platform supported by FLTK requires to create a derived class of Fl_Graphics_Driver that implements all its virtual member functions according to the platform. diff --git a/examples/SVG_File_Surface.cxx b/examples/SVG_File_Surface.cxx new file mode 100644 index 000000000..bd36d0f9a --- /dev/null +++ b/examples/SVG_File_Surface.cxx @@ -0,0 +1,234 @@ +#include +#include +#include +#include +#include +#include +#include + +class SVG_Graphics_Driver : public Fl_Graphics_Driver { + FILE *out_; + int width_; + const char *linecap_; + uchar red_, green_, blue_; +public: + SVG_Graphics_Driver(FILE*); + ~SVG_Graphics_Driver(); + FILE* file() {return out_;} +protected: + const char *family_; + const char *bold_; + const char *style_; + void rect(int x, int y, int w, int h); + void rectf(int x, int y, int w, int h); + void line_style(int style, int width, char *dashes=0); + void line(int x1, int y1, int x2, int y2); + void font_(int f, int s); + void font(int f, int s); + void draw(const char *str, int n, int x, int y); + void draw(const char*, int, float, float) ; + void draw(int, const char*, int, int, int) ; + void rtl_draw(const char*, int, int, int) {} + void color(uchar r, uchar g, uchar b); + void color(Fl_Color c); + void draw_image(const uchar*, int, int, int, int, int, int) {} + void draw_image_mono(const uchar*, int, int, int, int, int, int) {} + void draw_image(void (*)(void*, int, int, int, uchar*), void*, int, int, int, int, int) {} + void draw_image_mono(void (*)(void*, int, int, int, uchar*), void*, int, int, int, int, int) {} + void draw(Fl_RGB_Image*, int, int, int, int, int, int) {} + void draw(Fl_Pixmap*, int, int, int, int, int, int) {} + void draw(Fl_Bitmap*, int, int, int, int, int, int) {} + double width(const char*, int) ; + int height() ; + int descent() ; + + void push_clip(int x, int y, int w, int h) {} + void pop_clip(){} + void xyline(int x, int y, int x1){} + void xyline(int x, int y, int x1, int y2){} + void yxline(int x, int y, int y1){} + void yxline(int x, int y, int y1, int x2){} + virtual void point(int x, int y) {} + virtual void line(int x, int y, int x1, int y1, int x2, int y2) {} + virtual void xyline(int x, int y, int x1, int y2, int x3) {} + virtual void yxline(int x, int y, int y1, int x2, int y3) {} + virtual void loop(int x0, int y0, int x1, int y1, int x2, int y2) {} + virtual void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {} + virtual void polygon(int x0, int y0, int x1, int y1, int x2, int y2) {} + virtual void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {} + virtual int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) {return 0;} + virtual int not_clipped(int x, int y, int w, int h) {return 0;} + virtual void push_no_clip() {} + virtual void begin_complex_polygon() {} + virtual void transformed_vertex(double xf, double yf) {} + virtual void vertex(double x, double y) {} + virtual void end_points() {} + virtual void end_line() {} + virtual void end_loop() {} + virtual void end_polygon() {} + virtual void end_complex_polygon() {} + virtual void gap() {} + virtual void circle(double x, double y, double r) {} + virtual void arc(int x, int y, int w, int h, double a1, double a2) {} + virtual void pie(int x, int y, int w, int h, double a1, double a2) {} + virtual Fl_Bitmask create_bitmask(int w, int h, const uchar *array) {return 0;} + virtual void delete_bitmask(Fl_Bitmask bm) {} +}; + +class SVG_File_Surface : public Fl_Surface_Device { + int width_, height_; +public: + SVG_File_Surface(int width, int height, FILE*); + int width() { return width_; } + int height() { return height_; } + ~SVG_File_Surface(); +}; + + +SVG_Graphics_Driver::SVG_Graphics_Driver(FILE *f) { + out_ = f; + width_ = 1; + linecap_ = "butt"; + family_ = ""; + bold_ = ""; + style_ = ""; + red_ = green_ = blue_ = 0; +} + +SVG_Graphics_Driver::~SVG_Graphics_Driver() +{ +} + +void SVG_Graphics_Driver::rect(int x, int y, int w, int h) { + fprintf(out_, "\n", x, y, w, h, red_, green_, blue_, width_); +} + +void SVG_Graphics_Driver::rectf(int x, int y, int w, int h) { + fprintf(out_, "\n", x, y, w, h, red_, green_, blue_); +} + +void SVG_Graphics_Driver::line(int x1, int y1, int x2, int y2) { + fprintf(out_, + "\n", + x1,y1,x2,y2, red_, green_, blue_, width_, linecap_); +} + +void SVG_Graphics_Driver::font_(int ft, int s) { + Fl_Graphics_Driver::font(ft, s); + int famnum = ft/4; + if (famnum == 0) family_ = "Helvetica"; + else if (famnum == 1) family_ = "Courier"; + else family_ = "Times"; + int modulo = ft % 4; + int use_bold = modulo == 1 || modulo == 3; + int use_italic = modulo >= 2; + bold_ = ( use_bold ? " font-weight=\"bold\"" : "" ); + style_ = ( use_italic ? " font-style=\"italic\"" : "" ); + if (use_italic && famnum != 2) style_ = " font-style=\"oblique\""; +} + +void SVG_Graphics_Driver::font(int ft, int s) { + Fl_Display_Device::display_device()->driver()->font(ft, s); + font_(ft, s); +} + +void SVG_Graphics_Driver::line_style(int style, int width, char *dashes) { + if (width == 0) width = 1; + width_ = width; + if (style & FL_CAP_SQUARE) linecap_ = "square"; + if (style & FL_CAP_ROUND) linecap_ = "round"; + else linecap_ = "butt"; +} + +void SVG_Graphics_Driver::draw(const char *str, int n, int x, int y) { + // Caution: Internet Explorer ignores the xml:space="preserve" attribute + // work-around: replace all spaces by no-break space = U+00A0 = 0xC2-0xA0 (UTF-8) before sending to IE + fprintf(out_, "%.*s\n",x, y, family_, bold_, style_, size(), red_, green_, blue_, (int)width(str, n), n, str); + +} + +void SVG_Graphics_Driver::draw(const char* str, int n, float fx, float fy) { + return draw(str, n, (int)fx, (int)fy); +} + +void SVG_Graphics_Driver::draw(int angle, const char* str, int n, int x, int y) { + fprintf(out_, "", x, y, -angle); + draw(str, n, 0, 0); + fputs("\n", out_); +} + +void SVG_Graphics_Driver::color(Fl_Color c) { + Fl_Graphics_Driver::color(c); + Fl::get_color(c, red_, green_, blue_); +} + +void SVG_Graphics_Driver::color(uchar r, uchar g, uchar b) { + red_ = r; + green_ = g; + blue_ = b; +} + +double SVG_Graphics_Driver::width(const char* str, int l) { + return Fl_Display_Device::display_device()->driver()->width(str, l); +} + +int SVG_Graphics_Driver::height() { + return Fl_Display_Device::display_device()->driver()->height(); +} + +int SVG_Graphics_Driver::descent() { + return Fl_Display_Device::display_device()->driver()->descent(); +} + +SVG_File_Surface::SVG_File_Surface(int w, int h, FILE *f) : Fl_Surface_Device(NULL) { + fprintf(f, + "\n" + "\n" + "\n", w, h, w, h); + width_ = w; height_ = h; + driver(new SVG_Graphics_Driver(f)); +} + +SVG_File_Surface::~SVG_File_Surface() { + SVG_Graphics_Driver *driver = (SVG_Graphics_Driver*)this->driver(); + fputs("\n", driver->file()); + fflush(driver->file()); + delete driver; +} + + +int main(int argc, char **argv) { + Fl_Window *window = new Fl_Window(340,180); + Fl_Box *box = new Fl_Box(20,40,300,100,"Hello, World!"); + box->box(FL_UP_BOX); + box->labelfont(FL_BOLD+FL_ITALIC); + box->labelsize(36); + box->labeltype(FL_SHADOW_LABEL); + window->end(); + window->show(argc, argv); + + FILE *out = fl_fopen("hello.svg", "w"); + if (out) { + SVG_File_Surface *svg = new SVG_File_Surface(box->w(), box->h(), out); + Fl_Surface_Device::push_current(svg); + fl_color(box->color()); + fl_rectf(0, 0, box->w(), box->h()); + fl_font(box->labelfont(), 36); + fl_color(box->labelcolor()); + fl_draw(box->label(), 5, 50); + Fl_Surface_Device::pop_current(); + delete svg; + fclose(out); + } + + return Fl::run(); +} + +