mirror of https://github.com/fltk/fltk
546 lines
19 KiB
Plaintext
546 lines
19 KiB
Plaintext
|
||
FLUID .fl file format version 1.4
|
||
=================================
|
||
|
||
This text explains the history of the FLUID .fl format and faithfully describes
|
||
all elements of the format and its caveats.
|
||
|
||
|
||
History
|
||
-------
|
||
|
||
FLUID, the Fast Light User Interface Designer was started in the 1990's loosely
|
||
based on 'fdesign', a GUI designer that came with the 'Forms Library', later
|
||
'XForms Library'. FLUID's .fl file format was originally compatible with the
|
||
fdesign '.fd' format, but evolved somewhat ad hoc to become what it is today.
|
||
|
||
|
||
Basics
|
||
======
|
||
|
||
FLUID is a visual editor, storing the user interface description in .fl files
|
||
with the ability to create ready-to-compile C++ code. FLUID can also be used
|
||
as a command line tool to translate .fl files directly into source code. It
|
||
can be integrated into build scripts and most IDEs as an external tool.
|
||
|
||
.fl files describe a hierarchical graphical user interface for the 'FLTK'
|
||
library as a tree structure. Elements in the tree can be FLTK Widgets as well
|
||
as functional components like classes, C++ functions, variables, etc. .
|
||
FLUID calls all elements in the hierarchy 'Type'.
|
||
|
||
|
||
Line Endings
|
||
------------
|
||
|
||
Although FLUID writes all line endings as '\n', readers should tolerate '\r\n'
|
||
MSWindows line endings as well. Except for the Header, the FLUID reader does not
|
||
differentiate between a line ending and a space character outside of a 'word'.
|
||
|
||
|
||
Unicode
|
||
-------
|
||
|
||
FLUID does not handle UTF-8 characters in any special manner (unescaped),
|
||
but stores and reads them verbatim, making UTF-8 character sequences perfectly
|
||
legal in .fl files. FLUID can translate UTF-8 into escape sequence when writing
|
||
source code files.
|
||
|
||
|
||
File Structure
|
||
--------------
|
||
|
||
.fl files start with a 'Header', followed by a list of 'Options', followed
|
||
by a hierarchy of 'Type' entries, the 'Tree'. All elements besides the Header
|
||
are composed of 'Words', 'Strings', and 'Groups'.
|
||
|
||
|
||
Words
|
||
-----
|
||
|
||
Words can be any sequence of ASCII and UTF-8 characters. Words are always
|
||
case-sensitive.
|
||
|
||
Simple Words that are composed of 'a'-'z', 'A'-'Z', '0'-'9', and '_' only are
|
||
written verbatim, followed by a space or newline.
|
||
|
||
All other character sequences are bracketed between between ‘{‘ and ‘}’ without
|
||
padding spaces. For example, an empty word with no characters is written
|
||
as '{}', and ".hello" is written as '{.hello}'.
|
||
|
||
The special characters ‘\’ and ‘#’ are escaped by prepending the ‘\’ character,
|
||
so "#define" is written as '{\#define}`.
|
||
|
||
The characters ‘{‘ and ‘}’ are also escaped with a '\' unless every opening
|
||
‘{‘ in the Word is matched with a closing ‘}’.
|
||
|
||
Note: line endings and the following indents are copied verbatim and become
|
||
significant within a Word.
|
||
|
||
|
||
Strings
|
||
-------
|
||
|
||
Strings are generated with 'printf' statements in the hope that the
|
||
generated text can be read back as one Word, set against a corresponding
|
||
'scanf' to retrieve the original values.
|
||
|
||
Note: As there are no defined start and end markers to a String, a reader must
|
||
know when these Strings appear and be prepared to read them correctly,
|
||
even if the String itself is not useful to the reader.
|
||
|
||
Note: All Strings that are generated by the current FLUID source code
|
||
can be read back as a single Word.
|
||
|
||
|
||
Groups
|
||
------
|
||
|
||
To create a hierarchy, Types can be grouped within Types. A Group starts with
|
||
a lone '{' and ends with a lone '}'.
|
||
|
||
Note: To know whether a '{' character starts a Word or a Group, the reader must
|
||
know its position within the Type sequence (see 'Types' below).
|
||
|
||
|
||
Elements
|
||
========
|
||
|
||
|
||
Header
|
||
------
|
||
|
||
The Header for any .fl file is
|
||
|
||
# data file for the Fltk User Interface Designer (fluid)
|
||
|
||
followed by a newline, followed by
|
||
|
||
version <float v>
|
||
|
||
wehere 'v' is the version number as in FL_VERSION (major*1.0 + minor * 0.01
|
||
+ patch * 0.0001). So for FLTK 1.3.4, 'v' would be 1.0304
|
||
|
||
Note: the version number corresponds not so much to the version of FLUID, but
|
||
to the version of the underlying FLTK library. So unless the version of
|
||
FLTK is finalised, the file format in the GitHub master branch can still
|
||
change unexpectedly.
|
||
|
||
Note: if the version number is above the internal version number, FLUID will
|
||
report an error and continue reading, hoping for the best.
|
||
There are no other uses inside the FLUID reader except for features for
|
||
the discontinued fltk2 which is beyond the scope of this document.
|
||
|
||
Note: fdesign files (.fd) start with the text "Magic:". FLUID can read these
|
||
files, but Forms/XForms files are beyond the scope of this document.
|
||
|
||
|
||
Options
|
||
-------
|
||
|
||
Options are usually comprised of a Word, two Words, or a Word and a String. If
|
||
an Option is missing, a default value is assumed.
|
||
|
||
"Magic:" : used by fdesign, not written by FLUID
|
||
|
||
"define_in_struct" : no longer used
|
||
|
||
"do_not_include_H_from_C" : don’t generate #include “myDesign.h”
|
||
|
||
"use_FL_COMMAND" : use macOS CMD key instead of Ctrl
|
||
|
||
"utf8_in_src" : allow UTF-8 when writing source code, otherwise
|
||
escape UTF-8 sequences in source code
|
||
|
||
"avoid_early_includes" : generate the '#include <FL/Fl.H>' statement late
|
||
|
||
"i18n_type" <word> : integer 0=default=none, 1=gettext, 2=catgets
|
||
|
||
--- the following list is valid until June 2023
|
||
|
||
"i18n_function" <word> : function name, e.g. “gettext”
|
||
|
||
"i18n_static_function" <word> : function name, e.g. “gettext_noop”
|
||
|
||
"i18n_file" <word> : file name
|
||
|
||
"i18n_set" <word> : string
|
||
|
||
--- the following list is valid from June 2023
|
||
|
||
"i18n_gnu_function" <word> : function name, e.g. “gettext”
|
||
|
||
"i18n_gnu_static_function" <word> : function name, e.g. “gettext_noop”
|
||
|
||
"i18n_pos_file" <word> : file name
|
||
|
||
"i18n_pos_set" <word> : string
|
||
|
||
--- end of June 2023 changes
|
||
|
||
"i18n_include" <word> : file name, e.g. “<libintl.h>”
|
||
|
||
"i18n_conditional" <word> : string
|
||
|
||
"header_name" <word> : can be the full filename, or just the
|
||
extension e.g. “.h” in which case FLUID will use the same filename
|
||
as the .fl file.
|
||
|
||
"code_name" <word> : can be the full filename, or just the
|
||
extension e.g. “.cxx”
|
||
|
||
"snap" <word> : starting in V1.4 from May 2023, the 'snap' keyword can be
|
||
used to store the selected layout and preset and include more suites
|
||
of presets. The following block can be skipped by reading it as a
|
||
single word. The format looks like this:
|
||
|
||
snap { optional snap Word since 5.2023
|
||
ver 1 version of following data
|
||
current_suite {My Test} opt. name of suite selected at save time
|
||
current_preset 1 opt. preset selected within suite
|
||
suite { optional suite store within project
|
||
name {MyLayout v0.3} name of the layout
|
||
preset { 1 3x preset, preset version
|
||
(24 integers) values representing the layout preset
|
||
}
|
||
... (two more presets)
|
||
}
|
||
... (opt. more suites)
|
||
}
|
||
|
||
"gridx" <word> : ignored
|
||
|
||
"gridy" <word> : ignored
|
||
|
||
"shell_commands" <word> : starting in V1.4 from Sep 2023, the 'shell_commands'
|
||
keyword can be used to store user configurable shell commands in a
|
||
project file. The following block can be skipped by reading it as a
|
||
single word.
|
||
|
||
shell_commands {
|
||
command {
|
||
name <string>
|
||
label <string>
|
||
shortcut <int> (optional if not 0)
|
||
condition <int> (optional if not 0, see Fd_Shell_Command enum)
|
||
condition_data <string> (optional if not "")
|
||
command <string> (optional, but usually there)
|
||
flags <int> (optional if not 0, see Fd_Shell_Command 2nd enum)
|
||
} ( repeat as needed)
|
||
}
|
||
|
||
Note: There is no keyword that marks the end of the Options section. The
|
||
Option list ends when a Word is not in the Options list and it is in
|
||
the list of known Types.
|
||
|
||
If the Word is neither an Option nor a vaild Type, FLUID will give an
|
||
error message and try to continue to read the file. Using new Option
|
||
keywords makes .fl files incompatible to earlier versions of FLUID.
|
||
Due to the forgiving interpreter, files may still be read correctly
|
||
despite error messages.
|
||
|
||
If a Word is in the list of known Types, the Type is read, including
|
||
optional children. No more Options are allowed beyond this point.
|
||
|
||
|
||
Tree
|
||
====
|
||
|
||
If a keyword is read that is not in the Option list, we start reading Types.
|
||
Types represent all possible entries in the hierarchy including C functions,
|
||
class definitions, and of course all Widgets. A Type is any of the supported
|
||
Widgets classes, or one of the following (case sensitive):
|
||
|
||
Function, code, codeblock, decl, data, declblock, comment, class, widget_class
|
||
|
||
Every Type keyword is followed by a Word, which is usually interpreted as the
|
||
C++ name of the Type, followed by an opening `{`, a list of properties, and
|
||
a closing ‘}’. If the Type has children, they are stored in a Group between
|
||
another opening ‘{‘, followed by a list of Types, followed by a closing ‘}’.
|
||
|
||
Fl_Group MyGroup { Type name start_of_options
|
||
label Surprise ... Option parameter
|
||
} { end_of_options start_of_children
|
||
Fl_Button {} { Type name start_of_options
|
||
label {Don't panic...!} Option parameter
|
||
hide Option
|
||
} end_of_options
|
||
} end_of_children
|
||
|
||
The file ends when there are no more Types.
|
||
|
||
Note: the "class" Type may have an additional Word following immediately after
|
||
the keyword. It contains the prefix for the class. A class definition may
|
||
be written as:
|
||
|
||
class FL_EXPORT MyClass { ...properties... } { ...children... }
|
||
|
||
or without a prefix as
|
||
|
||
class MyOtherClass { ...properties... } { ...children... }
|
||
|
||
According to the source code, we know if the word after class is a prefix
|
||
if the next word is not a lone '{'. We apologize for the inconvenience.
|
||
|
||
|
||
Types
|
||
-----
|
||
|
||
Type names are based on FLTK class names. Types derive properties from super
|
||
Types loosely similar to FLTK.
|
||
|
||
Note: the hierarchical dependency is implemented twice and somewhat conflicting
|
||
in FLUID via the Fl_..._Type hierarchy, and by using '::is_some_type()'
|
||
virtual functions, which does not always match the Type hierarchy.
|
||
|
||
|
||
The list of known Types and their inheritance is:
|
||
|
||
Fl_Type (note: can't be written)
|
||
+-- Function
|
||
+-- code
|
||
+-- codeblock
|
||
+-- decl
|
||
+-- data
|
||
+-- declblock
|
||
+-- comment
|
||
+-- class
|
||
+-- Fl_Widget (note: can't be written)
|
||
| +-- Fl_Window
|
||
| | +-- widget_class
|
||
| +-- Fl_Group
|
||
| | +-- Fl_Pack
|
||
| | +-- Fl_Flex
|
||
| | +-- Fl_Table
|
||
| | +-- Fl_Tabs
|
||
| | +-- Fl_Scroll
|
||
| | +-- Fl_Terminal
|
||
| | +-- Fl_Tile
|
||
| | +-- Fl_Wizard
|
||
| | +-- Fl_Grid
|
||
| +-- Fl_Menu_Type (note: can't be written)
|
||
| | +-- Fl_Menu_Button
|
||
| | +-- Fl_Choice
|
||
| | +-- Fl_Input_Choice
|
||
| | +-- Fl_Menu_Bar
|
||
| | +-- Fl_
|
||
| +-- Fl_Box
|
||
| +-- Fl_Button
|
||
| | +-- Fl_Return_Button
|
||
| | +-- Fl_Light_Button
|
||
| | +-- Fl_Check_Button
|
||
| | +-- Fl_Round_Button
|
||
| +-- Fl_Repeat_Button
|
||
| +-- Fl_Browser
|
||
| +-- Fl_Check_Browser
|
||
| +-- Fl_Tree
|
||
| +-- Fl_File_Browser
|
||
| +-- Fl_Counter
|
||
| +-- Fl_Spinner
|
||
| +-- Fl_Input
|
||
| | +-- Fl_Output
|
||
| +-- Fl_File_Input
|
||
| +-- Fl_Text_Display
|
||
| +-- Fl_Text_Editor
|
||
| +-- Fl_Clock
|
||
| +-- Fl_Help_View
|
||
| +-- Fl_Progress
|
||
| +-- Fl_Adjuster
|
||
| +-- Fl_Dial
|
||
| +-- Fl_Roller
|
||
| +-- Fl_Slider
|
||
| | +-- Fl_Scrollbar
|
||
| | +-- Fl_Value_Slider
|
||
| +-- Fl_Value_Input
|
||
| +-- Fl_Value_Output
|
||
.
|
||
|
||
|
||
Properties
|
||
----------
|
||
|
||
Properties have zero or one Words as their arguments. The number of arguments
|
||
are defined per property per Type. The content of the argument Word is defined
|
||
by the implementation of the property and can contain mutiple values, as
|
||
described above in Strings.
|
||
|
||
Properties are inherited from super Types. They can be limited to certain Types
|
||
by calls to 'MyType->is_some_type()'. All properties are optional, some are
|
||
mutually exclusive.
|
||
|
||
Note: It is possible that the same property by name has different arguments
|
||
when used in a different Type.
|
||
|
||
Every node can have properties that it holds for its parent. Parent properties
|
||
are stored as "parent_properties { ...list... }". If a node encounters this
|
||
property tag, it must ask its parent to interpret the contents of that list.
|
||
See Fl_Grid for an example.
|
||
|
||
Type Fl_Type <word>
|
||
|
||
"uid" <4-digit-hex> : since Oct 2023, optional, a unique id for this node
|
||
within the project file
|
||
“label” <word> : text
|
||
“user_data” <word> : a value or an expression
|
||
“user_data_type” <word> : usually “void*” or “long”
|
||
“callback” <word> : a function name or a function body
|
||
“comment” <word> : one or many lines of text
|
||
“open” : Group content visible in the FLUID tree browser
|
||
“selected” : Type was selected in tree view
|
||
|
||
Type "Function" <word> : function signature
|
||
|
||
none or "private" or "protected" : for methods in classes, or to mark
|
||
functions static in a file, default is public
|
||
“C” : if set, function is extern “C”
|
||
“return_type” <word> : C or C++ type descriptor, can start with “virtual”
|
||
and/or “static” to further define the function.
|
||
... : inherits more from Fl_Type
|
||
|
||
Type codeblock <word> : C++ code, for example "if (test())"
|
||
|
||
"after" <word> : C++ code or comment following the closing '}'
|
||
... : inherits more from Fl_Type
|
||
|
||
Type "decl" <word> : C++ code to declare a variable or class member
|
||
|
||
none or "public" or "private" or "protected" : for declarations within classes
|
||
defaults to "private"
|
||
none or "local" or "global": for declaration in the code body
|
||
defaults to "global"
|
||
... : inherits more from Fl_Type
|
||
|
||
Type "data" <word> : C++ variable name
|
||
|
||
"filename" <word> : name or path as entered by user, forward slashes
|
||
"textmode" : defaults to binary mode
|
||
"compressed" : defaults to not compressed
|
||
... : inherits more from decl
|
||
|
||
Type "declblock" <word> : C++ code
|
||
|
||
none or "public" or "protected" : defaults to private (obsolete)
|
||
"map" <word> : integer value, default is 2 (CODE_IN_SOURCE),
|
||
see Fl_DeclBlock_Type::write_map_
|
||
"after" <word> : C++ code or comment following the block
|
||
... : inherits more from Fl_Type
|
||
|
||
Type "comment" <word> : comment text
|
||
|
||
"in_source" or "not_in_source": default to in_source
|
||
"in_header" or "not_in_header": default to in_header
|
||
... : inherits more from Fl_Type
|
||
|
||
Type "class" <word> <word> : prefix, class name
|
||
|
||
none or "private" or "protected" : defaults to public
|
||
":" <word> : name of super class
|
||
... : inherits more from Fl_Type
|
||
|
||
Type "Fl_Widget" <word> : C++ variable name
|
||
|
||
none or "private" or "protected" : default is public
|
||
"xywh" <word> : "{%d %d %d %d}" x, y, w, h
|
||
"tooltip" <word> : tooltip text
|
||
"scale_image <word>: "{%d %d}" width, height, default is 0, 0
|
||
"image" <word> : image name
|
||
"compress_image" <word> : integer (1.4 and up, only if `image` is set)
|
||
"bind_image" <word> : integer (1.4 and up)
|
||
"scale_deimage <word>: "{%d %d}" width, height, default is 0, 0
|
||
"deimage" <word> : deactivated image name
|
||
"compress_deimage" <word> : integer (1.4 and up, only if `deimage` is set)
|
||
"bind_deimage" <word> : integer (1.4 and up)
|
||
"type" <word> : integer
|
||
"box" <word> : text or integer (see FLTK boxtypes)
|
||
"down_box" <word> : (is_button() or Fl_Input_choice" or is_menu_button())
|
||
text or integer (see FLTK boxtypes)
|
||
"value" <word> : (is_button()) integer
|
||
"value" <word> : (is_valuator(), is_spinner()) double
|
||
"color" <word> :
|
||
If Word starts with "0x", the rest of the field is a hex number.
|
||
If two integers follow, this is color and selection_color (deprecated).
|
||
If one integer follows, it's the color index.
|
||
"selection_color" <word> : integer color index
|
||
"labeltype" <word> :
|
||
If the Word is "image", TBD.
|
||
Or one of "NORMAL_LABEL", "SHADOW_LABEL", "ENGRAVED_LABEL",
|
||
"EMBOSSED_LABEL", or "NO_LABEL"
|
||
"labelfont" <word> : integer, font index
|
||
"labelsize" <word> : integer
|
||
"labelcolor" <word> : integer, color index
|
||
"align" <word> : integer, see Fl_Align
|
||
"h_label_margin" <word> : integer, horizontal label margin
|
||
"v_label_margin" <word> : integer, vertical label margin
|
||
"image_spacing" <word> : integer, see Fl_Widget::label_image_spacing()
|
||
"when" <word> : integer, see Fl_When
|
||
"minimum" <word> : (is_valuator(), is_spinner()) double
|
||
"maximum" <word> : (is_valuator(), is_spinner()) double
|
||
"step" <word> : (is_valuator(), is_spinner()) double
|
||
"slider_size" <word> : (is_valuator()==2) double
|
||
"size" <word> : (is_valuator()==2) double
|
||
"textfont" <word> : integer, font index
|
||
"textsize" <word> : integer
|
||
"textcolor" <word> : integer, color index
|
||
"hide" : default visible
|
||
"deactivate" : default active
|
||
"resizable" : default fixed
|
||
"hotspot" : make a Widget a hotspot
|
||
"divider" : add a divider under a menu item
|
||
"class" <word> : superclass
|
||
"shortcut" <word> : integer
|
||
"code0" or "code1" or "code2" or "code3" <word> : C++ extra code lines
|
||
"extra_code" <word> : C++ extra code lines
|
||
... : inherits more from Fl_Type
|
||
|
||
Type "Fl_Button" <word> : C++ variable name
|
||
|
||
"compact" <word> : integer, set the flag for compact buttons, defaults to 0
|
||
|
||
Type "Fl_Flex" <word> : C++ variable name
|
||
|
||
"margins" <word> : this Word is written with printf as "{%d %d %d %d}",
|
||
left, top, right, bottom
|
||
"gap" <word> : integer
|
||
"fixed_size_tuples" <word> : this Word is written with printf "{%d", where %d
|
||
encodes the number of tuples to follow, and zero or more " %d %d"
|
||
containing the index and size of that child, followed by a '}'.
|
||
... : inherits more from Fl_Group
|
||
|
||
Type "Fl_Window" <word> : C++ variable name
|
||
|
||
none or "modal", or "non_modal": defaults to not modal (which is
|
||
different to non_modal!)
|
||
"visible" : show window when opening file in FLUID
|
||
"noborder" : borderless window
|
||
"xclass" <word> : see FLTK
|
||
"size_range" : this Word is written with printf as "{%d %d %d %d}",
|
||
min_w, min_h, max_w, max_h
|
||
"xywh" <word> : this Word is written with printf as "{%d %d %d %d}",
|
||
x, y, w, h. This as actually read in the Fl_Widget Type, but here
|
||
it ensures that window is not created as a subwindow.
|
||
... : inherits more from Fl_Widget (not Fl_Group)
|
||
|
||
Type "Fl_Grid" <word> : C++ variable name
|
||
|
||
"dimensions" <word> : {int rows, int cols}
|
||
"margin" <word> : {int left, int top, int right, int bottom}
|
||
"gap" <word> : {int row gap, int col gap}
|
||
"rowheights" <word> : {int h, ...*rows}
|
||
"rowweights" <word> : {int h, ...*rows}
|
||
"rowgaps" <word> : {int h, ...*rows}
|
||
"colwidths" <word> : {int h, ...*cols}
|
||
"colweights" <word> : {int h, ...*cols}
|
||
"colgaps" <word> : {int h, ...*cols}
|
||
|
||
Fl_Grid can also produce parent properties in their children
|
||
|
||
"location" <word> : {int row, int col}
|
||
"colspan" <int>"
|
||
"rowspan" <int>
|
||
"align" <int> : see Fl_Grid_Align enum
|
||
"min_size" <word> : {int width, int height}
|
||
|
||
Please report errors and omissions to the fltk.coredev or fltk.general
|
||
Google group. Thank you.
|
||
|
||
- Matthias
|