mirror of
https://github.com/fltk/fltk.git
synced 2026-02-07 00:41:48 +08:00
CMake: execute `code_snapshot` separately for each file we want to scan so we can create timestamps and generate PNG images only if the source file (e.g. unicode.dox) was modified. documentation/src/unicode.dox: remove output folder `generated`, use only the filename. CMake sets the current working directory as needed. util/code_snapshot.cxx: format and improve comments, reset code buffer so we can generate multiple images per input file.
181 lines
5.7 KiB
C++
181 lines
5.7 KiB
C++
//
|
|
// PDF documentation tool to generate a png image from a Doxygen `@code`
|
|
// segment with international characters for the Fast Light Tool Kit (FLTK).
|
|
//
|
|
// Copyright 2025 by Bill Spitzak and others.
|
|
//
|
|
// This library is free software. Distribution and use rights are outlined in
|
|
// the file "COPYING" which should have been included with this file. If this
|
|
// file is missing or damaged, see the license at:
|
|
//
|
|
// https://www.fltk.org/COPYING.php
|
|
//
|
|
// Please see the following page on how to report bugs and issues:
|
|
//
|
|
// https://www.fltk.org/bugs.php
|
|
//
|
|
|
|
//
|
|
// Our documentation for the FLTK unicode contains international characters
|
|
// to illustrate use of non ASCII characters in the GUI. To generate PDF
|
|
// output, Doxygen uses LaTeX which can not easily handle UTF-8 characters
|
|
// beyond Western encoding. This tool generates PNG images from code segments
|
|
// containing international characters so that they can be included in the
|
|
// PDF documentation instead of the code segments with UTF-8 characters.
|
|
//
|
|
// Notes:
|
|
// - This program is work in progress...
|
|
// - The PDF generation process (CMake) calls it once for each source file
|
|
// that needs image generation. The loop over all commandline arguments is
|
|
// currently not necessary but kept for potential extensions.
|
|
// - The program exits silently if no commandline is given.
|
|
// - If the terminating "\endcode_international" line is missing or misspelled,
|
|
// the program reads the "code" until the end of the file is reached and
|
|
// terminates w/o error message. This could be improved...
|
|
|
|
#include <FL/Fl_Window.H>
|
|
#include <FL/Fl_Group.H>
|
|
#include <FL/filename.H>
|
|
#include <FL/fl_draw.H>
|
|
#include <FL/Fl_Image_Surface.H>
|
|
#include <FL/Fl_PNG_Image.H>
|
|
|
|
#include "../fluid/widgets/Code_Editor.h"
|
|
#include "../fluid/widgets/Code_Viewer.h"
|
|
#include "../fluid/widgets/Style_Parser.h"
|
|
|
|
#include <stdio.h>
|
|
#include <algorithm>
|
|
|
|
|
|
Fl_Window* window = nullptr;
|
|
Fl_Group* group = nullptr;
|
|
fld::widget::Code_Viewer* code_viewer = nullptr;
|
|
int line_height = 10;
|
|
|
|
void create_window() {
|
|
window = new Fl_Window(1024, 100);
|
|
group = new Fl_Group(0, 0, 1024, 100);
|
|
group->color(0xf7f7ff00);
|
|
group->box(FL_FLAT_BOX);
|
|
|
|
code_viewer = new fld::widget::Code_Viewer(5, 5, 1014, 94);
|
|
code_viewer->box(FL_FLAT_BOX);
|
|
code_viewer->color(0xf7f7ff00);
|
|
code_viewer->textsize(30);
|
|
// code_viewer->cursor_style(CARET_CURSOR);
|
|
|
|
window->resizable(group);
|
|
group->resizable(code_viewer);
|
|
|
|
// Make sure the display is opened.
|
|
Fl_Display_Device::display_device();
|
|
|
|
line_height = fl_height(code_viewer->textfont(), code_viewer->textsize());
|
|
line_height = std::max(line_height, fl_height(FL_COURIER, code_viewer->textsize()));
|
|
line_height = std::max(line_height, fl_height(FL_COURIER_BOLD, code_viewer->textsize()));
|
|
line_height = std::max(line_height, fl_height(FL_COURIER_ITALIC, code_viewer->textsize()));
|
|
line_height = std::max(line_height, fl_height(FL_COURIER_BOLD_ITALIC, code_viewer->textsize()));
|
|
}
|
|
|
|
void save_snapshot(const char* code, const char* filename) {
|
|
// fprintf(stderr, "\\code\n%s\n\\endcode\n", code);
|
|
|
|
code_viewer->buffer()->text(code);
|
|
int n_lines = 1;
|
|
for (const char* s=code; *s; ++s) if (*s == '\n') n_lines++;
|
|
// 300 dpi for 7 inches = 2100 pixels
|
|
window->size(2100, (line_height * n_lines) + 18 );
|
|
|
|
// Generate the Image Surface
|
|
Fl_Image_Surface *srfc = new Fl_Image_Surface(window->w(), window->h());
|
|
|
|
// Draw the window and its content
|
|
Fl_Image_Surface::push_current(srfc);
|
|
srfc->draw(group, 0, 0);
|
|
fl_rect(0, 0, window->w(), window->h(), 0xccccff00);
|
|
Fl_Image_Surface::pop_current();
|
|
|
|
// fprintf(stderr, " Saving to \"%s\".\n", filename);
|
|
|
|
// Write the generated image
|
|
Fl_RGB_Image *img = srfc->image();
|
|
fl_write_png(filename, img);
|
|
|
|
// Clean up
|
|
delete img;
|
|
delete srfc;
|
|
}
|
|
|
|
/**
|
|
Main entry point for the PDF documentation helper tool.
|
|
|
|
The app scans the input file for the `\code_international{"filename"}`
|
|
directive, reads the following code segment until
|
|
`\endcode_international`, and generates a PNG image file with the given
|
|
filename containing the code segment rendered with FLTK's
|
|
code rendering capabilities.
|
|
|
|
\param[in] argc Argument count
|
|
\param[in] argv a list of input files with documentation in Doxygen format
|
|
\return Exit code (0 for success, non-zero for failure)
|
|
*/
|
|
int main(int argc, char *argv[]) {
|
|
int ret = 0;
|
|
char line[1024];
|
|
char cwd[FL_PATH_MAX];
|
|
|
|
// fl_getcwd(cwd, FL_PATH_MAX-1);
|
|
// fprintf(stderr, "code_snapshot:\n");
|
|
// fprintf(stderr, "Working directory is \"%s\".\n", cwd);
|
|
|
|
create_window();
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
FILE* f = fl_fopen(argv[i], "rb");
|
|
if (!f) {
|
|
fl_getcwd(cwd, FL_PATH_MAX-1);
|
|
fprintf(stderr, "code_snapshot:\nCan't open file \"%s\".\n", argv[i]);
|
|
fprintf(stderr, "Working directory is \"%s\".\n", cwd);
|
|
ret = -1;
|
|
break;
|
|
}
|
|
|
|
// fprintf(stderr, "Reading \"%s\".\n", argv[i]);
|
|
|
|
std::string code;
|
|
std::string filename;
|
|
bool in_code_block = false;
|
|
for (;;) {
|
|
fgets(line, 1023, f);
|
|
if (feof(f)) break;
|
|
if (in_code_block) {
|
|
if (strstr(line, "\\endcode_international")) {
|
|
if (!code.empty()) {
|
|
code.resize(code.size() - 1);
|
|
save_snapshot(code.c_str(), filename.c_str());
|
|
}
|
|
in_code_block = false;
|
|
code = "";
|
|
} else {
|
|
code += line;
|
|
}
|
|
} else {
|
|
if (strstr(line, "\\code_international")) {
|
|
const char* fn_start = strstr(line, "{\"");
|
|
const char* fn_end = strstr(line, "\"}");
|
|
if (fn_start && fn_end && (fn_end > fn_start)) {
|
|
filename = std::string(fn_start+2, fn_end-fn_start-2);
|
|
in_code_block = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
delete window;
|
|
|
|
return ret;
|
|
}
|