Separate FLUID user documentation, screen shot automation (#936)

* CMake integration, no autotiools
* alignment panel is now correctly renamed to setting panel
* source view is now correctly renamed to code view
* Merge FLTK FLUID docs into FLUID user manual.
* Add two simple entry tutorials
* Remove FLUID chapter form FLTK docs.
* GitHub action to generate HTML and PDF docs and
  make the available as artefacts
This commit is contained in:
Matthias Melcher 2024-04-17 17:51:32 +02:00 committed by GitHub
parent b4cf1a9824
commit fd791a068e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
122 changed files with 7954 additions and 3050 deletions

84
.github/workflows/build_fluid_docs.yml vendored Normal file
View File

@ -0,0 +1,84 @@
#
# This script builds the FLUID User Handbook as html directory and pdf
# document on a Linux machine.
#
name: 'Build FLUID User Handbook'
# This job must be called explicitly form the 'Actions' tab in GitHub
on: [workflow_dispatch]
permissions:
contents: read
jobs:
build-html:
runs-on: ubuntu-latest
## This can also run on macOS, but BasicTeX will not generate the pdf document
# runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Install prerequisites
run: |
sudo apt-get update -y
sudo apt-get install -y libwayland-dev wayland-protocols libdbus-1-dev libxkbcommon-dev libpango1.0-dev libgtk-3-dev
sudo apt-get install -y doxygen
sudo apt-get install -y doxygen-latex
sudo apt-get install -y xvfb
sudo apt-get install -y x11-xkb-utils xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic x11-apps
## Use the following line when 1.10.0 becomes available on Ubuntu. On 4/14/24 it's 1.9.2
# sudo apt-get install -y doxygen=1.10.0
## xvfb creates a headless X server for us, so we can render snapshot with FLUID
## We need at least Doxygen on macOS. BasicTeX is not enough though.
# brew install doxygen
# brew install --cask basictex
# eval "$(/usr/libexec/path_helper)"
- name: Create Build Environment
run: cmake -E make_directory ${{github.workspace}}/build
- name: Configure CMake
shell: bash
working-directory: ${{github.workspace}}/build
run: |
cmake $GITHUB_WORKSPACE \
-D CMAKE_BUILD_TYPE=Debug \
-D CMAKE_CXX_STANDARD=11 \
-D CMAKE_CXX_EXTENSIONS=OFF \
-D CMAKE_C_FLAGS_INIT="-Wall -Wunused" \
-D CMAKE_CXX_FLAGS_INIT="-Wall -Wunused -Wsuggest-override" \
-D FLTK_BUILD_FLTK_OPTIONS=OFF \
-D FLTK_BUILD_FLUID=ON \
-D FLTK_BUILD_GL=OFF \
-D FLTK_BUILD_TEST=OFF \
-D FLTK_BUILD_FLUID_DOCS=ON
- name: Build
working-directory: ${{github.workspace}}/build
shell: bash
run: |
Xvfb :19 -screen 0 1024x768x16 &
export DISPLAY=:19
cmake --build . --config Debug --target fluid_docs
cmake --build . --config Debug --target fluid_pdf
- name: Store html docs as an artifact
uses: actions/upload-artifact@v4
with:
name: fluid-html
path: build/fluid/documentation/html
retention-days: 3
overwrite: true
- name: Store pdf docs as an artifact
uses: actions/upload-artifact@v4
with:
name: fluid-pdf
path: build/fluid/documentation/fluid.pdf
retention-days: 3
overwrite: true

View File

@ -459,6 +459,8 @@ endif()
if(DOXYGEN_FOUND) if(DOXYGEN_FOUND)
option(FLTK_BUILD_HTML_DOCS "build html docs" ON) option(FLTK_BUILD_HTML_DOCS "build html docs" ON)
option(FLTK_INSTALL_HTML_DOCS "install html docs" OFF) option(FLTK_INSTALL_HTML_DOCS "install html docs" OFF)
option(FLTK_BUILD_FLUID_DOCS "build FLUID docs" OFF)
option(FLTK_INSTALL_FLUID_DOCS "install FLUID docs" OFF)
option(FLTK_INCLUDE_DRIVER_DOCS "include driver (developer) docs" OFF) option(FLTK_INCLUDE_DRIVER_DOCS "include driver (developer) docs" OFF)
mark_as_advanced(FLTK_INCLUDE_DRIVER_DOCS) mark_as_advanced(FLTK_INCLUDE_DRIVER_DOCS)
@ -473,6 +475,10 @@ if(FLTK_BUILD_HTML_DOCS OR FLTK_BUILD_PDF_DOCS)
add_subdirectory(documentation) add_subdirectory(documentation)
endif(FLTK_BUILD_HTML_DOCS OR FLTK_BUILD_PDF_DOCS) endif(FLTK_BUILD_HTML_DOCS OR FLTK_BUILD_PDF_DOCS)
if(FLTK_BUILD_FLUID_DOCS)
add_subdirectory(fluid/documentation)
endif(FLTK_BUILD_FLUID_DOCS)
####################################################################### #######################################################################
# Include optional Cairo support # Include optional Cairo support
####################################################################### #######################################################################

View File

@ -325,6 +325,12 @@ FLTK_BUILD_PDF_DOCS - default ON
You can safely leave these two options ON if you want to save build time You can safely leave these two options ON if you want to save build time
because the docs are not built automatically. because the docs are not built automatically.
FLTK_BUILD_FLUID_DOCS - default OFF
If this option is ON, the FLUID user documentation will be built. If
FLTK_BUILD_PDF_DOCS is ON, the FLUID documentation will be generated
in PDF forma. To generate the screen shots used in the handbook,
the CMake build mode must be set to "Debug".
FLTK_INCLUDE_DRIVER_DOCS - default OFF FLTK_INCLUDE_DRIVER_DOCS - default OFF
This option adds driver documentation to HTML and PDF docs (if ON). This This option adds driver documentation to HTML and PDF docs (if ON). This
option is marked as "advanced" since it is only useful for FLTK developers option is marked as "advanced" since it is only useful for FLTK developers
@ -332,8 +338,9 @@ FLTK_INCLUDE_DRIVER_DOCS - default OFF
options above is ON as well. options above is ON as well.
FLTK_INSTALL_HTML_DOCS - default OFF FLTK_INSTALL_HTML_DOCS - default OFF
FLTK_INSTALL_FLUID_DOCS - default OFF
FLTK_INSTALL_PDF_DOCS - default OFF FLTK_INSTALL_PDF_DOCS - default OFF
If these options are ON then the HTML and/or PDF docs are installed If these options are ON then the HTML, FLUID, and/or PDF docs are installed
when the 'install' target is executed, e.g. with `make install'. You when the 'install' target is executed, e.g. with `make install'. You
need to select above options FLTK_BUILD_*_DOCS as well. need to select above options FLTK_BUILD_*_DOCS as well.

View File

@ -52,7 +52,7 @@ if(GENERATE_DOCS)
# find git revision # find git revision
# FIXME: This must also work with tarballs where git is not available. # FIXME: This must also work with tarballs where git is not available.
# For now we just ignore errors and set GIT_REVISION = "unkown". # For now we just ignore errors and set GIT_REVISION = "unknown".
# In the future tarball/zip generation should create a file # In the future tarball/zip generation should create a file
# that contains the git revision. # that contains the git revision.

View File

@ -794,7 +794,6 @@ INPUT = @CMAKE_CURRENT_SOURCE_DIR@/src/index.dox \
@CMAKE_CURRENT_SOURCE_DIR@/src/events.dox \ @CMAKE_CURRENT_SOURCE_DIR@/src/events.dox \
@CMAKE_CURRENT_SOURCE_DIR@/src/subclassing.dox \ @CMAKE_CURRENT_SOURCE_DIR@/src/subclassing.dox \
@CMAKE_CURRENT_SOURCE_DIR@/src/opengl.dox \ @CMAKE_CURRENT_SOURCE_DIR@/src/opengl.dox \
@CMAKE_CURRENT_SOURCE_DIR@/src/fluid.dox \
@CMAKE_CURRENT_SOURCE_DIR@/src/fltk-options.dox \ @CMAKE_CURRENT_SOURCE_DIR@/src/fltk-options.dox \
@CMAKE_CURRENT_SOURCE_DIR@/src/advanced.dox \ @CMAKE_CURRENT_SOURCE_DIR@/src/advanced.dox \
@CMAKE_CURRENT_SOURCE_DIR@/src/unicode.dox \ @CMAKE_CURRENT_SOURCE_DIR@/src/unicode.dox \

View File

@ -36,7 +36,6 @@ HTMLFILES = \
$(SRC_DOCDIR)/events.dox \ $(SRC_DOCDIR)/events.dox \
$(SRC_DOCDIR)/subclassing.dox \ $(SRC_DOCDIR)/subclassing.dox \
$(SRC_DOCDIR)/opengl.dox \ $(SRC_DOCDIR)/opengl.dox \
$(SRC_DOCDIR)/fluid.dox \
$(SRC_DOCDIR)/fltk-options.dox \ $(SRC_DOCDIR)/fltk-options.dox \
$(SRC_DOCDIR)/advanced.dox \ $(SRC_DOCDIR)/advanced.dox \
$(SRC_DOCDIR)/unicode.dox \ $(SRC_DOCDIR)/unicode.dox \

View File

@ -252,7 +252,7 @@ and shows OpenGL text.
\subsection examples_CubeView CubeView \subsection examples_CubeView CubeView
\par \par
\c CubeView shows how to create a UI containing OpenGL with Fluid. \c CubeView shows how to create a UI containing OpenGL with FLUID.
\subsection examples_cursor cursor \subsection examples_cursor cursor
@ -577,7 +577,7 @@ come in handy. They remember any kind of data between program launches.
\subsection examples_radio radio \subsection examples_radio radio
\par \par
The \c radio tool was created entirely with <i>fluid</i>. It The \c radio tool was created entirely with <i>FLUID</i>. It
shows some of the available button types and tests radio shows some of the available button types and tests radio
button behavior. button behavior.
@ -658,7 +658,7 @@ The \c table demo shows the features of the Fl_Table widget.
\subsection examples_tabs tabs \subsection examples_tabs tabs
\par \par
The \c tabs tool was created with <i>fluid</i>. It tests The \c tabs tool was created with <i>FLUID</i>. It tests
correct hiding and redisplaying of tabs, navigation across tabs, correct hiding and redisplaying of tabs, navigation across tabs,
resize behavior, and no unneeded redrawing of invisible widgets. resize behavior, and no unneeded redrawing of invisible widgets.
@ -733,13 +733,13 @@ font draws each of the Unicode code points ranging between U+0020 and U+FFFF.
while the focus stays in the original window. while the focus stays in the original window.
\subsection examples_fluid fluid \subsection examples_fluid FLUID
\par \par
\c fluid is not only a big test program, but also a very \c FLUID is not only a big test program, but also a very
useful visual UI designer. Many parts of \c fluid were useful visual UI designer. Many parts of \c FLUID were
created using \c fluid. See the \link fluid Fluid Tutorial \endlink created using \c FLUID. Check out the FLUID User Manual and
for more details. the tutorials that come with it at https://www.fltk.org/documentation.php .

View File

@ -41,8 +41,8 @@ tool called fltk-options.
`fltk-options` is a hybrid app that is part of FLTK and can be installed on `fltk-options` is a hybrid app that is part of FLTK and can be installed on
the target system. It includes an up-to-date man page. the target system. It includes an up-to-date man page.
\image html fluid-edit-global-fltk-settings.png "fltk-options Application" \image html fltk-options.png "fltk-options Application"
\image latex fluid-edit-global-fltk-settings.png "fltk-options Application" width=10cm \image latex fltk-options.png "fltk-options Application" width=10cm
When fltk-options is called without any command-line arguments, it opens in When fltk-options is called without any command-line arguments, it opens in
interactive mode and provides a user interface to view and alter all interactive mode and provides a user interface to view and alter all
@ -67,9 +67,9 @@ A full list of options can be found in the manual at Fl::Fl_Option.
<table summary="navigation bar" width="100%" border="0"> <table summary="navigation bar" width="100%" border="0">
<tr> <tr>
<td width="45%" align="LEFT"> <td width="45%" align="LEFT">
<a class="el" href="fluid.html"> <a class="el" href="opengl.html">
[Prev] [Prev]
Programming with FLUID Using OpenGL
</a> </a>
</td> </td>
<td width="10%" align="CENTER"> <td width="10%" align="CENTER">

View File

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

View File

@ -67,11 +67,6 @@
\subpage opengl \subpage opengl
\subpage fluid
- \ref fluid_widget_attributes
- \ref fluid_selecting_moving
- \ref fluid_images
\subpage fltk-options \subpage fltk-options
\subpage advanced \subpage advanced

View File

@ -142,6 +142,17 @@ the toolkit, which was already in use by several people, Bill
came up with "FLTK", including a bogus excuse that it came up with "FLTK", including a bogus excuse that it
stands for "The Fast Light Toolkit". stands for "The Fast Light Toolkit".
\section intro_fluid FLUID
FLTK comes bundled with FLUID. FLUID, short for Fast Light User Interface
Designer, is a graphical editor capable of generating C++ source code and
header files ready for compilation. These files ultimately create the graphical
user interface for an application.
The FLUID User Handbook is available at https://www.fltk.org/documentation.php .
It can also be compiled from the FLTK source repository using the `fluid_docs`
target in the CMake build environment.
\section intro_cmake Building and Installing FLTK with CMake \section intro_cmake Building and Installing FLTK with CMake
Starting with version 1.4, the recommended FLTK building system Starting with version 1.4, the recommended FLTK building system

View File

@ -164,9 +164,7 @@ loading functions by doing:
Your main program can now create one of your windows by doing Your main program can now create one of your windows by doing
<tt>new MyWindow(...)</tt>. <tt>new MyWindow(...)</tt>.
You can also use your new window class in You can also use your new window class in FLUID by:
\ref fluid "FLUID"
by:
-# Putting your class definition in a \p MyWindow.H file. -# Putting your class definition in a \p MyWindow.H file.
-# Creating a Fl_Box widget in FLUID. -# Creating a Fl_Box widget in FLUID.
@ -670,8 +668,8 @@ Link with libGLEW.so (with X11 or Wayland), libglew32.a (with MinGW) or glew32.l
<a class="el" href="index.html">[Index]</a> <a class="el" href="index.html">[Index]</a>
</td> </td>
<td width="45%" align="RIGHT"> <td width="45%" align="RIGHT">
<a class="el" href="fluid.html"> <a class="el" href="fltk-options.html">
Programming with FLUID FLTK Runtime Options
[Next] [Next]
</a> </a>
</td> </td>

View File

@ -968,7 +968,7 @@ internally in the same way.
\subsection osissues_mac_files Mac File System Specifics \subsection osissues_mac_files Mac File System Specifics
\par Resource Forks \par Resource Forks (OS X pre 10.6)
FLTK does not access the resource fork of an application. FLTK does not access the resource fork of an application.
However, a minimal resource fork must be created for OS X However, a minimal resource fork must be created for OS X

View File

@ -31,7 +31,6 @@ This manual is organized into the following chapters and appendices:
\li \ref events \li \ref events
\li \ref subclassing \li \ref subclassing
\li \ref opengl \li \ref opengl
\li \ref fluid
\li \ref fltk-options \li \ref fltk-options
\li \ref advanced \li \ref advanced
\li \ref unicode \li \ref unicode

View File

@ -40,9 +40,7 @@ The constructor should have the following arguments:
MyClass(int x, int y, int w, int h, const char *label = 0); MyClass(int x, int y, int w, int h, const char *label = 0);
\endcode \endcode
This will allow the class to be used in This will allow the class to be used in FLUID without problems.
\ref fluid "FLUID"
without problems.
The constructor must call the constructor for the base class and The constructor must call the constructor for the base class and
pass the same arguments: pass the same arguments:

View File

@ -37,7 +37,8 @@ set(CPPFILES
Fluid_Image.cxx Fluid_Image.cxx
about_panel.cxx about_panel.cxx
align_widget.cxx align_widget.cxx
alignment_panel.cxx settings_panel.cxx
autodoc.cxx
code.cxx code.cxx
custom_widgets.cxx custom_widgets.cxx
factory.cxx factory.cxx
@ -47,7 +48,7 @@ set(CPPFILES
mergeback.cxx mergeback.cxx
pixmaps.cxx pixmaps.cxx
shell_command.cxx shell_command.cxx
sourceview_panel.cxx codeview_panel.cxx
template_panel.cxx template_panel.cxx
undo.cxx undo.cxx
widget_browser.cxx widget_browser.cxx
@ -71,19 +72,19 @@ set(HEADERFILES
StyleParse.h StyleParse.h
about_panel.h about_panel.h
align_widget.h align_widget.h
alignment_panel.h settings_panel.h
autodoc.h
code.h code.h
comments.h comments.h
custom_widgets.h custom_widgets.h
factory.h factory.h
file.h file.h
fluid.h
function_panel.h function_panel.h
mergeback.h mergeback.h
print_panel.h print_panel.h
pixmaps.h pixmaps.h
shell_command.h shell_command.h
sourceview_panel.h codeview_panel.h
template_panel.h template_panel.h
undo.h undo.h
widget_browser.h widget_browser.h

View File

@ -72,7 +72,7 @@ public:
/** /**
A widget derived from CodeEditor with highlighting for code blocks. A widget derived from CodeEditor with highlighting for code blocks.
This widget is used by the SourceView system to show the design's This widget is used by the codeview system to show the design's
source and header code. The secondary highlighting show the text source and header code. The secondary highlighting show the text
part that corresponds to the selected widget(s). part that corresponds to the selected widget(s).
*/ */

View File

@ -17,7 +17,7 @@
#include "Fd_Snap_Action.h" #include "Fd_Snap_Action.h"
#include "Fl_Group_Type.h" #include "Fl_Group_Type.h"
#include "alignment_panel.h" #include "settings_panel.h"
#include "shell_command.h" // get and set Fl_String preferences #include "shell_command.h" // get and set Fl_String preferences
#include "file.h" #include "file.h"

View File

@ -1279,7 +1279,7 @@ void Fl_Data_Type::write_code1(Fd_Code_Writer& f) {
int nData = -1; int nData = -1;
int uncompressedDataSize = 0; int uncompressedDataSize = 0;
// path should be set correctly already // path should be set correctly already
if (filename_ && !f.write_sourceview) { if (filename_ && !f.write_codeview) {
enter_project_dir(); enter_project_dir();
FILE *f = fl_fopen(filename_, "rb"); FILE *f = fl_fopen(filename_, "rb");
leave_project_dir(); leave_project_dir();
@ -1395,8 +1395,8 @@ void Fl_Data_Type::write_code1(Fd_Code_Writer& f) {
} }
} }
// if we are in interactive mode, we pop up a warning dialog // if we are in interactive mode, we pop up a warning dialog
// giving the error: (batch_mode && !write_sourceview) ??? // giving the error: (batch_mode && !write_codeview) ???
if (message && !f.write_sourceview) { if (message && !f.write_codeview) {
if (batch_mode) if (batch_mode)
fprintf(stderr, "FLUID ERROR: %s %s\n", message, fn); fprintf(stderr, "FLUID ERROR: %s %s\n", message, fn);
else else
@ -1535,20 +1535,24 @@ BREAK2:
*/ */
void Fl_DeclBlock_Type::write_code1(Fd_Code_Writer& f) { void Fl_DeclBlock_Type::write_code1(Fd_Code_Writer& f) {
const char* c = name(); const char* c = name();
if (c && *c) {
if (public_) if (public_)
f.write_h("%s\n", c); f.write_h("%s\n", c);
f.write_c("%s\n", c); f.write_c("%s\n", c);
} }
}
/** /**
Write the \b after code to the source file, and to the header file if declared public. Write the \b after code to the source file, and to the header file if declared public.
*/ */
void Fl_DeclBlock_Type::write_code2(Fd_Code_Writer& f) { void Fl_DeclBlock_Type::write_code2(Fd_Code_Writer& f) {
const char* c = after; const char* c = after;
if (c && *c) {
if (public_) if (public_)
f.write_h("%s\n", c); f.write_h("%s\n", c);
f.write_c("%s\n", c); f.write_c("%s\n", c);
} }
}
// ---- Fl_Comment_Type declaration // ---- Fl_Comment_Type declaration

View File

@ -696,8 +696,8 @@ void Fl_Type::move_before(Fl_Type* g) {
// write a widget and all its children: // write a widget and all its children:
void Fl_Type::write(Fd_Project_Writer &f) { void Fl_Type::write(Fd_Project_Writer &f) {
if (f.write_sourceview()) proj1_start = (int)ftell(f.file()) + 1; if (f.write_codeview()) proj1_start = (int)ftell(f.file()) + 1;
if (f.write_sourceview()) proj2_start = (int)ftell(f.file()) + 1; if (f.write_codeview()) proj2_start = (int)ftell(f.file()) + 1;
f.write_indent(level); f.write_indent(level);
f.write_word(type_name()); f.write_word(type_name());
@ -712,9 +712,9 @@ void Fl_Type::write(Fd_Project_Writer &f) {
write_properties(f); write_properties(f);
if (parent) parent->write_parent_properties(f, this, true); if (parent) parent->write_parent_properties(f, this, true);
f.write_close(level); f.write_close(level);
if (f.write_sourceview()) proj1_end = (int)ftell(f.file()); if (f.write_codeview()) proj1_end = (int)ftell(f.file());
if (!is_parent()) { if (!is_parent()) {
if (f.write_sourceview()) proj2_end = (int)ftell(f.file()); if (f.write_codeview()) proj2_end = (int)ftell(f.file());
return; return;
} }
// now do children: // now do children:
@ -722,9 +722,9 @@ void Fl_Type::write(Fd_Project_Writer &f) {
Fl_Type *child; Fl_Type *child;
for (child = next; child && child->level > level; child = child->next) for (child = next; child && child->level > level; child = child->next)
if (child->level == level+1) child->write(f); if (child->level == level+1) child->write(f);
if (f.write_sourceview()) proj2_start = (int)ftell(f.file()) + 1; if (f.write_codeview()) proj2_start = (int)ftell(f.file()) + 1;
f.write_close(level); f.write_close(level);
if (f.write_sourceview()) proj2_end = (int)ftell(f.file()); if (f.write_codeview()) proj2_end = (int)ftell(f.file());
} }
void Fl_Type::write_properties(Fd_Project_Writer &f) { void Fl_Type::write_properties(Fd_Project_Writer &f) {
@ -1092,7 +1092,7 @@ Fl_Type *Fl_Type::find_by_uid(unsigned short uid) {
return NULL; return NULL;
} }
/** Find a type node by using the sourceview text positions. /** Find a type node by using the codeview text positions.
\param[in] text_type 0=source file, 1=header, 2=.fl project file \param[in] text_type 0=source file, 1=header, 2=.fl project file
\param[in] crsr cursor position in text \param[in] crsr cursor position in text

View File

@ -146,7 +146,7 @@ public: // things that should not be public:
Fl_Type *factory; Fl_Type *factory;
const char *callback_name(Fd_Code_Writer& f); const char *callback_name(Fd_Code_Writer& f);
// text positions of this type in code, header, and project file (see SourceView) // text positions of this type in code, header, and project file (see codeview)
int code_static_start, code_static_end; int code_static_start, code_static_end;
int code1_start, code1_end; int code1_start, code1_end;
int code2_start, code2_end; int code2_start, code2_end;

View File

@ -24,7 +24,7 @@
#include "file.h" #include "file.h"
#include "code.h" #include "code.h"
#include "Fluid_Image.h" #include "Fluid_Image.h"
#include "alignment_panel.h" #include "settings_panel.h"
#include "widget_panel.h" #include "widget_panel.h"
#include "undo.h" #include "undo.h"
#include "mergeback.h" #include "mergeback.h"
@ -383,7 +383,7 @@ void name_public_cb(Fl_Choice* i, void* v) {
/* Treating UNDO for text widget. /* Treating UNDO for text widget.
Goal: we want to continuously update the UI while the user is typing text Goal: we want to continuously update the UI while the user is typing text
(changing the label, in this case). Source View does deferred updates, and (changing the label, in this case). Code View does deferred updates, and
the widget browser and widget panel update on every keystroke. At the same the widget browser and widget panel update on every keystroke. At the same
time, we want to limit undo actions to few and logical units. time, we want to limit undo actions to few and logical units.
@ -2727,7 +2727,7 @@ void Fl_Widget_Type::open() {
extern void redraw_overlays(); extern void redraw_overlays();
extern void check_redraw_corresponding_parent(Fl_Type*); extern void check_redraw_corresponding_parent(Fl_Type*);
extern void redraw_browser(); extern void redraw_browser();
extern void update_sourceview_position(); extern void update_codeview_position();
// Called when ui changes what objects are selected: // Called when ui changes what objects are selected:
// p is selected object, null for all deletions (we must throw away // p is selected object, null for all deletions (we must throw away
@ -2761,8 +2761,8 @@ void selection_changed(Fl_Type *p) {
redraw_overlays(); redraw_overlays();
// load the panel with the new settings: // load the panel with the new settings:
load_panel(); load_panel();
// update the source viewer to show the code for the selected object // update the code viewer to show the code for the selected object
update_sourceview_position(); update_codeview_position();
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////

View File

@ -127,5 +127,6 @@ public:
void redraw(); void redraw();
}; };
extern Fl_Window *the_panel;
#endif // _FLUID_FL_WIDGET_TYPE_H #endif // _FLUID_FL_WIDGET_TYPE_H

View File

@ -25,7 +25,7 @@
#include "fluid.h" #include "fluid.h"
#include "widget_browser.h" #include "widget_browser.h"
#include "undo.h" #include "undo.h"
#include "alignment_panel.h" #include "settings_panel.h"
#include "file.h" #include "file.h"
#include "code.h" #include "code.h"
#include "widget_panel.h" #include "widget_panel.h"

View File

@ -31,7 +31,8 @@ CPPFILES = \
Fluid_Image.cxx \ Fluid_Image.cxx \
about_panel.cxx \ about_panel.cxx \
align_widget.cxx \ align_widget.cxx \
alignment_panel.cxx \ settings_panel.cxx \
autodoc.cxx \
code.cxx \ code.cxx \
custom_widgets.cxx \ custom_widgets.cxx \
factory.cxx \ factory.cxx \
@ -42,7 +43,7 @@ CPPFILES = \
mergeback.cxx \ mergeback.cxx \
pixmaps.cxx \ pixmaps.cxx \
shell_command.cxx \ shell_command.cxx \
sourceview_panel.cxx \ codeview_panel.cxx \
template_panel.cxx \ template_panel.cxx \
undo.cxx \ undo.cxx \
widget_browser.cxx \ widget_browser.cxx \
@ -141,9 +142,9 @@ uninstall-osx:
rebuild: fluid$(EXEEXT) rebuild: fluid$(EXEEXT)
echo 'Rebuilding fluid (.fl) and .cxx/.h files from .fl files ...' echo 'Rebuilding fluid (.fl) and .cxx/.h files from .fl files ...'
./fluid$(EXEEXT) -u -c about_panel.fl ./fluid$(EXEEXT) -u -c about_panel.fl
./fluid$(EXEEXT) -u -c alignment_panel.fl ./fluid$(EXEEXT) -u -c settings_panel.fl
./fluid$(EXEEXT) -u -c function_panel.fl ./fluid$(EXEEXT) -u -c function_panel.fl
./fluid$(EXEEXT) -u -c print_panel.fl ./fluid$(EXEEXT) -u -c print_panel.fl
./fluid$(EXEEXT) -u -c sourceview_panel.fl ./fluid$(EXEEXT) -u -c codeview_panel.fl
./fluid$(EXEEXT) -u -c template_panel.fl ./fluid$(EXEEXT) -u -c template_panel.fl
./fluid$(EXEEXT) -u -c widget_panel.fl ./fluid$(EXEEXT) -u -c widget_panel.fl

602
fluid/autodoc.cxx Normal file
View File

@ -0,0 +1,602 @@
//
// Self-generate snapshots of user interface for FLUID documentation.
//
// Copyright 2024 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
//
#ifndef NDEBUG
#include "autodoc.h"
#include "fluid.h"
#include "factory.h"
#include "widget_browser.h"
#include "widget_panel.h"
#include "Fl_Widget_Type.h"
#include "Fl_Window_Type.h"
#include "function_panel.h"
#include "settings_panel.h"
#include "codeview_panel.h"
#include <FL/Enumerations.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Image_Surface.H>
#include <FL/Fl_PNG_Image.H>
#include <FL/Fl_Menu_Bar.H>
extern Fl_Double_Window *settings_window;
/** \file autodoc.cxx
\todo Implement a function to snapshot a window including decoration
- see: void Fl_Widget_Surface::draw_decorated_window(Fl_Window *win, int win_offset_x, int win_offset_y)
- see: void Fl_Widget_Surface::origin(int x, int y)
- see: void Fl_Widget_Surface::draw(Fl_Widget* widget, int delta_x, int delta_y)
- see: void Fl_Widget_Surface::print_window_part(Fl_Window *win, int x, int y, int w, int h, int delta_x, int delta_y)
\todo Implement a version that snaps multiple windows in a desktop style situation.
\todo a version that takes snapshots of a range of menu items
\todo implement FL_SNAP_TO_GROUP, possibly with a number on how many groups up in the hierarchy
*/
/** \addtogroup fl_drawings
@{
*/
const int FL_SNAP_TO_WINDOW = 0x7f000000;
static Fl_Box snap_clear_(0, 0, 0, 0);
Fl_Widget *FL_SNAP_AREA_CLEAR = &snap_clear_;
static inline int fl_min(int a, int b) { return a < b ? a : b; }
static inline uchar fl_min(uchar a, uchar b) { return a < b ? a : b; }
static inline int fl_max(int a, int b) { return a > b ? a : b; }
/**
Create a rect by providing a margin around a zero size rectangle.
\param[in] dx, dy positive integers, move margin up and left
\param[in] dr, db move margin to the right and down
*/
Fl_Margin::Fl_Margin(int dx, int dy, int dr, int db)
: Fl_Rect(-dx, -dy, dx+dr, dy+db)
{
}
/**
Convert an RGB image into an RGBA image.
\param[inout] image pointer to an RGB image, deletes the RGB image, returns the RGBA image
\return 0 if the image is now in RGBA format, or -1 if it can't be converted
*/
static int convert_RGB_to_RGBA(Fl_RGB_Image *&img) {
if (img->d() == 4)
return 0;
if (img->d() != 3)
return -1;
// Copy pixel data from RGB to RGBA raw data
int img_w = img->w();
int img_h = img->h();
uchar *data = new uchar[img_w * img_h * 4], *dst = data;
int ld = img->ld(); if (ld == 0) ld = img_w * 3;
int i, j;
for (i=0; i<img_h; i++) {
const uchar *src = (const uchar*)img->data()[0] + i * ld;
for (j=0; j<img_w; j++) {
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
*dst++ = 255;
}
}
// Delete the old image
delete img;
// Create the new image
img = new Fl_RGB_Image(data, img_w, img_h, 4);
return 0;
}
/**
Blend the left side lines of the alpha channel of an RBGA image to full transparency.
\param[in] img must be an RGBA image
\param[in] dx number of lines to blend
*/
void blend_alpha_left(const Fl_RGB_Image *img, int dx) {
if (img->d() != 4)
return;
if (dx > img->w())
return;
if (dx > 0) {
int max_x = dx, max_y = img->h();
int ld = img->ld(); if (ld == 0) ld = img->w() * img->d();
float a = 255/max_x;
for (int i = 0; i < max_x; i++) {
uchar *rgba = (uchar*)img->data()[0] + i * img->d();
uchar alpha = static_cast<uchar>(i * a);
for (int j = 0; j < max_y; j++) {
rgba[3] = fl_min(alpha, rgba[3]);
rgba += ld;
}
}
}
}
/**
Blend the top lines of the alpha channel of an RBGA image to full transparency.
\param[in] img must be an RGBA image
\param[in] dy number of lines to blend
*/
void blend_alpha_top(const Fl_RGB_Image *img, int dy) {
if (img->d() != 4)
return;
if (dy > img->h())
return;
if (dy > 0) {
int max_x = img->w(), max_y = dy;
int ld = img->ld(); if (ld == 0) ld = img->w() * img->d();
float a = 255/max_y;
for (int i = 0; i < max_y; i++) {
uchar *rgba = (uchar*)img->data()[0] + i * ld;
uchar alpha = static_cast<uchar>(i * a);
for (int j = 0; j < max_x; j++) {
rgba[3] = fl_min(alpha, rgba[3]);
rgba += 4;
}
}
}
}
/**
Blend the right side lines of the alpha channel of an RBGA image to full transparency.
\param[in] img must be an RGBA image
\param[in] dx number of lines to blend
*/
void blend_alpha_right(const Fl_RGB_Image *img, int dx) {
if (img->d() != 4)
return;
if (dx > img->w())
return;
if (dx > 0) {
int max_x = dx, max_y = img->h();
int ld = img->ld(); if (ld == 0) ld = img->w() * img->d();
float a = 255/max_x;
for (int i = 0; i < max_x; i++) {
uchar *rgba = (uchar*)img->data()[0] + (img->w()-i-1) * img->d();
uchar alpha = static_cast<uchar>(i * a);
for (int j = 0; j < max_y; j++) {
rgba[3] = fl_min(alpha, rgba[3]);
rgba += ld;
}
}
}
}
/**
Blend the bottom lines of the alpha channel of an RBGA image to full transparency.
\param[in] img must be an RGBA image
\param[in] dy number of lines to blend
*/
void blend_alpha_bottom(const Fl_RGB_Image *img, int dy) {
if (img->d() != 4)
return;
if (dy > img->h())
return;
if (dy > 0) {
int max_x = img->w(), max_y = dy;
int ld = img->ld(); if (ld == 0) ld = img->w() * img->d();
float a = 255/max_y;
for (int i = 0; i < max_y; i++) {
uchar *rgba = (uchar*)img->data()[0] + (img->h()-i-1) * ld;
uchar alpha = static_cast<uchar>(i * a);
for (int j = 0; j < max_x; j++) {
rgba[3] = fl_min(alpha, rgba[3]);
rgba += 4;
}
}
}
}
/**
Take a snapshot of a number of widgets and save it as a png image.
Draw a rectangular snapshot that fits around all widgets inside a window.
All widgets must be inside the same window. It's up to the caller to ensure
that widgets are visible. This includes children of `Fl_Tabs`.
Outside labels of widgets are not taken into account, but a `frame` can be
provided to grow the snapshot rectangle. Setting individual parameters of the
frame to `FL_SNAP_TO_WINDOW` will extend the snapshot to the borders of the
top level window.
Another `blend` frame can be added around the image that fades to full
transparency on selected sides.
Use `Fl_Margin` to create `frame` and `blend` using positive integers to grow
the rectangle to the left, top, right, and bottom.
The image can be scaled after all processing. Note that snapshot is always
created in FLTK resolution, even if the screen uses a higher resolution.
\param[in] filename the snapshot will be written to this file in png format
\param[in] w draw a bounding box around all widgets in the NULL terminated list
\param[in] frame add a margin around the bounding box
\param[in] blend add another margin around the bounding box that fades to full transparency
\param[in] scale scale everything by this factor before saving it
\return the result of fl_write_png or -3 if another error occurred
*/
int fl_snapshot(const char *filename, Fl_Widget **w,
const Fl_Rect &frame,
const Fl_Rect &blend,
double scale)
{
int i, min_x = 0, min_y = 0, max_x = 0, max_y = 0, bb_w, bb_h, img_w, img_h;
// Get the bounding box for all widgets and make sure that all widgets are shown
for (i=0; w[i]; i++) {
int x, y;
Fl_Widget *ww = w[i];
if (ww == FL_SNAP_AREA_CLEAR) {
min_x = max_x = 0;
min_y = max_y = 0;
} else {
ww->top_window_offset(x, y);
if (i==0) {
min_x = x; max_x = x + ww->w();
min_y = y; max_y = y + ww->h();
} else {
min_x = fl_min(min_x, x); max_x = fl_max(max_x, x + ww->w());
min_y = fl_min(min_y, y); max_y = fl_max(max_y, y + ww->h());
}
}
// this does not help us with Fl_Tab groups
while (ww) { ww->show(); ww = ww->parent(); }
}
// Check for special values in frame and adjust bounding box
Fl_Rect c_frame = frame;
if (frame.x() == -FL_SNAP_TO_WINDOW) c_frame.x(-min_x);
if (frame.y() == -FL_SNAP_TO_WINDOW) c_frame.y(-min_y);
if (frame.r() == FL_SNAP_TO_WINDOW) c_frame.r(w[0]->top_window()->w()-max_x);
if (frame.b() == FL_SNAP_TO_WINDOW) c_frame.b(w[0]->top_window()->h()-max_y);
min_x += c_frame.x(); max_x += c_frame.r();
min_y += c_frame.y(); max_y += c_frame.b();
bb_w = max_x - min_x; bb_h = max_y - min_y;
img_w = bb_w + blend.w();
img_h = bb_h + blend.h();
// Generate the Image Surface
Fl_Image_Surface *srfc = new Fl_Image_Surface(img_w, img_h);
Fl_Image_Surface::push_current(srfc);
// Draw the background
fl_rectf(0, 0, img_w, img_h, 0x1395bf00);
// Draw the top level window
srfc->draw(w[0]->top_window(), -blend.x()-min_x, -blend.y()-min_y);
Fl_Image_Surface::pop_current();
Fl_RGB_Image *img = srfc->image();
// Do we want an alpha blended extension of the frame?
if ((blend.x()<0 || blend.y()<0 || blend.r()>0 || blend.b()>0)) {
if (convert_RGB_to_RGBA(img) == -1) {
delete img;
delete srfc;
return -3;
}
if (blend.x() < 0) blend_alpha_left(img, -blend.x());
if (blend.y() < 0) blend_alpha_top(img, -blend.y());
if (blend.r() > 0) blend_alpha_right(img, blend.r());
if (blend.b() > 0) blend_alpha_bottom(img, blend.b());
}
// If scale is set, scale the image
if (scale != 1.0) {
Fl_Image::scaling_algorithm(FL_RGB_SCALING_BILINEAR);
Fl_RGB_Image *scaled_img = (Fl_RGB_Image*)img->copy(img->w()*scale, img->h()*scale);
delete img;
img = scaled_img;
}
// Write the image to disk
int ret = fl_write_png(filename, img);
// Clean up
delete img;
delete srfc;
return ret;
}
/**
Take a snapshot of the size of the bounding box around two widgets and save it as a png image.
\param[in] filename the snapshot will be written to this file in png format
\param[in] w1, w2 top left and bottom right widget
\param[in] frame add a margin around the bounding box
\param[in] blend add another margin around the bounding box that fades to full transparency
\param[in] scale scale everything by this factor before saving it
\return the result of fl_write_png or -3 if another error occurred
\see fl_snapshot(const char*, Fl_Widget**, const Fl_Rect&, const Fl_Rect&, double)
*/
int fl_snapshot(const char *filename, Fl_Widget *w1, Fl_Widget *w2,
const Fl_Rect &frame,
const Fl_Rect &blend,
double scale)
{
Fl_Widget *ww[3] = { w1, w2, NULL };
return fl_snapshot(filename, ww, frame, blend, scale);
}
/**
Take a snapshot of a widget inside its window and save it as a png image.
\param[in] filename the snapshot will be written to this file in png format
\param[in] w snap this window, can also be a groups
\param[in] frame add a margin around the bounding box
\param[in] blend add another margin around the bounding box that fades to full transparency
\param[in] scale scale everything by this factor before saving it
\return the result of fl_write_png or -3 if another error occurred
\see fl_snapshot(const char*, Fl_Widget**, const Fl_Rect&, const Fl_Rect&, double)
*/
int fl_snapshot(const char *filename, Fl_Widget *w,
const Fl_Rect &frame,
const Fl_Rect &blend,
double scale)
{
Fl_Widget *ww[2] = { w, NULL };
return fl_snapshot(filename, ww, frame, blend, scale);
}
/** @} */
void run_autodoc(const Fl_String &target_dir) {
// A list of all the margins we will use later
Fl_Margin win_margin(0, 0, 0, 0);
Fl_Margin win_blend(10, 10, 10, 10);
Fl_Margin tab_margin(FL_SNAP_TO_WINDOW, 32, FL_SNAP_TO_WINDOW, 4);
Fl_Margin xtab_margin(FL_SNAP_TO_WINDOW, 50, FL_SNAP_TO_WINDOW, 4);
Fl_Margin row_margin(FL_SNAP_TO_WINDOW, 4, FL_SNAP_TO_WINDOW, 4);
Fl_Margin xrow_margin(FL_SNAP_TO_WINDOW, 14, FL_SNAP_TO_WINDOW, 4);
Fl_Margin row_blend(0, 10, 0, 10);
// Fl::scheme("gtk+");
// Create a silly project that contains all widgets that we want to document
new_project(false);
/*Fl_Type *t_func = */ add_new_widget_from_user("Function", kAddAsLastChild, false);
Fl_Window_Type *t_win = (Fl_Window_Type*)add_new_widget_from_user("Fl_Window", kAddAsLastChild, false);
t_win->label("My Main Window");
Fl_Widget_Type *t_grp = (Fl_Widget_Type*)add_new_widget_from_user("Fl_Group", kAddAsLastChild, false);
t_grp->public_ = 0;
Fl_Widget_Type *t_btn = (Fl_Widget_Type*)add_new_widget_from_user("Fl_Button", kAddAsLastChild, false);
t_btn->comment("Don't press this button!");
t_btn->name("emergency_btn");
((Fl_Button*)t_btn->o)->shortcut(FL_COMMAND|'g');
Fl_Type *t_sldr = add_new_widget_from_user("Fl_Slider", kAddAsLastChild, false);
Fl_Type *t_inp = add_new_widget_from_user("Fl_Input", kAddAsLastChild, false);
Fl_Type *t_flx = add_new_widget_from_user("Fl_Flex", kAddAsLastChild, false);
Fl_Type *t_flxc = add_new_widget_from_user("Fl_Button", kAddAsLastChild, false);
select_only(t_grp);
Fl_Type *t_grd = add_new_widget_from_user("Fl_Grid", kAddAsLastChild, false);
Fl_Type *t_grdc = add_new_widget_from_user("Fl_Button", kAddAsLastChild, false);
widget_browser->rebuild();
g_project.update_settings_dialog();
// TODO: FLUID overview
// TODO: explain FLUID command line usage
// TODO: take a snapshot of FLUID in a desktop situation
// (main, toolbar, document, widget editor, code view)
// ---- main window
// explain titlebar
// explain menubar?
// explain widget browser
// explain widget browser entry
main_window->size(350, 320);
fl_snapshot((target_dir + "main_window.png").c_str(), main_window, win_margin, win_blend);
fl_snapshot((target_dir + "main_menubar.png").c_str(), main_menubar, row_margin, row_blend);
fl_snapshot((target_dir + "main_browser.png").c_str(), widget_browser, FL_SNAP_AREA_CLEAR,
Fl_Rect(0, 30, FL_SNAP_TO_WINDOW, 100), row_blend, 2.0);
// TODO: document view
// explain dnd
// explain selection, multiple selection, keyboard shortcuts
// explain mouse functionality and alignment
// explain live resize
// arrow: move by 1
// shift: resize by one
// Meta: move by Widget Gap
// Shift Meta: resize by Widget Increment
// ---- widget bin
// show grouping
// explain non-widget types and where they will be located
// explain widgets types an their dnd option
// explain menu arrays
// list exceptions (subwindow, scroll)
if (!widgetbin_panel) make_widgetbin();
fl_snapshot((target_dir + "widgetbin_panel.png").c_str(), widgetbin_panel, win_margin, win_blend);
// ---- code view
// explain functionality
// explain live update and choices
// show various tabs
// explain find and locate
if (!codeview_panel) make_codeview();
update_codeview_cb(NULL, NULL);
cv_tab->value(cv_source_tab);
fl_snapshot((target_dir + "codeview_panel.png").c_str(), codeview_panel, win_margin, win_blend);
fl_snapshot((target_dir + "cv_find_row.png").c_str(), cv_find_row, row_margin, row_blend);
fl_snapshot((target_dir + "cv_settings_row.png").c_str(), cv_settings_row, row_margin, row_blend);
// ---- settings dialog
// show and explain all tabs
fl_snapshot((target_dir + "w_settings.png").c_str(), settings_window, win_margin, win_blend);
fl_snapshot((target_dir + "w_settings_general_tab.png").c_str(), w_settings_general_tab, xtab_margin, row_blend);
w_settings_tabs->value(w_settings_project_tab);
fl_snapshot((target_dir + "w_settings_project_tab.png").c_str(), w_settings_project_tab, xtab_margin, row_blend);
w_settings_tabs->value(w_settings_layout_tab);
fl_snapshot((target_dir + "w_settings_layout_tab.png").c_str(), w_settings_layout_tab, xtab_margin, row_blend);
w_settings_tabs->value(w_settings_shell_tab);
w_settings_shell_list->value(1);
w_settings_shell_list->do_callback();
fl_snapshot((target_dir + "w_settings_shell_tab.png").c_str(), w_settings_shell_tab, xtab_margin, row_blend);
w_settings_tabs->value(w_settings_i18n_tab);
i18n_type_chooser->value(1);
i18n_type_chooser->do_callback();
fl_snapshot((target_dir + "w_settings_i18n_gnu.png").c_str(), i18n_type_chooser, i18n_gnu_static_function_input, row_margin, row_blend);
i18n_type_chooser->value(2);
i18n_type_chooser->do_callback();
fl_snapshot((target_dir + "w_settings_i18n_psx.png").c_str(), i18n_type_chooser, i18n_pos_set_input, row_margin, row_blend);
w_settings_tabs->value(w_settings_user_tab);
fl_snapshot((target_dir + "w_settings_user_tab.png").c_str(), w_settings_user_tab, xtab_margin, row_blend);
// ---- dialog types
// list and show all non-widget types and their respective dialog boxes
// -- ID_Function
Fl_Window *adoc_function_panel = make_function_panel();
f_name_input->value("count_trees(const char *forest_name)");
f_return_type_input->value("unsigned int");
fl_snapshot((target_dir + "function_panel.png").c_str(), adoc_function_panel, win_margin, win_blend);
adoc_function_panel->hide();
// -- ID_Code
Fl_Window *adoc_code_panel = make_code_panel();
code_input->buffer()->text("// increment user count\nif (new_user) {\n user_count++;\n}\n");
fl_snapshot((target_dir + "code_panel.png").c_str(), adoc_code_panel, win_margin, win_blend);
adoc_code_panel->hide();
// -- ID_CodeBlock
Fl_Window *adoc_codeblock_panel = make_codeblock_panel();
code_before_input->value("if (test())");
code_after_input->value("// test widgets added...");
fl_snapshot((target_dir + "codeblock_panel.png").c_str(), adoc_codeblock_panel, win_margin, win_blend);
adoc_codeblock_panel->hide();
// -- ID_Decl
Fl_Window *adoc_decl_panel = make_decl_panel();
decl_class_choice->hide();
decl_input->buffer()->text("const char *damage = \"'tis but a scratch\";");
fl_snapshot((target_dir + "decl_panel.png").c_str(), adoc_decl_panel, win_margin, win_blend);
adoc_decl_panel->hide();
// -- ID_DeclBlock
Fl_Window *adoc_declblock_panel = make_declblock_panel();
decl_before_input->value("#ifdef NDEBUG");
decl_after_input->value("#endif // NDEBUG");
fl_snapshot((target_dir + "declblock_panel.png").c_str(), adoc_declblock_panel, win_margin, win_blend);
adoc_declblock_panel->hide();
// -- ID_Class
Fl_Window *adoc_class_panel = make_class_panel();
decl_class_choice->hide();
c_name_input->value("Zoo_Giraffe");
c_subclass_input->value("Zoo_Animal");
fl_snapshot((target_dir + "class_panel.png").c_str(), adoc_class_panel, win_margin, win_blend);
adoc_class_panel->hide();
// -- ID_Widget_Class is handled like Fl_Window_Type
// -- ID_Comment
Fl_Window *adoc_comment_panel = make_comment_panel();
comment_input->buffer()->text("Make sure that the giraffe gets enough hay,\nbut the monkey can't reach it.");
fl_snapshot((target_dir + "comment_panel.png").c_str(), adoc_comment_panel, win_margin, win_blend);
adoc_comment_panel->hide();
// -- ID_Data
Fl_Window *adoc_data_panel = make_data_panel();
data_class_choice->hide();
data_input->value("emulated_ROM");
data_filename->value("./ROM.bin");
fl_snapshot((target_dir + "data_panel.png").c_str(), adoc_data_panel, win_margin, win_blend);
adoc_data_panel->hide();
// ---- widget dialog
t_win->open(); // open the window
t_win->open(); // open the panel
select_only(t_win);
// -- snapshot of the widget properties panel
fl_snapshot((target_dir + "widget_panel.png").c_str(), the_panel, win_margin, win_blend);
fl_snapshot((target_dir + "wLiveMode.png").c_str(), wLiveMode, row_margin, row_blend);
// -- snapshot of the GUI tab
widget_tabs->value(wp_gui_tab);
fl_snapshot((target_dir + "wp_gui_tab.png").c_str(), wp_gui_tab, tab_margin, row_blend);
fl_snapshot((target_dir + "wp_gui_label.png").c_str(), wp_gui_label, row_margin, row_blend);
select_only(t_btn);
fl_snapshot((target_dir + "wp_gui_image.png").c_str(), widget_image_input, widget_deimage_input, row_margin, row_blend);
fl_snapshot((target_dir + "wp_gui_alignment.png").c_str(), wp_gui_alignment, row_margin, row_blend);
fl_snapshot((target_dir + "wp_gui_size.png").c_str(), widget_x_input, xrow_margin, row_blend);
select_only(t_sldr);
fl_snapshot((target_dir + "wp_gui_values.png").c_str(), wp_gui_values, xrow_margin, row_blend);
select_only(t_flxc);
fl_snapshot((target_dir + "wp_gui_flexp.png").c_str(), wp_gui_flexp, xrow_margin, row_blend);
select_only(t_flx);
fl_snapshot((target_dir + "wp_gui_margins.png").c_str(), wp_gui_margins, xrow_margin, row_blend);
select_only(t_win);
fl_snapshot((target_dir + "wp_gui_sizerange.png").c_str(), wp_gui_sizerange, xrow_margin, row_blend);
select_only(t_btn);
fl_snapshot((target_dir + "wp_gui_shortcut.png").c_str(), wp_gui_shortcut, row_margin, row_blend);
select_only(t_win);
fl_snapshot((target_dir + "wp_gui_xclass.png").c_str(), wp_gui_xclass, row_margin, row_blend);
select_only(t_btn);
fl_snapshot((target_dir + "wp_gui_attributes.png").c_str(), wp_gui_attributes, row_margin, row_blend);
fl_snapshot((target_dir + "wp_gui_tooltip.png").c_str(), wp_gui_tooltip, row_margin, row_blend);
// -- snapshot of the style tab
widget_tabs->value(wp_style_tab);
select_only(t_inp);
fl_snapshot((target_dir + "wp_style_tab.png").c_str(), wp_style_tab, tab_margin, row_blend);
fl_snapshot((target_dir + "wp_style_label.png").c_str(), wp_style_label, row_margin, row_blend);
select_only(t_btn);
fl_snapshot((target_dir + "wp_style_box.png").c_str(), wp_style_box, wp_style_downbox, row_margin, row_blend);
select_only(t_inp);
fl_snapshot((target_dir + "wp_style_text.png").c_str(), wp_style_text, row_margin, row_blend);
// -- snapshot of the C++ tab
widget_tabs->value(wp_cpp_tab);
select_only(t_btn);
fl_snapshot((target_dir + "wp_cpp_tab.png").c_str(), wp_cpp_tab, tab_margin, row_blend);
fl_snapshot((target_dir + "wp_cpp_class.png").c_str(), wp_cpp_class, row_margin, row_blend);
fl_snapshot((target_dir + "wp_cpp_name.png").c_str(), wp_cpp_name, row_margin, row_blend);
fl_snapshot((target_dir + "v_input.png").c_str(), v_input[0], v_input[3], row_margin, row_blend);
fl_snapshot((target_dir + "wComment.png").c_str(), wComment, row_margin, row_blend);
fl_snapshot((target_dir + "wp_cpp_callback.png").c_str(), wCallback, w_when_box, row_margin, row_blend);
// -- snapshot of the Grid tab
select_only(t_grd);
widget_tabs->value(widget_tab_grid);
fl_snapshot((target_dir + "wp_grid_tab.png").c_str(), widget_tab_grid, tab_margin, row_blend);
// -- snapshot of the Grid Child tab
select_only(t_grdc);
widget_tabs->value(widget_tab_grid_child);
fl_snapshot((target_dir + "wp_gridc_tab.png").c_str(), widget_tab_grid_child, tab_margin, row_blend);
}
#endif // NDEBUG

59
fluid/autodoc.h Normal file
View File

@ -0,0 +1,59 @@
//
// Widget snapshot header-only file for the Fast Light Tool Kit (FLTK).
//
// Copyright 2023-2024 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
//
/**
\file autodoc.h
\brief tools to take snapshots of UI elements for documentation purposes
*/
#ifndef fl_screenshot_H
#define fl_screenshot_H
#include "../src/Fl_String.H"
#include <FL/Fl_Export.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Rect.H>
/** Class to initialize a Rect by providing the margin around a rect. */
class Fl_Margin : public Fl_Rect {
public:
Fl_Margin(int dx, int dy, int dr, int db);
};
int fl_snapshot(const char *filename, Fl_Widget **w,
const Fl_Rect &frame = Fl_Margin(4, 4, 4, 4),
const Fl_Rect &blend = Fl_Margin(4, 4, 4, 4),
double scale=1.0);
int fl_snapshot(const char *filename, Fl_Widget *w1, Fl_Widget *w2,
const Fl_Rect &frame = Fl_Margin(4, 4, 4, 4),
const Fl_Rect &blend = Fl_Margin(4, 4, 4, 4),
double scale=1.0);
int fl_snapshot(const char *filename, Fl_Widget *w,
const Fl_Rect &frame = Fl_Margin(4, 4, 4, 4),
const Fl_Rect &blend = Fl_Margin(4, 4, 4, 4),
double scale=1.0);
extern const int FL_SNAP_TO_WINDOW;
extern Fl_Widget *FL_SNAP_AREA_CLEAR;
extern void run_autodoc(const Fl_String &target_dir);
#endif

View File

@ -414,7 +414,7 @@ void Fd_Code_Writer::write_cstring(const char *s, int length) {
} }
// if we are rendering to the source code preview window, and the text is // if we are rendering to the source code preview window, and the text is
// longer than four lines, we only render a placeholder. // longer than four lines, we only render a placeholder.
if (write_sourceview && ((s==NULL) || (length>300))) { if (write_codeview && ((s==NULL) || (length>300))) {
if (length>=0) if (length>=0)
crc_printf("\" ... %d bytes of text... \"", length); crc_printf("\" ... %d bytes of text... \"", length);
else else
@ -523,7 +523,7 @@ void Fd_Code_Writer::write_cdata(const char *s, int length) {
varused = 1; varused = 1;
return; return;
} }
if (write_sourceview) { if (write_codeview) {
if (length>=0) if (length>=0)
crc_printf("{ /* ... %d bytes of binary data... */ }", length); crc_printf("{ /* ... %d bytes of binary data... */ }", length);
else else
@ -707,11 +707,11 @@ Fl_Type* Fd_Code_Writer::write_code(Fl_Type* p) {
// write all code that comes before the children code // write all code that comes before the children code
// (but don't write the last comment until the very end) // (but don't write the last comment until the very end)
if (!(p==Fl_Type::last && p->is_a(ID_Comment))) { if (!(p==Fl_Type::last && p->is_a(ID_Comment))) {
if (write_sourceview) p->code1_start = (int)ftell(code_file); if (write_codeview) p->code1_start = (int)ftell(code_file);
if (write_sourceview) p->header1_start = (int)ftell(header_file); if (write_codeview) p->header1_start = (int)ftell(header_file);
p->write_code1(*this); p->write_code1(*this);
if (write_sourceview) p->code1_end = (int)ftell(code_file); if (write_codeview) p->code1_end = (int)ftell(code_file);
if (write_sourceview) p->header1_end = (int)ftell(header_file); if (write_codeview) p->header1_end = (int)ftell(header_file);
} }
// recursively write the code of all children // recursively write the code of all children
Fl_Type* q; Fl_Type* q;
@ -730,11 +730,11 @@ Fl_Type* Fd_Code_Writer::write_code(Fl_Type* p) {
} }
// write all code that come after the children // write all code that come after the children
if (write_sourceview) p->code2_start = (int)ftell(code_file); if (write_codeview) p->code2_start = (int)ftell(code_file);
if (write_sourceview) p->header2_start = (int)ftell(header_file); if (write_codeview) p->header2_start = (int)ftell(header_file);
p->write_code2(*this); p->write_code2(*this);
if (write_sourceview) p->code2_end = (int)ftell(code_file); if (write_codeview) p->code2_end = (int)ftell(code_file);
if (write_sourceview) p->header2_end = (int)ftell(header_file); if (write_codeview) p->header2_end = (int)ftell(header_file);
for (q = p->next; q && q->level > p->level;) { for (q = p->next; q && q->level > p->level;) {
if (is_class_member(q) || is_comment_before_class_member(q)) { if (is_class_member(q) || is_comment_before_class_member(q)) {
@ -752,11 +752,11 @@ Fl_Type* Fd_Code_Writer::write_code(Fl_Type* p) {
} else { } else {
for (q = p->next; q && q->level > p->level;) q = write_code(q); for (q = p->next; q && q->level > p->level;) q = write_code(q);
// write all code that come after the children // write all code that come after the children
if (write_sourceview) p->code2_start = (int)ftell(code_file); if (write_codeview) p->code2_start = (int)ftell(code_file);
if (write_sourceview) p->header2_start = (int)ftell(header_file); if (write_codeview) p->header2_start = (int)ftell(header_file);
p->write_code2(*this); p->write_code2(*this);
if (write_sourceview) p->code2_end = (int)ftell(code_file); if (write_codeview) p->code2_end = (int)ftell(code_file);
if (write_sourceview) p->header2_end = (int)ftell(header_file); if (write_codeview) p->header2_end = (int)ftell(header_file);
} }
return q; return q;
} }
@ -772,8 +772,8 @@ Fl_Type* Fd_Code_Writer::write_code(Fl_Type* p) {
\param[in] t filename of the header file \param[in] t filename of the header file
\return 0 if the operation failed, 1 if it was successful \return 0 if the operation failed, 1 if it was successful
*/ */
int Fd_Code_Writer::write_code(const char *s, const char *t, bool to_sourceview) { int Fd_Code_Writer::write_code(const char *s, const char *t, bool to_codeview) {
write_sourceview = to_sourceview; write_codeview = to_codeview;
delete id_root; id_root = 0; delete id_root; id_root = 0;
indentation = 0; indentation = 0;
current_class = 0L; current_class = 0L;
@ -791,7 +791,7 @@ int Fd_Code_Writer::write_code(const char *s, const char *t, bool to_sourceview)
header_file = f; header_file = f;
} }
// Remember the last code file location for MergeBack // Remember the last code file location for MergeBack
if (s && g_project.write_mergeback_data && !to_sourceview) { if (s && g_project.write_mergeback_data && !to_codeview) {
Fl_String proj_filename = g_project.projectfile_path() + g_project.projectfile_name(); Fl_String proj_filename = g_project.projectfile_path() + g_project.projectfile_name();
int i, n = proj_filename.size(); int i, n = proj_filename.size();
for (i=0; i<n; i++) if (proj_filename[i]=='\\') proj_filename[i] = '/'; for (i=0; i<n; i++) if (proj_filename[i]=='\\') proj_filename[i] = '/';
@ -803,13 +803,13 @@ int Fd_Code_Writer::write_code(const char *s, const char *t, bool to_sourceview)
// a copyright notice. We print that before anything else in the file! // a copyright notice. We print that before anything else in the file!
Fl_Type* first_type = Fl_Type::first; Fl_Type* first_type = Fl_Type::first;
if (first_type && first_type->is_a(ID_Comment)) { if (first_type && first_type->is_a(ID_Comment)) {
if (write_sourceview) { if (write_codeview) {
first_type->code1_start = first_type->code2_start = (int)ftell(code_file); first_type->code1_start = first_type->code2_start = (int)ftell(code_file);
first_type->header1_start = first_type->header2_start = (int)ftell(header_file); first_type->header1_start = first_type->header2_start = (int)ftell(header_file);
} }
// it is ok to write non-recursive code here, because comments have no children or code2 blocks // it is ok to write non-recursive code here, because comments have no children or code2 blocks
first_type->write_code1(*this); first_type->write_code1(*this);
if (write_sourceview) { if (write_codeview) {
first_type->code1_end = first_type->code2_end = (int)ftell(code_file); first_type->code1_end = first_type->code2_end = (int)ftell(code_file);
first_type->header1_end = first_type->header2_end = (int)ftell(header_file); first_type->header1_end = first_type->header2_end = (int)ftell(header_file);
} }
@ -835,7 +835,7 @@ int Fd_Code_Writer::write_code(const char *s, const char *t, bool to_sourceview)
write_h_once("#include <FL/Fl.H>"); write_h_once("#include <FL/Fl.H>");
} }
if (t && g_project.include_H_from_C) { if (t && g_project.include_H_from_C) {
if (to_sourceview) { if (to_codeview) {
write_c("#include \"CodeView.h\"\n"); write_c("#include \"CodeView.h\"\n");
} else if (g_project.header_file_name[0] == '.' && strchr(g_project.header_file_name.c_str(), '/') == NULL) { } else if (g_project.header_file_name[0] == '.' && strchr(g_project.header_file_name.c_str(), '/') == NULL) {
write_c("#include \"%s\"\n", fl_filename_name(t)); write_c("#include \"%s\"\n", fl_filename_name(t));
@ -896,17 +896,17 @@ int Fd_Code_Writer::write_code(const char *s, const char *t, bool to_sourceview)
} }
for (Fl_Type* p = first_type; p;) { for (Fl_Type* p = first_type; p;) {
// write all static data for this & all children first // write all static data for this & all children first
if (write_sourceview) p->header_static_start = (int)ftell(header_file); if (write_codeview) p->header_static_start = (int)ftell(header_file);
if (write_sourceview) p->code_static_start = (int)ftell(code_file); if (write_codeview) p->code_static_start = (int)ftell(code_file);
p->write_static(*this); p->write_static(*this);
if (write_sourceview) p->code_static_end = (int)ftell(code_file); if (write_codeview) p->code_static_end = (int)ftell(code_file);
if (write_sourceview) p->header_static_end = (int)ftell(header_file); if (write_codeview) p->header_static_end = (int)ftell(header_file);
for (Fl_Type* q = p->next; q && q->level > p->level; q = q->next) { for (Fl_Type* q = p->next; q && q->level > p->level; q = q->next) {
if (write_sourceview) q->header_static_start = (int)ftell(header_file); if (write_codeview) q->header_static_start = (int)ftell(header_file);
if (write_sourceview) q->code_static_start = (int)ftell(code_file); if (write_codeview) q->code_static_start = (int)ftell(code_file);
q->write_static(*this); q->write_static(*this);
if (write_sourceview) q->code_static_end = (int)ftell(code_file); if (write_codeview) q->code_static_end = (int)ftell(code_file);
if (write_sourceview) q->header_static_end = (int)ftell(header_file); if (write_codeview) q->header_static_end = (int)ftell(header_file);
} }
// then write the nested code: // then write the nested code:
p = write_code(p); p = write_code(p);
@ -918,12 +918,12 @@ int Fd_Code_Writer::write_code(const char *s, const char *t, bool to_sourceview)
Fl_Type* last_type = Fl_Type::last; Fl_Type* last_type = Fl_Type::last;
if (last_type && (last_type != Fl_Type::first) && last_type->is_a(ID_Comment)) { if (last_type && (last_type != Fl_Type::first) && last_type->is_a(ID_Comment)) {
if (write_sourceview) { if (write_codeview) {
last_type->code1_start = last_type->code2_start = (int)ftell(code_file); last_type->code1_start = last_type->code2_start = (int)ftell(code_file);
last_type->header1_start = last_type->header2_start = (int)ftell(header_file); last_type->header1_start = last_type->header2_start = (int)ftell(header_file);
} }
last_type->write_code1(*this); last_type->write_code1(*this);
if (write_sourceview) { if (write_codeview) {
last_type->code1_end = last_type->code2_end = (int)ftell(code_file); last_type->code1_end = last_type->code2_end = (int)ftell(code_file);
last_type->header1_end = last_type->header2_end = (int)ftell(header_file); last_type->header1_end = last_type->header2_end = (int)ftell(header_file);
} }
@ -973,7 +973,7 @@ Fd_Code_Writer::Fd_Code_Writer()
block_buffer_(NULL), block_buffer_(NULL),
block_buffer_size_(0), block_buffer_size_(0),
indentation(0), indentation(0),
write_sourceview(false), write_codeview(false),
varused_test(0), varused_test(0),
varused(0) varused(0)
{ {

View File

@ -68,7 +68,7 @@ public:
int indentation; int indentation;
/// set if we write abbreviated file for the source code previewer /// set if we write abbreviated file for the source code previewer
/// (disables binary data blocks, for example) /// (disables binary data blocks, for example)
bool write_sourceview; bool write_codeview;
/// silly thing to prevent declaring unused variables: /// silly thing to prevent declaring unused variables:
/// When this symbol is on, all attempts to write code don't write /// When this symbol is on, all attempts to write code don't write
/// anything, but set a variable if it looks like the variable "o" is used: /// anything, but set a variable if it looks like the variable "o" is used:
@ -100,7 +100,7 @@ public:
void write_hc(const char *, int, const char*, const char*); void write_hc(const char *, int, const char*, const char*);
void write_c_indented(const char *textlines, int inIndent, char inTrailwWith); void write_c_indented(const char *textlines, int inIndent, char inTrailwWith);
Fl_Type* write_code(Fl_Type* p); Fl_Type* write_code(Fl_Type* p);
int write_code(const char *cfile, const char *hfile, bool to_sourceview=false); int write_code(const char *cfile, const char *hfile, bool to_codeview=false);
void write_public(int state); // writes pubic:/private: as needed void write_public(int state); // writes pubic:/private: as needed
void tag(int type, unsigned short uid); void tag(int type, unsigned short uid);

548
fluid/codeview_panel.cxx Normal file
View File

@ -0,0 +1,548 @@
//
// Code dialogs for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2023 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
//
// generated by Fast Light User Interface Designer (fluid) version 1.0400
#include "codeview_panel.h"
#include "fluid.h"
#include "file.h"
#include "../src/flstring.h"
#include <FL/Fl_Tabs.H>
#include <FL/Fl_Button.H>
static char *cv_source_filename = NULL;
static char *cv_header_filename = NULL;
static char *cv_design_filename = NULL;
int cv_code_choice;
extern void select_only(Fl_Type *o);
extern void reveal_in_browser(Fl_Type *t);
/**
Update the header and source code highlighting depending on the
currently selected object
The Code View system offers an immediate preview of the code
files that will be generated by FLUID. It also marks the code
generated for the last selected item in the header and the source
file.
*/
void update_codeview_position() {
if (!codeview_panel || !codeview_panel->visible())
return;
if (cv_autoposition->value()==0)
return;
if (codeview_panel && codeview_panel->visible() && Fl_Type::current) {
int pos0 = 0, pos1 = 0;
if (cv_source->visible_r()) {
switch (cv_code_choice) {
case 0: // prolog: not yet (include statements)
pos0 = Fl_Type::current->code1_start;
pos1 = Fl_Type::current->code2_end;
break;
case 1: // static: callbacks, menu declarations
pos0 = Fl_Type::current->code_static_start;
pos1 = Fl_Type::current->code_static_end;
break;
case 2: // code: entire implementation block including children
pos0 = Fl_Type::current->code1_start;
pos1 = Fl_Type::current->code2_end;
break;
case 3: // code1: all implementation code before the children
pos0 = Fl_Type::current->code1_start;
pos1 = Fl_Type::current->code1_end;
break;
case 4: // code1: all implementation code before the children
pos0 = Fl_Type::current->code2_start;
pos1 = Fl_Type::current->code2_end;
break;
}
if (pos0>=0) {
if (pos1<pos0)
pos1 = cv_source->buffer()->line_end(pos0);
cv_source->buffer()->highlight(pos0, pos1);
int line = cv_source->buffer()->count_lines(0, pos0);
cv_source->scroll(line, 0);
}
}
if (cv_header->visible_r()) {
switch (cv_code_choice) {
case 0: // prolog: not yet (include statements)
case 1: // static: callbacks, menu declarations
pos0 = Fl_Type::current->header_static_start;
pos1 = Fl_Type::current->header_static_end;
break;
case 2: // code: entire implementation block including children
pos0 = Fl_Type::current->header1_start;
pos1 = Fl_Type::current->header2_end;
break;
case 3: // code1: all implementation code before the children
pos0 = Fl_Type::current->header1_start;
pos1 = Fl_Type::current->header1_end;
break;
case 4: // code1: all implementation code before the children
pos0 = Fl_Type::current->header2_start;
pos1 = Fl_Type::current->header2_end;
break;
}
if (pos0>=0) {
if (pos1<pos0)
pos1 = cv_header->buffer()->line_end(pos0);
cv_header->buffer()->highlight(pos0, pos1);
int line = cv_header->buffer()->count_lines(0, pos0);
cv_header->scroll(line, 0);
}
}
if (cv_project->visible_r()) {
switch (cv_code_choice) {
case 0: // prolog: not yet (include statements)
case 1: // static: callbacks, menu declarations
case 2: // code: entire implementation block including children
pos0 = Fl_Type::current->proj1_start;
pos1 = Fl_Type::current->proj2_end;
break;
case 3: // code1: all implementation code before the children
pos0 = Fl_Type::current->proj1_start;
pos1 = Fl_Type::current->proj1_end;
break;
case 4: // code1: all implementation code before the children
pos0 = Fl_Type::current->proj2_start;
pos1 = Fl_Type::current->proj2_end;
break;
}
if (pos0>=0) {
if (pos1<pos0)
pos1 = cv_project->buffer()->line_end(pos0);
cv_project->buffer()->highlight(pos0, pos1);
int line = cv_project->buffer()->count_lines(0, pos0);
cv_project->scroll(line, 0);
}
}
}
}
/**
Callback to update the codeview position.
*/
void update_codeview_position_cb(class Fl_Tabs*, void*) {
// make sure that the selected tab shows the current view
update_codeview_cb(0,0);
// highlight the selected widget in the selected tab
update_codeview_position();
}
/**
Generate a header, source, strings, or design file in a temporary directory
and load those into the Code Viewer widgets.
*/
void update_codeview_cb(class Fl_Button*, void*) {
if (!codeview_panel || !codeview_panel->visible())
return;
if (!cv_source_filename) {
cv_source_filename = (char*)malloc(FL_PATH_MAX);
fl_strlcpy(cv_source_filename, get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(cv_source_filename, "codeview_tmp.cxx", FL_PATH_MAX);
}
if (!cv_header_filename) {
cv_header_filename = (char*)malloc(FL_PATH_MAX);
fl_strlcpy(cv_header_filename, get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(cv_header_filename, "codeview_tmp.h", FL_PATH_MAX);
}
if (!cv_design_filename) {
cv_design_filename = (char*)malloc(FL_PATH_MAX);
fl_strlcpy(cv_design_filename, get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(cv_design_filename, "codeview_tmp.fl", FL_PATH_MAX);
}
if (cv_project->visible_r()) {
write_file(cv_design_filename, false, true);
int top = cv_project->top_line();
cv_project->buffer()->loadfile(cv_design_filename);
cv_project->scroll(top, 0);
} else if (cv_strings->visible_r()) {
static const char *exts[] = { ".txt", ".po", ".msg" };
char fn[FL_PATH_MAX+1];
fl_strlcpy(fn, get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(fn, "strings", FL_PATH_MAX);
fl_filename_setext(fn, FL_PATH_MAX, exts[g_project.i18n_type]);
write_strings(fn);
int top = cv_strings->top_line();
cv_strings->buffer()->loadfile(fn);
cv_strings->scroll(top, 0);
} else if (cv_source->visible_r() || cv_header->visible_r()) {
Fl_String code_file_name_bak = g_project.code_file_name;
g_project.code_file_name = cv_source_filename;
Fl_String header_file_name_bak = g_project.header_file_name;
g_project.header_file_name = cv_header_filename;
// generate the code and load the files
Fd_Code_Writer f;
// generate files
if (f.write_code(cv_source_filename, cv_header_filename, true))
{
// load file into source editor
int pos = cv_source->top_line();
cv_source->buffer()->loadfile(cv_source_filename);
cv_source->scroll(pos, 0);
// load file into header editor
pos = cv_header->top_line();
cv_header->buffer()->loadfile(cv_header_filename);
cv_header->scroll(pos, 0);
// update the source code highlighting
update_codeview_position();
}
g_project.code_file_name = code_file_name_bak;
g_project.header_file_name = header_file_name_bak;
}
}
/**
This is called by the timer itself
*/
void update_codeview_timer(void*) {
update_codeview_cb(0,0);
}
void codeview_defer_update() {
// we will only update earliest 0.5 seconds after the last change, and only
// if no other change was made, so dragging a widget will not generate any
// CPU load
Fl::remove_timeout(update_codeview_timer, 0);
Fl::add_timeout(0.5, update_codeview_timer, 0);
}
/**
Show or hide the source code preview.
The state is stored in the app preferences.
*/
void codeview_toggle_visibility() {
if (!codeview_panel) {
make_codeview();
codeview_panel->callback((Fl_Callback*)toggle_codeview_cb);
Fl_Preferences svp(fluid_prefs, "codeview");
int autorefresh;
svp.get("autorefresh", autorefresh, 1);
cv_autorefresh->value(autorefresh);
int autoposition;
svp.get("autoposition", autoposition, 1);
cv_autoposition->value(autoposition);
int tab;
svp.get("tab", tab, 0);
if (tab>=0 && tab<cv_tab->children()) cv_tab->value(cv_tab->child(tab));
svp.get("code_choice", cv_code_choice, 2);
cv_code_choice_w->value(cv_code_choice_w->find_item_with_argument(cv_code_choice));
if (!position_window(codeview_panel,"codeview_pos", 0, 320, 120, 550, 500)) return;
}
if (codeview_panel->visible()) {
codeview_panel->hide();
codeview_item->label("Show Code View");
} else {
codeview_panel->show();
codeview_item->label("Hide Code View");
update_codeview_cb(0,0);
}
}
Fl_Double_Window *codeview_panel=(Fl_Double_Window *)0;
Fl_Tabs *cv_tab=(Fl_Tabs *)0;
Fl_Group *cv_source_tab=(Fl_Group *)0;
CodeViewer *cv_source=(CodeViewer *)0;
CodeViewer *cv_header=(CodeViewer *)0;
TextViewer *cv_strings=(TextViewer *)0;
TextViewer *cv_project=(TextViewer *)0;
Fl_Group *cv_find_row=(Fl_Group *)0;
Fl_Button *cv_find_text_case=(Fl_Button *)0;
Fl_Input *cv_find_text=(Fl_Input *)0;
static void cb_cv_find_text(Fl_Input* o, void*) {
Fl_Text_Display *e = NULL;
if (cv_source->visible_r()) {
e = cv_source;
} else if (cv_header->visible_r()) {
e = cv_header;
} else if (cv_project->visible_r()) {
e = cv_project;
}
if (e) {
Fl_Text_Buffer *b = e->buffer();
int pos = e->insert_position();
int found = b->search_forward(pos, o->value(), &pos, cv_find_text_case->value());
if (found) {
b->select(pos, pos + (int)strlen(o->value()));
e->insert_position(pos);
e->show_insert_position();
}
}
}
static void cb_(Fl_Button*, void*) {
Fl_Text_Display *e = NULL;
if (cv_source->visible_r()) {
e = cv_source;
} else if (cv_header->visible_r()) {
e = cv_header;
} else if (cv_project->visible_r()) {
e = cv_project;
}
if (e) {
const char *needle = cv_find_text->value();
Fl_Text_Buffer *b = e->buffer();
int pos = e->insert_position()-1;
if (pos < 0) pos = b->length()-1;
int found = b->search_backward(pos, needle, &pos, cv_find_text_case->value());
if (!found)
found = b->search_backward(b->length()-1, needle, &pos, cv_find_text_case->value());
if (found) {
b->select(pos, pos + (int)strlen(needle));
e->insert_position(pos);
e->show_insert_position();
}
}
}
static void cb_1(Fl_Button*, void*) {
Fl_Text_Display *e = NULL;
if (cv_source->visible_r()) {
e = cv_source;
} else if (cv_header->visible_r()) {
e = cv_header;
} else if (cv_project->visible_r()) {
e = cv_project;
}
if (e) {
const char *needle = cv_find_text->value();
Fl_Text_Buffer *b = e->buffer();
int pos = e->insert_position() + 1;
if (pos+1 >= b->length()) pos = 0;
int found = b->search_forward(pos, needle, &pos, cv_find_text_case->value());
if (!found && (pos > 0))
found = b->search_forward(0, needle, &pos, cv_find_text_case->value());
if (found) {
b->select(pos, pos + (int)strlen(needle));
e->insert_position(pos);
e->show_insert_position();
}
}
}
static void cb_Reveal(Fl_Button*, void*) {
if (codeview_panel && codeview_panel->visible()) {
Fl_Type *node = NULL;
if (cv_source->visible_r())
node = Fl_Type::find_in_text(0, cv_source->insert_position());
else if (cv_header->visible_r())
node = Fl_Type::find_in_text(1, cv_header->insert_position());
else if (cv_project->visible_r())
node = Fl_Type::find_in_text(2, cv_project->insert_position());
if (node) {
select_only(node);
reveal_in_browser(node);
if (Fl::event_clicks()==1) // double click
node->open();
}
}
}
Fl_Group *cv_settings_row=(Fl_Group *)0;
Fl_Light_Button *cv_autorefresh=(Fl_Light_Button *)0;
Fl_Light_Button *cv_autoposition=(Fl_Light_Button *)0;
Fl_Choice *cv_code_choice_w=(Fl_Choice *)0;
static void cb_cv_code_choice_w(Fl_Choice* o, void*) {
cv_code_choice = (int)o->mvalue()->argument();
update_codeview_position();
}
Fl_Menu_Item menu_cv_code_choice_w[] = {
{"prolog", 0, 0, (void*)(0), 16, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
{"static", 0, 0, (void*)(1), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
{"code", 0, 0, (void*)(2), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
{"code 1", 0, 0, (void*)(3), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
{"code 2", 0, 0, (void*)(4), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
{0,0,0,0,0,0,0,0,0}
};
Fl_Double_Window* make_codeview() {
{ codeview_panel = new Fl_Double_Window(520, 515, "Code View");
codeview_panel->callback((Fl_Callback*)toggle_codeview_cb);
codeview_panel->align(Fl_Align(FL_ALIGN_CLIP|FL_ALIGN_INSIDE));
{ cv_tab = new Fl_Tabs(10, 10, 500, 440);
cv_tab->selection_color((Fl_Color)4);
cv_tab->labelcolor(FL_BACKGROUND2_COLOR);
cv_tab->callback((Fl_Callback*)update_codeview_position_cb);
{ cv_source_tab = new Fl_Group(10, 35, 500, 415, "Source");
cv_source_tab->labelsize(13);
{ CodeViewer* o = cv_source = new CodeViewer(10, 40, 500, 410);
cv_source->box(FL_DOWN_FRAME);
cv_source->color(FL_BACKGROUND2_COLOR);
cv_source->selection_color(FL_SELECTION_COLOR);
cv_source->labeltype(FL_NORMAL_LABEL);
cv_source->labelfont(0);
cv_source->labelsize(14);
cv_source->labelcolor(FL_FOREGROUND_COLOR);
cv_source->textfont(4);
cv_source->textsize(11);
cv_source->align(Fl_Align(FL_ALIGN_TOP));
cv_source->when(FL_WHEN_RELEASE);
Fl_Group::current()->resizable(cv_source);
o->linenumber_width(60);
o->linenumber_size(o->Fl_Text_Display::textsize());
} // CodeViewer* cv_source
cv_source_tab->end();
Fl_Group::current()->resizable(cv_source_tab);
} // Fl_Group* cv_source_tab
{ Fl_Group* o = new Fl_Group(10, 35, 500, 415, "Header");
o->labelsize(13);
o->hide();
{ CodeViewer* o = cv_header = new CodeViewer(10, 40, 500, 410);
cv_header->box(FL_DOWN_FRAME);
cv_header->color(FL_BACKGROUND2_COLOR);
cv_header->selection_color(FL_SELECTION_COLOR);
cv_header->labeltype(FL_NORMAL_LABEL);
cv_header->labelfont(0);
cv_header->labelsize(14);
cv_header->labelcolor(FL_FOREGROUND_COLOR);
cv_header->textfont(4);
cv_header->textsize(11);
cv_header->align(Fl_Align(FL_ALIGN_TOP));
cv_header->when(FL_WHEN_RELEASE);
Fl_Group::current()->resizable(cv_header);
o->linenumber_width(60);
o->linenumber_size(o->Fl_Text_Display::textsize());
} // CodeViewer* cv_header
o->end();
} // Fl_Group* o
{ Fl_Group* o = new Fl_Group(10, 35, 500, 415, "Strings");
o->labelsize(13);
o->hide();
{ TextViewer* o = cv_strings = new TextViewer(10, 40, 500, 410);
cv_strings->box(FL_DOWN_FRAME);
cv_strings->color(FL_BACKGROUND2_COLOR);
cv_strings->selection_color(FL_SELECTION_COLOR);
cv_strings->labeltype(FL_NORMAL_LABEL);
cv_strings->labelfont(0);
cv_strings->labelsize(14);
cv_strings->labelcolor(FL_FOREGROUND_COLOR);
cv_strings->textfont(4);
cv_strings->textsize(11);
cv_strings->align(Fl_Align(FL_ALIGN_TOP));
cv_strings->when(FL_WHEN_RELEASE);
Fl_Group::current()->resizable(cv_strings);
o->linenumber_width(60);
o->linenumber_size(o->Fl_Text_Display::textsize());
} // TextViewer* cv_strings
o->end();
} // Fl_Group* o
{ Fl_Group* o = new Fl_Group(10, 35, 500, 415, "Project");
o->labelsize(13);
o->hide();
{ TextViewer* o = cv_project = new TextViewer(10, 40, 500, 410);
cv_project->box(FL_DOWN_FRAME);
cv_project->color(FL_BACKGROUND2_COLOR);
cv_project->selection_color(FL_SELECTION_COLOR);
cv_project->labeltype(FL_NORMAL_LABEL);
cv_project->labelfont(0);
cv_project->labelsize(14);
cv_project->labelcolor(FL_FOREGROUND_COLOR);
cv_project->textfont(4);
cv_project->textsize(11);
cv_project->align(Fl_Align(FL_ALIGN_TOP));
cv_project->when(FL_WHEN_RELEASE);
Fl_Group::current()->resizable(cv_project);
o->linenumber_width(60);
o->linenumber_size(o->Fl_Text_Display::textsize());
} // TextViewer* cv_project
o->end();
} // Fl_Group* o
cv_tab->end();
Fl_Group::current()->resizable(cv_tab);
} // Fl_Tabs* cv_tab
{ cv_find_row = new Fl_Group(10, 460, 500, 20);
{ cv_find_text_case = new Fl_Button(244, 460, 25, 20, "aA");
cv_find_text_case->type(1);
cv_find_text_case->labelsize(11);
} // Fl_Button* cv_find_text_case
{ cv_find_text = new Fl_Input(40, 460, 200, 20, "Find:");
cv_find_text->labelsize(11);
cv_find_text->textsize(11);
cv_find_text->callback((Fl_Callback*)cb_cv_find_text);
cv_find_text->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY_CHANGED);
} // Fl_Input* cv_find_text
{ Fl_Button* o = new Fl_Button(273, 460, 25, 20, "<<");
o->labelsize(11);
o->callback((Fl_Callback*)cb_);
} // Fl_Button* o
{ Fl_Button* o = new Fl_Button(298, 460, 25, 20, ">>");
o->labelsize(11);
o->callback((Fl_Callback*)cb_1);
} // Fl_Button* o
{ Fl_Button* o = new Fl_Button(327, 460, 61, 20, "Reveal");
o->labelsize(11);
o->callback((Fl_Callback*)cb_Reveal);
} // Fl_Button* o
{ Fl_Box* o = new Fl_Box(490, 460, 20, 20);
Fl_Group::current()->resizable(o);
} // Fl_Box* o
cv_find_row->end();
} // Fl_Group* cv_find_row
{ cv_settings_row = new Fl_Group(10, 485, 500, 20);
{ Fl_Button* o = new Fl_Button(10, 485, 61, 20, "Refresh");
o->labelsize(11);
o->callback((Fl_Callback*)update_codeview_cb);
} // Fl_Button* o
{ Fl_Light_Button* o = cv_autorefresh = new Fl_Light_Button(77, 485, 91, 20, "Auto-Refresh");
cv_autorefresh->labelsize(11);
o->callback((Fl_Callback*)update_codeview_cb);
} // Fl_Light_Button* cv_autorefresh
{ cv_autoposition = new Fl_Light_Button(172, 485, 89, 20, "Auto-Position");
cv_autoposition->labelsize(11);
} // Fl_Light_Button* cv_autoposition
{ cv_code_choice_w = new Fl_Choice(265, 485, 70, 20);
cv_code_choice_w->down_box(FL_BORDER_BOX);
cv_code_choice_w->labelsize(11);
cv_code_choice_w->textsize(11);
cv_code_choice_w->callback((Fl_Callback*)cb_cv_code_choice_w);
cv_code_choice_w->menu(menu_cv_code_choice_w);
} // Fl_Choice* cv_code_choice_w
{ Fl_Box* o = new Fl_Box(375, 485, 80, 20);
Fl_Group::current()->resizable(o);
} // Fl_Box* o
{ Fl_Button* o = new Fl_Button(460, 485, 50, 20, "Close");
o->labelsize(11);
o->callback((Fl_Callback*)toggle_codeview_b_cb);
} // Fl_Button* o
cv_settings_row->end();
} // Fl_Group* cv_settings_row
codeview_panel->size_range(384, 120);
codeview_panel->end();
} // Fl_Double_Window* codeview_panel
return codeview_panel;
}
//

View File

@ -26,7 +26,7 @@ decl {\#include "fluid.h"} {private local
decl {\#include "file.h"} {private local decl {\#include "file.h"} {private local
} }
decl {\#include "../src/flstring.h"} {private local decl {\#include "../src/flstring.h"} {selected private local
} }
decl {\#include <FL/Fl_Tabs.H>} {private local decl {\#include <FL/Fl_Tabs.H>} {private local
@ -35,16 +35,16 @@ decl {\#include <FL/Fl_Tabs.H>} {private local
decl {\#include <FL/Fl_Button.H>} {private local decl {\#include <FL/Fl_Button.H>} {private local
} }
decl {char *sv_source_filename = NULL;} {private local decl {char *cv_source_filename = NULL;} {private local
} }
decl {char *sv_header_filename = NULL;} {private local decl {char *cv_header_filename = NULL;} {private local
} }
decl {char *sv_design_filename = NULL;} {private local decl {char *cv_design_filename = NULL;} {private local
} }
decl {int sv_code_choice;} {public local decl {int cv_code_choice;} {public local
} }
decl {extern void select_only(Fl_Type *o);} {private global decl {extern void select_only(Fl_Type *o);} {private global
@ -53,23 +53,23 @@ decl {extern void select_only(Fl_Type *o);} {private global
decl {extern void reveal_in_browser(Fl_Type *t);} {private global decl {extern void reveal_in_browser(Fl_Type *t);} {private global
} }
Function {update_sourceview_position()} { Function {update_codeview_position()} {
comment {Update the header and source code highlighting depending on the comment {Update the header and source code highlighting depending on the
currently selected object currently selected object
The Source View system offers an immediate preview of the code The Code View system offers an immediate preview of the code
files that will be generated by FLUID. It also marks the code files that will be generated by FLUID. It also marks the code
generated for the last selected item in the header and the source generated for the last selected item in the header and the source
file.} open return_type void file.} open return_type void
} { } {
code {if (!sourceview_panel || !sourceview_panel->visible()) code {if (!codeview_panel || !codeview_panel->visible())
return; return;
if (sv_autoposition->value()==0) if (cv_autoposition->value()==0)
return; return;
if (sourceview_panel && sourceview_panel->visible() && Fl_Type::current) { if (codeview_panel && codeview_panel->visible() && Fl_Type::current) {
int pos0 = 0, pos1 = 0; int pos0 = 0, pos1 = 0;
if (sv_source->visible_r()) { if (cv_source->visible_r()) {
switch (sv_code_choice) { switch (cv_code_choice) {
case 0: // prolog: not yet (include statements) case 0: // prolog: not yet (include statements)
pos0 = Fl_Type::current->code1_start; pos0 = Fl_Type::current->code1_start;
pos1 = Fl_Type::current->code2_end; pos1 = Fl_Type::current->code2_end;
@ -93,14 +93,14 @@ file.} open return_type void
} }
if (pos0>=0) { if (pos0>=0) {
if (pos1<pos0) if (pos1<pos0)
pos1 = sv_source->buffer()->line_end(pos0); pos1 = cv_source->buffer()->line_end(pos0);
sv_source->buffer()->highlight(pos0, pos1); cv_source->buffer()->highlight(pos0, pos1);
int line = sv_source->buffer()->count_lines(0, pos0); int line = cv_source->buffer()->count_lines(0, pos0);
sv_source->scroll(line, 0); cv_source->scroll(line, 0);
} }
} }
if (sv_header->visible_r()) { if (cv_header->visible_r()) {
switch (sv_code_choice) { switch (cv_code_choice) {
case 0: // prolog: not yet (include statements) case 0: // prolog: not yet (include statements)
case 1: // static: callbacks, menu declarations case 1: // static: callbacks, menu declarations
pos0 = Fl_Type::current->header_static_start; pos0 = Fl_Type::current->header_static_start;
@ -121,14 +121,14 @@ file.} open return_type void
} }
if (pos0>=0) { if (pos0>=0) {
if (pos1<pos0) if (pos1<pos0)
pos1 = sv_header->buffer()->line_end(pos0); pos1 = cv_header->buffer()->line_end(pos0);
sv_header->buffer()->highlight(pos0, pos1); cv_header->buffer()->highlight(pos0, pos1);
int line = sv_header->buffer()->count_lines(0, pos0); int line = cv_header->buffer()->count_lines(0, pos0);
sv_header->scroll(line, 0); cv_header->scroll(line, 0);
} }
} }
if (sv_project->visible_r()) { if (cv_project->visible_r()) {
switch (sv_code_choice) { switch (cv_code_choice) {
case 0: // prolog: not yet (include statements) case 0: // prolog: not yet (include statements)
case 1: // static: callbacks, menu declarations case 1: // static: callbacks, menu declarations
case 2: // code: entire implementation block including children case 2: // code: entire implementation block including children
@ -146,83 +146,83 @@ file.} open return_type void
} }
if (pos0>=0) { if (pos0>=0) {
if (pos1<pos0) if (pos1<pos0)
pos1 = sv_project->buffer()->line_end(pos0); pos1 = cv_project->buffer()->line_end(pos0);
sv_project->buffer()->highlight(pos0, pos1); cv_project->buffer()->highlight(pos0, pos1);
int line = sv_project->buffer()->count_lines(0, pos0); int line = cv_project->buffer()->count_lines(0, pos0);
sv_project->scroll(line, 0); cv_project->scroll(line, 0);
} }
} }
}} {} }} {}
} }
Function {update_sourceview_position_cb(class Fl_Tabs*, void*)} { Function {update_codeview_position_cb(class Fl_Tabs*, void*)} {
comment {Callback to update the sourceview position.} open return_type void comment {Callback to update the codeview position.} open return_type void
} { } {
code {// make sure that the selected tab shows the current view code {// make sure that the selected tab shows the current view
update_sourceview_cb(0,0); update_codeview_cb(0,0);
// highlight the selected widget in the selected tab // highlight the selected widget in the selected tab
update_sourceview_position();} {} update_codeview_position();} {}
} }
Function {update_sourceview_cb(class Fl_Button*, void*)} { Function {update_codeview_cb(class Fl_Button*, void*)} {
comment {Generate a header, source, strings, or design file in a temporary directory comment {Generate a header, source, strings, or design file in a temporary directory
and load those into the Code Viewer widgets.} open return_type void and load those into the Code Viewer widgets.} open return_type void
} { } {
code {if (!sourceview_panel || !sourceview_panel->visible()) code {if (!codeview_panel || !codeview_panel->visible())
return; return;
if (!sv_source_filename) { if (!cv_source_filename) {
sv_source_filename = (char*)malloc(FL_PATH_MAX); cv_source_filename = (char*)malloc(FL_PATH_MAX);
fl_strlcpy(sv_source_filename, get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcpy(cv_source_filename, get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(sv_source_filename, "source_view_tmp.cxx", FL_PATH_MAX); fl_strlcat(cv_source_filename, "codeview_tmp.cxx", FL_PATH_MAX);
} }
if (!sv_header_filename) { if (!cv_header_filename) {
sv_header_filename = (char*)malloc(FL_PATH_MAX); cv_header_filename = (char*)malloc(FL_PATH_MAX);
fl_strlcpy(sv_header_filename, get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcpy(cv_header_filename, get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(sv_header_filename, "source_view_tmp.h", FL_PATH_MAX); fl_strlcat(cv_header_filename, "codeview_tmp.h", FL_PATH_MAX);
} }
if (!sv_design_filename) { if (!cv_design_filename) {
sv_design_filename = (char*)malloc(FL_PATH_MAX); cv_design_filename = (char*)malloc(FL_PATH_MAX);
fl_strlcpy(sv_design_filename, get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcpy(cv_design_filename, get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(sv_design_filename, "source_view_tmp.fl", FL_PATH_MAX); fl_strlcat(cv_design_filename, "codeview_tmp.fl", FL_PATH_MAX);
} }
if (sv_project->visible_r()) { if (cv_project->visible_r()) {
write_file(sv_design_filename, false, true); write_file(cv_design_filename, false, true);
int top = sv_project->top_line(); int top = cv_project->top_line();
sv_project->buffer()->loadfile(sv_design_filename); cv_project->buffer()->loadfile(cv_design_filename);
sv_project->scroll(top, 0); cv_project->scroll(top, 0);
} else if (sv_strings->visible_r()) { } else if (cv_strings->visible_r()) {
static const char *exts[] = { ".txt", ".po", ".msg" }; static const char *exts[] = { ".txt", ".po", ".msg" };
char fn[FL_PATH_MAX+1]; char fn[FL_PATH_MAX+1];
fl_strlcpy(fn, get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcpy(fn, get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(fn, "strings", FL_PATH_MAX); fl_strlcat(fn, "strings", FL_PATH_MAX);
fl_filename_setext(fn, FL_PATH_MAX, exts[g_project.i18n_type]); fl_filename_setext(fn, FL_PATH_MAX, exts[g_project.i18n_type]);
write_strings(fn); write_strings(fn);
int top = sv_strings->top_line(); int top = cv_strings->top_line();
sv_strings->buffer()->loadfile(fn); cv_strings->buffer()->loadfile(fn);
sv_strings->scroll(top, 0); cv_strings->scroll(top, 0);
} else if (sv_source->visible_r() || sv_header->visible_r()) { } else if (cv_source->visible_r() || cv_header->visible_r()) {
Fl_String code_file_name_bak = g_project.code_file_name; Fl_String code_file_name_bak = g_project.code_file_name;
g_project.code_file_name = sv_source_filename; g_project.code_file_name = cv_source_filename;
Fl_String header_file_name_bak = g_project.header_file_name; Fl_String header_file_name_bak = g_project.header_file_name;
g_project.header_file_name = sv_header_filename; g_project.header_file_name = cv_header_filename;
// generate the code and load the files // generate the code and load the files
Fd_Code_Writer f; Fd_Code_Writer f;
// generate files // generate files
if (f.write_code(sv_source_filename, sv_header_filename, true)) if (f.write_code(cv_source_filename, cv_header_filename, true))
{ {
// load file into source editor // load file into source editor
int pos = sv_source->top_line(); int pos = cv_source->top_line();
sv_source->buffer()->loadfile(sv_source_filename); cv_source->buffer()->loadfile(cv_source_filename);
sv_source->scroll(pos, 0); cv_source->scroll(pos, 0);
// load file into header editor // load file into header editor
pos = sv_header->top_line(); pos = cv_header->top_line();
sv_header->buffer()->loadfile(sv_header_filename); cv_header->buffer()->loadfile(cv_header_filename);
sv_header->scroll(pos, 0); cv_header->scroll(pos, 0);
// update the source code highlighting // update the source code highlighting
update_sourceview_position(); update_codeview_position();
} }
g_project.code_file_name = code_file_name_bak; g_project.code_file_name = code_file_name_bak;
@ -230,71 +230,71 @@ and load those into the Code Viewer widgets.} open return_type void
}} {} }} {}
} }
Function {update_sourceview_timer(void*)} { Function {update_codeview_timer(void*)} {
comment {This is called by the timer itself comment {This is called by the timer itself
} open return_type void } open return_type void
} { } {
code {update_sourceview_cb(0,0);} {} code {update_codeview_cb(0,0);} {}
} }
Function {sourceview_defer_update()} {open return_type void Function {codeview_defer_update()} {open return_type void
} { } {
code {// we will only update earliest 0.5 seconds after the last change, and only code {// we will only update earliest 0.5 seconds after the last change, and only
// if no other change was made, so dragging a widget will not generate any // if no other change was made, so dragging a widget will not generate any
// CPU load // CPU load
Fl::remove_timeout(update_sourceview_timer, 0); Fl::remove_timeout(update_codeview_timer, 0);
Fl::add_timeout(0.5, update_sourceview_timer, 0);} {} Fl::add_timeout(0.5, update_codeview_timer, 0);} {}
} }
Function {sourceview_toggle_visibility()} { Function {codeview_toggle_visibility()} {
comment {Show or hide the source code preview. comment {Show or hide the source code preview.
The state is stored in the app preferences. The state is stored in the app preferences.
} open return_type void } open return_type void
} { } {
code {if (!sourceview_panel) { code {if (!codeview_panel) {
make_sourceview(); make_codeview();
sourceview_panel->callback((Fl_Callback*)toggle_sourceview_cb); codeview_panel->callback((Fl_Callback*)toggle_codeview_cb);
Fl_Preferences svp(fluid_prefs, "sourceview"); Fl_Preferences svp(fluid_prefs, "codeview");
int autorefresh; int autorefresh;
svp.get("autorefresh", autorefresh, 1); svp.get("autorefresh", autorefresh, 1);
sv_autorefresh->value(autorefresh); cv_autorefresh->value(autorefresh);
int autoposition; int autoposition;
svp.get("autoposition", autoposition, 1); svp.get("autoposition", autoposition, 1);
sv_autoposition->value(autoposition); cv_autoposition->value(autoposition);
int tab; int tab;
svp.get("tab", tab, 0); svp.get("tab", tab, 0);
if (tab>=0 && tab<sv_tab->children()) sv_tab->value(sv_tab->child(tab)); if (tab>=0 && tab<cv_tab->children()) cv_tab->value(cv_tab->child(tab));
svp.get("code_choice", sv_code_choice, 2); svp.get("code_choice", cv_code_choice, 2);
sv_code_choice_w->value(sv_code_choice_w->find_item_with_argument(sv_code_choice)); cv_code_choice_w->value(cv_code_choice_w->find_item_with_argument(cv_code_choice));
if (!position_window(sourceview_panel,"sourceview_pos", 0, 320, 120, 550, 500)) return; if (!position_window(codeview_panel,"codeview_pos", 0, 320, 120, 550, 500)) return;
} }
if (sourceview_panel->visible()) { if (codeview_panel->visible()) {
sourceview_panel->hide(); codeview_panel->hide();
sourceview_item->label("Show Source Code..."); codeview_item->label("Show Code View");
} else { } else {
sourceview_panel->show(); codeview_panel->show();
sourceview_item->label("Hide Source Code..."); codeview_item->label("Hide Code View");
update_sourceview_cb(0,0); update_codeview_cb(0,0);
}} {} }} {}
} }
Function {make_sourceview()} {open Function {make_codeview()} {open
} { } {
Fl_Window sourceview_panel { Fl_Window codeview_panel {
label {Code View} label {Code View}
callback toggle_sourceview_cb open callback toggle_codeview_cb open
xywh {389 507 520 515} type Double align 80 resizable size_range {384 120 0 0} visible xywh {389 507 520 515} type Double align 80 resizable size_range {384 120 0 0} visible
} { } {
Fl_Tabs sv_tab { Fl_Tabs cv_tab {
callback update_sourceview_position_cb open callback update_codeview_position_cb open
xywh {10 10 500 440} selection_color 4 labelcolor 7 resizable xywh {10 10 500 440} selection_color 4 labelcolor 7 resizable
} { } {
Fl_Group {} { Fl_Group cv_source_tab {
label Source open label Source open
xywh {10 35 500 415} labelsize 13 resizable xywh {10 35 500 415} labelsize 13 resizable
} { } {
Fl_Text_Editor sv_source { Fl_Text_Editor cv_source {
xywh {10 40 500 410} textfont 4 textsize 11 resizable xywh {10 40 500 410} textfont 4 textsize 11 resizable
code0 {\#include "CodeEditor.h"} code0 {\#include "CodeEditor.h"}
code1 {o->linenumber_width(60);} code1 {o->linenumber_width(60);}
@ -306,7 +306,7 @@ Function {make_sourceview()} {open
label Header open label Header open
xywh {10 35 500 415} labelsize 13 hide xywh {10 35 500 415} labelsize 13 hide
} { } {
Fl_Text_Editor sv_header { Fl_Text_Editor cv_header {
xywh {10 40 500 410} textfont 4 textsize 11 resizable xywh {10 40 500 410} textfont 4 textsize 11 resizable
code0 {\#include "CodeEditor.h"} code0 {\#include "CodeEditor.h"}
code1 {o->linenumber_width(60);} code1 {o->linenumber_width(60);}
@ -318,7 +318,7 @@ Function {make_sourceview()} {open
label Strings open label Strings open
xywh {10 35 500 415} labelsize 13 hide xywh {10 35 500 415} labelsize 13 hide
} { } {
Fl_Text_Display sv_strings { Fl_Text_Display cv_strings {
xywh {10 40 500 410} textfont 4 textsize 11 resizable xywh {10 40 500 410} textfont 4 textsize 11 resizable
code1 {o->linenumber_width(60);} code1 {o->linenumber_width(60);}
code2 {o->linenumber_size(o->Fl_Text_Display::textsize());} code2 {o->linenumber_size(o->Fl_Text_Display::textsize());}
@ -329,7 +329,7 @@ Function {make_sourceview()} {open
label Project open label Project open
xywh {10 35 500 415} labelsize 13 hide xywh {10 35 500 415} labelsize 13 hide
} { } {
Fl_Text_Display sv_project { Fl_Text_Display cv_project {
xywh {10 40 500 410} textfont 4 textsize 11 resizable xywh {10 40 500 410} textfont 4 textsize 11 resizable
code1 {o->linenumber_width(60);} code1 {o->linenumber_width(60);}
code2 {o->linenumber_size(o->Fl_Text_Display::textsize());} code2 {o->linenumber_size(o->Fl_Text_Display::textsize());}
@ -337,27 +337,27 @@ Function {make_sourceview()} {open
} }
} }
} }
Fl_Group {} {open Fl_Group cv_find_row {open
xywh {10 460 500 20} xywh {10 460 500 20}
} { } {
Fl_Button sv_find_text_case { Fl_Button cv_find_text_case {
label aA label aA
xywh {244 460 25 20} type Toggle labelsize 11 xywh {244 460 25 20} type Toggle labelsize 11
} }
Fl_Input sv_find_text { Fl_Input cv_find_text {
label {Find:} label {Find:}
callback {Fl_Text_Display *e = NULL; callback {Fl_Text_Display *e = NULL;
if (sv_source->visible_r()) { if (cv_source->visible_r()) {
e = sv_source; e = cv_source;
} else if (sv_header->visible_r()) { } else if (cv_header->visible_r()) {
e = sv_header; e = cv_header;
} else if (sv_project->visible_r()) { } else if (cv_project->visible_r()) {
e = sv_project; e = cv_project;
} }
if (e) { if (e) {
Fl_Text_Buffer *b = e->buffer(); Fl_Text_Buffer *b = e->buffer();
int pos = e->insert_position(); int pos = e->insert_position();
int found = b->search_forward(pos, o->value(), &pos, sv_find_text_case->value()); int found = b->search_forward(pos, o->value(), &pos, cv_find_text_case->value());
if (found) { if (found) {
b->select(pos, pos + (int)strlen(o->value())); b->select(pos, pos + (int)strlen(o->value()));
e->insert_position(pos); e->insert_position(pos);
@ -369,47 +369,47 @@ if (e) {
Fl_Button {} { Fl_Button {} {
label {<<} label {<<}
callback {Fl_Text_Display *e = NULL; callback {Fl_Text_Display *e = NULL;
if (sv_source->visible_r()) { if (cv_source->visible_r()) {
e = sv_source; e = cv_source;
} else if (sv_header->visible_r()) { } else if (cv_header->visible_r()) {
e = sv_header; e = cv_header;
} else if (sv_project->visible_r()) { } else if (cv_project->visible_r()) {
e = sv_project; e = cv_project;
} }
if (e) { if (e) {
const char *needle = sv_find_text->value(); const char *needle = cv_find_text->value();
Fl_Text_Buffer *b = e->buffer(); Fl_Text_Buffer *b = e->buffer();
int pos = e->insert_position()-1; int pos = e->insert_position()-1;
if (pos < 0) pos = b->length()-1; if (pos < 0) pos = b->length()-1;
int found = b->search_backward(pos, needle, &pos, sv_find_text_case->value()); int found = b->search_backward(pos, needle, &pos, cv_find_text_case->value());
if (!found) if (!found)
found = b->search_backward(b->length()-1, needle, &pos, sv_find_text_case->value()); found = b->search_backward(b->length()-1, needle, &pos, cv_find_text_case->value());
if (found) { if (found) {
b->select(pos, pos + (int)strlen(needle)); b->select(pos, pos + (int)strlen(needle));
e->insert_position(pos); e->insert_position(pos);
e->show_insert_position(); e->show_insert_position();
} }
}} selected }}
xywh {273 460 25 20} labelsize 11 xywh {273 460 25 20} labelsize 11
} }
Fl_Button {} { Fl_Button {} {
label {>>} label {>>}
callback {Fl_Text_Display *e = NULL; callback {Fl_Text_Display *e = NULL;
if (sv_source->visible_r()) { if (cv_source->visible_r()) {
e = sv_source; e = cv_source;
} else if (sv_header->visible_r()) { } else if (cv_header->visible_r()) {
e = sv_header; e = cv_header;
} else if (sv_project->visible_r()) { } else if (cv_project->visible_r()) {
e = sv_project; e = cv_project;
} }
if (e) { if (e) {
const char *needle = sv_find_text->value(); const char *needle = cv_find_text->value();
Fl_Text_Buffer *b = e->buffer(); Fl_Text_Buffer *b = e->buffer();
int pos = e->insert_position() + 1; int pos = e->insert_position() + 1;
if (pos+1 >= b->length()) pos = 0; if (pos+1 >= b->length()) pos = 0;
int found = b->search_forward(pos, needle, &pos, sv_find_text_case->value()); int found = b->search_forward(pos, needle, &pos, cv_find_text_case->value());
if (!found && (pos > 0)) if (!found && (pos > 0))
found = b->search_forward(0, needle, &pos, sv_find_text_case->value()); found = b->search_forward(0, needle, &pos, cv_find_text_case->value());
if (found) { if (found) {
b->select(pos, pos + (int)strlen(needle)); b->select(pos, pos + (int)strlen(needle));
e->insert_position(pos); e->insert_position(pos);
@ -420,14 +420,14 @@ if (e) {
} }
Fl_Button {} { Fl_Button {} {
label Reveal label Reveal
callback {if (sourceview_panel && sourceview_panel->visible()) { callback {if (codeview_panel && codeview_panel->visible()) {
Fl_Type *node = NULL; Fl_Type *node = NULL;
if (sv_source->visible_r()) if (cv_source->visible_r())
node = Fl_Type::find_in_text(0, sv_source->insert_position()); node = Fl_Type::find_in_text(0, cv_source->insert_position());
else if (sv_header->visible_r()) else if (cv_header->visible_r())
node = Fl_Type::find_in_text(1, sv_header->insert_position()); node = Fl_Type::find_in_text(1, cv_header->insert_position());
else if (sv_project->visible_r()) else if (cv_project->visible_r())
node = Fl_Type::find_in_text(2, sv_project->insert_position()); node = Fl_Type::find_in_text(2, cv_project->insert_position());
if (node) { if (node) {
select_only(node); select_only(node);
reveal_in_browser(node); reveal_in_browser(node);
@ -441,26 +441,26 @@ if (e) {
xywh {490 460 20 20} resizable xywh {490 460 20 20} resizable
} }
} }
Fl_Group {} {open Fl_Group cv_settings_row {open
xywh {10 485 500 20} xywh {10 485 500 20}
} { } {
Fl_Button {} { Fl_Button {} {
label Refresh label Refresh
callback update_sourceview_cb callback update_codeview_cb
xywh {10 485 61 20} labelsize 11 xywh {10 485 61 20} labelsize 11
} }
Fl_Light_Button sv_autorefresh { Fl_Light_Button cv_autorefresh {
label {Auto-Refresh} label {Auto-Refresh}
xywh {77 485 91 20} labelsize 11 xywh {77 485 91 20} labelsize 11
code0 {o->callback((Fl_Callback*)update_sourceview_cb);} code0 {o->callback((Fl_Callback*)update_codeview_cb);}
} }
Fl_Light_Button sv_autoposition { Fl_Light_Button cv_autoposition {
label {Auto-Position} label {Auto-Position}
xywh {172 485 89 20} labelsize 11 xywh {172 485 89 20} labelsize 11
} }
Fl_Choice sv_code_choice_w { Fl_Choice cv_code_choice_w {
callback {sv_code_choice = (int)o->mvalue()->argument(); callback {cv_code_choice = (int)o->mvalue()->argument();
update_sourceview_position();} open update_codeview_position();} open
xywh {265 485 70 20} down_box BORDER_BOX labelsize 11 textsize 11 xywh {265 485 70 20} down_box BORDER_BOX labelsize 11 textsize 11
} { } {
MenuItem {} { MenuItem {} {
@ -494,7 +494,7 @@ update_sourceview_position();} open
} }
Fl_Button {} { Fl_Button {} {
label Close label Close
callback toggle_sourceview_b_cb callback toggle_codeview_b_cb
xywh {460 485 50 20} labelsize 11 xywh {460 485 50 20} labelsize 11
} }
} }

58
fluid/codeview_panel.h Normal file
View File

@ -0,0 +1,58 @@
//
// Code dialogs for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2023 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
//
// generated by Fast Light User Interface Designer (fluid) version 1.0400
#ifndef codeview_panel_h
#define codeview_panel_h
#include <FL/Fl.H>
extern int cv_code_choice;
void update_codeview_position();
void update_codeview_position_cb(class Fl_Tabs*, void*);
void update_codeview_cb(class Fl_Button*, void*);
void update_codeview_timer(void*);
void codeview_defer_update();
void codeview_toggle_visibility();
#include <FL/Fl_Double_Window.H>
extern void toggle_codeview_cb(Fl_Double_Window*, void*);
extern Fl_Double_Window *codeview_panel;
#include <FL/Fl_Tabs.H>
extern Fl_Tabs *cv_tab;
#include <FL/Fl_Group.H>
extern Fl_Group *cv_source_tab;
#include "CodeEditor.h"
extern CodeViewer *cv_source;
extern CodeViewer *cv_header;
extern TextViewer *cv_strings;
extern TextViewer *cv_project;
extern Fl_Group *cv_find_row;
#include <FL/Fl_Button.H>
extern Fl_Button *cv_find_text_case;
#include <FL/Fl_Input.H>
extern Fl_Input *cv_find_text;
#include <FL/Fl_Box.H>
extern Fl_Group *cv_settings_row;
#include <FL/Fl_Light_Button.H>
extern Fl_Light_Button *cv_autorefresh;
extern Fl_Light_Button *cv_autoposition;
#include <FL/Fl_Choice.H>
extern Fl_Choice *cv_code_choice_w;
extern void toggle_codeview_b_cb(Fl_Button*, void*);
Fl_Double_Window* make_codeview();
extern Fl_Menu_Item menu_cv_code_choice_w[];
#endif
//

View File

@ -55,7 +55,7 @@ int Widget_Bin_Button::handle(int inEvent)
// fake a drag outside of the widget // fake a drag outside of the widget
Fl::e_x = x()-1; Fl::e_x = x()-1;
Fl_Button::handle(inEvent); Fl_Button::handle(inEvent);
// fake a buttton release // fake a button release
Fl_Button::handle(FL_RELEASE); Fl_Button::handle(FL_RELEASE);
// make it into a dnd event // make it into a dnd event
const char *type_name = (const char*)user_data(); const char *type_name = (const char*)user_data();

View File

@ -0,0 +1,232 @@
#
# CMakeLists.txt to build docs for the FLTK project using CMake (www.cmake.org)
#
# Copyright 1998-2024 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
#
set(DOCS)
set(GIT_REVISION "")
set(YEAR "")
set(CURRENT_DATE "")
#------------------------------------------------
# generate files used for both HTML and PDF docs
#------------------------------------------------
if(FLTK_BUILD_FLUID_DOCS OR FLTK_BUILD_PDF_DOCS)
# create required variables
execute_process(COMMAND date "+%Y"
OUTPUT_VARIABLE YEAR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# note: current locale is used for abbreviated month
execute_process(COMMAND date "+%b %d, %Y"
OUTPUT_VARIABLE CURRENT_DATE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# find git revision
# FIXME: This must also work with tarballs where git is not available.
# For now we just ignore errors and set GIT_REVISION = "unknown".
# In the future tarball/zip generation should create a file
# that contains the git revision.
execute_process(COMMAND
git rev-parse --short=10 HEAD
OUTPUT_VARIABLE GIT_REVISION
OUTPUT_STRIP_TRAILING_WHITESPACE
WORKING_DIRECTORY ${FLTK_SOURCE_DIR}
ERROR_QUIET
)
# set to "'unknown'" if git is not available
if(GIT_REVISION STREQUAL "")
set(GIT_REVISION "'unknown'")
endif()
# Find "short" doxygen version if it was built from Git
# Note: this is still needed in CMake 3.12.0 but later CMake versions
# (notably 3.25) remove the Git revision in 'DOXYGEN_VERSION'.
# Todo: Find the "first good" CMake version and remove this redundant
# code once we require this as our minimal version and replace the
# variable DOXYGEN_VERSION_SHORT with DOXYGEN_VERSION below.
if(DOXYGEN_FOUND)
# strip trailing git revision if doxygen was built from source
string(REGEX REPLACE " .*$" "" DOXYGEN_VERSION_SHORT ${DOXYGEN_VERSION})
endif(DOXYGEN_FOUND)
# configure copyright.dox (includes current year)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/copyright.dox.in
${CMAKE_CURRENT_BINARY_DIR}/copyright.dox
@ONLY
)
# configure generated.dox (includes date and versions)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/generated.dox.in
${CMAKE_CURRENT_BINARY_DIR}/generated.dox
@ONLY
)
endif(FLTK_BUILD_FLUID_DOCS OR FLTK_BUILD_PDF_DOCS)
#-------------------------------
# build FLUID html documentation
#-------------------------------
if(FLTK_BUILD_FLUID_DOCS)
#list(APPEND DOCS html)
# generate Doxygen file "Doxyfile"
set(GENERATE_FLUID_HTML YES)
set(GENERATE_LATEX NO)
set(LATEX_HEADER "")
set(FL_HTML_INDEX "FL_HTML_INDEX")
set(DOXYFILE "Doxyfile")
set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}_error.log")
# configure Doxygen input file for HTML docs (Doxyfile.in)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}.in
@ONLY
)
# convert Doxyfile to used doxygen version
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/convert_doxyfile
${DOXYGEN_EXECUTABLE}
${DOXYFILE}.in
${DOXYFILE}
${LOGFILE}
BYPRODUCTS ${LOGFILE}
COMMENT "Converting ${DOXYFILE} to doxygen version ${DOXYGEN_VERSION_SHORT}" VERBATIM
)
# generate screen shot using FLUID --autodoc target_dir
# generate HTML documentation
add_custom_target(fluid_docs
COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/src/
COMMAND fltk::fluid -scheme gtk+ --autodoc ${CMAKE_CURRENT_BINARY_DIR}/src/
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating HTML documentation" VERBATIM
)
add_dependencies(fluid_docs fltk::fluid)
endif(FLTK_BUILD_FLUID_DOCS)
#--------------------------
# build pdf documentation
#--------------------------
if(FLTK_BUILD_PDF_DOCS AND FLTK_BUILD_FLUID_DOCS)
# generate Doxygen input file "Doxybook"
set(GENERATE_FLUID_HTML NO)
set(GENERATE_LATEX YES)
set(LATEX_HEADER "${CMAKE_CURRENT_BINARY_DIR}/fluid-book.tex")
set(FL_HTML_INDEX "FL_NO_HTML_INDEX")
set(DOXYFILE "Doxybook")
set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}_error.log")
# configure Doxygen input file for PDF docs (Doxybook.in)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}.in
@ONLY
)
# convert Doxybook to current doxygen version
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/convert_doxyfile
${DOXYGEN_EXECUTABLE}
${DOXYFILE}.in
${DOXYFILE}
${LOGFILE}
BYPRODUCTS ${LOGFILE}
COMMENT "Converting ${DOXYFILE} to doxygen version ${DOXYGEN_VERSION_SHORT}" VERBATIM
)
# generate LaTeX title fluid-title.tex
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/src/fluid-title.tex.in
${CMAKE_CURRENT_BINARY_DIR}/fluid-title.tex
@ONLY
)
# generate fluid.pdf
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fluid.pdf
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/make_header
${DOXYGEN_EXECUTABLE}
${CMAKE_CURRENT_BINARY_DIR}/fluid-title.tex
${CMAKE_CURRENT_BINARY_DIR}/fluid-book.tex
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/make_pdf
COMMAND cp -f latex/refman.pdf fluid.pdf
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}
${CMAKE_CURRENT_BINARY_DIR}/fluid-title.tex
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating FLUID PDF documentation" VERBATIM
)
# add target 'pdf'
add_custom_target(fluid_pdf
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/fluid.pdf
)
add_dependencies(fluid_pdf fluid_docs)
endif(FLTK_BUILD_PDF_DOCS AND FLTK_BUILD_FLUID_DOCS)
#---------------------------------------
# install FLUID html + pdf documentation
#---------------------------------------
if(FLTK_INSTALL_FLUID_DOCS AND FLTK_BUILD_FLUID_DOCS)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html
DESTINATION ${FLTK_DATADIR}/doc/fltk/fluid
)
endif(FLTK_INSTALL_FLUID_DOCS AND FLTK_BUILD_FLUID_DOCS)
if(FLTK_INSTALL_PDF_DOCS AND FLTK_BUILD_PDF_DOCS AND FLTK_BUILD_FLUID_DOCS)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fluid.pdf
DESTINATION ${FLTK_DATADIR}/doc/fltk/
)
endif(FLTK_INSTALL_PDF_DOCS AND FLTK_BUILD_PDF_DOCS AND FLTK_BUILD_FLUID_DOCS)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
#!/bin/sh
#
# Convert 'Doxyfile.in' to 'Doxyfile' or 'Doxybook' for doxygen docs
#
# Usage:
#
# $ sh convert_doxyfile doxygen_path input output logfile
#
# where
# - 'doxygen_path' is the full path to the doxygen executable or just
# 'doxygen' if this is in the user's PATH. If the full path is used
# an arbitrary doxygen executable and thus doxygen version can be used.
# - 'input' is the file 'Doxyfile.in' stored in Git or any other file.
# - 'output' is the generated doxygen file, usually either 'Doxyfile'
# or 'Doxybook' which will be used subsequently to generate the
# HTML or PDF docs, respectively.
#
# Doxygen warnings and errors are stored in 'logfile' for review.
#
#=======================================================================
# This script requires a posix shell and uses the following commands:
# 'echo', 'date', and (obviously) doxygen.
#=======================================================================
# doxygen command, input and output file names
DOXYGEN="$1"
INFILE="$2"
OUTFILE="$3"
LOGFILE="$4"
# get doxygen version
VERSION=$("$DOXYGEN" --version)
# write info header to LOGFILE
echo "$OUTFILE created by doxygen version $VERSION" > $LOGFILE
echo " at `date`" >> $LOGFILE
echo "" >> $LOGFILE
# convert doxygen file and append errors and warnings to LOGFILE
"${DOXYGEN}" -u -s - < $INFILE > $OUTFILE 2>> $LOGFILE

View File

@ -0,0 +1 @@
Copyright &copy; 1998 - @YEAR@ by Bill Spitzak and others.

View File

@ -0,0 +1,6 @@
<br>
<small>
Generated on @CURRENT_DATE@
from Git revision @GIT_REVISION@
by Doxygen @DOXYGEN_VERSION_SHORT@
</small>

63
fluid/documentation/make_header Executable file
View File

@ -0,0 +1,63 @@
#!/bin/sh
#
# Create a new LaTeX header file for doxygen PDF docs
#
# Note: this LaTeX file depends on Doxygen and LaTeX versions, resp.
# and needs therefore to be created with current Doxygen and LaTeX
# versions on the build system.
#
# Usage:
#
# $ sh make_header doxygen_path input-file output-file
#
# where
# - 'doxygen_path' is the full path to the doxygen executable
# or just 'doxygen'. If the full path is used an arbitrary
# doxygen executable and thus doxygen version can be used.
# - 'input-file' is the pure (LaTeX) title page (template)
# - 'output-file' is the generated (LaTeX) title page (template)
# that is used by `make' or `cmake` to generate the final LaTeX
# page header (combined doxygen template + FLTK title page).
#
#=======================================================================
# This script requires a posix shell and uses the following commands:
# cat, rm and sed and (obviously) doxygen
#=======================================================================
# input and output file names
DOXY_CMD="$1"
FLTK_HEAD="$2"
DOXY_HEAD="$3"
# temp file
DOXY_TEMP="doxy-header.tex.$$"
if test x$FLTK_HEAD = x; then
echo "usage: $0 fltk-header-file output-file"
exit 1
fi
if test x$DOXY_HEAD = x; then
echo "usage: $0 fltk-header-file output-file"
exit 1
fi
# Create the doxygen LaTeX header template and replace the LaTeX
# code between (and including) the lines containing
# - 'begin{titlepage}' and
# - 'end{titlepage}'
# with our PDF document title page (LaTeX code) and write the
# result to $DOXY_HEAD.
"$DOXY_CMD" -w latex $DOXY_TEMP /dev/null /dev/null
# combine three parts of these files to the output file
# using '( ... ) > $DOXY_HEAD' to write (concatenate)
# all three parts to one file
( sed -e'/begin{titlepage}/,$d' < $DOXY_TEMP
cat $FLTK_HEAD
sed -e'1,/end{titlepage}/d' < $DOXY_TEMP
) > $DOXY_HEAD
# cleanup
rm -f $DOXY_TEMP

41
fluid/documentation/make_pdf Executable file
View File

@ -0,0 +1,41 @@
#! /bin/sh
#
# Makefile helper script for the Fast Light Tool Kit (FLTK) documentation.
#
# Copyright 1998-2020 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
#
# This script generates latex/refman.pdf after doxygen has been executed.
#
# Input: run `doxygen Doxybook' (creates files in subdirectory latex)
# Output: latex/refman.pdf (if successful)
#
# Next step: cp -f latex/refman.pdf fluid.pdf (why is this extra step needed ?)
#
# Working directory: fltk/documentation
#
# Used in: Makefile and CMakeLists.txt
( cd latex
pdflatex --interaction=nonstopmode refman.tex
makeindex refman.idx
pdflatex --interaction=nonstopmode refman.tex
latex_count=5
while egrep -s 'Rerun (LaTeX|to get cross-references right)' refman.log \
&& [ $latex_count -gt 0 ]
do
echo "Rerunning pdflatex ..."
pdflatex --interaction=nonstopmode refman.tex
latex_count=`expr $latex_count - 1`
done
cd ..) > pdfall.log 2>&1

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -0,0 +1,35 @@
%
% FLUID PDF documentation title page (LaTeX)
%
\begin{titlepage}
\vspace*{4cm}
\begin{center}%
{\Huge FLUID for FLTK @FLTK_VERSION@ User Manual}\\
\vspace*{2cm}
\begin{DoxyImageNoCaption}
\mbox{\includegraphics[width=4cm]{fluid-128.png}}
\end{DoxyImageNoCaption}\\
\vspace*{2cm}
{\Large
By F. Costantini, D. Gibson, M. Melcher, \\
A. Schlosser, B. Spitzak, and M. Sweet.}\\
\vspace*{1.5cm}
{\large Copyright © 1998 - @YEAR@ by Bill Spitzak and others.}\\
\vspace*{0.75cm}
{\small
This software and manual are provided under the terms of the GNU Library General Public License.}\\
{\small
Permission is granted to reproduce this manual or any portion for any purpose,}\\
{\small
provided this copyright and permission notice are preserved.}\\
\vspace*{1.5cm}
{\large Generated by Doxygen @DOXY_VERSION@}\\
\vspace*{0.5cm}
\today{}\\
\vspace*{0.5cm}
{\small Git revision @GIT_REVISION@}\\
\end{center}
\end{titlepage}
%
% end of FLUID PDF documentation title page (LaTeX)
%

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

View File

@ -0,0 +1,118 @@
/**
\cond FL_HTML_INDEX
\mainpage FLUID User Manual
<TABLE CELLPADDING="8" CELLSPACING="0" SUMMARY="TITLE BAR" WIDTH="100%" BORDER="0">
<TR>
<TD><CENTER>
\image html fluid-128.png
\image latex fluid-128.png "" width=3cm
</CENTER></TD>
<TD><CENTER>
<B>FLUID 1.4.0 User Manual</B>
By F.&nbsp;Costantini, D.&nbsp;Gibson, M.&nbsp;Melcher,
A.&nbsp;Schlosser, B.&nbsp;Spitzak and M.&nbsp;Sweet.
Copyright © 1998 - 2024 by Bill Spitzak and others.
</CENTER></TD>
</TR>
</TABLE>
<TABLE CELLPADDING="8" CELLSPACING="0" SUMMARY="TITLE BAR" WIDTH="100%" BORDER="0">
<TR>
<TD style="text-align: center;">
This software and manual are provided under the terms of the GNU
Library General Public License. Permission is granted to reproduce
this manual or any portion for any purpose, provided this copyright
and permission notice are preserved.
</TD>
</TR>
</TABLE>
<TABLE CELLPADDING="8" CELLSPACING="0" SUMMARY="Table of Contents" WIDTH="100%" BORDER="0">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
\subpage page_introduction
- \ref introduction_workflow
\subpage page_commandline
- \ref commandline_options
- \ref commandline_passive
- \ref commandline_windows
\subpage page_interactive
\subpage page_main_window
- \ref main_titlebar
- \ref main_menubar
- \ref main_widget_browser
- \ref main_menu_items
\subpage page_widgetbin_panel
\subpage page_edit_window
- \ref edit_selection
- \ref edit_layout
- \ref edit_snap
- \ref edit_resize
\subpage page_widget_panel
- \ref widget_panel_gui
- \ref widget_panel_style
- \ref widget_panel_cpp
- \ref widget_panel_grid
- \ref widget_panel_gridc
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
\subpage page_functional_nodes
- \ref functional_function
- \ref functional_code
- \ref functional_codeblock
- \ref functional_decl
- \ref functional_declblock
- \ref functional_class
- \ref functional_widgetclass
- \ref functional_comment
- \ref functional_data
\subpage page_codeview_panel
- \ref codeview_find
- \ref codeview_settings
\subpage page_setting_dialog
- \ref setting_general
- \ref setting_project
- \ref setting_layout
- \ref setting_shell
- \ref setting_i18n
- \ref setting_user
\subpage page_tutorial
- \ref fluid_hello_world_tutorial
- \ref fluid_1of7guis_tutorial
- \ref fluid_cubeview_tutorial
- \ref fluid_cubeview_ui
- \ref fluid_addconst
- \ref fluid_gencode
\subpage page_appendices
- \ref appendix_keyboard_shortcuts
- \ref appendix_fileformat
- \ref appendix_licenses
</TD>
</TR>
</TABLE>
\endcond
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,92 @@
/**
\page page_appendices Appendices
\tableofcontents
<!-- ---------------------------------------------------------------------- -->
\section appendix_keyboard_shortcuts Keyboard Shortcuts
On Apple computers, use the Apple Command key instead of Ctrl.
| Key Combo | Function |
| :-------: | :------- |
| `F1` | open widget dialog |
| `F2` | move widget earlier in tree |
| `F3` | move widget later in tree |
| `F7` | move widgets into group |
| `F8` | ungroup widgets |
| `Delete` | delete selected widgets |
| `Ctrl-1..9` | load project from history |
| `Ctrl-A` | select all |
| `Shift-Ctrl-A` | select none |
| `Alt-B` | show or hide Widget Bin |
| `Ctrl-C` | copy widgets |
| `Alt-C` | show or hide Code View window |
| `Shift-Ctrl-C` | generate C++ code files |
| `Ctrl-G` | grid setting dialog |
| `Ctrl-I` | merge project file into current project |
| `Ctrl-N` | start a new project, close the current project |
| `Shift-Ctrl-N` | new project from template |
| `Ctrl-O` | open project file |
| `Shift-Ctrl-O` | toggle overlays |
| `Ctrl-P` | print all visible project windows |
| `Alt-P` | open FLUID settings dialog |
| `Ctrl-Q` | quit FLUID |
| `Ctrl-S` | save project |
| `Shift-Ctrl-S` | save project with new name |
| `Ctrl-U` | duplicate selected widgets |
| `Ctrl-V` | paste last copied widgets |
| `Shift-Ctrl-W` | write i18n translation file |
| `Ctrl-X` | cut selected widgets |
| `Alt-X` | show shell command settings |
| `Ctrl-Z` | undo |
| `Shift-Ctrl-Z` | redo |
<!-- | `Alt-G` | rund last shell command again | -->
| Action | Function in Layout Editor |
| :----: | :------------------------ |
| `left mouse button (LMB)` | select one widget |
| `LMB-drag` | select multiple widgets with selection box |
| `Shift-LMB` | extend widget selection |
| `Shift-LMB-Drag` | toggle selection in selection box |
| `Shift-LMB-Drag` | resize window proportionally |
| `Tab` | select next widget |
| `Shift-Tab` | select previous widget |
| `Arrow` | move selected widgets by one unit |
| `Shift-Arrow` | resize by one unit |
| `Ctrl-Arrow` | move by grid units |
| `Shift-Ctrl-Arrow` | resize by grid units |
<!-- ---------------------------------------------------------------------- -->
\section appendix_fileformat .fl File Format
FLUID edits and saves its state in `.fl` project files. These files are text,
and you can (with care) edit them in a text editor, perhaps to get some special
effects. The `.fl` file format is described in detail in the file
`fluid/README_fl.txt` which is part of the FLTK source code repository.
<!-- ---------------------------------------------------------------------- -->
\section appendix_licenses External Licenses
FLUID uses graphical images based on the Zendesk Garden Stroke icon set:
[https://github.com/zendeskgarden](https://github.com/zendeskgarden)
Garden Stroke is licensed under the
[Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.html).
FLUID includes templates based on 7GUIs:
[7GUIs](https://7guis.github.io/7guis/) was created as a spin-off
of the masters thesis Comparison of Object-Oriented and Functional
Programming for GUI Development by Eugen Kiss at the Human-Computer
Interaction group of the Leibniz Universität Hannover in 2014.
With kind permission by Prof. Dr. Michael Rohs.
*/

View File

@ -0,0 +1,76 @@
/**
\page page_codeview_panel Code View Panel
\tableofcontents
# The Code View Panel #
\image html codeview_panel.png "Code View Panel"
\image latex codeview_panel.png "Code View Panel" width=9cm
The Code View panel shows all code files that can be generated by FLUID.
The Code View window can be activated via the main
menu: *Edit* > *Show Source Code* . FLUID will remember the state and
dimensions of the Code View panel.
If the Auto-Refresh option is selected, the code views will be updated
automatically while editing the project.
Code View has four tabs. The first tab shows the source code. Inlined data
is omitted in the code view for brevity.
The second tab shows the content of the header file. The size of inline data
is not calculated and shown as `-1`.
The third tab shows the list of labels and tooltips as they would be written
to a translation file, using the selected project internationalization method.
The fourth tab previews the contents of the `.fl` project file.
<!-- ---------------------------------------------------------------------- -->
\section codeview_find Code View Find
\image html cv_find_row.png
\image latex cv_find_row.png "Find in Code" width=9cm
This group of buttons makes it easy to find any text in the Source, Header, or
Project file. Press *Reveal* to select the widget that generated the indicated
line of code.
__Find__: enter any text you may want to find in the current tab
__aA__: press this button to activate case sensitive search
__&lt;&lt;__, __&gt;&gt;__: find the previous or next occurrence
__Reveal__: clicking this button reveals the widget that generated the
selected code in the widget browser
<!-- ---------------------------------------------------------------------- -->
\section codeview_settings Code View Settings
\image html cv_settings_row.png
\image latex cv_settings_row.png "Code View Settings" width=9cm
__Refresh__: preview the code in the selected tab as it would be generated
for the project in its current state
__Auto-Refresh__: Automatically refresh the code view when the project changes.
The Auto Refresh is designed to use relatively little resources, even when
continuously updating the selected code tab.
The Code View window can usually stay open and auto refresh during the entire
design process, even for relatively complex GUIs.
__Auto-Position__: highlight and reposition to the source code generated by
the currently selected widget whenever the selection changes
__code...__: choose the type of code that is highlighted. In source
files, *static* code is generated by Menu Items, *code* refers to widget
creation code, *code1* is the part before possible children, *code2* is
code generated after children. In header files, *static* highlights
`#include` statements generated by a widget, *code* refers to
the widget declaration.
*/

View File

@ -0,0 +1,124 @@
/**
\page page_commandline Command Line
\tableofcontents
FLUID can be used in interactive and in command line mode. If launched with
`-c`, followed by a project filename, FLUID will convert the project file
into C++ source files without ever opening a window (or opening an X11 server
connection under Linux/X11). This makes FLUID a great command line tool
for build processes with complex project files that reference
external resources. For example, an image referenced by a `.fl` file can be
modified and recompiled into the application binary without the need to reload
it in an interactive FLUID session.
<!-- ---------------------------------------------------------------------- -->
\section commandline_options Command Line Options
To launch FLUID in interactive mode from the command line, you can give it an
optional name of a project file. If no name is given, it will launch with an
empty project, or with the last open project, if so selected in the
application setting dialog.
The ampersand `&` is optional on Linux machines and lets FLUID run in its
own new process, giving the shell back to the caller.
```
fluid filename.fl &
```
If the file does not exist you will get an error pop-up, but if you dismiss it
you will be editing a blank file of that name.
FLUID understands all of the standard FLTK switches before the filename:
```
-display host:n.n
-geometry WxH+X+Y
-title windowtitle
-name classname
-iconic
-fg color
-bg color
-bg2 color
-scheme schemename
```
<!-- ---------------------------------------------------------------------- -->
\section commandline_passive Compile Tool Options
FLUID can also be called as a command-line only tool to create
the `.cxx` and `.h` file from a `.fl` file directly. To do this type:
```
fluid -c filename.fl
```
This is the same as the menu __File > Write Code...__ .
It will read the `filename.fl` file and write
`filename.cxx` and `filename.h`. Any leading
directory on `filename.fl` will be stripped, so they are
always written to the current directory. If there are any errors
reading or writing the files, FLUID will print the error and
exit with a non-zero code. You can use the following lines in a
Makefile to automate the creation of the source and header
files:
```
my_panels.h my_panels.cxx: my_panels.fl
fluid -c my_panels.fl
```
Most versions of "make" support rules that cause `.fl` files to be compiled:
```
.SUFFIXES: .fl .cxx .h
.fl.h .fl.cxx:
fluid -c $<
```
Check `README.CMake.txt` for examples on how to integrate FLUID into the
`CMake` build process.
If you use
\code
fluid -cs filename.fl
\endcode
FLUID will also write the "strings" for internationalization into the file
'filename.txt', 'filename.po', or 'filename.msg', depending on the chosen type
of i18n (menu: 'File/Write Strings...').
Finally there is another option which is useful for program developers
who have many `.fl` files and want to upgrade them to the current FLUID
version. FLUID will read the `filename.fl` file, save it, and exit
immediately. This writes the file with current syntax and options and
the current FLTK version in the header of the file. Use
```
fluid -u filename.fl
```
to 'upgrade' `filename.fl` . You may combine this with `-c` or `-cs`.
\note All these commands overwrite existing files w/o warning. You should
particularly take care when running `fluid -u` since this overwrites the
original `.fl` project file.
<!-- ---------------------------------------------------------------------- -->
\section commandline_windows Windows Specifics
FLTK uses Linux-style forward slashes to separate path segments in file names.
When running on Windows, FLUID will understand Microsoft drive names and
backward slashes as path separators and convert them internally into
forward slashes.
Under Windows, binaries can only be defined either as command line tools, or
as interactive apps. FLTK generates two almost identical binaries under
Windows. `fluid.exe` is meant to be used in interactive mode, and
`fluid-cmd.exe` is generated for the command line. Both tools do exactly the
same thing, except `fluid-cmd.exe` can use stdio to output error messages.
*/

View File

@ -0,0 +1,179 @@
/**
\page page_edit_window Layout Editor Window
\tableofcontents
\image html edit_window.png "Layout Editor Window"
\image latex edit_window.png "Layout Editor Window" width=7cm
The Layout Editor window is used to interactively add groups and widgets, and
resize and align them. The editor window already looks very much like the
final product that will be built by the FLUID generated C++ source code.
To create a user interface, first add a function to the project tree by either
clicking the Function icon in the widget bin, or by selecting __New* > Code >
Function/Method__ from the main menu.
Now just drag the Window icon from the widget bin onto the desktop. FLUID
will generate code that instantiates this window when the function is called.
The return value of the function is a pointer to that window, unless changed
in the Function Panel. Widgets can be added to the window by dragging them from
the widget bin. If a widget is dropped on a group, it will automatically
become a child of that group.
<!-- ---------------------------------------------------------------------- -->
\section edit_selection Selecting and Moving Widgets
To move or resize a widget, it must be selected first by clicking on it.
Multiple widgets can be selected by holding down the Shift key when clicking
on them, or by dragging a selection box around widgets. Widgets can also be
selected in the widget browser the main window. Shift-click will select a
range of widgets, Ctrl-click will add widgets to the selection.
\image html edit_select_multiple.png
\image latex edit_select_multiple.png "Select Multiple Widgets" width=5cm
Menu items are selected by clicking on the menu button and selecting it from
the popup menu. Multiple menu items can only be selected in the widget browser
in the main application window.
Once selected, widgets can be moved by clicking and dragging the center
of the selection box. The outer edges allow resizing in one direction, and
dragging the corners resizes widgets horizontally and vertically.
Widgets can also be repositioned with the arrow keys. Without a shift key,
the selection moves by a single pixel. With the Meta key held down, they
move by the amount indicated in the *Gap* field in the *Widget* section of
the *Layout* setting panel.
Holding down the Shift key resizes a selected widget by moving the bottom
right corner of the widget. Holding Shift and Meta while pressing arrow keys
resizes by the amount in the *Widget* *Gap* layout setting.
Children of groups that reposition their contained widgets may behave
differently. Pressing the arrow keys on children of `Fl_Grid` will move
the widget from grid cell to grid cell instead. Resizing a child of `Fl_Flex`
will also mark the child size as `fixed`.
The tab and shift+tab keys "navigate" the selection. Tab or shift+tab move to
the next or previous widgets in the hierarchy. If the navigation does not seem
to work you probably need to "Sort" the widgets. This is important if you have
input fields, as FLTK uses the same rules when using tab keys
to move between input fields.
<!-- ---------------------------------------------------------------------- -->
\section edit_layout Layout Helpers
\image html edit_overlap.png
\image latex edit_overlap.png "Overlapping Widgets" width=5cm
In FLTK, the behavior of overlapping children of a group is undefined. If
enabled in the settings, FLUID will show overlapping widgets in a group
with a green hash pattern.
\image html edit_outside.png
\image latex edit_outside.png "Out Of Bounds" width=5cm
The behavior of widgets that reach outside the bounds of their parent group
is also undefined. They may be visible, but confuse the user when they don't
react to mouse clicks or don't redraw as expected. Outside widgets are marked
with a red hash pattern.
Note that `Fl_Tile` requires that all children exactly fill the area of the
tile group to function properly. The hash patterns are great helpers to align
children correctly.
<!-- ---------------------------------------------------------------------- -->
\section edit_snap Layout Alignment
FLUID layouts are a handful of rules that help creating a clean and consistent
user interface. When repositioning widgets, the mouse pointer snaps to the
closest position based on those rules. A guide line is drawn for the rule that was
applied. Guides and snaps can be disabled with `Ctrl-Shift-G` or via the
*Edit* > *Hide Guides* menu.
\image html edit_snap_group.png
\image latex edit_snap_group.png "Snap To Group" width=5cm
If a horizontal or vertical outline snaps to the group, the
border of that group will highlight. If the outline snaps to the margin
of the parent window or group, an additional arrow is drawn.
Children of `Fl_Tabs` use the top and bottom margin from the *Tabs*
section. If all children use this rule, the margin height will also be the
height of all tabs.
\image html edit_snap_sibling.png
\image latex edit_snap_sibling.png "Snap To Sibling" width=5cm
The selection can also snap to the outline of other widgets in the same group,
or to the outline plus the Widget Gap. The outline that triggers the snap
action is highlighted.
Note that only the first snap guide found is drawn for horizontal and vertical
movement. Multiple rules may apply, but are not highlighted.
\image html edit_snap_size.png
\image latex edit_snap_size.png "Snap To Size" width=7cm
Widget size rules define a minimum size and an increment value that may
be applied multiple times to the size. For example, with a minimum width of 25
and an increment of 10, the widget will snap horizontally to 25, 35, 45,
55, etc. .
\image html edit_snap_grid.png
\image latex edit_snap_grid.png "Snap To Grid" width=5cm
The grid rule is the easiest to explain. All corners of a selection snap to
a fixed grid. If the selected widgets are children of a window, they will snap
to the window grid. If they are in a group, they snap to the group grid.
<!-- ---------------------------------------------------------------------- -->
\section edit_resize Live Resize
\image html edit_select_group.png
\image latex edit_select_group.png "Selected Group" width=9cm
The Resizable system within FLTK is smart, but not always obvious. When
constructing a sophisticated GUI, it is helpful to organize widgets into
multiple levels of nested groups. Sometimes, incorporating an invisible
resizable box can improve the behavior of a group. FLUID offers a Live Resize
feature, allowing designers to experiment with resizing at each level within
the hierarchy independently.
To test the resizing behavior of a group, begin by selecting it:
\image html edit_live_resize.png
\image latex edit_live_resize.png "Live Resize" width=7cm
Click on *Live Resize* in the widget panel. FLUID will generate a new window
with all the resizing attributes inherited from the original design. This
enables the designer to thoroughly test the behavior and limitations,
making adjustments until they are satisfied. This streamlined process makes
it significantly easier to address resizing behavior at a higher level,
particularly once the lower levels are behaving as intended.
In the example above, the radio buttons are not fixed to the left side of
the group and the text snippet "of the bed" does not stay aligned
to "right side". To fix this, a thin hidden box could be added to the right
edge of the group that holds the radio button which is then marked `resizable`.
<!-- ---------------------------------------------------------------------- -->
\section edit_limits Limitations
Almost all FLTK widgets can be edited with FLUID. Notable exceptions include
- FLUID does not support an `Fl_Window` inside another `Fl_Window`
- widgets inside `Fl_Scroll` can not be created in the hidden areas of the
scrollable rectangle. It is recommended to organize the children in
a separate Widget Class that is derived from `Fl_Scroll` and then inserted
as a single custom widget.
- children of `Fl_Pack` are not automatically reorganized to fit the packing
group. Again, a Widget Class is recommended here.
- if children of `Fl_Grid` are again some kind of group, their internal layout
may not follow changes in the grid widgets. It's best to complete the grid
first, then add children to the grid cells, size them correctly, and
then finally lay out the grid cell children.
*/

View File

@ -0,0 +1,450 @@
/**
\page page_functional_nodes Functional Node Panels
\tableofcontents
<!-- ---------------------------------------------------------------------- -->
\section functional_function Function and Method Panel
![](flFunction.png) Functions and Methods
Fluid can generate C functions, C++ functions, and methods in classes.
Functions can contain widgets to build windows and dialogs. *Code* nodes can
be used to add more source code to a function.
### Parents ###
To generate a function, the function node must be created at the top level or
inside a declaration block. If added inside a class node, this node generates
a method inside that class.
### Children ###
Function nodes can contain code nodes and windows that in turn contain widgets.
If the function node has no children, only a forward declaration will be
created in the header, but no source code will be generated.
\image html function_panel.png "Function/Method Properties"
\image latex function_panel.png "Function/Method Properties" width=7cm
### Declaring a Function ###
A function node at the top level or inside a declaration block generates a C
or C++ function.
The *Name* field contains the function name and all arguments.
If the *Name* field is left empty, Fluid will generate a typical 'main()' function.
```
// .cxx
int main(int argc, char **argv) {
// code generated by children
w->show(argc, argv); // <-- code generated if function has a child widget
Fl::run();
}
```
If a function node has a name but no children, a forward declaration is
generated in the header, but the implementation in the source file is omitted.
This is used to reference functions in other modules.
```
// .h
void make_window();
```
If the function contains one or more Code nodes, the implementation code will
be generated. The default return type is `void`. Text in the *Return Type* field
overrides the default type.
```
// .cxx
void make_window() {
// code generated by children
}
```
If the function contains one or more windows, a pointer to the first window
will be returned. The default return type will match the window class.
```
// .h
Fl_Window* make_window();
```
```
// .cxx
Fl_Window* make_window() {
Fl_Window* w;
// code generated by children:
// w = new Fl_Window(...)
return w;
}
```
#### Options for Functions ####
Choosing *static* in the pulldown menu will generate the function `static` in
the source file. No forward declaration will be generated in the header file.
```
// .cxx
static Fl_Window* make_window() { ... }
```
Choosing *global* will generate a forward declaration of the function in the
header file and no `static` attribute in the source file.
```
// .h
void make_window();
// .cxx
Fl_Window* make_window() { ... }
```
Additionally,
if the *C* option is checked, the function will be declared as a plain C
function in the header file.
```
// .h
extern "C" { void my_plain_c_function(); }
// .cxx
void my_plain_c_function() { ... }
```
The *local* option will generate a function in the source file with no `static`
attribute. No forward declaration will be generated in the header file.
```
// .cxx
Fl_Window* make_window() { ... }
```
### Declaring a Method ###
A function node inside a class node generates a C++ method. If a method node has
no children, the declaration is generated in the header, but no implementation
in the source file.
```
// .h
class UserInterface {
public:
void make_window();
};
```
If the method contains one or more Code nodes, an implementation will also be
generated.
```
// .cxx
void UserInterface::make_window() {
printf("Hello, World!\n");
}
```
If the method contains at least one widget, a pointer to the topmost widget
will be returned and the return type will be generated accordingly.
```
// .h
class UserInterface {
public:
Fl_Double_Window* make_window();
};
```
```
// .cxx
Fl_Double_Window* UserInterface::make_window() {
Fl_Double_Window* w;
// code generated by children
return w;
}
```
#### Options for Methods ####
Class access can be defined with the pulldown menu. It provides a choice of
`private`, `protected`, and `public`.
Fluid recognizes the keyword `static` or `virtual` at the beginning of the
*return type* and will generate the declaration including the keyword, but will
omit it in the implementation. The return type defaults still apply if there
is no text after the keyword.
#### Further Options ####
Users can define a comment text in the *comment* field. The first line of the
comment will be shown in the widget browser. The comment text will be generated
in the source file before the function.
```
// .cxx
//
// My multilen comment will be here... .
// Fluid may actually use C style comment markers.
//
Fl_Window* make_window() {
```
FLUID recognizes default values in the argument list and generates them in the
declaration, but omits them in the implementation.
A short function body can be appended in the *Name* field. With no child, this
creates an inlined function in the header file.
<!-- ---------------------------------------------------------------------- -->
\section functional_code C Source Code
![](flCode.png) Code
Code nodes hold arbitrary C++ code that is copied verbatim into the
source code file. They are commonly used inside Function nodes.
### Parents ###
Code nodes can be added inside Functions, Code Blocks, and Widget Classes.
\image html code_panel.png "Code Properties"
\image latex code_panel.png "Code Properties" width=9cm
The Code Properties panel features a syntax-highlighting C++ code editor.
Some basic bracket and braces match checking is done when closing the dialog.
When inside a Function or Code Block, the C++ code is inserted directly.
Inside a Widget Class, the code will be added to the constructor of the
widget class.
<!-- ---------------------------------------------------------------------- -->
\section functional_codeblock Code Block
![](flCodeBlock.png) Code Block
Code Blocks are used when a single function generates different GUI elements
conditionally.
### Parents ###
Code Blocks are used inside functions and methods.
### Children ###
Code Blocks can contain widgets, code, or more code blocks.
\image html codeblock_panel.png "Code Block Properties"
\image latex codeblock_panel.png "Code Block Properties" width=7cm
The two fields expect the code before and after the `{ ... }` statements. The
second field can be empty.
Two consecutive Code Blocks can be used to generate `else`/`else if`
statements by leaving the second field of the first node empty.
<!-- ---------------------------------------------------------------------- -->
\section functional_decl Declaration
![](flDeclaration.png) Declaration
### Parents ###
Declarations can be added at the top level or inside classes and widget classes.
\image html decl_panel.png "Declaration Properties"
\image latex decl_panel.png "Declaration Properties" width=7cm
Declaration nodes are quite flexible and can be a simple variable declaration
such as `int i;`. But include statements are also allowed, as are type
declarations, and comments. FLUID does its best to understand user intention,
but the generated code should be verified by the user.
Declarations nodes at the top level can selectively generate code in the header
and /or in the source file. If a declaration is inside a class, the user can
select if the class member is *private*, *protected*, or *public* instead.
<!-- ---------------------------------------------------------------------- -->
\section functional_declblock Declaration Block
![](flDeclarationBlock.png) Declaration Block
Declaration Blocks are a way to selectively compile child nodes via
preprocessor commands, typically `#ifdef TEST` and `#endif`.
### Parents ###
Declaration Blocks can be created at the top level or inside classes.
### Children ###
Declaration Blocks can contain classes, functions, methods, declarations, and
comments.
\image html declblock_panel.png "Declaration Block Properties"
\image latex declblock_panel.png "Declaration Block Properties" width=7cm
Users can select if the block is generated in the source file only, or in the
header file as well. The two input fields are used to enter the line of code
before and after the child nodes. Two consecutive Declaration Blocks can be
used to generate `#else`/`#elif` style code by leaving the second field of
the first node empty.
\note Declaration Blocks are not smart, and child nodes may still generate
unexpected code outside the scope of this block. This may change in future
versions of FLUID.
<!-- ---------------------------------------------------------------------- -->
\section functional_class Classes
![](flClass.png) Class
FLUID can generate code to implement C++ classes. Classes can be used to keep
dialogs and groups of UI elements organized. See Widget Class nodes as an
alternative to implement compound widgets.
### Parents ###
Class nodes can be created at top level or inside a Class or Widget
Class node.
### Children ###
Class nodes can contain Functions, Declarations, Widgets, Data, and
other classes.
\image html class_panel.png "Class Properties"
\image latex class_panel.png "Class Properties" width=7cm
The *Name:* and *Subclass of:* fields should be set to standard C++ class
names.
Function nodes inside classes are implemented as methods. Constructors and
destructors are recognized and implemented as such. Inlined data is declared
as a static class member.
Note that methods without a code or widget node are only declared in the
header file, but no code is generated for them in the source file.
<!-- ---------------------------------------------------------------------- -->
\section functional_widgetclass Widget Class
![](flWidgetClass.png) Widget Class
The Widget Class node creates a new widget type by deriving a class from another
widget class. These are often compound widgets derived from `Fl_Group`. A less
automated but more flexible way to implement compound widgets is the Class node.
### Parents ###
Widget Class nodes can be created at top level or inside a Class or Widget
Class node.
### Children ###
Widget Class nodes can contain Functions, Declarations, Widgets, Data, and
other classes.
### Properties ###
Widget Class nodes use the Widget panel to edit their properties. The super
class can be set in the *C++* tab in the *Class* field. If that field is empty,
FLUID derives from `Fl_Group`.
The Widget Class always creates a constructor with the common widget parameters:
```
MyWidget::MyWidget(int X, int Y, int W, int H, const char *L)
: Fl_Group(X, Y, W, H, L) { ... }
```
If the super class name contains the text `Window`, two more constructors
and a common initializer method are created:
```
MyWidget::MyWidget(int W, int H, const char *L) :
Fl_Window(0, 0, W, H, L) { ... }
MyWidget::MyWidget() :
Fl_Window(0, 0, 480, 320, 0) { ... }
void MyWidget::_MyWidget() { ... }
```
Code and Widget nodes are then added to the constructor. Function nodes are
added as methods to the class. Declarations are added as class members.
Data nodes generate static class members.
It may be useful to design compound widgets with a variable size. The Widget
Panel provides a choice menu in the *GUI* tab's *Position* row under
*Children*. The options *resize* and *reposition* generate code to fix up
the coordinates of the widget after instantiation.
Note that methods without a code or widget node are only declared in the
header file, but no code is generated for them in the source file.
<!-- ---------------------------------------------------------------------- -->
\section functional_comment Comments
![](flComment.png) Comment
This node adds a comment block to the generated source code.
### Parents ###
Comment nodes can be added inside Functions, Code Blocks, and Widget Classes.
If a Comment node is the top node in a tree, it will appear in the source
files even before the `// generated by FLUID ...` line.
\image html comment_panel.png "Comment Properties"
\image latex comment_panel.png "Comment Properties" width=9cm
Comment blocks are generated by adding `// ` to the start of each line unless
the first line of a comment starts with `/``*`. In that case, FLUID assumes
a correct block comment and will copy the text verbatim.
Comments can be generated in the header file, the source file, or both.
FLUID keeps a small database of predefined comments. Users can add reoccurring
comment blocks, license information for example, to this database via the
pulldown menu.
Comments can also be imported from an external file.
<!-- ---------------------------------------------------------------------- -->
\section functional_data Inlined Data
![](flData.png) Inlined Data
The Data node makes it easy to inline data from an external file into the
source code.
### Parents ###
Data nodes can be added at the top level or inside Widget Classes, Classes,
and Declaration Blocks.
\image html data_panel.png "Data Properties"
\image latex data_panel.png "Data Properties" width=7cm
At top level, or inside a Declaration Block, Data can be declared *in source
file only*, *static in source file*, or *in source and extern in header*.
If Data is inside a Class node, it is always declared `static`. The user can
select *private*, *protected*, or *public*.
Data in binary mode will be stored in an `unsigned char` array. The data size
can be queried with `sizeof()`. In Text mode, it will be stored as `const
char*` and terminated with a `NUL` character.
In compressed mode, data will be compressed with zlib `compress()` and stored
in an `unsigned char` array. A second variable, holding the original data size,
is declared `int` by appending `_size` to the variable name.
```
// .cxx
int myInlineData_size = 12034;
unsigned char myInlineData[380] = { 65, 128, ... };
```
The Variable Name should be a regular C++ name. The Filename field expects
the path and name of a file, relative to the location of the .fl file.
*/

View File

@ -0,0 +1,57 @@
/**
\page page_interactive Interactive Mode
\tableofcontents
<!-- ---------------------------------------------------------------------- -->
In interactive mode, FLUID allows users to construct and modify their GUI
design by organizing widgets hierarchically through drag-and-drop actions.
The project windows provide a live preview of the final UI layout.
Most widget attributes can be adjusted in detail using the
\ref page_widget_panel.
Users can also incorporate C++ coding elements such as functions, code blocks,
and classes. FLUID supports the integration of external sources, for
example images, text, or binary data, by embedding them directly into the
generated source code.
\image html fluid_gui_overview_800.png
\image latex fluid_gui_overview_800.png "FLUID Overview"
A typical FLUID session manages the widget hierarchy in the main application
window on the left. The project file name is shown in the title bar. In the
example above, we edit the FLTK _Preferences_ example file
`test/preferences.fl`.
\see \ref page_main_window
The layout editor window left of center, titled
"My Preferences" shows the GUI design as it will be generated by the C++
source file. The widgets "shower", "shave", and "brush teeth" are shown
in their selected state and can now be resized or moved by grabbing any of
the red boxes around the selection frame.
\see \ref page_edit_window
To the right, we have the "Widget Properties" panel. We can use this to
edit many more parameters of the selected widget. If multiple widgets are
selected, changes are applied to all of them where appropriate.
\see \ref page_widget_panel
The Widget Bin at the top is an optional tool bar (__Edit > Show Widget Bin__,
Alt-B). It gives quick access to all widget and code types. Widgets can
be added by clicking onto the tool, or by dragging them out of the tool box
into the layout editor.
\see \ref page_widgetbin_panel
The optional panel on the right shows a live source code preview. This is
very helpful for verifying how changes in the GUI will be reflected in the
generated C++ code (__Edit > Show Code View__, Alt-C).
\see \ref page_codeview_panel
*/

View File

@ -0,0 +1,69 @@
/**
\page page_introduction Introduction
\tableofcontents
<!-- ---------------------------------------------------------------------- -->
\image latex fluid-128.png "FLUID" width=3cm
FLUID, short for Fast Light User Interface Designer, is a graphical editor
capable of generating C++ source code and header files ready for compilation.
These files ultimately create an FLTK based graphical user interface
for an application.
The FLTK programming manual is available at https://www.fltk.org/documentation.php .
This manual provides instructions on launching FLUID as a command line tool
and integrating `.fl` project files into the application build process.
FLTK utilizes _CMake_, but other build systems and IDEs capable of running
external tools can also build applications based on FLUID.
The majority of the manual focuses on using FLUID as an interactive GUI
design tool. It covers an overview of windows, menu items, and dialog boxes,
detailing how to create visually appealing and consistent user experiences
through drag and drop functionality, a "what you see is what you get" editor,
and alignment tools. The \ref page_setting_dialog will detail the process of initiating
a new project, creating an alignment template, and incorporating
internationalization.
Several tutorials will explain how to generate small apps in FLUID alone,
and how to create more complex user interfaces, followed by some advanced
subjects like creating integrated reusable widget classes.
The appendices contain additional technical information for reference.
<!-- ---------------------------------------------------------------------- -->
\section introduction_workflow Workflow
FLUID stores user interface designs within `.fl` project files. These files
are transformed into a binary application through a multi-step process.
Initially, FLUID converts `.fl` files into C++ source and header files.
Subsequently, these files are compiled into object files, which are then
linked with other object files to form an executable binary.
FLUID-generated header files give access to UI elements from other C++ modules
within the project. FLUID can also generate forward declarations to
variables and callback functions that are defined and implemented in other
C++ modules.
\image html fluid_flow_chart_800.png "FLUID Workflow"
\image latex fluid_flow_chart.png "FLUID Workflow"
Small applications can be fully designed and developed with FLUID alone.
Users have the option to include shell scripts in FLUID projects, enabling
them to directly call compilers and linkers to produce the binaries.
For medium-sized projects, a build system such as _CMake_ or an IDE
with integrated build setup is recommended. FLUID in interactive mode
can pre-generate C++ code files for direct compilation by the IDE.
In larger projects, FLUID projects frequently reference external resources
such as graphics, binary data, and internationalized text.
In such scenarios, it is very useful to distribute the `.fl` project files
instead of prebuilt source files. FLUID in command-line mode can then be
called as an external tool, dynamically generating C++ source code from all
external resources at build time.
*/

View File

@ -0,0 +1,371 @@
/**
\page page_main_window Main Application Window
\tableofcontents
\image html main_window.png "Main Application Window"
\image latex main_window.png "Main Application Window" width=5cm
A FLUID project is a hierarchy of nodes. Each node holds information to
generate C++ source code which in turn generates the user interface that
is created in the layout editor windows. Projects usually define one or more
functions. These functions can generate one or more
FLTK windows and all the widgets that go inside those windows.
The FLUID Main Window is split into three parts. The title bar shows the
status of the source and project files. The menu bar provides a wealth of
menu items for all major actions in FLUID. The biggest part of the
app window is the widget browser, a tree structure that lists every code
node and widget in the project.
<!-- ---------------------------------------------------------------------- -->
\section main_titlebar Title Bar
\image html main_titlebar.png
\image latex main_titlebar.png "Title Bar" width=5cm
The title bar shows the status of the project file, _function_panel.fl_ in this
case, followed by an asterisk if the project was changed after it was saved.
If the asterisk shows, FLUID will ask the user to save changes before closing
the project, loading another project, or starting a new one. Pressing `Ctrl-S`
will save the project and make the asterisk disappear.
The _.cxx_ in the title bar reflects the status of header and source files
in relation to the project. A trailing asterisk indicates that the project and code
files differ. Pressing `Ctrl-Shift-C` to write the code files will make this
asterisk go away.
\note FLUID currently supports only one open project at a time.
<!-- ---------------------------------------------------------------------- -->
\section main_menubar Application Menu Bar
\image html main_menubar.png
\image latex main_menubar.png "Main Menu" width=5cm
The menu bar is the true control center of FLUID. All actions start here.
The *File* menu offers the common file operation for FLUID projects. Projects
can be loaded, merged, and saved. *Print* will print a snapshot of all open
project windows.
The *New From Template* item opens a dialog that provides access to a small
number of sample projects. More projects can be added using *Save as Template*.
Use *Write Code* to write the header and source code files, and *Write Strings*
to write the translation file if one of the internationalization options
is active.
The *Edit* menu is mainly used to manipulate widgets within the widget tree.
The bottom entries toggle various dialogs and pop up the settings panel.
The *New* menu holds a list of all widgets that can be used in FLUID. They
are grouped by functionality, very similarly to the widget bin. New widgets are
added inside or right after the selected widget. If the parent widget is not
compatible, FLUID tries to find another location for the widget. If that also
fails, FLUID will pop up a dialog, describing the required parent type.
The *Layout* menu is used to adjust the position and size of widgets in
relation to each other.
The *Shell* menu gives quick access to user definable shell scripts. Note that
scripts can be stored inside `.fl` project files.
\see \ref main_menu_items
<!-- ---------------------------------------------------------------------- -->
\section main_widget_browser Widget Tree View
\image html main_browser.png
\image latex main_browser.png "Widget Browser" width=5cm
Widgets are stored in a hierarchy. You can open and close a level by clicking
the "triangle" at the left of a widget. The leftmost widgets are the
\e parents, and all the widgets listed below them are their \e children.
Parents don't have to have any children.
The top level of the hierarchy is composed of \e functions and
\e classes. Each of these will produce a single C++ public function
or class in the output <tt>.cxx</tt> file. Calling the function or
instantiating the class will create all of the child widgets.
The second level of the hierarchy contains the \e windows.
Each of these produces an instance of class Fl_Window.
Below that are either \e widgets (subclasses of Fl_Widget) or
\e groups of widgets (including other groups). Plain groups are for
layout, navigation, and resize purposes. <i>Tab groups</i> provide the
well-known file-card tab interface.
Widgets are shown in the browser by either their \e name (such
as "Button emergency_btn" in the example), or by their \e type
and \e label (such as "Double_Window "My Main Window"").
You \e select widgets by clicking on their names, which highlights
them (you can also select widgets from any displayed window). You can
select many widgets by dragging the mouse across them, or by using
Shift+Click to toggle them on and off. To select no widgets, click in
the blank area under the last widget. Note that hidden children may
be selected even when there is no visual indication of this.
You \e open widgets by double-clicking on them, or (to open several
widgets you have picked) by typing the F1 key. A control panel will appear
so you can change the widget(s).
Nodes are moved within their group using
`F2` and `F3`. They can be grouped and ungrouped with `F7` and `F8`, and
relocated by selecting them and using cut, copy, and paste.
Every line in the browser has the same basic format. The level of indentation
reflects the depth of a node within the tree.
The triangle appears only in front of nodes that can have children. If it is
white, the group has no children. If it is black, there is at least one child.
If the triangle points to the right, the children are hidden in the tree view.
Click the triangle to reveal all children.
The icon to the right is a small representation of the base type of the node.
Widgets are gray, windows have a blue title bar, and functional nodes are
green. If the widget is static or private, a padlock icon will appear in the
bottom right corner of the type icon.
The content of text fields depends on the node type. If a comment is set, it
appears in green over the text. Widgets combine their type (bold black) and
label text (red), or their C++ name in black (not bold).
All colors and font styles can be customized in the User tab of the
Settings panel.
<!-- ---------------------------------------------------------------------- -->
\section main_menu_items The Main Menu
The "New" menu of the main menu bar is duplicated as a pop-up menu on any
layout editor window. The shortcuts for all the menu items work in any
window. The menu items are:
__File > New (Ctrl+n)__: Close the current project and start a new, empty project.
__File > Open... (Ctrl+o)__: Discard the current editing session and read in a
different `.fl` project file. You are asked for confirmation if you have
changed the current file.
FLUID can also read `.fd` files produced by the Forms and XForms "fdesign"
programs. It is best to _File > Merge_ them instead of opening them. FLUID does
not understand everything in a `.fd` file, and will print a warning message on
the controlling terminal for all data it does not understand. You will probably
need to edit the resulting setup to fix these errors. Be careful not to save
the file without changing the name, as FLUID will write over the `.fd` file
with its own format, which fdesign cannot read!
__File > Insert... (Ctrl+i)__: Insert the contents of another `.fl` file
without changing the name of the current `.fl` file. All the functions (even if
they have the same names as the current ones) are added, and you will have to
use cut/paste to put the widgets where you want.
__File > Save (Ctrl+s)__: Write the current data to the `.fl` file. If the
file is unnamed then FLUID will ask for a filename.
__File > Save As... (Ctrl+Shift+S)__: Ask for a new filename and
save the file.
__File > Save A Copy...__: Save a copy of the `.fl` data to a different file.
__File > Revert...__: Revert the `.fl` data to the previously saved state.
__File > New From Template...__: Create a new user interface design from a
previously saved template. This can be useful for including a predefined
enterprise copyright message for projects, or for managing boilerplate code
for repeating project code.
__File > Save As Template...__: Save the current project as a starting point
for future projects.
__File > Print... (Ctrl-P)__: Generate a printout containing all currently
open windows within your project.
__File > Write Code (Ctrl+Shift+C)__: Write the GUI layout as a `.cxx` and
`.h` file. These are exactly the same as the files you get when you run
FLUID with the `-c` switch.
The output file names are the same as the `.fl` file, with the leading directory
and trailing ".fl" stripped, and ".h" or ".cxx" appended.
__File > Write Strings (Ctrl+Shift+W)__: Write a message file for all of the
text labels and tooltips defined in the current file.
The output file name is the same as the `.fl` file, with the leading directory
and trailing ".fl" stripped, and ".txt", ".po", or ".msg" appended depending on
the \ref setting_i18n "Internationalization Mode".
__File > Quit (Ctrl+q)__: Exit FLUID. You are asked for confirmation if you
have changed the current file.
__Edit > Undo (Ctrl+z)__ and __Redo (Shift+Ctrl+z)__: FLUID saves the project
state for undo and redo operations after every major change.
__Edit > Cut (Ctrl+x)__: Delete the selected widgets and all of their children.
These are saved to a "clipboard" file and can be pasted back into any
FLUID window.
__Edit > Copy (Ctrl+c)__: Copy the selected widgets and all of their children
to the "clipboard" file.
__Edit > Paste (Ctrl+v)__: Paste the widgets from the clipboard file.
If the widget is a window, it is added to whatever function
is selected, or contained in the current selection.
If the widget is a normal widget, it is added to whatever
window or group is selected. If none is, it is added to the
window or group that is the parent of the current selection.
To avoid confusion, it is best to select exactly one widget
before doing a paste.
Cut/paste is the only way to change the parent of a
widget.
__Edit > Duplicate (Ctrl-u)__: Duplicate all currently selected widgets and
insert the duplicates after the last selected widget.
__Edit > Delete__: Delete all selected widgets.
__Edit > Select All (Ctrl+a)__: Select all widgets in the same group as the
current selection.
If they are all selected already then this selects all
widgets in that group's parent. Repeatedly typing `Ctrl+a` will
select larger and larger groups of widgets until everything is
selected.
__Edit > Properties... (F1 or double click)__: Display the current widget in
the widgets panel. If the widget is a window and it is not visible then the
window is shown instead.
__Edit > Sort__: Sort the selected widgets into left to right, top to bottom
order. You need to do this to make navigation keys in FLTK work correctly.
You may then fine-tune the sorting with "Earlier" and "Later". This does not
affect the positions of windows or functions.
__Edit > Earlier (F2)__: Move all of the selected widgets one earlier in order
among the children of their parent (if possible). This will affect navigation
order, and if the widgets overlap it will affect how they draw, as the later
widget is drawn on top of the earlier one. You can also use this to reorder
functions, classes, and windows within functions.
__Edit > Later (F3)__: Move all of the selected widgets one later in order
among the children of their parent (if possible).
__Edit > Group (F7)__: Create a new Fl_Group and make all the currently
selected widgets children of it.
__Edit > Ungroup (F8)__: Delete the parent group if all the children of a
group are selected.
__Edit > Show or Hide Overlays (Ctrl+Shift+O)__: Toggle the display of the
red overlays off, without changing the selection. This makes it easier to see
box borders and how the layout looks. The overlays will be forced back on if
you change the selection.
__Edit > Show or Hide Guides (Ctrl+Shift+G)__: Guides can be used to arrange a
widget layout easily and consistently. They indicate preferred widget
positions and sizes with user definable margins, grids, and gap sizes. See
the "Layout" tab in the "Settings" dialog, \ref setting_layout.
This menu item enables and disables guides and the snapping action when dragging
widgets and their borders.
__Edit > Show or Hide Restricted (Ctrl+Shift+R)__: The behavior of overlapping
widgets in FLTK is undefined. By activating this button, a hatch pattern is
shown, highlighting areas where restricted or undefined behavior may occur.
__Edit > Show or Hide Widget Bin (Alt+B)__: The widget bin provides quick
access to all widget types supported by FLUID. Layouts can be created by
clicking on elements in the widget bin, or by dragging them from the bin to
their position within the layout. This button shows or hides the widget bin.
__Edit > Show or Hide Code View (Alt+C)__: Shows or hide
the source code preview window. Any changes to the layout or code in the layout
editor can be previewed and verified immediately in the Code View window.
__Edit > Settings... (Alt+p)__: Open the application and project settings
dialog: \ref page_setting_dialog
__New > Code > Function__: Create a new C function. You will be asked for a
name for the function. This name should be a legal C++ function
template, without the return type. You can pass arguments which
can be referred to by code you type into the individual widgets.
If the function contains any unnamed windows, it will be
declared as returning an Fl_Window pointer. The unnamed window
will be returned from it (more than one unnamed window is
useless). If the function contains only named windows, it will
be declared as returning nothing (\c void ).
It is possible to make the <tt>.cxx</tt> output be a
self-contained program that can be compiled and executed. This
is done by deleting the function name so
\p main(argc,argv) is used. The function will call
\p show() on all the windows it creates and then call
\p Fl::run(). This can also be used to test resize
behavior or other parts of the user interface.
You can change the function name by double-clicking on the
function.
\see \ref functional_function
__New > Group > Window__: Create a new Fl_Window widget. The window is added
to the currently selected function, or to the function containing the currently
selected item. The window will appear, sized to 480x320. You can resize it to
whatever size you require.
The widget panel will also appear and is described later in
this chapter.
__New > ...__: All other items on the New menu are subclasses of
`Fl_Widget`. Creating them will add them to the
currently selected group or window, or the group or window
containing the currently selected widget. The initial
dimensions and position are chosen by copying the current
widget, if possible.
When you create the widget you will get the widget's control
panel, which is described later in this chapter.
__Layout > Align > ...__: Align all selected widgets to the first widget in
the selection.
__Layout > Space Evenly > ...__: Space all selected widgets evenly inside the
selected space. Widgets will be sorted from first to last.
__Layout > Make Same Size > ...__: Make all selected widgets the same size as
the first selected widget.
__Layout > Center in Group > ...__: Center all selected widgets relative to
their parent widget
__Layout > Grid and Size Settings... (Ctrl+g)__: Display the grid settings
panel. See \ref setting_layout .
This panel controls dimensions that all widgets snap to when you move
and resize them, and for the "snap" which is how far a widget has to be
dragged from its original position to actually change.
Layout preferences are defined using margins to parent groups and windows, gaps
between widget, and/or by overlaying a grid over a group or window. A layout
comes as a suite of three presets, one for the main application window, one
for dialog boxes, and one for toolboxes.
FLUID comes with two included layout suites. `FLTK` was used to design FLUID and
other included apps, and `Grid` is a more rigid grid layout. Users can add
more suites, import and export them, and include them into their `.fl`
project files.
__Shell > Customize... (Alt+x)__: Displays the shell command settings panel.
Shell commands are commonly used to run a 'make' script to compile the FLUID
output. See \ref setting_shell .
__Help > About FLUID__: Pops up a panel showing the version of FLUID.
*/

View File

@ -0,0 +1,338 @@
/**
\page page_setting_dialog Settings Dialog
\tableofcontents
<img src="w_settings.png" align="left" hspace="10" vspace="10" />
\image latex w_settings.png "Settings Dialog" width=7cm
The *Settings* dialog combines application preferences
and project settings in a compact set of six tabs.
The *General* tab contains a collection of application wide settings. They are
stored as user preferences.
The *Project* tab holds settings for the current project. They are saved with
the `.fl` file.
The *Layout* tab manages databases of preferred widget alignment. These
preferences can be saved per user, or as part of the project, or exported for
use in other projects.
The *Shell* tab manages a database of quick access shell commands and scripts.
Shell commands can be saved as a user preference and also as part of the
`.fl` project file.
The *Locale* tab sets the method of internationalizing texts in the project,
commonly used for labels and tooltips.
The *User* tab manages customization of fonts and colors in the widget browser.
These settings are stored as user preferences.
<div style="clear:both;"></div>
<!-- ---------------------------------------------------------------------- -->
\section setting_general Application Settings
<img src="w_settings_general_tab.png" align="left" hspace="10" vspace="10" />
\image latex w_settings_general_tab.png "General Settings Tab" width=7cm
__Scheme__:
Select one of the graphics schemes built into FLTK. It's helpful
to verify the look of various schemes for an application design.
__Options__:
Various options to make life as a developer more convenient.
__Recent Files__:
FLUID keeps track of recently opened files.
__External Editor__:
Users that don't like the built-in FLUID code editor can enter a shell command
here that opens the content of Code nodes in an external editor. FLUID does
its best to pick up on changed content or when the editor is closed.
__Overlays__:
The *Position Guides* are little red arrows that indicate if snap points are
found. See the *Layout* tab for details. *Restricted Areas* are areas where
widgets from within the same group overlap. They are visible in the project
window as a diagonally hashed pattern. *Ghosted Group Outlines* show faint
frames around groups that would otherwise be invisible in the project window.
<div style="clear:both;"></div>
<!-- ---------------------------------------------------------------------- -->
\section setting_project Project Settings
<img src="w_settings_project_tab.png" align="left" hspace="10" vspace="10" />
\image latex w_settings_project_tab.png "Project Settings Tab" width=7cm
__Header File__, __Code File__:
These fields are used to build the file path and name of the generated header
and source file. If one field is empty the value defaults to `.h` and `.cxx`
respectively. If a name starts with a `.`, FLUID assumes that the rest of the
text is a file extension. The code file name is then generated by replacing
the extension of the `.fl` project file name.
\todo Document the exact way the source and header file paths are calculated
for interactive FLUID, and for FLUID launched from the command line.
__Include Header from Code__:
If checked, the statement to include the header file is automatically
generated in one of the first lines of the source file.
__Menu shortcuts use FL_COMMAND__:
Setting this option will replace FL_CTRL and FL_META as a modifier for
shortcuts with the platform aware modifiers FL_COMMAND and FL_CONTROL, making
shortcuts more portable between macOS and Windows/Linux.
__allow Unicode__:
If unchecked, Unicode characters in strings are escaped. If checked, the Unicode
character is stored in the source code in UTF-8 encoding.
__avoid early include__:
FLUID by default includes `<FL/Fl.H>` early in the header file. If this option
is checked, users can include other files before including the FL header. The
user must then include `<FL/Fl.H>` later using a Declaration node.
<div style="clear:both;"></div>
<!-- ---------------------------------------------------------------------- -->
\section setting_layout Layout Preferences
<img src="w_settings_layout_tab.png" align="left" hspace="10" vspace="10" />
\image latex w_settings_layout_tab.png "Layout Settings Tab" width=7cm
Layouts are a collection of hints that help when interactively positioning and
resizing widgets in the project window. Layouts come in a set of three for
the application window, for dialog boxes, and for toolboxes.
__Layout__:
The layout pulldown menu lets users choose from a list of existing layouts.
The plus button creates a new set of layouts based on the currently selected
layout.
The pulldown menu has items to rename, load, and save layouts. It can also
change the location where the layout is stored. The FLUID beaker is for
layouts that are predefined in FLUID, the portrait icon stores as user
preference, the document
icon stores the layout in the `.fl` file, and the disk icon lets users store
layout in external files.
__Window Margin and Grid__:
Snap widget position to that margin in relation to the window. The grid
snaps widgets to fixed intervals.
__Group Margin and Grid__:
Snap widget position to that margin in relation to the group. The grid
snaps widgets to fixed intervals relative to the top left of the group.
__Tabs Margin__:
Snap the tab inside `Fl_Tabs` to the tab border and the offset given in
Margins.
__Widget Minimum, Increment, and Gap__:
_Minimum_ sets the minimal width of a widget. _Increment_ is the size multiplier
added to the _Minimum_ value. _Gap_ is the preferred distance to other widgets
in the same group.
__Label Font__, __Text Font__:
The preferred label and text font and size for new widgets.
<div style="clear:both;"></div>
<!-- ---------------------------------------------------------------------- -->
\section setting_shell Shell Commands
<img src="w_settings_shell_tab.png" align="left" hspace="10" vspace="10" />
\image latex w_settings_shell_tab.png "Shell Settings Tab" width=7cm
__Shell Command List__:
A list of all currently available shell commands. The portrait symbol in front
of the name indicates that the script is stored in the user preferences. The
document symbol saves them within the `.fl` project file.
`[+]` adds a fresh new script to the list, `[++]` duplicates the currently
selected script. `[DEL]` deletes it, and `[v]` offers import and export
functionality. The `[T]` button shows the terminal window, and finally the
`[Run]` button runs the selected shell script.
Selecting a shell script will fill in the bottom half of the dialog.
__Name__:
This is the name of the script as it appears in the Shell Command List.
__Menu Label__:
Shell scripts that match the *Condition* flag are also available for quick
access in the *Shell* menu in the main window and via shortcut key
combinations. This is the text that is used for the menu entry.
__Shortcut__:
Assign a keyboard shortcut to this shell script for even faster access. FLUID
does not check if a shortcut is already used elsewhere. Try to avoid
collisions, especially when the script is part of a project file.
__Store__:
Choose where to store the settings of this shell script, either in the user
preferences or as part of the `.fl` project file.
__Condition__:
Shell scripts can be quite different for different platforms hosting FLUID.
This choice limits scripts to specific platforms. Multiple scripts can have
the same shortcut if they have different conditions.
__Shell Script__:
This is a text field for the shell script. The `[v]` pulldown menu has a list
of variables that are replaced with the corresponding value before running
the script. The zoom button gives access to a much larger shell script editor.
The options below are a list of actions that can be executed before running
the script.
<div style="clear:both;"></div>
<!-- ---------------------------------------------------------------------- -->
\section setting_i18n Internationalization
The *Locale* tab can be used to configure optional internationalization.
FLUID supports GNU `gettext` and POSIX `catgets`.
FLUID supports internationalization (I18N for short) of label
strings and tooltips used by widgets. The GNU gettext option also
supports deferred translation of statically initialized menu item
labels. The setting panel (`Alt+p`) provides access
to the I18N options.
\image html w_settings_i18n_gnu.png
\image latex w_settings_i18n_gnu.png "I18N With GNU gettext" width=7cm
FLUID supports three methods of I18N: none, GNU
gettext, and POSIX catgets. The "none" method is the
default and just passes the label strings as-is to the widget
constructors.
The "GNU gettext" method uses GNU gettext (or a similar
text-based I18N library) to retrieve a localized string before
calling the widget constructor.
The GNU gettext option adds some preprocessor code to the source file:
```
#include <libintl.h>
#ifndef gettext_noop
# define gettext_noop(text) text
#endif
```
and the gettext call around strings in the source code:
```
new Fl_Button(50, 50, 54, 40, "Button");
// ->
new Fl_Button(50, 50, 54, 40, gettext("Button"));
```
FLUID's code support for GNU gettext is limited to calling a
function or macro to retrieve the localized label; you still
need to call \p setlocale() and \p textdomain() or
\p bindtextdomain() to select the appropriate language and
message file.
__Include__: controls the header file to include for
I18N; by default this is \b <libintl.h>, the
standard I18N file for GNU gettext.
__Conditional__: If this field contains a macro name, i18n will only be
compiled into the product if this macro is defined. The build system should
define the macro only if all required headers and libraries are available. If
the macro is not defined, no headers are included and `gettext` passes text
through untranslated.
__Function__: controls the function (or macro) that will retrieve the localized
message; by default the \p gettext function will be called.
__Static Function__: names a macro that will mark static text fields for
extraction with the `xgettext` tool. The default macro name is
\p gettext_noop and will be defined as `#define gettext_noop(text) text`
right after the `#include` statement. FLUID will call `gettext` on static
texts later, after the textdomain was set by the user.
\see [GNU gettext special cases](https://www.gnu.org/software/gettext/manual/html_node/Special-cases.html)
\image html w_settings_i18n_psx.png
\image latex w_settings_i18n_psx.png "I18N With POSIX catgets" width=7cm
The "POSIX catgets" method uses the POSIX catgets function to
retrieve a numbered message from a message catalog before
calling the widget constructor.
FLUID's code support for POSIX catgets allows you to use a
global message file for all interfaces or a file specific to
each <tt>.fl</tt> file; you still need to call
\p setlocale() to select the appropriate language.
This option adds some preprocessor code to the source file:
```
#include <nl_types.h>
// Initialize I18N stuff now for menus...
#include <locale.h>
static char *_locale = setlocale(LC_MESSAGES, "");
static nl_catd _catalog = catopen("", 0);
```
and the catgets call around strings in the source code:
```
new Fl_Button(50, 50, 54, 40, "Button");
// ->
new Fl_Button(50, 50, 54, 40, catgets(_catalog,1,6,"Button"));
```
__Include__: controls the header file to include for
I18N; by default this is \b <nl_types.h>, the
standard I18N file for POSIX catgets.
__Conditional__: include the header file only if this preprocessor macro is
defined.
__Catalog__: controls the name of the catalog file
variable to use when retrieving localized messages; by default
the file field is empty which forces a local (static) catalog
file to be used for all of the windows defined in your
<tt>.fl</tt> file.
__Set__: controls the set number in the catalog file.
The default set is 1 and rarely needs to be changed.
<!-- ---------------------------------------------------------------------- -->
\section setting_user User Interface Preferences
<img src="w_settings_user_tab.png" align="left" hspace="10" vspace="10" />
\image latex w_settings_user_tab.png "User Settings Tab" width=7cm
This tab lets users change the font and color of text in the widget browser.
The settings are stored in the user preferences.
All changes are directly visible in the widget browser.
<div style="clear:both;"></div>
*/

Some files were not shown because too many files have changed in this diff Show More