Generate code block documentation using FLTK (#1353)
The Doxygen-to-pdf toolchain can not easily generate pdf's with Japanese and Chinese characters. This patch generates code blocks by rendering them in FLTK.
This commit is contained in:
parent
22c1730261
commit
f5e7d62f90
@ -257,6 +257,12 @@ if(FLTK_BUILD_FLTK_OPTIONS)
|
|||||||
add_subdirectory(fltk-options)
|
add_subdirectory(fltk-options)
|
||||||
endif(FLTK_BUILD_FLTK_OPTIONS)
|
endif(FLTK_BUILD_FLTK_OPTIONS)
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# build utilities
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
add_subdirectory(util)
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
# variables shared by export and install
|
# variables shared by export and install
|
||||||
# export.cmake creates configuration files for direct use in a built but uninstalled FLTK
|
# export.cmake creates configuration files for direct use in a built but uninstalled FLTK
|
||||||
|
|||||||
@ -103,6 +103,7 @@ if(FLTK_BUILD_HTML_DOCS)
|
|||||||
|
|
||||||
set(GENERATE_HTML YES)
|
set(GENERATE_HTML YES)
|
||||||
set(GENERATE_LATEX NO)
|
set(GENERATE_LATEX NO)
|
||||||
|
set(EXTRA_SECTIONS "HTML_SECTIONS")
|
||||||
set(LATEX_HEADER "")
|
set(LATEX_HEADER "")
|
||||||
set(DOXYFILE "Doxyfile")
|
set(DOXYFILE "Doxyfile")
|
||||||
set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}_error.log")
|
set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}_error.log")
|
||||||
@ -152,6 +153,7 @@ if(FLTK_BUILD_PDF_DOCS)
|
|||||||
|
|
||||||
set(GENERATE_HTML NO)
|
set(GENERATE_HTML NO)
|
||||||
set(GENERATE_LATEX YES)
|
set(GENERATE_LATEX YES)
|
||||||
|
set(EXTRA_SECTIONS "LATEX_SECTIONS")
|
||||||
set(LATEX_HEADER "${CMAKE_CURRENT_BINARY_DIR}/fltk-book.tex")
|
set(LATEX_HEADER "${CMAKE_CURRENT_BINARY_DIR}/fltk-book.tex")
|
||||||
set(DOXYFILE "Doxybook")
|
set(DOXYFILE "Doxybook")
|
||||||
set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}_error.log")
|
set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}_error.log")
|
||||||
@ -202,6 +204,7 @@ if(FLTK_BUILD_PDF_DOCS)
|
|||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fltk.pdf
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fltk.pdf
|
||||||
|
COMMAND code_snapshot ${CMAKE_CURRENT_SOURCE_DIR}/src/unicode.dox
|
||||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/make_header
|
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/make_header
|
||||||
${DOXYGEN_EXECUTABLE}
|
${DOXYGEN_EXECUTABLE}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/fltk-title.tex
|
${CMAKE_CURRENT_BINARY_DIR}/fltk-title.tex
|
||||||
@ -220,6 +223,7 @@ if(FLTK_BUILD_PDF_DOCS)
|
|||||||
add_custom_target(pdf
|
add_custom_target(pdf
|
||||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/fltk.pdf
|
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/fltk.pdf
|
||||||
)
|
)
|
||||||
|
add_dependencies(pdf code_snapshot)
|
||||||
|
|
||||||
endif(FLTK_BUILD_PDF_DOCS)
|
endif(FLTK_BUILD_PDF_DOCS)
|
||||||
|
|
||||||
|
|||||||
@ -229,7 +229,8 @@ TAB_SIZE = 8
|
|||||||
# newlines (in the resulting output). You can put ^^ in the value part of an
|
# newlines (in the resulting output). You can put ^^ in the value part of an
|
||||||
# alias to insert a newline as if a physical newline was in the original file.
|
# alias to insert a newline as if a physical newline was in the original file.
|
||||||
|
|
||||||
ALIASES =
|
ALIASES = code_international{1}="@if LATEX_SECTIONS^^@image latex \1 width=\\linewidth^^@endif^^@if HTML_SECTIONS^^@code"
|
||||||
|
ALIASES += endcode_international="@endcode^^@endif"
|
||||||
|
|
||||||
# This tag can be used to specify a number of word-keyword mappings (TCL only).
|
# This tag can be used to specify a number of word-keyword mappings (TCL only).
|
||||||
# A mapping has the form "name=value". For example adding "class=itcl::class"
|
# A mapping has the form "name=value". For example adding "class=itcl::class"
|
||||||
@ -639,7 +640,7 @@ GENERATE_DEPRECATEDLIST= YES
|
|||||||
# sections, marked by \if <section_label> ... \endif and \cond <section_label>
|
# sections, marked by \if <section_label> ... \endif and \cond <section_label>
|
||||||
# ... \endcond blocks.
|
# ... \endcond blocks.
|
||||||
|
|
||||||
ENABLED_SECTIONS = @DRIVER_DOCS@
|
ENABLED_SECTIONS = @DRIVER_DOCS@ @EXTRA_SECTIONS@
|
||||||
|
|
||||||
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
|
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
|
||||||
# initial value of a variable or macro / define can have for it to appear in the
|
# initial value of a variable or macro / define can have for it to appear in the
|
||||||
@ -920,7 +921,8 @@ EXAMPLE_RECURSIVE = NO
|
|||||||
# that contain images that are to be included in the documentation (see the
|
# that contain images that are to be included in the documentation (see the
|
||||||
# \image command).
|
# \image command).
|
||||||
|
|
||||||
IMAGE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/src
|
IMAGE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/src \
|
||||||
|
@CMAKE_CURRENT_BINARY_DIR@/generated
|
||||||
|
|
||||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||||
|
|||||||
@ -20,6 +20,16 @@ are not yet implemented.
|
|||||||
|
|
||||||
\section unicode_quick_start Quick Start
|
\section unicode_quick_start Quick Start
|
||||||
|
|
||||||
|
International code test for HTML and PDF:
|
||||||
|
|
||||||
|
\code_international{"generated/unicode_about.png"}
|
||||||
|
// This is a test
|
||||||
|
// 日本語テストテキスト
|
||||||
|
// 中文测试文本
|
||||||
|
// Ελληνικό κείμενο δοκιμής
|
||||||
|
\endcode_international
|
||||||
|
|
||||||
|
|
||||||
For most applications, you simply need to ensure your text is UTF-8 encoded:
|
For most applications, you simply need to ensure your text is UTF-8 encoded:
|
||||||
|
|
||||||
\code
|
\code
|
||||||
|
|||||||
@ -53,6 +53,7 @@ public:
|
|||||||
Code_Editor(int X, int Y, int W, int H, const char *L=nullptr);
|
Code_Editor(int X, int Y, int W, int H, const char *L=nullptr);
|
||||||
~Code_Editor();
|
~Code_Editor();
|
||||||
void textsize(Fl_Fontsize s);
|
void textsize(Fl_Fontsize s);
|
||||||
|
Fl_Fontsize textsize() const { return Fl_Text_Editor::textsize(); }
|
||||||
|
|
||||||
/// access to protected member get_absolute_top_line_number()
|
/// access to protected member get_absolute_top_line_number()
|
||||||
int top_line() { return get_absolute_top_line_number(); }
|
int top_line() { return get_absolute_top_line_number(); }
|
||||||
|
|||||||
76
util/CMakeLists.txt
Normal file
76
util/CMakeLists.txt
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#
|
||||||
|
# CMakeLists.txt to build utilities for the FLTK project using CMake (www.cmake.org)
|
||||||
|
#
|
||||||
|
# Copyright 1998-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
|
||||||
|
#
|
||||||
|
|
||||||
|
# Build utilities for FLTK development
|
||||||
|
|
||||||
|
# Note: utilities are only built internally during the build process
|
||||||
|
# and not installed. They are tools used to generate source files or
|
||||||
|
# assist in building documentation.
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# cmap - colormap generation program
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
# This program produces the contents of "fl_cmap.h"
|
||||||
|
# It's used during the build process to generate src/fl_cmap.h
|
||||||
|
|
||||||
|
add_executable(cmap cmap.cxx)
|
||||||
|
|
||||||
|
# cmap doesn't need to link against FLTK libraries - it's a standalone tool
|
||||||
|
target_link_libraries(cmap PRIVATE m)
|
||||||
|
|
||||||
|
# Set properties
|
||||||
|
set_target_properties(cmap PROPERTIES
|
||||||
|
OUTPUT_NAME cmap
|
||||||
|
EXCLUDE_FROM_ALL TRUE
|
||||||
|
)
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# PDF documentation tool to generate a png image from a
|
||||||
|
# Doxygen `@code` segment with international characters
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
if(FLTK_BUILD_PDF_DOCS)
|
||||||
|
|
||||||
|
# PDF documentation helper tool
|
||||||
|
add_executable(code_snapshot
|
||||||
|
code_snapshot.cxx
|
||||||
|
../fluid/Widgets/Code_Viewer.cxx
|
||||||
|
../fluid/Widgets/Code_Editor.cxx
|
||||||
|
../fluid/Widgets/Style_Parser.cxx
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(code_snapshot PRIVATE fltk::images)
|
||||||
|
|
||||||
|
set_target_properties(code_snapshot PROPERTIES
|
||||||
|
OUTPUT_NAME code_snapshot
|
||||||
|
EXCLUDE_FROM_ALL FALSE
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(code_snapshot PRIVATE
|
||||||
|
../fluid
|
||||||
|
)
|
||||||
|
|
||||||
|
message(STATUS "PDF code snapshot tools will be built (FLTK_BUILD_PDF_DOCS=ON)")
|
||||||
|
|
||||||
|
endif(FLTK_BUILD_PDF_DOCS)
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Install rules (if any tools need to be installed)
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
# Currently no utilities are installed as they are build-time tools only
|
||||||
|
# If you need to install any utilities, add install() commands here
|
||||||
@ -4,3 +4,16 @@ Utility programs used to build the FLTK library.
|
|||||||
Contents:
|
Contents:
|
||||||
|
|
||||||
cmap.cxx generate src/fl_cmap.h
|
cmap.cxx generate src/fl_cmap.h
|
||||||
|
code_snapshot.cxx PDF documentation tool to generate a png image from a
|
||||||
|
Doxygen `@code` segment with international characters
|
||||||
|
|
||||||
|
Build System:
|
||||||
|
|
||||||
|
The util directory includes CMake support. Utilities are built
|
||||||
|
automatically during the build process when needed. Some utilities
|
||||||
|
are only built when specific features are enabled:
|
||||||
|
|
||||||
|
- the PDF documentation helper is only built when FLTK_BUILD_PDF_DOCS=ON
|
||||||
|
|
||||||
|
To add a new utility, edit util/CMakeLists.txt and follow the existing
|
||||||
|
patterns for conditional building and target configuration.
|
||||||
|
|||||||
159
util/code_snapshot.cxx
Normal file
159
util/code_snapshot.cxx
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
//
|
||||||
|
// 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 in
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
|
Fl_Window* window = nullptr;
|
||||||
|
Fl_Group* group = nullptr;
|
||||||
|
fld::widget::Code_Viewer* code_viewer = nullptr;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
window->resizable(group);
|
||||||
|
group->resizable(code_viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = 2000 pixels
|
||||||
|
window->size(2100, 6 + 34*n_lines );
|
||||||
|
|
||||||
|
// 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 argc Argument count
|
||||||
|
\param 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;
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user