Mercurial > dillo_port1.3
changeset 347:e5955ab8dafb
- Moved the dw2 tree into dillo2's tree.
line wrap: on
line diff
--- a/ChangeLog Wed Sep 24 16:20:42 2008 +0200 +++ b/ChangeLog Wed Sep 24 18:44:40 2008 +0200 @@ -181,6 +181,135 @@ - test no_proxy (set a list in dillorc). ----------------------------------------------------------------------------- +dw + +0.0.43 + - Fixed bug in dw::core::ExtIterator (wrong mask, see also Jorge's + patch "createvar.diff" from Nov 08). + - Applied Jorge's patch for dw::core::AlignedTextblock + ("lists.diff" in mail from Nov 08). + - Applied Jorge's patch for dw::core::Textblock ("links.diff" in + mail from Nov 08). + - Applied Jorge's patch for configure.in ("conf.diff" in mail from + Nov 08). + - Renamed ExtIterator to DeepIterator. + - Implemented CharIterator (as an alternative to word iterators). + - Implemented text search (simple KMP based on CharIterator). + - Completed scrolling. + Patches: Sebastian Geerken + + + Implemented drag scrolling with mouse's middle button. + - Enabled commented out partial image redraw, adding some checks. + - Enabled clipped redraws (avoids some flickering). + - Improvement: avoid complete redraws for child widget updates. + - Added code to really delete fltk2 widgets embedded in dw2. + - Fixed partial redraws and scrolling interference. + - Added combination of drawing rectangles into a larger one. + - Bug fix: a newly added rectangle may contain others. + - Made draw() check whether a rectangle is visible at drawing time. + - The background is now cleared properly on partial redraws. + - Made getWidgetAtPoint() a virtual method of widget and implemented a + custom one for TextBlock, reducing CPU usage on pages full of links. + - Added a style reference and an initialization to mustQueueResize. + - Replaced prepareCreateFltkWidget with an explicit call to add(). + - Fixed an assertion-exit bug in DeepIterator. + - Fixed two viewport bugs: in drawing and scrolling. + - Made scrollbars really children of FltkViewport. + - Avoided multiple redraws when Layout::resizeIdle() queues itself. + - Set FltkViewBase::draw to intersect with view area for expose. + - Set cursor shape to CURSOR_MOVE on drag. Disabled drag over links. + - Added Layout::queueDrawExcept(), it reduces flickering by avoiding + a redraw when another rectangle is added. + - Fixed a scrollIdleId test to properly compare against -1. + - Set FltkPlatform::removeIdle to use removeRef() instead of remove(). + - Cleaned up scroll code and moved updateCanvasWidgets() out of draw(). + - Switched begin-end pairs with add() calls (fixes side-effect bugs!). + - Fixed checks in adjustScrollPos() to not allow wild values. + - Added double buffering for partial redraws! + - Implemented ComplexButton. + - Fixed find text so it works for phrases and PRE-wrapped text. + - Fixed a bug in DeepIterator::prev. + - Added the "lout" namespace. + - Reduced memory usage in 30% by reusing styles, reducing the size + of struct Content, and not preallocating in SimpleVector. ! + - Made fontsTable and colorsTable static members of Font and Color. + - Moved highlighting information from struct Word into Textblock + to save memory. + - Reduced memory usage 10% with a custom memory handler in Textblock. + - Fixed a segfault when searching for single characters. + - Fixed memory leaks by s/delete/delete[]/ where necessary. + - Fixed three iterator memory leaks in Iterator::scrollTo(). + - Changed DeepIterator to always clone its parameter (segfault bug). + - Implemented selection of multibyte glyphs (UTF-8). + - Removed the canvasWidgets list (fltk's children seem enough). + - Switched misc:assert() to the standard assert() call. + Patches: Johannes Hofmann + + Fixed a segfault-on-empty-strings bug in ConstString::hashValue. + - Fixed a segfault in reallocChildren (colspan/rowspan related). + - Fixed another assertion-exit bug in DeepIterator. + - Added the dw::fltk::ui::FltkMultiLineTextResource class. + - Implemented TEXTAREA using fltk::TextEditor. + - Bugfix: added the missing fltk::setfont calls before ::getwidth. + - Bugfix: initialized scrollIdleNotInterrupted variable. + - Commented out obsolete DEBUG_MSG lines in widget.cc. + - Fixed rowspan apportion when no single rowspan=1 row is found. + - Fixed allocateFltkWidget to handle and display FltkListResource. + - Fixed a slithery BUG in lout::misc::Stringbuffer. + - Implemented multiple item selection in FltkSelectionResource. + Patches: Jeremy Henty + + Added an extra argument in the link signals + (I recommended that instead of an array of image handlers --jcid) + - Aded an x_img camp to style (an image array index, like x_link). + - Added the same workaround in ui.cc for WHEN_ENTER_KEY_ALWAYS. + - Fixed shading (style.cc) and implemented FltkViewBase::drawPolygon(). + - Implemented Circle and Disk bullet drawing. + - Fixed a bug in FltkViewBase::getClippingView. + - Made FltkColor::FltkColor use ::fltk::BLACK (bugfix). + - Fixed a bug with dissappearing widgets when scrolling with low CPU. + - Fixed a bug with the canvas offset of scrolling bars. + - Fixed a typo bug in scrollIdle() and a typo in processMouseEvent(). + - Fixed an offset arithmetic bug with widgets inside textblock. + - Fixed RTFL debugging messages. + - Switched ComplexButton to use "Activate" instead of "Clicked" signal. + - Made the ComplexButton resource remember its click x,y. + - Added "enter" and "leave" signals into class Resource. + Patches: place + + Enabled mouse wheel scrolling. + FltkViewport::setScrollStep() sets how many points at a time. + - Added setDeleteCallback(DW_Callback_t func, void *data) to widget. + This allows to hook a callback when the widget is destroyed. + - Implemented a weighted apportionment algorithm for table rowspan. + - Implemented a weighted apportionment algorithm for table colspan. + - Implemented percentage widths in tables (better rendering!). + - Fixed an initialization bug in hruler. + - Fixed a bug in the textblock's wrapping algorithm. + - Fixed a bug in table cellpadding. + - Fixed a bug in getContentHeight(). + - Changed the table-apportion algorithms + bug fixes. Big work! + - Fixed a mistake in the CSS-box-model PNG image (style-box-model.png). + - Added initialization for scrollX and scrollY. + - Fixed a typo bug in adjustScrollPos(). + - Fixed two typo bugs in Textblock::drawLine(). + - Changed Textblock::addText() to internally allocate its text string, + making the memory handling opaque to the caller. + Patches: Jorge Arellano Cid + + Added actual text selection. + Patch: Sebastian Geerken, place + + Implemented dw::fltk::ui::FltkOptionMenuResource::isSelected(), + added Item::createNewGroupWidget(), Item::createNewWidget(). + Patch: Jeremy Henty, Johannes Hofmann + + Implemented the necessary base for image maps. + Patch: Johannes Hofmann, place + +0.0.42 + - Fixed event handling in FLTK views. (Fixes links and several + problems with UI resources.) + - Implemented clipping views. (dw::Image used this already in + version 0.0.41.) + - Added "activated" signals to UI resources. + Patches: Sebastian Geerken + +----------------------------------------------------------------------------- 0.8.5-pre-dw-redesign-1 [internal]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Doxyfile Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,1143 @@ +# Doxyfile 1.3.7 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = Dillo + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 2 levels of 10 sub-directories under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of source +# files, where putting all generated files in the same directory would otherwise +# cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en +# (Japanese with English messages), Korean, Korean-en, Norwegian, Polish, Portuguese, +# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is used +# as the annotated text. Otherwise, the brief description is used as-is. If left +# blank, the following values are used ("$name" is automatically replaced with the +# name of the entity): "The $name class" "The $name widget" "The $name file" +# "is" "provides" "specifies" "contains" "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm + +FILE_PATTERNS = *.cc *.hh *.doc + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = dlib dpi dpid dpip src test + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = doc + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 3 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superseded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES +#HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = NO + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = NO + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = NO + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 20480 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes that +# lay further from the root node will be omitted. Note that setting this option to +# 1 or 2 may greatly reduce the computation time needed for large code bases. Also +# note that a graph may be further truncated if the graph's image dimensions are +# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). +# If 0 is used for the depth value (the default), the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO
--- a/Makefile.am Wed Sep 24 16:20:42 2008 +0200 +++ b/Makefile.am Wed Sep 24 18:44:40 2008 +0200 @@ -1,5 +1,5 @@ -SUBDIRS = doc dlib dpip src dpid dpi +SUBDIRS = lout dw dlib dpip src doc dpid dpi test -EXTRA_DIST = ChangeLog.old dillo2rc install-dpi-local README-port +EXTRA_DIST = ChangeLog.old Doxyfile dillo2rc install-dpi-local README-port sysconf_DATA = dillo2rc
--- a/configure.in Wed Sep 24 16:20:42 2008 +0200 +++ b/configure.in Wed Sep 24 18:44:40 2008 +0200 @@ -34,6 +34,8 @@ enable_ssl=$enableval, enable_ssl=yes) AC_ARG_ENABLE(threaded-dns,[ --disable-threaded-dns Disable the advantage of a reentrant resolver library], enable_threaded_dns=$enableval, enable_threaded_dns=yes) +AC_ARG_ENABLE(rtfl, [ --enable-rtfl Build with rtfl messages]) +AC_ARG_ENABLE(doublebuffer, [ --disable-doublebuffer Disable double buffering for drawing], , enable_doublebuffer=yes) AC_PROG_CC AC_PROG_CXX @@ -425,6 +427,12 @@ if test "x$enable_threaded_dns" = "xyes" ; then CFLAGS="$CFLAGS -DD_DNS_THREADED" fi +if test "x$enable_rtfl" = "xyes" ; then + CXXFLAGS="$CXXFLAGS -DDBG_RTFL" +fi +if test "x$enable_doublebuffer" = "xno" ; then + CXXFLAGS="$CXXFLAGS -DNO_DOUBLEBUFFER" +fi dnl ----------------------- dnl Checks for header files @@ -487,5 +495,5 @@ AC_SUBST(LIBICONV_LIBS) AC_SUBST(datadir) -AC_OUTPUT(Makefile dlib/Makefile dpip/Makefile dpid/Makefile dpi/Makefile doc/Makefile src/Makefile src/IO/Makefile) +AC_OUTPUT(Makefile dlib/Makefile dpip/Makefile dpid/Makefile dpi/Makefile doc/Makefile dw/Makefile lout/Makefile src/Makefile src/IO/Makefile test/Makefile)
--- a/doc/Makefile.am Wed Sep 24 16:20:42 2008 +0200 +++ b/doc/Makefile.am Wed Sep 24 18:44:40 2008 +0200 @@ -1,19 +1,44 @@ EXTRA_DIST = \ - Cache.txt \ - Cookies.txt \ - Dillo.txt \ - Dw.txt \ - DwImage.txt \ - DwPage.txt \ - DwRender.txt \ - DwStyle.txt \ - DwTable.txt \ - DwWidget.txt \ - HtmlParser.txt \ - IO.txt \ - Images.txt \ - Imgbuf.txt \ - NC_design.txt \ - Selection.txt \ - Dpid.txt \ - README + index.doc \ + lout.doc \ + dw-map.doc \ + dw-overview.doc \ + dw-usage.doc \ + dw-layout-views.doc \ + dw-layout-widgets.doc \ + dw-widget-sizes.doc \ + dw-changes.doc \ + dw-images-and-backgrounds.doc \ + fltk-problems.doc \ + rounding-errors.doc \ + uml-legend.doc \ + dw-example-screenshot.png \ + dw-viewport-without-scrollbar.png \ + dw-viewport-with-scrollbar.png \ + dw-size-of-widget.png \ + dw-style-box-model.png \ + dw-style-length-absolute.png \ + dw-style-length-percentage.png \ + dw-style-length-relative.png \ + dw-textblock-collapsing-spaces-1-1.png \ + dw-textblock-collapsing-spaces-1-2.png \ + dw-textblock-collapsing-spaces-2-1.png \ + dw-textblock-collapsing-spaces-2-2.png \ + Cache.txt \ + Cookies.txt \ + Dillo.txt \ + Dw.txt \ + DwImage.txt \ + DwPage.txt \ + DwRender.txt \ + DwStyle.txt \ + DwTable.txt \ + DwWidget.txt \ + HtmlParser.txt \ + IO.txt \ + Images.txt \ + Imgbuf.txt \ + NC_design.txt \ + Selection.txt \ + Dpid.txt \ + README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/dw-changes.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,109 @@ +/** \page dw-changes Changes to the GTK+-based Release Version + +<h2>Changes in Dw</h2> + +Related to the FLTK port, there have been many changes, this is a +(hopefully complete) list: + +<ul> +<li> Rendering abstraction, read \ref dw-overview and \ref dw-layout-views + for details. Some important changes: + + <ul> + <li> The underlying platform (e.g. the UI toolkit) is fully abstract, + there are several platform independent structures replacing + GTK+ structures, e.g. dw::core::Event. + + <li> The central class managing the widget tree is not anymore + GtkDwViewport, but dw::core::Layout. + + <li> There are multiple views (implementations of dw::core::View). + Typically, you keep a reference on dw::core::Layout and a "main" + view (a viewport). + + <li> Drawing is done via dw::core::View, a pointer is passed to + dw::core::Widget::draw. + + <li> The distinction between viewport coordinates and canvas + coordinates (formerly world coordinates) has been mostly + removed. (Only for views, it sometimes plays a role, see + \ref dw-layout-views). +</ul> + +<li> Cursors have been moved to dw::core::style, see + dw::core::style::Style::cursor. dw::core::Widget::setCursor is now + protected (and so only called by widget implementations). + +<li> World coordinates are now called canvas coordinates. + +<li> There is now a distinction between dw::core::style::StyleAttrs and + dw::core::style::Style. + +<li> There is no base class for container widgets anymore. The former + DwContainer::for_all has been removed, instead this functionality + is now done via iterators (dw::core::Widget::iterator, + dw::core::Iterator). + +<li> DwPage is now called dw::Textblock, and DwAlignedPage + dw::AlignedTextblock. + +<li> dw::Textblock, all sub classes of it, and dw::Table do not read + "limit_text_width" from the preferences, but get it as an argument. + (May change again.) + +<li> dw::Table has been rewritten. + +<li> Instead of border_spacing in the old DwStyle, there are two attributes, + dw::core::style::Style::hBorderSpacing and + dw::core::style::Style::vBorderSpacing, since CSS allowes to specify + two values. Without CSS, both attributes should have the same value. + +<li> Images are handled differently, see \ref dw-images-and-backgrounds. + +<li> Embedded UI widgets (formerly GtkWidget's) are handled differently, + see dw::core::ui. + +<li> DwButton has been removed, instead, embedded UI widgets are used. See + dw::core::ui and dw::core::ui::ComplexButtonResource. +</ul> + +Dw is now written C++, the transition should be obvious. All "Dw" +prefixes have been removed, instead, namespaces are used now: + +<ul> +<li>dw::core contains the core, +<li>dw::core::style styles, +<li>dw::core::ui embedded UI resources, +<li>dw::fltk classes related to FLTK, and +<li>::dw the widgets. +</ul> + +<h2>Documentation</h2> + +The old documentation has been moved to: + +<table> +<tr><th colspan="2">Old <th>New +<tr><td rowspan="2">Dw.txt + <td>general part <td>\ref dw-overview, \ref dw-usage, + \ref dw-layout-widgets, + \ref dw-widget-sizes +<tr><td>remarks on specific widgets <td>respective source files: dw::Bullet, + dw::core::ui::Embed +<tr><td rowspan="2">DwImage.txt + <td>signals <td>dw::core::Widget::LinkReceiver +<tr><td>rest <td>dw::Image, + \ref dw-images-and-backgrounds +<tr><td colspan="2">Imgbuf.txt <td>dw::core::Imgbuf, + \ref dw-images-and-backgrounds +<tr><td colspan="2">DwPage.txt <td>dw::Textblock +<tr><td colspan="2">DwRender.txt <td>\ref dw-overview, \ref dw-layout-views, + dw::core::ui +<tr><td colspan="2">DwStyle.txt <td>dw::core::style +<tr><td colspan="2">DwTable.txt <td>dw::Table +<tr><td colspan="2">DwWidget.txt <td>dw::core::Widget, \ref dw-layout-widgets, + \ref dw-widget-sizes +<tr><td colspan="2">Selection.txt <td>dw::core::SelectionState +</table> + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/dw-images-and-backgrounds.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,146 @@ +/** \page dw-images-and-backgrounds Images and Backgrounds in Dw + +<h2>General</h2> + +Representation of the image data is delegated to dw::core::Imgbuf, see +there for details. Drawing is delegated to dw::core::View +(dw::core::View::drawImgbuf). + +Since dw::core::Imgbuf provides memory management based on reference +counting, there may be an 1-to-n relation from image renderers (image +widgets or backgrounds, see below) and dw::core::Imgbuf. Since +dw::core::Imgbuf does not know about renderers, but just provides +rendering functionality, the caller must (typically after calling +dw::core::Imgbuf::copyRow) notify all renderers connected to the +buffer. + + +<h2>Images</h2> + +This is the simplest renderer, displaying an image. For each row to be +drawn, + +<ol> +<li> first dw::core::Imgbuf::copyRow, and then +<li> for each dw::Image, dw::Image::drawRow must be called, with the same + argument (no scaling is necessary). +</ol> + +dw::Image automatically scales the dw::core::Imgbuf, the root buffer +should be passed to dw::Image::setBuffer. + +\see dw::Image for more details. + +<h2>Future Extensions</h2> + +(This is not implemented yet.) Rendering itself (image widgets and +background) will be abstracted, by a new interface +dw::core::ImageRenderer. In the current code for image decoding, this +interface will replace references to dw::Image, which implements +dw::core::ImageRenderer, in most cases. + +<h2>Backgrounds</h2> + +(This is based on future extensions described above.) Since background +are style resources, they are associated with +dw::core::style::Style. For backgrounds, another level is needed, +because of the 1-to-n relation from dw::core::style::Style to +dw::core::Widget: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", arrowtail="none", labelfontname=Helvetica, + labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + "background renderer (as a part of style)" -> "image buffer" [headlabel="*", + taillabel="1"]; + "widget (or a part of it)" -> "background renderer (as a part of style)" + [headlabel="*", taillabel="1"]; +} +\enddot + +Unlike dw::Image, dw::core::style::BgRenderer is not associated with a +certain rectangle on the canvas. Instead, widgets, or parts of widgets +take this role. This is generally represented by an implementation of +the interface dw::core::style::BgAllocation, which is implemented by +dw::core::Widget, but also by all parts of widget implementation, +which may have an own background image. + +The following diagram gives a total overview: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", arrowtail="none", labelfontname=Helvetica, + labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + "DICache Entry"; + + subgraph cluster_dw_images { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="Dw Images"; + + ImageRenderer [URL="\ref dw::core::ImageRenderer", color="#ff8080"]; + Imgbuf [URL="\ref dw::core::Imgbuf", color="#ff8080"]; + } + + subgraph cluster_widgets { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="Widgets"; + + Widget [URL="\ref dw::core::Widget", color="#a0a0a0"]; + Textblock [URL="\ref dw::Textblock"]; + "Textblock::Word" [URL="\ref dw::Textblock::Word"]; + Table [URL="\ref dw::Table"]; + "Table::Row" [URL="\ref dw::Table::Row"]; + Image [URL="\ref dw::Image"]; + } + + subgraph cluster_style { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="dw::core::style"; + + Style [URL="\ref dw::core::style::Style"]; + BgRenderer [URL="\ref dw::core::style::BgRenderer"]; + BgAllocation [URL="\ref dw::core::style::BgAllocation", color="#ff8080"]; + } + + "DICache Entry" -> ImageRenderer [headlabel="*", taillabel="1"]; + "DICache Entry" -> Imgbuf [headlabel="1", taillabel="1"]; + + BgRenderer -> Imgbuf [headlabel="1", taillabel="*"]; + BgRenderer -> BgAllocation [headlabel="*", taillabel="1"]; + ImageRenderer -> BgRenderer [arrowhead="none", arrowtail="empty", + style="dashed"]; + ImageRenderer -> Image [arrowhead="none", arrowtail="empty", + style="dashed"]; + + Style -> BgRenderer [headlabel="0..1", taillabel="1"]; + + Widget -> Textblock [arrowhead="none", arrowtail="empty"]; + Textblock -> "Textblock::Word" [headlabel="*", taillabel="1"]; + Widget -> Table [arrowhead="none", arrowtail="empty"]; + Table -> "Table::Row" [headlabel="*", taillabel="1"]; + Widget -> Image [arrowhead="none", arrowtail="empty"]; + + BgAllocation -> Widget [arrowhead="none", arrowtail="empty", + style="dashed"]; + BgAllocation -> "Textblock::Word" [arrowhead="none", arrowtail="empty", + style="dashed"]; + BgAllocation -> "Table::Row" [arrowhead="none", arrowtail="empty", + style="dashed"]; +} +\enddot + +<center>[\ref uml-legend "legend"]</center> + + +<h2>Integration into dillo</h2> + +\todo Add some references. + + +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/dw-layout-views.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,270 @@ +/** \page dw-layout-views Layout and Views + +Rendering of Dw is done in a way resembling the model-view pattern, at +least formally. Actually, the counterpart of the model, the layout +(dw::core::Layout), does a bit more than a typical model, namely the +layouting (delegated to the widget tree, see \ref dw-layout-widgets), +and the views do a bit less than a typical view, i.e. only the actual +drawing. + +Additionally, there is a structure representing common properties of +the platform, views generally work only together with one specific +platform. A platform is typically related to the underlying UI +toolkit, but other uses may be thought of. + +This design helps to archieve three important goals: + +<ul> +<li> It makes different views of the same document simple, e.g. the + normal viewport and the preview window. + +<li> Abstraction of the actual drawing, by different implementations + of dw::core::View. Most important, there must be a viewport, but + some other views are possible, e.g. a preview window. + +<li> It makes portability simple. +</ul> + + +<h2>Viewports</h2> + +Although the design implies that the usage of viewports should be +fully transparent to the layout module, this cannot be fully archived, +for the following reasons: + +<ul> +<li> Some features, which are used on the level of dw::core::Widget, + e.g. anchors, refer to scrolling positions. + +<li> Size hints (see \ref dw-layout-widgets) depend on the viewport + sizes, e.g. when the user changes the window size, and so also + the size of a viewport, the text within should be rewrapped. +</ul> + +Therefor, dw::core::Layout keeps track of the viewport size, the +viewport position, and even the thickness of the scrollbars, they are +relevant, see below for more details. These sizes are always equal in +all views. However, a given view may not use viewports at all, and +there may be the case, that no view related to a layout uses +viewports, in this case, the viewport size is not defined at all. + +(The case, that there is no viewport at all, is currently not well +defined, but this case does not occur currently within dillo.) + +Whether a given dw::core::View implementation is a viewport or not, is +defined by the return value of dw::core::View::usesViewport. If this +method returns false, the following methods need not to be implemented +at all: + +<ul> +<li> dw::core::View::getHScrollbarThickness, +<li> dw::core::View::getVScrollbarThickness, +<li> dw::core::View::scrollTo, and +<li> dw::core::View::setViewportSize. +</ul> + +<h3>Scrolling Positions</h3> + +The scrolling position is the canvas position at the upper left corner +of the viewport. Views using viewports must + +<ol> +<li> change this value on request (dw::core::View::scrollTo), and +<li> tell other changes to the layout, e.g. caused by user events + (dw::core::Layout::scrollPosChanged). +</ol> + +Applications of scrolling positions (anchors, test search etc.) are +handled by the layout, in a way fully transparent to the views. + +<h3>Scrollbars</h3> + +A feature of the viewport size model are scrollbars. There may be a +vertical scrollbar and a horizontal scrollbar, displaying the +relationship between canvas and viewport height or width, +respectively. If they are not needed, they are hidden, to save screen +space. + +Since scrollbars decrease the usable space of a view, dw::core::Layout +must know how much space they take. Each view returns, via +dw::core::View::getHScrollbarThickness and +dw::core::View::getVScrollbarThickness, how thick they will be, when +visible. The total space difference is then the maximum of all values, +which the views return. + +Viewport sizes, which denote the size of the viewport widgets, include +scrollbar thicknesses. When referring to the viewport \em excluding +the scrollbars space, we will call it "usable viewport size", this is +the area, which is used to display the canvas. + +<h2>Drawing</h2> + +A view must implement several drawing methods, which work on the whole +canvas. If it is neccesary to convert them (e.g. into +dw::fltk::FltkViewport), this is done in a way fully transparent to +dw::core::Widget and dw::core::Layout, instead, this is done by the +view implementation. + +There exist following situations: + +<ul> +<li> A view gets an expose event: It will delegate this to the + layout (dw::core::Layout::draw), which will then pass it to the + widgets (dw::core::Widget::draw), with the view as a parameter. + Eventually, the widgets will call drawing methods of the view. + +<li> A widget requests a redraw: In this case, the widget will + delegate this to the layout (dw::core::Layout::queueDraw), which + delegates it to all views (dw::core::View::queueDraw). + Typically, the views will queue these requests, for efficiency. + +<li> A widget requests a resize: This case is described below, in short, + dw::core::View::queueDrawTotal is called for the view. +</ul> + +If the draw method of a widget is implemented in a way that it may +draw outside of the widget's allocation, it should draw into a +<i>clipping view.</i> A clipping view is a view related to the actual +view, which guarantees that the parts drawn outside are discarded. At +the end, the clipping view is merged into the actual view. Sample +code: + +\code +void Foo::draw (dw::core::View *view, dw::core::Rectangle *area) +{ + // 1. Create a clipping view. + dw::core::View clipView = + view->getClippingView (allocation.x, allocation.y, + allocation.width, getHeight ()); + + // 2. Draw into clip_view + clipView->doSomeDrawing (...); + + // 3. Draw the children, they receive the clipping view as argument. + dw::core::Rectangle *childArea + for (<all relevant children>) { + if (child->intersects (area, &childArea)) + child->draw (clipView, childArea); + } + + // 4. Merge + view->mergeClippingView (clipView); +} +\endcode + +A drawing process is always embedded into calls of +dw::core::View::startDrawing and dw::core::View::finishDrawing. An +implementation of this may e.g. use backing pixmaps, to prevent +flickering. + + +<h2>Sizes</h2> + +Generally, all views show the same layout, which has a given size +(canvas size). In the simplest case, views do not have an influence on +the canvas size, so that they are just told about changes of the +canvas size, by a call to dw::core::View::setCanvasSize. This happens +in the following situations: + +<ul> +<li> dw::core::Layout::addWidget, +<li> dw::core::Layout::removeWidget (called by dw::core::Widget::~Widget), + and +<li> dw::core::Layout::queueResize (called by + dw::core::Widget::queueResize, when a widget itself requests a size + change). +</ul> + +<h3>Viewports</h3> + +Furthermore, viewport sizes and scrollbar thicknesses are always the +same. There are two cases, in which the viewport size changes: + +<ul> +<li> As an reaction on a user event, e.g. when the user changes the + window size. In this case, the affected view delegates this + change to the layout, by calling + dw::core::Layout::viewportSizeChanged. All other views are + told about this, by calling dw::core::Layout::setViewportSize. + +<li> The viewport size may also depend on the visibility of UI + widgets, which depend on the world size, e.g scrollbars, + generally called "viewport markers". This is described in an own + section. +</ul> + +After the creation of the layout, the viewport size is undefined. When +a view is attached to a layout, and this view is already to be able to +define its viewport size, it may already call +dw::core::Layout::viewportSizeChanged within the implementation of +dw::core::Layout::setLayout. If not, it may do this, as soon as the +viewport size gets known. + +Generally, the scrollbars have to be considered. If e.g. an HTML page +is rather small, it looks like this: + +\image html dw-viewport-without-scrollbar.png + +If some more data is retrieved, so that the height exceeds the +viewport size, the text has to be rewrapped, since the available width +gets smaller, due to the vertical scrollbar: + +\image html dw-viewport-with-scrollbar.png + +Notice the different line breaks. + +This means circular dependencies between these different sizes: + +<ol> +<li> Whether the scrollbars are visible or not, determines the + usable space of the viewport. + +<li> From the usable space of the viewport, the size hints for the + toplevel are calculated. + +<li> The size hints for the toplevel widgets may have an effect on its + size, which is actually the canvas size. + +<li> The canvas size determines the visibility of the scrollbarss. +</ol> + +To make an implementation simpler, we simplify the model: + +<ol> +<li> For the calls to dw::core::Widget::setAscent and + dw::core::Widget::setDescent, we will always exclude the + horizontal scrollbar thickness (i.e. assume the horizontal + scrollbar is used, although the visibility is determined correctly). + +<li> For the calls to dw::core::Widget::setWidth, we will calculate + the usable viewport width, but with the general assumption, that + the widget generally gets higher. +</ol> + +This results in the following rules: + +<ol> +<li> Send always (when it changes) dw::core::Layout::viewportHeight + minus the maximal value of dw::core::View::getHScrollbarThickness as + argument to dw::core::Widget::setAscent, and 0 as argument to + dw::core::Widget::setDescent. + +<li> There is a flag, dw::core::Layout::canvasHeightGreater, which is set + to false in the following cases: + + <ul> + <li> dw::core::Layout::addWidget, + <li> dw::core::Layout::removeWidget (called by dw::core::Widget::~Widget), + and + <li> dw::core::Layout::viewportSizeChanged. + </ul> + + Whenever the canvas size is calculated (dw::core::Layout::resizeIdle), + and dw::core::Layout::canvasHeightGreater is false, a test is made, + whether the widget has in the meantime grown that high, that the second + argument should be set to true (i.e. the vertical scrollbar gets visible). + As soon as and dw::core::Layout::canvasHeightGreater is true, no such test + is done anymore. +</ol> + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/dw-layout-widgets.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,270 @@ +/** \page dw-layout-widgets Layout and Widgets + +Both, the layouting and the drawing is delegated to a tree of +widgets. A widget represents a given part of the document, e.g. a text +block, a table, or an image. Widgets may be nested, so layouting and +drawing may be delegated by one widget to its child widgets. + +Where do define the borders of a widget, wheather to combine different +widgets to one, or to split one widget into multiple ones, should be +considered based on different concerns: + +<ul> +<li> First, there are some restrictions of Dw: + + <ul> + <li> The allocation (this is the space a widget allocates at + a time) of a dillo widget is always rectangular, and + <li> the allocation of a child widget must be a within the allocation + of the parent widget. + </ul> + +<li> Since some widgets are already rather complex, an important goal + is to keep the implementation of the widget simple. + +<li> Furthermore, the granularity should not be to fine, because of the + overhead each single widget adds. +</ul> + +For CSS, there will be a document tree on top of Dw, this will be +flexible enough when mapping the document structure on the widget +structure, so you should not have the document structure in mind. + +<h2>Sizes</h2> + +\ref dw-widget-sizes + + +<h2>Styles</h2> + +Each widget is assigned a style, see dw::core::style for more +informations. + + +<h2>Iterators</h2> + +Widgets must implement dw::core::Widget::iterator. There are several +common iterators: + +<ul> +<li>dw::core::EmptyIterator, and +<li>dw::core::TextIterator. +</ul> + +Both hide the constructor, use the \em create method. + +These simple iterators only iterate through one widget, it does not +have to iterate recursively through child widgets. Instead, the type +dw::core::Content::WIDGET is returned, and the next call of +dw::core::Iterator::next will return the piece of contents \em after +(not within) this child widget. + +This makes implementation much simpler, for recursive iteration, there +is dw::core::DeepIterator. + + +<h2>Anchors and Scrolling</h2> + +\todo This section is not implemented yet, after the implementation, + the documentation should be reviewed. + +Here is a description, what is to be done for a widget +implementation. How to jump to anchors, set scrolling positions +etc. is described in \ref dw-usage. + +<h3>Anchors</h3> + +Anchors are position markers, which are identified by a name, which is +unique in the widget tree. The widget must care about anchors in three +different situations: + +<ol> +<li> Adding an anchor is inititiated by a specific widget method, e.g. + dw::Textblock::addAnchor. Here, dw::core::Widget::addAnchor must be + called, + +<li> Whenever the position of an anchor is changed, + dw::core::Widget::changeAnchor is called (typically, this is done + in the implementation of dw::core::Widget::sizeAllocateImpl). + +<li> When a widget is destroyed, the anchor must be removed, by calling + dw::core::Widget::removeAnchor. +</ol> + +All these methods are delegated to dw::core::Layout, which manages +anchors centrally. If the anchor in question has been set to jump to, +the viewport position is automatically adjusted, see \ref +dw-usage. + + +<h2>Drawing</h2> + +In two cases, a widget has to be drawn: + +<ol> +<li> as a reaction on an expose event, +<li> if the widget content has changed and it needs to be redrawn. +</ol> + +In both cases, drawing is done by the implementation of +dw::core::Widget::draw. Generally, a widget draws into different views +(see \ref dw-layout-views), the view to draw into is passed as the +first argument. In the first case, only the view, which causes the +expose event, is passed, in the second case, dw::core::Widget::draw is +called multiple times, once for each view connected to the layout. + +Each view provides some primitive methods for drawing, most should be +obvious. Notice that the views do not know anything about dillo +widgets, and so coordinates have to be passed as canvas coordinates. + +A widget may only draw in its own allocation. If this cannot be +achieved, a <i>clipping view</i> can be used, this is described in +\ref dw-layout-views. Generally, drawing should then look like: + +\code +void Foo::draw (dw::core::View *view, dw::core::Rectangle *area) +{ + // 1. Create a clipping view. + dw::core::View clipView = + view->getClippingView (allocation.x, allocation.y, + allocation.width, getHeight ()); + + // 2. Draw into clip_view + clipView->doSomeDrawing (...); + + // 3. Draw the children, they receive the clipping view as argument. + dw::core::Rectangle *childArea + for (<all relevant children>) { + if (child->intersects (area, &childArea)) + child->draw (clipView, childArea); + } + + // 4. Merge + view->mergeClippingView (clipView); +} +\endcode + +Clipping views are expensive, so they should be avoided, when possible. + +The second argument to dw::core::Widget::draw is the region, which has +to be drawn. This may (but needs not) be used for optimization. + +If a widget contains child widgets, it must explicitly draw these +children (see also code example above). For this, there is the useful +method dw::core::Widget::intersects, which returns, which area of the +child must be drawn. + +<h3>Explicit Redrawing</h3> + +If a widget changes its contents, so that it must be redrawn, it must +call dw::core::Widget::queueDrawArea or +dw::core::Widget::queueDraw. The first variant expects a region within +the widget, the second will cause the whole widget to be redrawn. This +will cause an asynchronous call of dw::core::Widget::draw. + +If only the size changes, a call to dw::core::Widget::queueResize is +sufficient, this will also queue a complete redraw (see \ref +dw-widget-sizes.) + + +<h2>Mouse Events</h2> + +A widget may process mouse events. The views (\ref dw-layout-views) +pass mouse events to the layout, which then passes them to the +widgtes. There are two kinds of mouse events: + +<ul> +<li>events returning bool, and +<li>events returning nothing (void). +</ul> + +The first group consists of: + +<ul> +<li>dw::core::Widget::buttonPressImpl, +<li>dw::core::Widget::buttonReleaseImpl, and +<li>dw::core::Widget::motionNotifyImpl. +</ul> + +For these events, a widget returns a boolean value, which denotes, +whether the widget has processed this event (true) or not (false). In +the latter case, the event is delegated according to the following +rules: + +<ol> +<li> First, this event is passed to the bottom-most widget, in which + allocation the mouse position is in. +<li> If the widget does not process this event (returning false), it is + passed to the parent, and so on. +<li> The final result (whether \em any widget has processed this event) is + returned to the view. +</ol> + +The view may return this to the UI toolkit, which then interprets this +in a similar way (whether the viewport, a UI widget, has processed +this event). + +These events return nothing: + +<ul> +<li>dw::core::Widget::enterNotifyImpl and +<li>dw::core::Widget::leaveNotifyImpl. +</ul> + +since they are bound to a widget. + +When processing mouse events, the layout always deals with two +widgets: the widget, the mouse pointer was in, when the previous mouse +event was processed, (below called the "old widget") and the widget, +in which the mouse pointer is now ("new widget"). + +The following paths are calculated: + +<ol> +<li> the path from the old widget to the nearest common anchestor of the old + and the new widget, and +<li> the path from this anchestor to the new widget. +</ol> + +For the widgets along these paths, dw::core::Widget::enterNotifyImpl +and dw::core::Widget::leaveNotifyImpl are called. + +<h3>Signals</h3> + +If a caller outside of the widget is interested in these events, he +can connect a dw::core::Widget::EventReceiver. For those events with a +boolean return value, the results of the signal emission is regarded, +i.e. the delegation of an event to the parent of the widget can be +stopped by a signal receiver returning true, even if the widget method +returns false. + +First, the widget method is called, then (in any case) the signal is +emitted. + +<h3>Selection</h3> + +If your widget has selectable contents, it should delegate the events +to dw::core::SelectionState (dw::core::Layout::selectionState). + + +<h2>Miscellaneous</h2> + +<h3>Cursors</h3> + +Each widget has a cursor, which is set by +dw::core::Widget::setCursor. If a cursor is assigned to a part of a +widget, this widget must process mouse events, and call +dw::core::Widget::setCursor explicitly. + +(This will change, cursors should become part of +dw::core::style::Style.) + +<h3>Background</h3> + +Backgrounds are part of styles +(dw::core::style::Style::backgroundColor). If a widget assigns +background colors to parts of a widget (as dw::Table does for rows), +it must call dw::core::Widget::setBgColor for the children inside this +part. + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/dw-map.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,59 @@ +/** \page dw-map Dillo Widget Documentation Map + +This maps includes special documentations as well as longer comments +in the sources. Arrows denote references between the documents. + +\dot +digraph G { + rankdir=LR; + node [shape=record, fontname=Helvetica, fontsize=8]; + fontname=Helvetica; fontsize=8; + + dw_overview [label="Dillo Widget Overview", URL="\ref dw-overview"]; + dw_usage [label="Dillo Widget Usage", URL="\ref dw-usage"]; + dw_layout_views [label="Layout and Views", URL="\ref dw-layout-views"]; + dw_layout_widgets [label="Layout and Widgets", + URL="\ref dw-layout-widgets"]; + dw_widget_sizes [label="Sizes of Dillo Widgets", + URL="\ref dw-widget-sizes"]; + dw_changes [label="Changes to the GTK+-based Release Version", + URL="\ref dw-changes"]; + dw_images_and_backgrounds [label="Images and Backgrounds in Dw", + URL="\ref dw-images-and-backgrounds"]; + dw_Image [label="dw::Image", URL="\ref dw::Image"]; + dw_core_Imgbuf [label="dw::core::Imgbuf", URL="\ref dw::core::Imgbuf"]; + dw_core_SelectionState [label="dw::core::SelectionState", + URL="\ref dw::core::SelectionState"]; + dw_core_style [label="dw::core::style", URL="\ref dw::core::style"]; + dw_Table [label="dw::Table", URL="\ref dw::Table"]; + dw_Textblock [label="dw::Textblock", URL="\ref dw::Textblock"]; + dw_core_ui [label="dw::core::ui", URL="\ref dw::core::ui"]; + + dw_overview -> dw_changes; + dw_overview -> dw_usage; + dw_overview -> dw_core_style; + dw_overview -> dw_core_ui; + dw_overview -> dw_images_and_backgrounds; + dw_overview -> dw_layout_widgets; + dw_overview -> dw_widget_sizes; + dw_overview -> dw_layout_views; + + dw_usage -> dw_Table; + dw_usage -> dw_Textblock; + dw_usage -> dw_core_style; + dw_usage -> dw_core_ui; + dw_usage -> dw_images_and_backgrounds; + + dw_layout_widgets -> dw_widget_sizes; + dw_layout_widgets -> dw_core_SelectionState; + + dw_widget_sizes -> dw_Table; + dw_widget_sizes -> dw_Textblock; + + dw_images_and_backgrounds -> dw_core_Imgbuf; + dw_images_and_backgrounds -> dw_Image; + + dw_core_style -> dw_Textblock; +} +\enddot +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/dw-overview.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,157 @@ +/** \page dw-overview Dillo Widget Overview + +Note: If you are already familiar with the Gtk+-based version of Dw, +read \ref dw-changes. + + +The module Dw (Dillo Widget) is responsible for the low-level rendering of +all resources, e.g. images, plain text, and HTML pages (this is the +most complex type). Dw is \em not responsible for parsing HTML, or +decoding image data. Furthermore, the document tree, which is planned +for CSS, is neither a part of Dw, instead, it is a new module on top +of Dw. + +The rendering, as done by Dw, is split into two phases: + +<ul> +<li> the \em layouting, this means calculating the exact positions of + words, lines, etc. (in pixel position), and +<li> the \em drawing, i.e. making the result of the layouting visible + on the screen. +</ul> + +The result of the layouting allocates an area, which is called +\em canvas. + +<h2>Structure</h2> + +The whole Dw module can be split into the following parts: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", fontname=Helvetica, fontsize=10, + labelfontname=Helvetica, labelfontsize=10, + color="#404040", labelfontcolor="#000080"]; + + subgraph cluster_core { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="Platform independent core"; + + Layout [URL="\ref dw::core::Layout"]; + Platform [URL="\ref dw::core::Platform", color="#ff8080"]; + View [URL="\ref dw::core::View", color="#ff8080"]; + Widget [URL="\ref dw::core::Widget", color="#a0a0a0"]; + } + + subgraph cluster_fltk { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="FLTK specific part (as an\nexample for the platform specific\n\ +implementations)"; + + subgraph cluster_fltkcore { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="FLTK core"; + + FltkPlatform [URL="\ref dw::fltk::FltkPlatform"]; + FltkView [URL="\ref dw::fltk::FltkView", color="#ff8080"]; + } + + FltkViewport [URL="\ref dw::fltk::FltkViewport"]; + FltkPreview [URL="\ref dw::fltk::FltkPreview"]; + } + + subgraph cluster_widgets { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="Platform independent widgets"; + + Textblock [URL="\ref dw::Textblock"]; + AlignedTextblock [URL="\ref dw::AlignedTextblock", color="#a0a0a0"]; + Table [URL="\ref dw::Table"]; + Image [URL="\ref dw::Image"]; + etc1 [label="..."]; + etc2 [label="..."]; + } + + Layout -> Platform [headlabel="1", taillabel="1"]; + Layout -> View [headlabel="*", taillabel="1"]; + + Layout -> Widget [headlabel="1", taillabel="1", label="topLevel"]; + Widget -> Widget [headlabel="*", taillabel="1", label="children"]; + + Widget -> Textblock [arrowhead="none", arrowtail="empty"]; + Widget -> Table [arrowhead="none", arrowtail="empty"]; + Widget -> Image [arrowhead="none", arrowtail="empty"]; + Widget -> etc1 [arrowhead="none", arrowtail="empty"]; + Textblock -> AlignedTextblock [arrowhead="none", arrowtail="empty"]; + AlignedTextblock -> etc2 [arrowhead="none", arrowtail="empty"]; + + Platform -> FltkPlatform [arrowhead="none", arrowtail="empty", + style="dashed"]; + FltkPlatform -> FltkView [headlabel="*", taillabel="1"]; + + View -> FltkView [arrowhead="none", arrowtail="empty"]; + FltkView -> FltkViewport [arrowhead="none", arrowtail="empty", + style="dashed"]; + FltkView -> FltkPreview [arrowhead="none", arrowtail="empty", + style="dashed"]; +} +\enddot + +<center>[\ref uml-legend "legend"]</center> + +\em Platform means in most cases the underlying UI toolkit +(e.g. FLTK). A layout is bound to a specific platform, but multiple +platforms may be handled in one program. + +A short overview: + +<ul> +<li> dw::core::Layout is the central class, it manages the widgets and the + views, and provides delegation methods for the platform. + +<li> The layouting is done by a tree of widgets (details are described in + \ref dw-layout-widgets), also the drawing, which is finally delegated + to the views. + +<li> The views (implementations of dw::core::View) provide primitive methods + for drawing, but also have an influence on + the canvas size (via size hints). See \ref dw-layout-views for details. + +<li> Some platform dependencies are handled by implementations + of dw::core::Platform. +</ul> + + +<h3>Header Files</h3> + +The structures mentioned above can be found in the following header +files: + +<ul> +<li> Anything from the Dw core in core.hh. Do not include the single files. + +<li> The single widgets can be found in the respective header files, e.g. + image.hh for dw::Image. + +<li> The core of the FLTK implementation is defined in fltkcore.hh. This + includes dw::fltk::FltkPlatform, dw::fltk::FltkView, but not the concrete + view implementations. + +<li> The views can be found in single header files, e.g fltkviewport.hh for + dw::fltk::FltkViewport. +</ul> + + +<h2>Further Documentations</h2> + +A complete map can be found at \ref dw-map. + +<ul> +<li> For learning, how to use Dw, read \ref dw-usage and related documents, + dw::core::style, dw::core::ui and \ref dw-images-and-backgrounds. +<li> Advanced topics are described in \ref dw-layout-widgets, + \ref dw-widget-sizes and \ref dw-layout-views. +</ul> + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/dw-usage.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,373 @@ +/** \page dw-usage Dillo Widget Usage + +This document describes the usage of Dw, without going too much into +detail. + + +<h2>Getting Started</h2> + +In this section, a small runnable example is described, based on the +FLTK implementation. + +As described in \ref dw-overview, the following objects are needed: + +<ul> +<li> dw::core::Layout, +<li> an implementation of dw::core::Platform (we will use + dw::fltk::FltkPlatform), +<li> at least one implementation of dw::core::View (dw::fltk::FltkViewport), + and +<li> some widgets (for this example, only a simple dw::Textblock). +</ul> + +First of all, the necessary #include's: + +\code +#include <fltk/Window.h> +#include <fltk/run.h> + +#include "dw/core.hh" +#include "dw/fltkcore.hh" +#include "dw/fltkviewport.hh" +#include "dw/textblock.hh" +\endcode + +Everything is put into one function: + +\code +int main(int argc, char **argv) +{ +\endcode + +As the first object, the platform is instanciated: + +\code + dw::fltk::FltkPlatform *platform = new dw::fltk::FltkPlatform (); +\endcode + +Then, the layout is created, with the platform attached: + +\code + dw::core::Layout *layout = new dw::core::Layout (platform); +\endcode + +For the view, we first need a FLTK window: + +\code + fltk::Window *window = new fltk::Window(200, 300, "Dw Example"); + window->begin(); +\endcode + +After this, we can create a viewport, and attach it to the layout: + +\code + dw::fltk::FltkViewport *viewport = + new dw::fltk::FltkViewport (0, 0, 200, 300); + layout->attachView (viewport); +\endcode + +Each widget needs a style (dw::core::style::Style, see dw::core::style), +so we construct it here. For this, we need to fill a +dw::core::style::StyleAttrs structure with values, and call +dw::core::style::Style::create (latter is done further below): + +\code + dw::core::style::StyleAttrs styleAttrs; + styleAttrs.initValues (); + styleAttrs.margin.setVal (5); +\endcode + +dw::core::style::StyleAttrs::initValues sets several default +values. The last line sets a margin of 5 pixels. Next, we need a +font. Fonts are created in a similar way, first, the attributes are +defined: + +\code + dw::core::style::FontAttrs fontAttrs; + fontAttrs.name = "Bitstream Charter"; + fontAttrs.size = 14; + fontAttrs.weight = 400; + fontAttrs.style = dw::core::style::FONT_STYLE_NORMAL; +\endcode + +Now, the font can be created: + +\code + styleAttrs.font = dw::core::style::Font::create (layout, &fontAttrs); +\endcode + +As the last attributes, the background and forground colors are +defined, here dw::core::style::Color::createSimple must be called: + +\code + styleAttrs.color = + dw::core::style::Color::createSimple (layout, 0x000000); + styleAttrs.backgroundColor = + dw::core::style::Color::createSimple (layout, 0xffffff); +\endcode + +Finally, the style for the widget is created: + +\code + dw::core::style::Style *widgetStyle = + dw::core::style::Style::create (layout, &styleAttrs); +\endcode + +Now, we create a widget, assign a style to it, and set it as the +toplevel widget of the layout: + +\code + dw::Textblock *textblock = new dw::Textblock (false); + textblock->setStyle (widgetStyle); + layout->setWidget (textblock); +\endcode + +The style is not needed anymore (a reference is added in +dw::core::Widget::setStyle), so it should be unreferred: + +\code + widgetStyle->unref(); +\endcode + +Now, some text should be added to the textblock. For this, we first +need another style. \em styleAttrs can still be used for this. We set +the margin to 0, and the background color to "transparent": + +\code + styleAttrs.margin.setVal (0); + styleAttrs.backgroundColor = NULL; + + dw::core::style::Style *wordStyle = + dw::core::style::Style::create (layout, &styleAttrs); +\endcode + +This loop adds some paragraphs: + +\code + for(int i = 1; i <= 10; i++) { + char buf[4]; + sprintf(buf, "%d.", i); + + char *words[] = { "This", "is", "the", buf, "paragraph.", + "Here", "comes", "some", "more", "text", + "to", "demonstrate", "word", "wrapping.", + NULL }; + + for(int j = 0; words[j]; j++) { + textblock->addText(strdup(words[j]), wordStyle); +\endcode + +Notice the \em strdup, dw::Textblock::addText will feel responsible +for the string, and free the text at the end. (This has been done to +avoid some overhead in the HTML parser.) + +The rest is simple, it also includes spaces (which also have styles): + +\code + textblock->addSpace(wordStyle); + } +\endcode + +Finally, a paragraph break is added, which is 10 pixels high: + +\code + textblock->addParbreak(10, wordStyle); + } +\endcode + +Again, this style should be unreferred: + +\code + wordStyle->unref(); +\endcode + +After adding text, this method should always be called (for faster +adding large text blocks): + +\code + textblock->flush (); +\endcode + +Some FLTK stuff to finally show the window: + +\code + window->resizable(viewport); + window->show(); + int errorCode = fltk::run(); +\endcode + +For cleaning up, it is sufficient to destroy the layout: + +\code + delete layout; +\endcode + +And the rest + +\code + return errorCode; +} +\endcode + +If you compile and start the program, you should see the following: + +\image html dw-example-screenshot.png + +Try to scroll, or to resize the window, you will see, that everything +is done automatically. + +Of course, creating new widgets, adding text to widgets etc. can also +be done while the program is running, i.e. after fltk::run has been +called, within timeouts, idles, I/O functions etc. Notice that Dw is +not thread safe, so that everything should be done within one thread. + +With the exception, that you have to call dw::Textblock::flush, +everything gets imediately visible, within reasonable times; Dw has +been optimized for frequent updates. + + +<h2>List of all Widgets</h2> + +These widgets are used within dillo: + +<ul> +<li>dw::core::ui::Embed +<li>dw::AlignedTextblock +<li>dw::Bullet +<li>dw::Ruler +<li>dw::Image +<li>dw::ListItem +<li>dw::Table +<li>dw::TableCell +<li>dw::Textblock +</ul> + +If you want to create a new widget, refer to \ref dw-layout-widgets. + + +<h2>List of Views</h2> + +There are three dw::core::View implementations for FLTK: + +<ul> +<li> dw::fltk::FltkViewport implements a viewport, which is used in the + example above. + +<li> dw::fltk::FltkPreview implements a preview window, together with + dw::fltk::FltkPreviewButton, it is possible to have a scaled down + overview of the whole canvas. + +<li> dw::fltk::FltkFlatView is a "flat" view, i.e. it does not support + scrolling. It is used for HTML buttons, see + dw::fltk::ui::FltkComplexButtonResource and especially + dw::fltk::ui::FltkComplexButtonResource::createNewWidget for details. +</ul> + +More informations about views in general can be found in \ref +dw-layout-views. + + +<h2>Iterators</h2> + +For examining generally the contents of widgets, there are iterators +(dw::core::Iterator), created by the method +dw::core::Widget::iterator (see there for more details). + +These simple iterators only iterate through one widget, and return +child widgets as dw::core::Content::WIDGET. The next call of +dw::core::Iterator::next will return the piece of contents \em after +(not within) this child widget. + +If you want to iterate through the whole widget trees, there are two +possibilities: + +<ol> +<li> Use a recursive function. Of course, with this approach, you are + limited by the program flow. + +<li> Maintain a stack of iterators, so you can freely pass this stack + around. This is already implemented, as dw::core::DeepIterator. +</ol> + +As an example, dw::core::SelectionState represents the selected region +as two instances of dw::core::DeepIterator. + + +<h2>Finding Text</h2> + +See dw::core::Layout::findtextState and dw::core::FindtextState +(details in the latter). There are delegation methods: + +<ul> +<li> dw::core::Layout::search and +<li> dw::core::Layout::resetSearch. +</ul> + + +<h2>Anchors and Scrolling</h2> + +In some cases, it is necessary to scroll to a given position, or to +an anchor, programmatically. + +<h3>Anchors</h3> + +Anchors are defined by widgets, e.g. dw::Textblock defines them, when +dw::Textblock::addAnchor is called. To jump to a specific anchor +within the current widget tree, use dw::core::Layout::setAnchor. + +This can be done immediately after assignig a toplevel widget, even +when the anchor has not yet been defined. The layout will remember the +anchor, and jump to the respective position, as soon as possible. Even +if the anchor position changes (e.g., when an anchor is moved +downwards, since some space is needed for an image in the text above), +the position is corrected. + +As soon as the user scrolls the viewport, this correction is not done +anymore. If in dillo, the user request a page with an anchor, which is +quite at the bottom of the page, he may be get interested in the text +at the beginning of the page, and so scrolling down. If then, after +the anchor has been read and added to the dw::Textblock, this anchor +would be jumped at, the user would become confused. + +The anchor is dismissed, too, when the toplevel widget is removed +again. + +\todo Currently, anchors only define vertical positions. + +<h3>Scrolling</h3> + +To scroll to a given position, use the method +dw::core::Layout::scrollTo. It expects several parameters: + +<ul> +<li>a horizontal adjustment parameter, defined by dw::core::HPosition, +<li>a vertical adjustment parameter, defined by dw::core::VPosition, and +<li>a rectangle (\em x, \em y, \em width and \em heigh) of the region + to be adjusted. +</ul> + +If you just want to move the canvas coordinate (\em x, \em y) into the +upper left corner of the viewport, you can call: + +\code +dw::core::Layout *layout; +// ... +layout->scrollTo(dw::core::HPOS_LEFT, dw::core::VPOS_TOP, 0, 0, 0, 0); +\endcode + +By using dw::core::HPOS_NO_CHANGE or dw::core::VPOS_NO_CHANGE, you can +change only one dimension. dw::core::HPOS_INTO_VIEW and +dw::core::VPOS_INTO_VIEW will cause the viewport to move as much as +necessary, that the region is visible in the viewport (this is +e.g. used for finding text). + + +<h2>Further Documentations</h2> + +<ul> +<li> dw::core::style +<li> dw::core::ui +<li> \ref dw-images-and-backgrounds +</ul> + +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/dw-widget-sizes.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,186 @@ +/** \page dw-widget-sizes Sizes of Dillo Widgets + +<h2>Allocation</h2> + +Each widget has an \em allocation at a given time, this includes + +<ul> +<li> the position (\em x, \em y) relative to the upper left corner of the + canvas, and +<li> the size (\em width, \em ascent, \em descent). +</ul> + +The \em canvas is the whole area available for the widgets, in most +cases, only a part is seen in a viewport. The allocation of the toplevel widget is exactly the allocation of the canvas, i.e. + +<ul> +<li> the position of the toplevel widget is always (0, 0), and +<li> the canvas size is defined by the size of the toplevel widget. +</ul> + +The size of a widget is not simply defined by the width and the +height, instead, widgets may have a base line, and so are vertically +divided into an ascender (which height is called \em ascent), and a +descender (which height is called \em descent). The total height is so +the sum of \em ascent and \em descent. + +Sizes of zero are allowed. The upper limit for the size of a widget is +defined by the limits of the C++ type \em int. + +\image html dw-size-of-widget.png Allocation of a Widget + +In the example in the image, the widget has the following allocation: + +<ul> +<li>\em x = 50 +<li>\em y = 50 +<li>\em width = 150 +<li>\em ascent = 150 +<li>\em descent = 100 +</ul> + +The current allocation of a widget is hold in +dw::core::Widget::allocation. It can be set from outside by +callcalling dw::core::Widget::sizeAllocate. This is a concrete method, +which will call dw::core::Widget::sizeAllocateImpl (see code of +dw::core::Widget::sizeAllocate for details). + +For trivial widgets (like dw::Bullet), +dw::core::Widget::sizeAllocateImpl does not need to be +implemented. For more complex widgets, the implementation should call +dw::core::Widget::sizeAllocate (not +dw::core::Widget::sizeAllocateImpl) on all child widgets, with +appropriate child allocations. dw::core::Widget::allocation should not +be changed here, this is already done in +dw::core::Widget::sizeAllocate. + +<h2>Requisitions</h2> + +A widget may prefer a given size for the allocation. This size, the +\em requisition, should be returned by the method +dw::core::Widget::sizeRequestImpl. In the simplest case, this is +independent of the context, e.g. for an +image. dw::Image::sizeRequestImpl returns the following size: + +<ul> +<li> If no buffer has yet been assigned (see dw::Image for more details), + the size necessary for the alternative text is returned. If no + alternative text has been set, zero is returned. + +<li> If a buffer has been assigned (by dw::Image::setBuffer), the root + size is returned (i.e. the original size of the image to display). +</ul> + +This is a bit simplified, dw::Image::sizeRequestImpl should also deal +with margins, borders and paddings, see dw::core::style. + +From the outside, dw::Image::sizeRequest should be called, which does +a bit of optimization. Notice that in dw::Image::sizeRequestImpl, no +optimization like lazy evaluation is necessary, this is already done +in dw::Image::sizeRequest. + +A widget, which has children, will likely call dw::Image::sizeRequest +on its children, to calculate the total requisition. + +The caller (this is either the dw::core::Layout, or the parent +widget), may, but also may not consider the requisition. Instead, a +widget must deal with any allocation. (For example, dw::Image scales +the image buffer when allocated at another size.) + +<h2>Size Hints</h2> + +Some widgets do not have an inherent size, but depend on the context, +e.g. the viewport size. These widgets should adhere to <i>size hints</i>, +i.e. implement the methods dw::core::Widget::setWidth, +dw::core::Widget::setAscent and dw::core::Widget::setDescent. The values +passed to the calles are + +<ul> +<li> the viewport size (ascent is the heigt here, while descent is 0) for + the toplevel widget, and +<li> determined by the parent for its child widgets. +</ul> + +Generally, the values should define the available space for the +widget. + +A widget, which depends on size hints, should call +dw::core::Widget::queueResize, when apropriate. + +\todo There should be a definition of "available space". + +<h2>Width Extremes</h2> + +dw::Table uses width extremes for fast calculation of column +widths. The structure dw::core::Extremes represents the minimal and +maximal width of a widget, as defined by: + +<ul> +<li> the minimal width is the smallest width, at which a widget can still + display contents, and +<li> the maximal width is the largest width, above which increasing the width + does not make any sense. +</ul> + +Especially the latter is vaguely defined, here are some examples: + +<ul> +<li> For those widgets, which do not depend on size hints, the minimal and + the maximal width is the inherent width (the one returned by + dw::core::Widget::sizeRequest). + +<li> For a textblock, the minimal width is the width of the widest + (unbreakable) word, the maximal width is the width of the total + paragraph (stretching a paragraph further would only waste space). + Actually, the implementation of dw::Textblock::getExtremesImpl is + a bit more complex. + +<li> dw::Table is an example, where the width extremes are calculated + from the width extremes of the children. +</ul> + +Handling width extremes is similar to handling requisitions, a widget +must implement dw::core::Widget::getExtremesImpl, but a caller will +use dw::core::Widget::getExtremes. + + +<h2>Resizing</h2> + +When the widget changes its size (requisition), it should call +dw::core::Widget::queueResize. The next call of +dw::core::Widget::sizeRequestImpl should then return the new +size. See dw::Image::setBuffer as an example. + +Interna are described in the code of dw::core::Widget::queueResize. + +<h3>Incremental Resizing</h3> + +A widget may calculate its size based on size calculations already +done before. In this case, a widget must exactly know the reasons, why +a call of dw::core::Widget::sizeRequestImpl is necessary. To make use +of this, a widget must implement the following: + +<ol> +<li> There is a member dw::core::Widget::parentRef, which is + totally under control of the parent widget (and so sometimes not + used at all). It is necessary to define how parentRef is used + by a specific parent widget, and it has to be set to the correct + value whenever necessary. + +<li> The widget must implement dw::core::Widget::markSizeChange and + dw::core::Widget::markExtremesChange, these methods are called in + two cases: + + <ol> + <li> directly after dw::core::Widget::queueResize, with the argument + ref was passed to dw::core::Widget::queueResize, and + <li> if a child widget has called dw::core::Widget::queueResize, + with the value of the parent_ref member of this child. + </ol> +</ol> + +This way, a widget can exactly keep track on size changes, and so +implement resizing in a faster way. A good example on how to use this +is dw::Textblock. + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/fltk-problems.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,219 @@ +/** \page fltk-problems Problems with FLTK + +<h2>dw::fltk::FltkViewport</h2> + +Current problems: + +<ul> +<li> dw::fltk::FltkViewport::draw should only draw the region, for which e.g. + an expose event was received. + +<li> dw::fltk::FltkViewport::queueDraw will collect data, which has to be + redrawn. Currently, it calls redraw (DAMAGE_EXPOSE), can this be changed, + so that dw::fltk::FltkViewport::draw will distinguish between the two + cases? + +<li> For Scrolling, something similar applies, only parts of the viewport + have to be redrawn. + +<li> Also for Scrolling, it is necessary to copy parts of the window. + +<li> How should dw::fltk::FltkViewport::cancelQueueDraw be implemented? + +<li> If the value of a scrollbar is changed by the program, not the user, + the callback seems not to be called. Can this be assured? + +<li> The same for dw::fltk::FltkViewport::layout? + +<li> Also, the problems with the widgets seems to work. Also sure? + +<li> When drawing, clipping of 32 bit values seems to work. + +<li> Who is responsable for clearing before drawing? + +<li> The embedded buttons are not redrawn, when pressing the mouse button + on them. + +<li> The item group within a selection widget (menu) should not be selectable. +</ul> + + +<h2>dw::fltk::FltkPlatform</h2> + +<ul> +<li> There is the problem, that fltk::font always returns a font, the + required one, or a replacements. The latter is not wanted in all + cases, e.g. when several fonts are tested. Perhaps, this could be + solved by searching in the font list. + +<li> In dw::fltk::FltkFont::FltkFont, fltk::measure does not seem to work + for the calculation of dw::core::style::Font::xHeight. + +<li> Distinction between italics and oblique would be nice + (dw::fltk::FltkFont::FltkFont). +</ul> + + +<h2>dw::fltk::ui::FltkCheckButtonResource</h2> + +Groups of fltk::RadioButton must be added to one fltk::Group, which is +not possible in this context. There are two alternatives: + +<ol> +<li>there is a more flexible way to group radio buttons, or +<li>radio buttons are not grouped, instead, grouping (especially + unchecking other buttons) is done by the application. +</ol> + +(This is mostly solved.) + +<h2>dw::fltk::FltkImgbuf</h2> + +Alpha transparency should be best abstracted by FLTK itself. If not, +perhaps different implementations for different window systems could +be used. Then, it is for X necessary to use GCs with clipping masks. + + +<h2>Lower Priority</h2> + +There needs to be an XEmbed implementation. + + +<h2>dw::fltk::ui::ComplexButton</h2> + +Unfortunately, FLTK does not provide a button with Group as parent, so +that children may be added to the button. dw::fltk::ui::ComplexButton does +exactly this, and is, in an ugly way, a modified copy of the FLTK +button. + +It would be nice, if this is merged with the standard FLTK +button. Furthermore, setting the type is strange. + +If the files do not compile, it may be useful to create a new one from +the FLTK source: + +<ol> +<li> Copy fltk/Button.h from FLTK to dw/fltkcomplexbutton.hh and + src/Button.cxx to dw/fltkcomplexbutton.cc. + +<li> In both files, rename "Button" to "ComplexButton". Automatic replacing + should work. + +<li> Apply the changes below. +</ol> + +The following changes should be applied manually. + +<h3>Changes in fltkcomplexbutton.hh</h3> + +First of all, the #define's for avoiding multiple includes: + +\code +-#ifndef fltk_ComplexButton_h // fltk_Button_h formerly +-#define fltk_ComplexButton_h ++#ifndef __FLTK_COMPLEX_BUTTON_HH__ ++#define __FLTK_COMPLEX_BUTTON_HH__ +\endcode + +at the beginning and + +\code +-#endif ++#endif // __FLTK_COMPLEX_BUTTON_HH__ +\endcode + +at the end. Then, the namespace is changed: + +\code +-namespace fltk { ++namespace dw { ++namespace fltk { ++namespace ui { +\endcode + +at the beginning and + +\code +-} ++} // namespace ui ++} // namespace fltk ++} // namespace dw +\endcode + +at the end. Most important, the base class is changed: + +\code +-#ifndef fltk_Widget_h +-#include "Widget.h" +-#endif ++#include <fltk/Group.h> +\endcode + +and + +\code +-class FL_API ComplexButton : public Widget { ++class ComplexButton: public ::fltk::Group ++{ +\endcode + +Finally, for dw::fltk::ui::ComplexButton::default_style, there is a +namespace conflict: + +\code +- static NamedStyle* default_style; ++ static ::fltk::NamedStyle* default_style; +\endcode + +<h3>Changes in fltkcomplexbutton.cc</h3> + +First, #include's: + +\code + + #include <fltk/events.h> + #include <fltk/damage.h> +-#include <fltk/ComplexButton.h> // <fltk/Button.h> formerly + #include <fltk/Group.h> + #include <fltk/Box.h> + #include <stdlib.h> ++ ++#include "fltkcomplexbutton.hh" +\endcode + +Second, namespaces: + +\code ++using namespace dw::fltk::ui; + using namespace fltk; +\endcode + +Since the base class is now Group, the constructor must be changed: + +\code +-ComplexButton::ComplexButton(int x,int y,int w,int h, const char *l) : Widget(x,y,w,h,l) { ++ComplexButton::ComplexButton(int x,int y,int w,int h, const char *l) : ++ Group(x,y,w,h,l) ++{ +\endcode + +At the end of the constructor, + +\code ++ type (NORMAL); + } +\endcode + +must be added (I've forgotten, what this is for). + +Finally, the button must draw its children (end of +dw::fltk::ui::ComplexButton::draw()): + +\code ++ ++ for (int i = 0; i < children (); i++) ++ draw_child (*child (i)); + } +\endcode + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/index.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,48 @@ +/** \mainpage + +<h2>Overview</h2> + +This is a list of documents to start with: + +<ul> +<li> \ref lout +<li> \ref dw-overview (map at \ref dw-map) +</ul> + +Currently, a document \ref fltk-problems is maintained, ideally, it +will be removed soon. + +<h2>Historical</h2> + +<h3>Replacements for GTK+ and GLib</h3> + +There are several classes etc., which are used for tasks formerly (in the GTK+ +version of dillo) achieved by GtkObject (in 1.2.x, this is part of Gtk+) and +GLib. For an overview on all this, take a look at \ref lout. + +GtkObject is replaced by the following: + +<ul> +<li> object::Object is a common base class for many classes used dillo. In + the namespace ::object, there are also some more common classes and + interfaces. + +<li> A sub class of object::Object is identity::IdentifiableObject, which + allows to determine the class at run-time (equivalent to GTK_CHECK_CAST + in GtkObject). + +<li> For signals, there is the namespace ::signal. +</ul> + +Hash tables, linked lists etc. can be found in the ::container namespace, +several useful macros from GLib have been implemented as inline functions +in the ::misc namespace. + +As an alternative to the macros defined in list.h, there is also a template +class, misc::SimpleVector, which does the same. + +<h3>Changes in Dw</h3> + +If you have been familiar with Dw before, take a look at \ref dw-changes. + +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/lout.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,94 @@ +/** \page lout Lots of Useful Tools + +In the "lout" directory, there are some common base functionality for +C++. Most is described as doxygen comments, this text gives an +overview. + +<h2>Common Base Class</h2> + +Many classes are derived from object::Object, which defines some +general methods. See there for more information. + +For the case, that you need primitive C++ types, there are some +wrappers: + +<table> +<tr><th>C++ Type <th>Wrapper Class +<tr><td>void* <td>object::Pointer +<tr><td>specific pointer <td>object::TypedPointer (template class) +<tr><td>int <td>object::Integer +<tr><td>const char* <td>object::ConstString +<tr><td>char* <td>object::String +</table> + + +<h2>Containers</h2> + +In the namespace ::container, several container classes are defined, +which all deal with instances of object::Object. + +<h3>Untyped Containers</h3> + +In container::untyped, there are the following containers: + +<ul> +<li>container::untyped::Vector, a dynamically increases array, +<li>container::untyped::List, a linked list, +<li>container::untyped::HashTable, a hash table, and +<li>container::untyped::Stack, a stack. +</ul> + +All provide specific methods, but since they have a common base class, +container::untyped::Collection, they all provide iterators, by the +method container::untyped::Collection::iterator. + +<h3>Typed Containers</h3> + +container::typed provides wrappers for the container classes defined +in container::untyped, which are more type safe, by using C++ +templates. + + +<h2>Signals</h2> + +For how to connect objects at run-time (to reduce dependencies), take a +look at the ::signal namespace. + +There is also a base class signal::ObservedObject, which implements +signals for deletion. + + +<h2>Debugging</h2> + +In debug.hh, there are some some useful macros for debugging messages, +see the file for mor informations. + + +<h2>Identifying Classes at Runtime</h2> + +If the class of an object must be identified at runtime, +identity::IdentifiableObject should be used as the base class, see +there for more details. + + +<h2>Miscellaneous</h2> + +The ::misc namespace provides several miscellaneous stuff: + +<ul> +<li> In some contexts, it is necessary to compare objects + (less/greater), for this, also misc::Comparable must be + implemented. For example., container::untyped::Vector::sort and + container::typed::Vector::sort cast the elements to + misc::Comparable. This can be mixed with object::Object. +<li> misc::SimpleVector, a simple, template based vector class (not + depending on object::Object), +<li> misc::StringBuffer, class for fast concatenation of a large number + of strings, +<li> misc::BitSet implements a bitset. +<li> useful (template) functions (misc::min, misc::max), and +<li> some functions useful for runtime checks (misc::assert, + misc::assertNotReached). +</ul> + +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/rounding-errors.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,24 @@ +/** \page rounding-errors How to Avoid Rounding Errors + +(Probably, this is a standard algorithm, so if someone knows the name, +drop me a note.) + +If something like + +\f[y_i = {x_i a \over b}\f] + +is to be calculated, and all numbers are integers, a naive +implementation would result in something, for which + +\f[\sum y_i \ne {(\sum x_i) a \over b}\f] + +because of rounding errors, due to the integer division. This can be +avoided by transforming the formula into + +\f[y_i = {(\sum_{j=0}^{j=i} x_j) a \over b} - \sum_{j=0}^{j=i} y_j\f] + +Of corse, when all \f$y_i\f$ are calculated in a sequence, +\f$\sum_{j=0}^{j=i} x_j\f$ and \f$\sum_{j=0}^{j=i} y_j\f$ can be +accumulated in the same loop. + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/uml-legend.doc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,192 @@ +/** \page uml-legend UML Legend + +This page describes the notation for several diagrams used in the +documentation, which is a slight variation of UML. + + +<h2>Classes</h2> + +Classes are represented by boxes, containing there names: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + fontname=Helvetica; fontsize=8; + "Concrete Class"; + "Abstract Class" [color="#a0a0a0"]; + Interface [color="#ff8080"]; +} +\enddot + +(In most cases, the attributes and operations are left away, for +better readibility. Just click on it, to get to the detailed +description.) + +Of course, in C++, there are no interfaces, but here, we call a class, +which has only virtual abstract methods, and so does not provide any +functionality, an interface. + +Templates get a yellow background color: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10, + fillcolor="#ffffc0", style="filled"]; + fontname=Helvetica; fontsize=8; + "Concrete Class Template"; + "Abstract Class Template" [color="#a0a0a0"]; + "Interface Template" [color="#ff8080"]; +} +\enddot + + +<h2>Objects</h2> + +In some cases, an examle for a concrete constellation of objects is +shown. An object is represented by a box containing a name and the +class, separated by a colon. + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", labelfontname=Helvetica, labelfontsize=10, + color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + "x: A" -> "y1: B"; + "x: A" -> "y2: B"; +} +\enddot + +The names (\em x, \em y, and \em z) are only meant within the context +of the diagram, there needs not to be a relation to the actual names +in the program. They should be unique within the diagram. + +Classes and objects may be mixed in one diagram. + + +<h2>Associations</h2> + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", labelfontname=Helvetica, labelfontsize=10, + color="#404040", labelfontcolor="#000080", + fontname=Helvetica, fontsize=10, fontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + A -> B [headlabel="*", taillabel="1", label="x"]; +} +\enddot + +In this example, one instance of A refers to an arbitrary number of B +instances (denoted by the "*"), and each instance of B is referred by +exactly one ("1") A. The label \em x is the name of the association, +in most cases the name of the field, e.g. A::x. + +Possible other values for the \em multiplicity: + +<ul> +<li> a concrete number, in most cases "1", +<li> a range, e.g. "0..1", +<li> "*", denoting an arbitrary number. +</ul> + + +<h2>Implementations and Inheritance</h2> + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica, + labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + A[color="#ff8080"]; + B[color="#ff8080"]; + C; + D; + A -> B; + A -> C [style="dashed"]; + C -> D; +} +\enddot + +In this example, + +<ul> +<li> the interface B extends the interface A, +<li> the class C implements the interface A, and +<li> the class D extends the class C. +</ul> + + +<h2>Template Instanciations</h2> + +Template instanciations are shown as own classes/interfaces, the +instanciation by the template is shown by a yellow dashed arrow: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica, + labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + A[color="#ff8080"]; + B[color="#ff8080"]; + C[color="#ff8080", fillcolor="#ffffc0", style="filled"]; + C_A[color="#ff8080", label="C \<A\>"]; + C_B[color="#ff8080", label="C \<A\>"]; + D; + + C -> C_A [arrowhead="open", arrowtail="none", style="dashed", + color="#808000"]; + C -> C_B [arrowhead="open", arrowtail="none", style="dashed", + color="#808000"]; + A -> C_A; + B -> C_B; + C_A -> D [style="dashed"]; +} +\enddot + +In this example, the interface template C uses the template argument +as super interface. + + +<h2>Packages</h2> + +Packages are presented by dashed rectangles: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica, + labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + subgraph cluster_1 { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="package 1"; + + A; + B [color="#a0a0a0"]; + } + + subgraph cluster_2 { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="package 2"; + + C; + D [color="#a0a0a0"]; + E + } + + A -> C; + B -> D; + D -> E; + E -> A [arrowhead="open", arrowtail="none"]; +} +\enddot + +Packages may be nested. + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/Makefile.am Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,70 @@ +noinst_LIBRARIES = \ + libDw-core.a \ + libDw-fltk.a \ + libDw-widgets.a + +libDw_core_a_SOURCES = \ + core.hh \ + events.hh \ + findtext.cc \ + findtext.hh \ + imgbuf.hh \ + iterator.cc \ + iterator.hh \ + layout.cc \ + layout.hh \ + platform.hh \ + selection.hh \ + selection.cc \ + style.cc \ + style.hh \ + types.cc \ + types.hh \ + ui.cc \ + ui.hh \ + view.hh \ + widget.cc \ + widget.hh + +libDw_fltk_a_SOURCES = \ + fltkcomplexbutton.cc \ + fltkcomplexbutton.hh \ + fltkcore.hh \ + fltkflatview.cc \ + fltkflatview.hh \ + fltkimgbuf.cc \ + fltkimgbuf.hh \ + fltkmisc.cc \ + fltkmisc.hh \ + fltkplatform.cc \ + fltkplatform.hh \ + fltkpreview.hh \ + fltkpreview.cc \ + fltkui.cc \ + fltkui.hh \ + fltkviewbase.cc \ + fltkviewbase.hh \ + fltkviewport.cc \ + fltkviewport.hh + +libDw_fltk_a_CXXFLAGS = @LIBFLTK_CXXFLAGS@ + +libDw_widgets_a_SOURCES = \ + alignedtextblock.cc \ + alignedtextblock.hh \ + bullet.cc \ + bullet.hh \ + image.cc \ + image.hh \ + listitem.cc \ + listitem.hh \ + ruler.cc \ + ruler.hh \ + table.cc \ + table.hh \ + tablecell.cc \ + tablecell.hh \ + textblock.cc \ + textblock.hh + +EXTRA_DIST = preview.xbm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/alignedtextblock.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,105 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "alignedtextblock.hh" +#include <stdio.h> + +namespace dw { + +AlignedTextblock::List::List () +{ + textblocks = new misc::SimpleVector <AlignedTextblock*> (4); + values = new misc::SimpleVector <int> (4); + maxValue = 0; + refCount = 0; +} + +AlignedTextblock::List::~List () +{ + delete textblocks; + delete values; +} + +int AlignedTextblock::List::add(AlignedTextblock *textblock) +{ + textblocks->increase (); + values->increase (); + textblocks->set (textblocks->size () - 1, textblock); + refCount++; + return textblocks->size () - 1; +} + +void AlignedTextblock::List::unref(int pos) +{ + assert (textblocks->get (pos) != NULL); + textblocks->set (pos, NULL); + refCount--; + + if(refCount == 0) + delete this; +} + +int AlignedTextblock::CLASS_ID = -1; + +AlignedTextblock::AlignedTextblock (bool limitTextWidth): + Textblock (limitTextWidth) +{ + registerName ("dw::AlignedTextblock", &CLASS_ID); +} + +void AlignedTextblock::setRefTextblock (AlignedTextblock *ref) +{ + if(ref == NULL) + list = new List(); + else + list = ref->list; + + listPos = list->add (this); + updateValue (); +} + +AlignedTextblock::~AlignedTextblock() +{ + list->unref (listPos); +} + +void AlignedTextblock::updateValue () +{ + if (list) { + list->setValue (listPos, getValue ()); + + if (list->getValue (listPos) > list->getMaxValue ()) { + // New value greater than current maximum -> apply it to others. + list->setMaxValue (list->getValue (listPos)); + + for (int i = 0; i < list->size (); i++) + if (list->getTextblock (i)) + list->getTextblock (i)->setMaxValue (list->getMaxValue (), + list->getValue (i)); + } else { + /* No change, apply old max_value only to this page. */ + setMaxValue (list->getMaxValue (), list->getValue (listPos)); + } + } +} + +} // namespace dw
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/alignedtextblock.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,61 @@ +#ifndef __DW_ALIGNEDTEXTBLOCK_HH__ +#define __DW_ALIGNEDTEXTBLOCK_HH__ + +#include "core.hh" +#include "textblock.hh" + +namespace dw { + +/** + * \brief Base widget for all textblocks (sub classes of dw::Textblock), which + * are positioned vertically and aligned horizontally. + */ +class AlignedTextblock: public Textblock +{ +private: + class List + { + private: + misc::SimpleVector <AlignedTextblock*> *textblocks; + misc::SimpleVector <int> *values; + int maxValue, refCount; + + ~List (); + + public: + List (); + inline int add (AlignedTextblock *textblock); + void unref (int pos); + + inline int getMaxValue () { return maxValue; } + inline void setMaxValue (int maxValue) { this->maxValue = maxValue; } + + inline int size () { return textblocks->size (); } + inline AlignedTextblock *getTextblock (int pos) { + return textblocks->get (pos); } + inline int getValue (int pos) {return values->get (pos); } + inline void setValue (int pos, int value) { + return values->set (pos, value); } + }; + + List *list; + int listPos; + +protected: + AlignedTextblock(bool limitTextWidth); + + virtual int getValue () = 0; + virtual void setMaxValue (int maxValue, int value) = 0; + + void setRefTextblock (AlignedTextblock *ref); + void updateValue (); + +public: + static int CLASS_ID; + + ~AlignedTextblock(); +}; + +} // namespace dw + +#endif // __DW_ALIGNEDTEXTBLOCK_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/bullet.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,72 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "bullet.hh" + +#include <stdio.h> + +namespace dw { + +Bullet::Bullet () +{ +} + +void Bullet::sizeRequestImpl (core::Requisition *requisition) +{ + requisition->width = lout::misc::max (getStyle()->font->xHeight * 4 / 5, 1); + requisition->ascent = lout::misc::max (getStyle()->font->xHeight, 1); + requisition->descent = 0; +} + +void Bullet::draw (core::View *view, core::Rectangle *area) +{ + int x, y, l; + bool filled = true; + + l = lout::misc::min (allocation.width, allocation.ascent); + x = allocation.x; + y = allocation.y + allocation.ascent - getStyle()->font->xHeight; + + switch (getStyle()->listStyleType) { + case core::style::LIST_STYLE_TYPE_SQUARE: + view->drawRectangle (getStyle()->color, + core::style::Color::SHADING_NORMAL, + false, x, y, l, l); + break; + case core::style::LIST_STYLE_TYPE_CIRCLE: + filled = false; + // Fall Through + case core::style::LIST_STYLE_TYPE_DISC: + default: + view->drawArc (getStyle()->color, core::style::Color::SHADING_NORMAL, + filled, x, y, l, l, 0, 360); + } +} + +core::Iterator *Bullet::iterator (core::Content::Type mask, bool atEnd) +{ + //return new core::TextIterator (this, mask, atEnd, "*"); + /** \bug Not implemented. */ + return new core::EmptyIterator (this, mask, atEnd); +} + +} // namespace dw
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/bullet.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,27 @@ +#ifndef __BULLET_HH__ +#define __BULLET_HH__ + +#include "core.hh" + +namespace dw { + +/** + * \brief Displays different kind of bullets. + * + * Perhaps, in the future, Unicode characters are used for bullets, so this + * widget is not used anymore. + */ +class Bullet: public core::Widget +{ +protected: + void sizeRequestImpl (core::Requisition *requisition); + void draw (core::View *view, core::Rectangle *area); + core::Iterator *iterator (core::Content::Type mask, bool atEnd); + +public: + Bullet (); +}; + +} // namespace dw + +#endif // __BULLET_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/core.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,58 @@ +#ifndef __DW_CORE_HH__ +#define __DW_CORE_HH__ + +#define __INCLUDED_FROM_DW_CORE_HH__ + +/** + * \brief Dw is in this namespace, or sub namespaces of this one. + * + * The core can be found in dw::core, widgets are defined directly here. + * + * \sa \ref dw-overview + */ +namespace dw { + +/** + * \brief The core of Dw is defined in this namespace. + * + * \sa \ref dw-overview + */ +namespace core { + +typedef unsigned char byte; + +class Layout; +class View; +class Widget; +class Iterator; + +namespace ui { + +class ResourceFactory; + +} // namespace ui + + +} // namespace dw +} // namespace core + +#include "../lout/object.hh" +#include "../lout/container.hh" +#include "../lout/signal.hh" + +#include "types.hh" +#include "events.hh" +#include "imgbuf.hh" +#include "style.hh" +#include "view.hh" +#include "platform.hh" +#include "iterator.hh" +#include "findtext.hh" +#include "selection.hh" +#include "layout.hh" +#include "widget.hh" +#include "ui.hh" + +#undef __INCLUDED_FROM_DW_CORE_HH__ + +#endif // __DW_CORE_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/events.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,83 @@ +#ifndef __DW_EVENTS_HH__ +#define __DW_EVENTS_HH__ + +#ifndef __INCLUDED_FROM_DW_CORE_HH__ +# error Do not include this file directly, use "core.hh" instead. +#endif + +namespace dw { +namespace core { + +/** + * \brief Platform independant representation. + */ +enum ButtonState +{ + /* We won't use more than these ones. */ + SHIFT_MASK = 1 << 0, + CONTROL_MASK = 1 << 1, + META_MASK = 1 << 2, + BUTTON1_MASK = 1 << 3, + BUTTON2_MASK = 1 << 4, + BUTTON3_MASK = 1 << 5 +}; + +/** + * \brief Base class for all events. + * + * The dw::core::Event hierarchy describes events in a platform independant + * way. + */ +class Event: public object::Object +{ +public: +}; + +/** + * \brief Base class for all mouse events. + */ +class MouseEvent: public Event +{ +public: + ButtonState state; +}; + +/** + * \brief Base class for all mouse events related to a specific position. + */ +class MousePositionEvent: public MouseEvent +{ +public: + int xCanvas, yCanvas, xWidget, yWidget; +}; + +/** + * \brief Represents a button press or release event. + */ +class EventButton: public MousePositionEvent +{ +public: + int numPressed; /* 1 for simple click, 2 for double click, etc. */ + int button; +}; + +/** + * \brief Represents a mouse motion event. + */ +class EventMotion: public MousePositionEvent +{ +}; + +/** + * \brief Represents a enter or leave notify event. + */ +class EventCrossing: public MouseEvent +{ +public: + Widget *lastWidget, *currentWidget; +}; + +} // namespace dw +} // namespace core + +#endif // __DW_EVENTS_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/findtext.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,209 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "core.hh" + +namespace dw { +namespace core { + +FindtextState::FindtextState () +{ + key = NULL; + nexttab = NULL; + widget = NULL; + iterator = NULL; + hlIterator = NULL; +} + +FindtextState::~FindtextState () +{ + if (key) + delete key; + if (nexttab) + delete[] nexttab; + if (iterator) + delete iterator; + if (hlIterator) + delete hlIterator; +} + +void FindtextState::setWidget (Widget *widget) +{ + this->widget = widget; + + // A widget change will restart the search. + if (key) + delete key; + key = NULL; + if (nexttab) + delete[] nexttab; + nexttab = NULL; + + if (iterator) + delete iterator; + iterator = NULL; + if (hlIterator) + delete hlIterator; + hlIterator = NULL; +} + +FindtextState::Result FindtextState::search (const char *key, bool caseSens) +{ + if (!widget || *key == 0) // empty keys are not found + return NOT_FOUND; + + bool wasHighlighted = unhighlight (); + bool newKey; + + // If the key (or the widget) changes (including case sensitivity), + // the search is started from the beginning. + if (this->key == NULL || this->caseSens != caseSens || + strcmp (this->key, key) != 0) { + newKey = true; + if (this->key) + delete this->key; + this->key = strdup (key); + this->caseSens = caseSens; + + if (nexttab) + delete[] nexttab; + nexttab = createNexttab (key, caseSens); + + if (iterator) + delete iterator; + iterator = new CharIterator (widget); + iterator->next (); + } else + newKey = false; + + bool firstTrial = !wasHighlighted || newKey; + + if (search0 ()) { + // Highlighlighting is done with a clone. + hlIterator = iterator->cloneCharIterator (); + for (int i = 0; key[i]; i++) + hlIterator->next (); + CharIterator::highlight (iterator, hlIterator, HIGHLIGHT_FINDTEXT); + CharIterator::scrollTo (iterator, hlIterator, + HPOS_INTO_VIEW, VPOS_CENTER); + + // The search will continue from the word after the found position. + iterator->next (); + return SUCCESS; + } else { + if (firstTrial) + return NOT_FOUND; + else { + // Nothing found anymore, reset the state for the next trial. + delete iterator; + iterator = new CharIterator (widget); + iterator->next (); + + // We expect a success. + Result result2 = search (key, caseSens); + assert (result2 == SUCCESS); + return RESTART; + } + } +} + +/** + * \brief This method is called when the user closes the "find text" dialog. + */ +void FindtextState::resetSearch () +{ + unhighlight (); + + if (key) + delete key; + key = NULL; +} + +int *FindtextState::createNexttab (const char *key, bool caseSens) +{ + int i = 0; + int j = -1; + int l = strlen (key); + int *nexttab = new int[l + 1]; // + 1 is necessary for l == 1 case + nexttab[0] = -1; + + do { + if (j == -1 || charsEqual (key[i], key[j], caseSens)) { + i++; + j++; + nexttab[i] = j; + //_MSG ("nexttab[%d] = %d\n", i, j); + } else + j = nexttab[j]; + } while (i < l - 1); + + return nexttab; +} + +/** + * \brief Unhighlight, and return whether a region was highlighted. + */ +bool FindtextState::unhighlight () +{ + if (hlIterator) { + CharIterator *start = hlIterator->cloneCharIterator (); + for (int i = 0; key[i]; i++) + start->prev (); + + CharIterator::unhighlight (start, hlIterator, HIGHLIGHT_FINDTEXT); + delete start; + delete hlIterator; + hlIterator = NULL; + + return true; + } else + return false; +} + +bool FindtextState::search0 () +{ + if (iterator->getChar () == CharIterator::END) + return false; + + int j = 0; + bool nextit = true; + int l = strlen (key); + + do { + if (j == -1 || charsEqual (iterator->getChar (), key[j], caseSens)) { + j++; + nextit = iterator->next (); + } else + j = nexttab[j]; + } while (nextit && j < l); + + if (j >= l) { + // Go back to where the word was found. + for (int i = 0; i < l; i++) + iterator->prev (); + return true; + } else + return false; +} + +} // namespace dw +} // namespace core
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/findtext.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,82 @@ +#ifndef __DW_FINDTEXT_STATE_H__ +#define __DW_FINDTEXT_STATE_H__ + +#ifndef __INCLUDED_FROM_DW_CORE_HH__ +# error Do not include this file directly, use "core.hh" instead. +#endif + +#include <ctype.h> + +namespace dw { +namespace core { + +class FindtextState +{ +public: + typedef enum { + /** \brief The next occurance of the pattern has been found. */ + SUCCESS, + + /** + * \brief There is no further occurance of the pattern, instead, the + * first occurance has been selected. + */ + RESTART, + + /** \brief The patten does not at all occur in the text. */ + NOT_FOUND + } Result; + +private: + /** + * \brief The key used for the last search. + * + * If dw::core::Findtext::search is called with the same key, the search + * is continued, otherwise it is restarted. + */ + char *key; + + /** \brief Whether the last search was case sensitive. */ + bool caseSens; + + /** \brief The table used for KMP search. */ + int *nexttab; + + /** \brief The top of the widget tree, in which the search is done. + * + * From this, the iterator will be constructed. Set by + * dw::core::Findtext::widget + */ + Widget *widget; + + /** \brief The position from where the next search will start. */ + CharIterator *iterator; + + /** + * \brief The position from where the characters are highlighted. + * + * NULL, when no text is highlighted. + */ + CharIterator *hlIterator; + + static int *createNexttab (const char *key, bool caseSens); + bool unhighlight (); + bool search0 (); + + inline static bool charsEqual (char c1, char c2, bool caseSens) + { return caseSens ? c1 == c2 : tolower (c1) == tolower (c2) || + isspace (c1) && isspace (c2); } + +public: + FindtextState (); + ~FindtextState (); + + void setWidget (Widget *widget); + Result search (const char *key, bool caseSens); + void resetSearch (); +}; + +} // namespace dw +} // namespace core + +#endif // __DW_FINDTEXT_STATE_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkcomplexbutton.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,282 @@ +// +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to "fltk-bugs@fltk.org". +// + +#include <fltk/events.h> +#include <fltk/damage.h> +#include <fltk/Group.h> +#include <fltk/Box.h> +#include <stdlib.h> + +#include "fltkcomplexbutton.hh" + +using namespace fltk; +using namespace dw::fltk::ui; + +/*! \class fltk::ComplexButton + + ComplexButtons generate callbacks when they are clicked by the user. You + control exactly when and how by changing the values for when(): + - fltk::WHEN_NEVER: The callback is not done, instead changed() is + turned on. + - fltk::WHEN_RELEASE: This is the default, the callback is done + after the user successfully clicks the button (i.e. they let it go + with the mouse still pointing at it), or when a shortcut is typed. + - fltk::WHEN_CHANGED : The callback is done each time the value() + changes (when the user pushes and releases the button, and as the + mouse is dragged around in and out of the button). + + ComplexButtons can also generate callbacks in response to fltk::SHORTCUT + events. The button can either have an explicit shortcut() value or a + letter shortcut can be indicated in the label() with an '&' + character before it. For the label shortcut it does not matter if + Alt is held down, but if you have an input field in the same window, + the user will have to hold down the Alt key so that the input field + does not eat the event first as an fltk::KEY event. + + \image html buttons.gif +*/ + +/*! \fn bool ComplexButton::value() const + The current value. True means it is pushed down, false means it is + not pushed down. The ToggleComplexButton subclass provides the ability for + the user to change this value permanently, otherwise it is just + temporary while the user is holding the button down. + + This is the same as Widget::state(). +*/ + +/*! \fn bool ComplexButton::value(bool) + Change the value(). Redraws the button and returns true if the new + value is different. This is the same function as Widget::state(). + See also Widget::set(), Widget::clear(), and Widget::setonly(). + + If you turn it on, a normal button will draw pushed-in, until + the user clicks it and releases it. +*/ + +static bool initial_state; + +int ComplexButton::handle(int event) { + return handle(event, Rectangle(w(),h())); +} + +int ComplexButton::handle(int event, const Rectangle& rectangle) { + switch (event) { + case ENTER: + case LEAVE: + redraw_highlight(); + case MOVE: + return 1; + case PUSH: + if (pushed()) return 1; // ignore extra pushes on currently-pushed button + initial_state = state(); + clear_flag(PUSHED); + do_callback(); + case DRAG: { + bool inside = event_inside(rectangle); + if (inside) { + if (!flag(PUSHED)) { + set_flag(PUSHED); + redraw(DAMAGE_VALUE); + } + } else { + if (flag(PUSHED)) { + clear_flag(PUSHED); + redraw(DAMAGE_VALUE); + } + } + if (when() & WHEN_CHANGED) { // momentary button must record state() + if (state(inside ? !initial_state : initial_state)) + do_callback(); + } + return 1;} + case RELEASE: + if (!flag(PUSHED)) return 1; + clear_flag(PUSHED); + redraw(DAMAGE_VALUE); + if (type() == RADIO) + setonly(); + else if (type()) // TOGGLE + state(!initial_state); + else { + state(initial_state); + if (when() & WHEN_CHANGED) {do_callback(); return 1;} + } + if (when() & WHEN_RELEASE) do_callback(); else set_changed(); + return 1; + case FOCUS: + redraw(1); // minimal redraw to just add the focus box + // grab initial focus if we are an ReturnComplexButton: + return shortcut()==ReturnKey ? 2 : 1; + case UNFOCUS: + redraw(DAMAGE_HIGHLIGHT); + return 1; + case KEY: + if (event_key() == ' ' || event_key() == ReturnKey + || event_key() == KeypadEnter) goto EXECUTE; + return 0; + case SHORTCUT: + if (!test_shortcut()) return 0; + EXECUTE: + if (type() == RADIO) { + if (!state()) { + setonly(); + if (when() & WHEN_CHANGED) do_callback(); else set_changed(); + } + } else if (type()) { // TOGGLE + state(!state()); + if (when() & WHEN_CHANGED) do_callback(); else set_changed(); + } + if (when() & WHEN_RELEASE) do_callback(); + return 1; + default: + return 0; + } +} + +//////////////////////////////////////////////////////////////// + +#include <fltk/draw.h> + +extern Widget* fl_did_clipping; + +/*! + This function provides a mess of back-compatabilty and Windows + emulation to subclasses of ComplexButton to draw with. It will draw the + button according to the current state of being pushed and it's + state(). If non-zero is passed for \a glyph_width then the glyph() + is drawn in that space on the left (or on the right if negative), + and it assummes the glyph indicates the state(), so the box is only + used to indicate the pushed state. +*/ +void ComplexButton::draw(int glyph_width) const +{ + // For back-compatability, setting color() or box() directly on a plain + // button will cause it to act like buttoncolor() or buttonbox() are + // set: + Style localstyle; + const Style* style = this->style(); + if (!glyph_width) { + localstyle = *style; + if (localstyle.color_) localstyle.buttoncolor_ = localstyle.color_; + if (localstyle.box_) localstyle.buttonbox_ = localstyle.box_; + if (localstyle.labelcolor_) localstyle.textcolor_ = localstyle.labelcolor_; + style = &localstyle; + } + + Box* box = style->buttonbox(); + + Flags box_flags = flags() | OUTPUT; + Flags glyph_flags = box_flags & ~(HIGHLIGHT|OUTPUT); + if (glyph_width) box_flags &= ~STATE; + + // only draw "inside" labels: + Rectangle r(0,0,w(),h()); + + if (box == NO_BOX) { + Color bg; + if (box_flags & HIGHLIGHT && (bg = style->highlight_color())) { + setcolor(bg); + fillrect(r); + } else if (label() || (damage()&(DAMAGE_EXPOSE|DAMAGE_HIGHLIGHT))) { + // erase the background so we can redraw the label in the new color: + draw_background(); + } + // this allows these buttons to be put into browser/menus: + //fg = fl_item_labelcolor(this); + } else { + if ((damage()&(DAMAGE_EXPOSE|DAMAGE_HIGHLIGHT)) + && !box->fills_rectangle()) { + // Erase the area behind non-square boxes + draw_background(); + } + } + + // Draw the box: + drawstyle(style,box_flags); + // For back-compatability we use any directly-set selection_color() + // to color the box: + if (!glyph_width && state() && style->selection_color_) { + setbgcolor(style->selection_color_); + setcolor(contrast(style->selection_textcolor(),style->selection_color_)); + } + box->draw(r); + Rectangle r1(r); box->inset(r1); + + if (glyph_width) { + int g = abs(glyph_width); + Rectangle lr(r1); + Rectangle gr(r1, g, g); + if (glyph_width < 0) { + lr.w(lr.w()-g-3); + gr.x(r1.r()-g-3); + } else { + lr.set_x(g+3); + gr.x(r1.x()+3); + } + this->draw_label(lr, box_flags); + drawstyle(style,glyph_flags); + this->glyph()->draw(gr); + drawstyle(style,box_flags); + } else { + this->draw_label(r1, box_flags); + } + box->draw_symbol_overlay(r); +} + +void ComplexButton::draw() { + if (type() == HIDDEN) { + fl_did_clipping = this; + return; + } + draw(0); + + // ComplexButton is a Group, draw its children + for (int i = children () - 1; i >= 0; i--) + draw_child (*child (i)); +} + +//////////////////////////////////////////////////////////////// + +static NamedStyle style("ComplexButton", 0, &ComplexButton::default_style); +NamedStyle* ComplexButton::default_style = &::style; + +ComplexButton::ComplexButton(int x,int y,int w,int h, const char *l) : + Group(x,y,w,h,l) +{ + style(default_style); + highlight_color(GRAY20); + //set_click_to_focus(); +} + +//////////////////////////////////////////////////////////////// + +/*! \class fltk::ToggleComplexButton + This button turns the state() on and off each release of a click + inside of it. + + You can also convert a regular button into this by doing + type(ComplexButton::TOGGLE) to it. +*/ + +// +//
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkcomplexbutton.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,59 @@ +// +// +// Push button widget +// +// Copyright 2002 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to "fltk-bugs@fltk.org". +// + +#ifndef __FLTK_COMPLEX_BUTTON_HH__ +#define __FLTK_COMPLEX_BUTTON_HH__ + +#include <fltk/Group.h> + +namespace dw { +namespace fltk { +namespace ui { + +class ComplexButton: public ::fltk::Group +{ +public: + enum {HIDDEN=3}; // back-comptability value to hide the button + + bool value() const { return state(); } + bool value(bool v) { return state(v); } + + int handle(int); + int handle(int event, const Rectangle&); + ComplexButton(int,int,int,int,const char * = 0); + ~ComplexButton() { remove_all ();}; + static ::fltk::NamedStyle* default_style; + + virtual void draw(); + void draw(int glyph_width) const; +}; + +} // namespace ui +} // namespace fltk +} // namespace dw + +#endif // __FLTK_COMPLEX_BUTTON_HH__ + +// +//
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkcore.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,25 @@ +#ifndef __DW_FLTK_CORE_HH__ +#define __DW_FLTK_CORE_HH__ + +#define __INCLUDED_FROM_DW_FLTK_CORE_HH__ + +namespace dw { +namespace fltk { +namespace ui { + +class FltkResource; + +} // namespace ui +} // namespace fltk +} // namespace core + +#include <fltk/Widget.h> + +#include "core.hh" +#include "fltkimgbuf.hh" +#include "fltkplatform.hh" +#include "fltkui.hh" + +#undef __INCLUDED_FROM_DW_FLTK_CORE_HH__ + +#endif // __DW_FLTK_CORE_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkflatview.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,108 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "fltkflatview.hh" + +#include <fltk/draw.h> +#include <fltk/events.h> + +#include <stdio.h> + +using namespace fltk; +using namespace lout::container::typed; + +namespace dw { +namespace fltk { + +FltkFlatView::FltkFlatView (int x, int y, int w, int h, const char *label): + FltkWidgetView (x, y, w, h, label) +{ +} + +FltkFlatView::~FltkFlatView () +{ +} + +void FltkFlatView::setCanvasSize (int width, int ascent, int descent) +{ + /** + * \bug It has to be clarified, who is responsible for setting the + * FLTK widget size. In the only used context (complex buttons), + * it is done elsewhere. + */ + +#if 0 + FltkWidgetView::setCanvasSize (width, ascent, descent); + + w (width); + h (ascent + descent); +#endif +} + +bool FltkFlatView::usesViewport () +{ + return false; +} + +int FltkFlatView::getHScrollbarThickness () +{ + return 0; +} + +int FltkFlatView::getVScrollbarThickness () +{ + return 0; +} + +void FltkFlatView::scrollTo (int x, int y) +{ +} + +void FltkFlatView::setViewportSize (int width, int height, + int hScrollbarThickness, + int vScrollbarThickness) +{ +} + +int FltkFlatView::translateViewXToCanvasX (int x) +{ + return x; +} + +int FltkFlatView::translateViewYToCanvasY (int y) +{ + return y; +} + +int FltkFlatView::translateCanvasXToViewX (int x) +{ + return x; +} + +int FltkFlatView::translateCanvasYToViewY (int y) +{ + return y; +} + + +} // namespace fltk +} // namespace dw
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkflatview.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,40 @@ +#ifndef __DW_FLTKFLATVIEW_HH__ +#define __DW_FLTKFLATVIEW_HH__ + +#include <fltk/Group.h> +#include <fltk/Scrollbar.h> + +#include "core.hh" +#include "fltkcore.hh" +#include "fltkviewbase.hh" + +namespace dw { +namespace fltk { + +class FltkFlatView: public FltkWidgetView +{ +protected: + int translateViewXToCanvasX (int x); + int translateViewYToCanvasY (int y); + int translateCanvasXToViewX (int x); + int translateCanvasYToViewY (int y); + +public: + FltkFlatView (int x, int y, int w, int h, const char *label = 0); + ~FltkFlatView (); + + void setCanvasSize (int width, int ascent, int descent); + + bool usesViewport (); + int getHScrollbarThickness (); + int getVScrollbarThickness (); + void scrollTo (int x, int y); + void setViewportSize (int width, int height, + int hScrollbarThickness, int vScrollbarThickness); +}; + +} // namespace fltk +} // namespace dw + +#endif // __DW_FLTKFLATVIEW_HH__ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkimgbuf.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,347 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "fltkcore.hh" +#include "../lout/misc.hh" + +#include <fltk/draw.h> +#include <fltk/Color.h> + +using namespace fltk; + +namespace dw { +namespace fltk { + +using namespace container::typed; + +FltkImgbuf::FltkImgbuf (Type type, int width, int height) +{ + //printf("FltkImgbuf: new root %p\n", this); + init (type, width, height, NULL); +} + +FltkImgbuf::FltkImgbuf (Type type, int width, int height, FltkImgbuf *root) +{ + //printf("FltkImgbuf: new scaled %p, root is %p\n", this, root); + init (type, width, height, root); +} + +void FltkImgbuf::init (Type type, int width, int height, FltkImgbuf *root) +{ + this->root = root; + this->type = type; + this->width = width; + this->height = height; + + // TODO: Maybe this is only for root buffers + switch (type) { + case RGBA: bpp = 4; break; + case RGB: bpp = 3; break; + default: bpp = 1; break; + } + //fprintf(stderr,"FltkImgbuf::init width=%d height=%d bpp=%d\n", + // width, height, bpp); + rawdata = new uchar[bpp * width * height]; + // Set light-gray as interim background color. + memset(rawdata, 222, width*height*bpp); + + refCount = 1; + deleteOnUnref = true; + copiedRows = new misc::BitSet (height); + + // The list is only used for root buffers. + if (isRoot()) + scaledBuffers = new container::typed::List <FltkImgbuf> (true); + else + scaledBuffers = NULL; + + if (!isRoot()) { + // Scaling + for (int row = 0; row < root->height; row++) { + if (root->copiedRows->get (row)) + scaleRow (row, root->rawdata + row*root->width*root->bpp); + } + } +} + +FltkImgbuf::~FltkImgbuf () +{ + //printf ("FltkImgbuf::~FltkImgbuf (%s)\n", isRoot() ? "root" : "scaled"); + + //if (root) + // printf("FltkImgbuf[scaled %p, root is %p]: deleted\n", this, root); + //else + // printf("FltkImgbuf[root %p]: deleted\n", this); + + if (!isRoot()) + root->detachScaledBuf (this); + + delete[] rawdata; + delete copiedRows; + + if (scaledBuffers) + delete scaledBuffers; +} + +/** + * \brief This method is called for the root buffer, when a scaled buffer + * removed. + */ +void FltkImgbuf::detachScaledBuf (FltkImgbuf *scaledBuf) +{ + scaledBuffers->detachRef (scaledBuf); + + //printf("FltkImgbuf[root %p]: scaled buffer %p is detached, %d left\n", + // this, scaledBuf, scaledBuffers->size ()); + + if (refCount == 0 && scaledBuffers->isEmpty () && deleteOnUnref) + // If the root buffer is not used anymore, but this is the last scaled + // buffer. + // See also: FltkImgbuf::unref(). + delete this; +} + +void FltkImgbuf::setCMap (int *colors, int num_colors) +{ +} + +inline void FltkImgbuf::scaleRow (int row, const core::byte *data) +{ + int sr1 = scaledY (row); + int sr2 = scaledY (row + 1); + + for(int sr = sr1; sr < sr2; sr++) { + // Avoid multiple passes. + if (copiedRows->get(sr)) continue; + + copiedRows->set (sr, true); + if (sr == sr1) { + for(int px = 0; px < root->width; px++) { + int px1 = px * width / root->width; + int px2 = (px+1) * width / root->width; + for(int sp = px1; sp < px2; sp++) { + memcpy(rawdata + (sr*width + sp)*bpp, data + px*bpp, bpp); + } + } + } else { + memcpy(rawdata + sr*width*bpp, rawdata + sr1*width*bpp, width*bpp); + } + } +} + +void FltkImgbuf::copyRow (int row, const core::byte *data) +{ + assert (isRoot()); + + // Flag the row done and copy its data. + copiedRows->set (row, true); + memcpy(rawdata + row * width * bpp, data, width * bpp); + + // Update all the scaled buffers of this root image. + for (Iterator <FltkImgbuf> it = scaledBuffers->iterator(); it.hasNext(); ) { + FltkImgbuf *sb = it.getNext (); + sb->scaleRow(row, data); + } +} + +void FltkImgbuf::newScan () +{ + if (isRoot()) { + for (Iterator<FltkImgbuf> it = scaledBuffers->iterator(); it.hasNext();){ + FltkImgbuf *sb = it.getNext (); + sb->copiedRows->clear(); + } + } +} + +core::Imgbuf* FltkImgbuf::getScaledBuf (int width, int height) +{ + if (root) + return root->getScaledBuf (width, height); + + if (width == this->width && height == this->height) { + ref (); + return this; + } + + for (Iterator <FltkImgbuf> it = scaledBuffers->iterator(); it.hasNext(); ) { + FltkImgbuf *sb = it.getNext (); + if (sb->width == width && sb->height == height) { + sb->ref (); + return sb; + } + } + + /* This size is not yet used, so a new buffer has to be created. */ + FltkImgbuf *sb = new FltkImgbuf (type, width, height, this); + scaledBuffers->append (sb); + return sb; +} + +void FltkImgbuf::getRowArea (int row, dw::core::Rectangle *area) +{ + // TODO: May have to be adjusted. + + if (isRoot()) { + /* root buffer */ + area->x = 0; + area->y = row; + area->width = width; + area->height = 1; + //fprintf(stderr,"::getRowArea: area x=%d y=%d width=%d height=%d\n", + // area->x, area->y, area->width, area->height); + } else { + // scaled buffer + int sr1 = scaledY (row); + int sr2 = scaledY (row + 1); + + area->x = 0; + area->y = sr1; + area->width = width; + area->height = sr2 - sr1; + //fprintf(stderr,"::getRowArea: area x=%d y=%d width=%d height=%d\n", + // area->x, area->y, area->width, area->height); + } +} + +int FltkImgbuf::getRootWidth () +{ + return root ? root->width : width; +} + +int FltkImgbuf::getRootHeight () +{ + return root ? root->height : height; +} + +void FltkImgbuf::ref () +{ + refCount++; + + //if (root) + // printf("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n", + // this, root, refCount); + //else + // printf("FltkImgbuf[root %p]: ref() => %d\n", this, refCount); +} + +void FltkImgbuf::unref () +{ + //if (root) + // printf("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n", + // this, root, refCount - 1); + //else + // printf("FltkImgbuf[root %p]: ref() => %d\n", this, refCount - 1); + + if (--refCount == 0) { + if (isRoot ()) { + // Root buffer, it must be ensured that no scaled buffers are left. + // See also FltkImgbuf::detachScaledBuf(). + if (scaledBuffers->isEmpty () && deleteOnUnref) + delete this; + else + printf("FltkImgbuf[root %p]: not deleted\n", this); + } else + // Scaled buffer buffer, simply delete it. + delete this; + } +} + +bool FltkImgbuf::lastReference () +{ + return refCount == 1 && + (scaledBuffers == NULL || scaledBuffers->isEmpty ()); +} + +void FltkImgbuf::setDeleteOnUnref (bool deleteOnUnref) +{ + assert (isRoot ()); + this->deleteOnUnref = deleteOnUnref; +} + +bool FltkImgbuf::isReferred () +{ + return refCount != 0 || + (scaledBuffers != NULL && !scaledBuffers->isEmpty ()); +} + + +int FltkImgbuf::scaledY(int ySrc) +{ + // TODO: May have to be adjusted. + assert (root != NULL); + return ySrc * height / root->height; +} + +void FltkImgbuf::draw (::fltk::Widget *target, int xRoot, int yRoot, + int x, int y, int width, int height) +{ + // TODO (i): Implementation. + // TODO (ii): Clarify the question, whether "target" is the current widget + // (and so has not to be passed at all). + +/* + setcolor (0); + + for (int row = y; row < y + height; row++) { + if (copiedRows->get (row)) { + ::fltk::Rectangle rect (x + xRoot, row + yRoot, width, 1); + fillrect (rect); + } + } +*/ + + //fprintf(stderr,"::draw: xRoot=%d x=%d yRoot=%d y=%d width=%d height=%d\n" + // " this->width=%d this->height=%d\n", + // xRoot, x, yRoot, y, width, height, this->width, this->height); + +//{ +#if 1 + if (x > this->width || y > this->height) { + return; + } + + if (x + width > this->width) { + width = this->width - x; + } + + if (y + height > this->height) { + height = this->height - y; + } + + // almost OK for rows. For some unknown reason it trims the bottom and + // rightmost parts when scrolling. + ::fltk::Rectangle rect (xRoot + x, yRoot + y, width, height); + PixelType ptype = (type == RGBA) ? ::fltk::RGBA : ::fltk::RGB; + drawimage(rawdata+bpp*(y*this->width + x),ptype,rect,bpp*this->width); + +#else + // OK for full image. + ::fltk::Rectangle rect (xRoot, yRoot, this->width, this->height); + PixelType ptype = (type == RGBA) ? ::fltk::RGBA : ::fltk::RGB; + drawimage(rawdata,ptype,rect); +#endif +//} +} + +} // namespace dw +} // namespace fltk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkimgbuf.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,65 @@ +#ifndef __DW_FLTKIMGBUF_HH__ +#define __DW_FLTKIMGBUF_HH__ + +#ifndef __INCLUDED_FROM_DW_FLTK_CORE_HH__ +# error Do not include this file directly, use "fltkcore.hh" instead. +#endif + +namespace dw { +namespace fltk { + +class FltkImgbuf: public core::Imgbuf +{ +private: + FltkImgbuf *root; + int refCount; + bool deleteOnUnref; + lout::container::typed::List <FltkImgbuf> *scaledBuffers; + + int width, height; + Type type; + +//{ + int bpp; + uchar *rawdata; +//} + + // This is just for testing drawing, it has to be replaced by + // the image buffer. + lout::misc::BitSet *copiedRows; + + FltkImgbuf (Type type, int width, int height, FltkImgbuf *root); + void init (Type type, int width, int height, FltkImgbuf *root); + int scaledY(int ySrc); + int isRoot() { return (root == NULL); } + void detachScaledBuf (FltkImgbuf *scaledBuf); + +protected: + ~FltkImgbuf (); + +public: + FltkImgbuf (Type type, int width, int height); + + void setCMap (int *colors, int num_colors); + inline void scaleRow (int row, const core::byte *data); + void newScan (); + void copyRow (int row, const core::byte *data); + core::Imgbuf* getScaledBuf (int width, int height); + void getRowArea (int row, dw::core::Rectangle *area); + int getRootWidth (); + int getRootHeight (); + void ref (); + void unref (); + + bool lastReference (); + void setDeleteOnUnref (bool deleteOnUnref); + bool isReferred (); + + void draw (::fltk::Widget *target, int xRoot, int yRoot, + int x, int y, int width, int height); +}; + +} // namespace dw +} // namespace fltk + +#endif // __DW_FLTK_IMGBUF_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkmisc.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,50 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "fltkmisc.hh" + +#include <fltk/events.h> +#include <fltk/Monitor.h> +#include <stdio.h> + +namespace dw { +namespace fltk { +namespace misc { + +int screenWidth () +{ + return ::fltk::Monitor::all ().w (); +} + +int screenHeight () +{ + return ::fltk::Monitor::all ().h (); +} + +void warpPointer (int x, int y) +{ + ::fltk::warp_mouse (x, y); +} + +} // namespace misc +} // namespace fltk +} // namespace dw
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkmisc.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,22 @@ +#ifndef __FLTKMISC_HH__ +#define __FLTKMISC_HH__ + +namespace dw { +namespace fltk { + +/** + * \brief Miscellaneous FLTK stuff. + */ +namespace misc { + +int screenWidth (); +int screenHeight (); + +void warpPointer (int x, int y); + +} // namespace misc +} // namespace fltk +} // namespace dw + + +#endif // __FLTKMISC_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkplatform.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,421 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "fltkcore.hh" + +#include <fltk/draw.h> +#include <fltk/run.h> +#include <fltk/events.h> +#include <fltk/utf.h> +#include <stdio.h> + +namespace dw { +namespace fltk { + +using namespace ::fltk; + +/** + * \todo Distinction between italics and oblique would be nice. + */ + +container::typed::HashTable <dw::core::style::FontAttrs, + FltkFont> *FltkFont::fontsTable = + new container::typed::HashTable <dw::core::style::FontAttrs, + FltkFont> (false, false); + +FltkFont::FltkFont (core::style::FontAttrs *attrs) +{ + copyAttrs (attrs); + + int fa = 0; + if(weight >= 500) + fa |= BOLD; + if(style != core::style::FONT_STYLE_NORMAL) + fa |= ITALIC; + + font = ::fltk::font(name, fa); + if(font == NULL) { + fprintf(stderr, "No font '%s', using default sans-serif font.\n", name); + /* + * If using xft, fltk::HELVETICA just means sans, fltk::COURIER + * means mono, and fltk::TIMES means serif. + */ + font = HELVETICA; + } + + setfont(font, size); + spaceWidth = (int)getwidth(" "); + int xw, xh; + measure("x", xw, xh); + xHeight = xh; + ascent = (int)getascent(); + descent = (int)getdescent(); + + /** + * \bug The code above does not seem to work, so this workaround. + */ + xHeight = ascent * 3 / 5; +} + +FltkFont::~FltkFont () +{ + fontsTable->remove (this); +} + +FltkFont* +FltkFont::create (core::style::FontAttrs *attrs) +{ + FltkFont *font = fontsTable->get (attrs); + + if (font == NULL) { + font = new FltkFont (attrs); + fontsTable->put (font, font); + } + + return font; +} + +container::typed::HashTable <dw::core::style::ColorAttrs, + FltkColor> + *FltkColor::colorsTable = + new container::typed::HashTable <dw::core::style::ColorAttrs, + FltkColor> (false, false); + +FltkColor::FltkColor (int color, core::style::Color::Type type): + Color (color, type) +{ + this->color = color; + this->type = type; + + /* + * fltk/setcolor.cxx: + * "A Color of zero (fltk::NO_COLOR) will draw black but is + * ambiguous. It is returned as an error value or to indicate portions + * of a Style that should be inherited, and it is also used as the + * default label color for everything so that changing color zero can + * be used by the -fg switch. You should use fltk::BLACK (56) to get + * black." + * + * i.e., zero only works sometimes. + */ + + if (!(colors[SHADING_NORMAL] = shadeColor (color, SHADING_NORMAL) << 8)) + colors[SHADING_NORMAL] = ::fltk::BLACK; + if (!(colors[SHADING_INVERSE] = shadeColor (color, SHADING_INVERSE) << 8)) + colors[SHADING_INVERSE] = ::fltk::BLACK; + + if(type == core::style::Color::TYPE_SHADED) { + if (!(colors[SHADING_DARK] = shadeColor (color, SHADING_DARK) << 8)) + colors[SHADING_DARK] = ::fltk::BLACK; + if (!(colors[SHADING_LIGHT] = shadeColor (color, SHADING_LIGHT) << 8)) + colors[SHADING_LIGHT] = ::fltk::BLACK; + } +} + +FltkColor::~FltkColor () +{ + colorsTable->remove (this); +} + +FltkColor * FltkColor::create (int col, core::style::Color::Type type) +{ + ColorAttrs attrs(col, type); + FltkColor *color = colorsTable->get (&attrs); + + if (color == NULL) { + color = new FltkColor (col, type); + colorsTable->put (color, color); + } + + return color; +} + +void FltkView::addFltkWidget (::fltk::Widget *widget, + core::Allocation *allocation) +{ +} + +void FltkView::removeFltkWidget (::fltk::Widget *widget) +{ +} + +void FltkView::allocateFltkWidget (::fltk::Widget *widget, + core::Allocation *allocation) +{ +} + +void FltkView::drawFltkWidget (::fltk::Widget *widget, core::Rectangle *area) +{ +} + + +core::ui::LabelButtonResource * +FltkPlatform::FltkResourceFactory::createLabelButtonResource (const char + *label) +{ + return new ui::FltkLabelButtonResource (platform, label); +} + +core::ui::ComplexButtonResource * +FltkPlatform::FltkResourceFactory::createComplexButtonResource (core::Widget + *widget, + bool relief) +{ + return new ui::FltkComplexButtonResource (platform, widget, relief); +} + +core::ui::ListResource * +FltkPlatform::FltkResourceFactory::createListResource (core::ui + ::ListResource + ::SelectionMode + selectionMode) +{ + return new ui::FltkListResource (platform, selectionMode); +} + +core::ui::OptionMenuResource * +FltkPlatform::FltkResourceFactory::createOptionMenuResource () +{ + return new ui::FltkOptionMenuResource (platform); +} + +core::ui::EntryResource * +FltkPlatform::FltkResourceFactory::createEntryResource (int maxLength, + bool password) +{ + return new ui::FltkEntryResource (platform, maxLength, password); +} + +core::ui::MultiLineTextResource * +FltkPlatform::FltkResourceFactory::createMultiLineTextResource (int cols, + int rows) +{ + return new ui::FltkMultiLineTextResource (platform, cols, rows); +} + +core::ui::CheckButtonResource * +FltkPlatform::FltkResourceFactory::createCheckButtonResource (bool activated) +{ + return new ui::FltkCheckButtonResource (platform, activated); +} + +core::ui::RadioButtonResource +*FltkPlatform::FltkResourceFactory::createRadioButtonResource +(core::ui::RadioButtonResource *groupedWith, bool activated) +{ + return + new ui::FltkRadioButtonResource (platform, + (ui::FltkRadioButtonResource*) + groupedWith, + activated); +} + +// ---------------------------------------------------------------------- + +FltkPlatform::FltkPlatform () +{ + layout = NULL; + idleQueue = new container::typed::List <IdleFunc> (true); + idleFuncRunning = false; + idleFuncId = 0; + + views = new container::typed::List <FltkView> (false); + resources = new container::typed::List <ui::FltkResource> (false); + + resourceFactory.setPlatform (this); +} + +FltkPlatform::~FltkPlatform () +{ + if(idleFuncRunning) + remove_idle (generalStaticIdle, (void*)this); + delete idleQueue; + delete views; + delete resources; +} + +void FltkPlatform::setLayout (core::Layout *layout) +{ + this->layout = layout; +} + + +void FltkPlatform::attachView (core::View *view) +{ + views->append ((FltkView*)view); + + for (container::typed::Iterator <ui::FltkResource> it = + resources->iterator (); it.hasNext (); ) { + ui::FltkResource *resource = it.getNext (); + resource->attachView ((FltkView*)view); + } +} + + +void FltkPlatform::detachView (core::View *view) +{ + views->removeRef ((FltkView*)view); + + for (container::typed::Iterator <ui::FltkResource> it = + resources->iterator (); it.hasNext (); ) { + ui::FltkResource *resource = it.getNext (); + resource->detachView ((FltkView*)view); + } +} + + +int FltkPlatform::textWidth (core::style::Font *font, const char *text, + int len) +{ + FltkFont *ff = (FltkFont*) font; + setfont (ff->font, ff->size); + return (int) getwidth (text, len); +} + +int FltkPlatform::nextGlyph (const char *text, int idx) +{ + return utf8fwd (&text[idx + 1], text, &text[strlen (text)]) - text; +} + +int FltkPlatform::prevGlyph (const char *text, int idx) +{ + return utf8back (&text[idx - 1], text, &text[strlen (text)]) - text; +} + +void FltkPlatform::generalStaticIdle (void *data) +{ + ((FltkPlatform*)data)->generalIdle(); +} + +void FltkPlatform::generalIdle () +{ + IdleFunc *idleFunc; + + if (!idleQueue->isEmpty ()) { + /* Execute the first function in the list. */ + idleFunc = idleQueue->getFirst (); + (layout->*(idleFunc->func)) (); + + /* Remove this function. */ + idleQueue->removeRef(idleFunc); + } + + if(idleQueue->isEmpty()) { + idleFuncRunning = false; + remove_idle (generalStaticIdle, (void*)this); + } +} + +/** + * \todo Incomplete comments. + */ +int FltkPlatform::addIdle (void (core::Layout::*func) ()) +{ + /* + * Since ... (todo) we have to wrap around fltk_add_idle. There is only one + * idle function, the passed idle function is put into a queue. + */ + if(!idleFuncRunning) { + add_idle (generalStaticIdle, (void*)this); + idleFuncRunning = true; + } + + idleFuncId++; + + IdleFunc *idleFunc = new IdleFunc(); + idleFunc->id = idleFuncId; + idleFunc->func = func; + idleQueue->append (idleFunc); + + return idleFuncId; +} + +void FltkPlatform::removeIdle (int idleId) +{ + bool found; + container::typed::Iterator <IdleFunc> it; + IdleFunc *idleFunc; + + for(found = false, it = idleQueue->iterator(); !found && it.hasNext(); ) { + idleFunc = it.getNext(); + if(idleFunc->id == idleId) { + idleQueue->removeRef (idleFunc); + found = true; + } + } + + if(idleFuncRunning && idleQueue->isEmpty()) + remove_idle (generalStaticIdle, (void*)this); +} + +core::style::Font *FltkPlatform::createFont (core::style::FontAttrs + *attrs, + bool tryEverything) +{ + return FltkFont::create (attrs); +} + +core::style::Color *FltkPlatform::createSimpleColor (int color) +{ + return FltkColor::create (color, core::style::Color::TYPE_SIMPLE); +} + +core::style::Color *FltkPlatform::createShadedColor (int color) +{ + return FltkColor::create (color, core::style::Color::TYPE_SHADED); +} + +void FltkPlatform::copySelection(const char *text) +{ + fltk::copy(text, strlen(text), false); +} + +core::Imgbuf *FltkPlatform::createImgbuf (core::Imgbuf::Type type, + int width, int height) +{ + return new FltkImgbuf (type, width, height); +} + +core::ui::ResourceFactory *FltkPlatform::getResourceFactory () +{ + return &resourceFactory; +} + + +void FltkPlatform::attachResource (ui::FltkResource *resource) +{ + resources->append (resource); + + for (container::typed::Iterator <FltkView> it = views->iterator (); + it.hasNext (); ) { + FltkView *view = it.getNext (); + resource->attachView (view); + } +} + +void FltkPlatform::detachResource (ui::FltkResource *resource) +{ + resources->removeRef (resource); +} + +} // namespace fltk +} // namespace dw
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkplatform.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,150 @@ +#ifndef __DW_FLTKPLATFORM_HH__ +#define __DW_FLTKPLATFORM_HH__ + +#ifndef __INCLUDED_FROM_DW_FLTK_CORE_HH__ +# error Do not include this file directly, use "fltkcore.hh" instead. +#endif + +#include <fltk/Font.h> + +namespace dw { + +/** + * \brief This namespace contains FLTK implementations of Dw interfaces. + */ +namespace fltk { + +class FltkFont: public core::style::Font +{ + static lout::container::typed::HashTable <dw::core::style::FontAttrs, + FltkFont> *fontsTable; + + FltkFont (core::style::FontAttrs *attrs); + ~FltkFont (); + +public: + ::fltk::Font *font; + + static FltkFont *create (core::style::FontAttrs *attrs); +}; + + +class FltkColor: public core::style::Color +{ + static lout::container::typed::HashTable <dw::core::style::ColorAttrs, + FltkColor> *colorsTable; + + FltkColor (int color, core::style::Color::Type type); + ~FltkColor (); + +public: + int colors[SHADING_NUM]; + + static FltkColor *create(int color, core::style::Color::Type type); +}; + + +/** + * \brief This interface adds some more methods for all flkt-based views. + */ +class FltkView: public core::View +{ +public: + virtual bool usesFltkWidgets () = 0; + + virtual void addFltkWidget (::fltk::Widget *widget, + core::Allocation *allocation); + virtual void removeFltkWidget (::fltk::Widget *widget); + virtual void allocateFltkWidget (::fltk::Widget *widget, + core::Allocation *allocation); + virtual void drawFltkWidget (::fltk::Widget *widget, core::Rectangle *area); +}; + + +class FltkPlatform: public core::Platform +{ +private: + class FltkResourceFactory: public core::ui::ResourceFactory + { + private: + FltkPlatform *platform; + + public: + inline void setPlatform (FltkPlatform *platform) { + this->platform = platform; } + + core::ui::LabelButtonResource *createLabelButtonResource (const char + *label); + core::ui::ComplexButtonResource * + createComplexButtonResource (core::Widget *widget, bool relief); + core::ui::ListResource * + createListResource (core::ui::ListResource::SelectionMode selectionMode); + core::ui::OptionMenuResource *createOptionMenuResource (); + core::ui::EntryResource *createEntryResource (int maxLength, + bool password); + core::ui::MultiLineTextResource *createMultiLineTextResource (int cols, + int rows); + core::ui::CheckButtonResource *createCheckButtonResource (bool + activated); + core::ui::RadioButtonResource * + createRadioButtonResource (core::ui::RadioButtonResource + *groupedWith, bool activated); + }; + + FltkResourceFactory resourceFactory; + + class IdleFunc: public lout::object::Object + { + public: + int id; + void (core::Layout::*func) (); + }; + + core::Layout *layout; + + lout::container::typed::List <IdleFunc> *idleQueue; + bool idleFuncRunning; + int idleFuncId; + + static void generalStaticIdle(void *data); + void generalIdle(); + + lout::container::typed::List <FltkView> *views; + lout::container::typed::List <ui::FltkResource> *resources; + +public: + FltkPlatform (); + ~FltkPlatform (); + + void setLayout (core::Layout *layout); + + void attachView (core::View *view); + + void detachView (core::View *view); + + int textWidth (core::style::Font *font, const char *text, int len); + int nextGlyph (const char *text, int idx); + int prevGlyph (const char *text, int idx); + + int addIdle (void (core::Layout::*func) ()); + void removeIdle (int idleId); + + core::style::Font *createFont (core::style::FontAttrs *attrs, + bool tryEverything); + core::style::Color *createSimpleColor (int color); + core::style::Color *createShadedColor (int color); + + core::Imgbuf *createImgbuf (core::Imgbuf::Type type, int width, int height); + + void copySelection(const char *text); + + core::ui::ResourceFactory *getResourceFactory (); + + void attachResource (ui::FltkResource *resource); + void detachResource (ui::FltkResource *resource); +}; + +} // namespace fltk +} // namespace dw + +#endif // __DW_FLTKPLATFORM_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkpreview.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,298 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "fltkpreview.hh" +#include "fltkmisc.hh" + +#include <fltk/events.h> +#include <fltk/xbmImage.h> +#include <fltk/draw.h> +#include <stdio.h> + +#include "preview.xbm" + +using namespace ::fltk; + +namespace dw { +namespace fltk { + +FltkPreview::FltkPreview (int x, int y, int w, int h, + dw::core::Layout *layout, const char *label): + FltkViewBase (x, y, w, h, label) +{ + layout->attachView (this); + + scrollX = 0; + scrollY = 0; + scrollWidth = 1; + scrollHeight = 1; +} + +FltkPreview::~FltkPreview () +{ +} + +int FltkPreview::handle (int event) +{ + return FltkViewBase::handle (event); +} + +int FltkPreview::translateViewXToCanvasX (int x) +{ + return x * canvasWidth / w (); +} + +int FltkPreview::translateViewYToCanvasY (int y) +{ + return y * canvasHeight / h (); +} + +int FltkPreview::translateCanvasXToViewX (int x) +{ + return x * w () / canvasWidth; +} + +int FltkPreview::translateCanvasYToViewY (int y) +{ + return y * h () / canvasHeight; +} + +void FltkPreview::setCanvasSize (int width, int ascent, int descent) +{ + FltkViewBase::setCanvasSize (width, ascent, descent); + if (parent() && parent()->visible ()) + ((FltkPreviewWindow*)parent())->reallocate (); +} + +bool FltkPreview::usesViewport () +{ + return true; +} + +int FltkPreview::getHScrollbarThickness () +{ + return 0; +} + +int FltkPreview::getVScrollbarThickness () +{ + return 0; +} + +void FltkPreview::scrollTo (int x, int y) +{ + scrollX = x; + scrollY = y; +} + +void FltkPreview::setViewportSize (int width, int height, + int hScrollbarThickness, + int vScrollbarThickness) +{ + scrollWidth = width - vScrollbarThickness; + scrollHeight = height - hScrollbarThickness; +} + +void FltkPreview::drawText (core::style::Font *font, + core::style::Color *color, + core::style::Color::Shading shading, + int x, int y, const char *text, int len) +{ + /* + * We must call setfont() before calling getwidth() (or anything + * else that measures text). + */ + FltkFont *ff = (FltkFont*)font; + setfont(ff->font, translateCanvasXToViewX (ff->size)); +#if 0 + /** + * \todo Normally, this should already be known, maybe it + * should be passed? + */ + int width = (int)getwidth (text, len); + int height = font->ascent; // No descent, this would look to "bold". + + int x1 = translateCanvasXToViewX (x); + int y1 = translateCanvasYToViewY (y); + int x2 = translateCanvasXToViewX (x + width); + int y2 = translateCanvasYToViewY (y + height); + Rectangle rect (x1, y1, x2 - x1, y2 - y1); + + setcolor(((FltkColor*)color)->colors[shading]); + fillrect (rect); +#endif + setcolor(((FltkColor*)color)->colors[shading]); + drawtext(text, len, + translateCanvasXToViewX (x), translateCanvasYToViewY (y)); +} + +void FltkPreview::drawImage (core::Imgbuf *imgbuf, int xRoot, int yRoot, + int x, int y, int width, int height) +{ +} + +bool FltkPreview::usesFltkWidgets () +{ + return false; +} + +void FltkPreview::drawFltkWidget (Widget *widget, + core::Rectangle *area) +{ +} + +// ---------------------------------------------------------------------- + +FltkPreviewWindow::FltkPreviewWindow (dw::core::Layout *layout): + MenuWindow (1, 1) +{ + box (EMBOSSED_BOX); + + begin (); + preview = new FltkPreview (BORDER_WIDTH, BORDER_WIDTH, 1, 1, layout); + end (); + + hide (); +} + +FltkPreviewWindow::~FltkPreviewWindow () +{ +} + +void FltkPreviewWindow::showWindow () +{ + reallocate (); + show (); +} + +void FltkPreviewWindow::reallocate () +{ + int maxWidth = misc::screenWidth () / 2; + int maxHeight = misc::screenHeight () * 4 / 5; + int mx, my, width, height; + bool warp = false; + + if(preview->canvasHeight * maxWidth > maxHeight * preview->canvasWidth) { + // Expand to maximal height (most likely case). + width = preview->canvasWidth * maxHeight / preview->canvasHeight; + height = maxHeight; + } else { + // Expand to maximal width. + width = maxWidth; + height = preview->canvasHeight * maxWidth / preview->canvasWidth; + } + + get_mouse(mx, my); + + posX = mx - preview->translateCanvasXToViewX (preview->scrollX + + preview->scrollWidth / 2); + posY = my - preview->translateCanvasYToViewY (preview->scrollY + + preview->scrollHeight / 2); + + if (posX < 0) { + mx -= posX; + posX = 0; + warp = true; + } else if (posX + width > misc::screenWidth ()) { + mx -= (posX - (misc::screenWidth () - width)); + posX = misc::screenWidth () - width; + warp = true; + } + + if (posY < 0) { + my -= posY; + posY = 0; + warp = true; + } else if (posY + height > misc::screenHeight ()) { + my -= (posY - (misc::screenHeight () - height)); + posY = misc::screenHeight () - height; + warp = true; + } + + if (warp) + misc::warpPointer (mx, my); + + resize (posX, posY, width, height); + + preview->w (w () - 2 * BORDER_WIDTH); + preview->h (h () - 2 * BORDER_WIDTH); +} + +void FltkPreviewWindow::hideWindow () +{ + Window::hide (); +} + +void FltkPreviewWindow::scrollTo (int mouseX, int mouseY) +{ + preview->scrollX = + preview->translateViewXToCanvasX (mouseX - posX - BORDER_WIDTH) + - preview->scrollWidth / 2; + preview->scrollY = + preview->translateViewYToCanvasY (mouseY - posY - BORDER_WIDTH) + - preview->scrollHeight / 2; + preview->theLayout->scrollPosChanged (preview, + preview->scrollX, preview->scrollY); +} + +// ---------------------------------------------------------------------- + +FltkPreviewButton::FltkPreviewButton (int x, int y, int w, int h, + dw::core::Layout *layout, + const char *label): + Button (x, y, w, h, label) +{ + image (new xbmImage (preview_bits, preview_width, preview_height)); + window = new FltkPreviewWindow (layout); +} + +FltkPreviewButton::~FltkPreviewButton () +{ +} + +int FltkPreviewButton::handle (int event) +{ + /** \bug Some parts are missing. */ + + switch (event) { + case PUSH: + window->showWindow (); + return Button::handle (event); + + case DRAG: + if (window->visible ()) { + window->scrollTo (event_x_root (), event_y_root ()); + return 1; + } + return Button::handle (event); + + case RELEASE: + window->hideWindow (); + return Button::handle (event); + + default: + return Button::handle (event); + } +} + +} // namespace fltk +} // namespace dw
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkpreview.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,89 @@ +#ifndef __FlTKPREVIEW_HH__ +#define __FlTKPREVIEW_HH__ + +#include <fltk/Button.h> +#include <fltk/MenuWindow.h> +#include "fltkviewbase.hh" + +namespace dw { +namespace fltk { + +class FltkPreview: public FltkViewBase +{ + friend class FltkPreviewWindow; + +private: + int scrollX, scrollY, scrollWidth, scrollHeight; + +protected: + int translateViewXToCanvasX (int x); + int translateViewYToCanvasY (int y); + int translateCanvasXToViewX (int x); + int translateCanvasYToViewY (int y); + +public: + FltkPreview (int x, int y, int w, int h, dw::core::Layout *layout, + const char *label = 0); + ~FltkPreview (); + + int handle (int event); + + void setCanvasSize (int width, int ascent, int descent); + + bool usesViewport (); + int getHScrollbarThickness (); + int getVScrollbarThickness (); + void scrollTo (int x, int y); + void setViewportSize (int width, int height, + int hScrollbarThickness, int vScrollbarThickness); + + void drawText (core::style::Font *font, + core::style::Color *color, + core::style::Color::Shading shading, + int x, int y, const char *text, int len); + void drawImage (core::Imgbuf *imgbuf, int xRoot, int yRoot, + int x, int y, int width, int height); + + bool usesFltkWidgets (); + void drawFltkWidget (::fltk::Widget *widget, core::Rectangle *area); +}; + + +class FltkPreviewWindow: public ::fltk::MenuWindow +{ +private: + enum { BORDER_WIDTH = 2 }; + + FltkPreview *preview; + int posX, posY; + +public: + FltkPreviewWindow (dw::core::Layout *layout); + ~FltkPreviewWindow (); + + void reallocate (); + + void showWindow (); + void hideWindow (); + + void scrollTo (int mouseX, int mouseY); +}; + + +class FltkPreviewButton: public ::fltk::Button +{ +private: + FltkPreviewWindow *window; + +public: + FltkPreviewButton (int x, int y, int w, int h, + dw::core::Layout *layout, const char *label = 0); + ~FltkPreviewButton (); + + int handle (int event); +}; + +} // namespace fltk +} // namespace dw + +#endif // __FlTKPREVIEW_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkui.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,1202 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "fltkcore.hh" +#include "fltkflatview.hh" +#include "fltkcomplexbutton.hh" +#include "../lout/misc.hh" + +#include <stdio.h> +#include <fltk/Widget.h> +#include <fltk/Group.h> +#include <fltk/Input.h> +#include <fltk/SecretInput.h> +#include <fltk/TextEditor.h> +#include <fltk/RadioButton.h> +#include <fltk/CheckButton.h> +#include <fltk/Choice.h> +#include <fltk/Browser.h> +#include <fltk/MultiBrowser.h> +#include <fltk/Font.h> +#include <fltk/draw.h> +#include <fltk/Symbol.h> +#include <fltk/Item.h> +#include <fltk/ItemGroup.h> +#include <fltk/events.h> + +namespace dw { +namespace fltk { +namespace ui { + +enum { RELIEF_X_THICKNESS = 5, RELIEF_Y_THICKNESS = 3 }; + +using namespace object; +using namespace container::typed; + +FltkResource::FltkResource (FltkPlatform *platform) +{ + this->platform = platform; + + allocation.x = 0; + allocation.y = 0; + allocation.width = 1; + allocation.ascent = 1; + allocation.descent = 0; + + style = NULL; +} + +/** + * This is not a constructor, since it calls some virtual methods, which + * should not be done in a C++ base constructor. + */ +void FltkResource::init (FltkPlatform *platform) +{ + viewsAndWidgets = new container::typed::List <ViewAndWidget> (true); + platform->attachResource (this); +} + +FltkResource::~FltkResource () +{ + platform->detachResource (this); + for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator (); + it.hasNext(); ) { + ViewAndWidget *viewAndWidget = it.getNext (); + + if (viewAndWidget->widget) { + if (viewAndWidget->view) { + viewAndWidget->view->removeFltkWidget(viewAndWidget->widget); + } + delete viewAndWidget->widget; + } + + } + delete viewsAndWidgets; + if(style) + style->unref (); +} + +void FltkResource::attachView (FltkView *view) +{ + if (view->usesFltkWidgets ()) { + ViewAndWidget *viewAndWidget = new ViewAndWidget(); + viewAndWidget->view = view; + + viewAndWidget->widget = createNewWidget (&allocation); + viewAndWidget->view->addFltkWidget (viewAndWidget->widget, &allocation); + viewsAndWidgets->append (viewAndWidget); + if (style) + setWidgetStyle (viewAndWidget->widget, style); + } +} + +void FltkResource::detachView (FltkView *view) +{ + for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator (); + it.hasNext(); ) { + ViewAndWidget *viewAndWidget = it.getNext (); + if (viewAndWidget->view == view) { + viewsAndWidgets->removeRef (viewAndWidget); + return; + } + } + + fprintf (stderr, "FltkResource::detachView: View not found."); +} + +void FltkResource::sizeAllocate (core::Allocation *allocation) +{ + this->allocation = *allocation; + + for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator (); + it.hasNext(); ) { + ViewAndWidget *viewAndWidget = it.getNext (); + viewAndWidget->view->allocateFltkWidget (viewAndWidget->widget, + allocation); + } +} + +void FltkResource::draw (core::View *view, core::Rectangle *area) +{ + FltkView *fltkView = (FltkView*)view; + if (fltkView->usesFltkWidgets ()) { + for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator (); + it.hasNext(); ) { + ViewAndWidget *viewAndWidget = it.getNext (); + if (viewAndWidget->view == fltkView) { + fltkView->drawFltkWidget (viewAndWidget->widget, area); + break; + } + } + } +} + +void FltkResource::setStyle (core::style::Style *style) +{ + if(this->style) + this->style->unref (); + + this->style = style; + style->ref (); + + for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator (); + it.hasNext(); ) { + ViewAndWidget *viewAndWidget = it.getNext (); + setWidgetStyle (viewAndWidget->widget, style); + } +} + +void FltkResource::setWidgetStyle (::fltk::Widget *widget, + core::style::Style *style) +{ + /** \bug label or text? */ + + FltkFont *font = (FltkFont*)style->font; + widget->labelsize (font->size); + widget->labelfont (font->font); + widget->textsize (font->size); + widget->textfont (font->font); + + FltkColor *bg = (FltkColor*)style->backgroundColor; + if (bg) { + if (style->color) { + /* + * todo: if/when CSS is implemented, test whether style->color + * will consistently provide readable widgets. + */ + int32_t c = bg->colors[FltkColor::SHADING_NORMAL]; + int r = (c >> 24) & 0xff, g = (c >> 16) & 0xff, b = (c >> 8) & 0xff; + bool light = (r + g >= 0x150) || (r + g + b >= 0x180); + + widget->labelcolor(light? ::fltk::BLACK : ::fltk::WHITE); + widget->textcolor(light? ::fltk::BLACK : ::fltk::WHITE); + widget->selection_color(light? ::fltk::BLACK : ::fltk::WHITE); + } + + widget->color(bg->colors[FltkColor::SHADING_NORMAL]); + widget->buttoncolor(bg->colors[FltkColor::SHADING_NORMAL]); + widget->highlight_color(bg->colors[FltkColor::SHADING_LIGHT]); + widget->selection_textcolor(bg->colors[FltkColor::SHADING_NORMAL]); + } +} + +bool FltkResource::isEnabled () +{ + /** \bug Not implemented. */ + return true; +} + +void FltkResource::setEnabled (bool enabled) +{ + /** \bug Not implemented. */ +} + +// ---------------------------------------------------------------------- + +template <class I> void FltkSpecificResource<I>::sizeAllocate (core::Allocation + *allocation) +{ + FltkResource::sizeAllocate (allocation); +} + +template <class I> void FltkSpecificResource<I>::draw (core::View *view, + core::Rectangle *area) +{ + FltkResource::draw (view, area); +} + +template <class I> void FltkSpecificResource<I>::setStyle (core::style::Style + *style) +{ + FltkResource::setStyle (style); +} + +template <class I> bool FltkSpecificResource<I>::isEnabled () +{ + return FltkResource::isEnabled (); +} + +template <class I> void FltkSpecificResource<I>::setEnabled (bool enabled) +{ + FltkResource::setEnabled (enabled); +} + +// ---------------------------------------------------------------------- + +FltkLabelButtonResource::FltkLabelButtonResource (FltkPlatform *platform, + const char *label): + FltkSpecificResource <dw::core::ui::LabelButtonResource> (platform) +{ + this->label = strdup (label); + init (platform); +} + +FltkLabelButtonResource::~FltkLabelButtonResource () +{ + delete label; +} + +::fltk::Widget *FltkLabelButtonResource::createNewWidget (core::Allocation + *allocation) +{ + ::fltk::Button *button = + new ::fltk::Button (allocation->x, allocation->y, allocation->width, + allocation->ascent + allocation->descent, + label); + button->callback (widgetCallback, this); + button->when (::fltk::WHEN_RELEASE); + return button; +} + +void FltkLabelButtonResource::sizeRequest (core::Requisition *requisition) +{ + if (style) { + FltkFont *font = (FltkFont*)style->font; + ::fltk::setfont(font->font,font->size); + requisition->width = + (int)::fltk::getwidth (label, strlen (label)) + + 2 * RELIEF_X_THICKNESS; + requisition->ascent = font->ascent + RELIEF_Y_THICKNESS; + requisition->descent = font->descent + RELIEF_Y_THICKNESS; + } else { + requisition->width = 1; + requisition->ascent = 1; + requisition->descent = 0; + } +} + +void FltkLabelButtonResource::widgetCallback (::fltk::Widget *widget, + void *data) +{ + if (widget->when () & ::fltk::WHEN_RELEASE) + ((FltkLabelButtonResource*)data)->emitActivate (); +} + +const char *FltkLabelButtonResource::getLabel () +{ + return label; +} + + +void FltkLabelButtonResource::setLabel (const char *label) +{ + delete this->label; + this->label = strdup (label); + + for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator (); + it.hasNext(); ) { + ViewAndWidget *viewAndWidget = it.getNext (); + viewAndWidget->widget->label (this->label); + } + + queueResize (true); +} + +// ---------------------------------------------------------------------- + +FltkComplexButtonResource::FltkComplexButtonResource (FltkPlatform *platform, + dw::core::Widget + *widget, bool relief): + FltkSpecificResource <dw::core::ui::ComplexButtonResource> (platform) +{ + viewsAndViews = new container::typed::List <ViewAndView> (true); + this->relief = relief; + FltkResource::init (platform); + ComplexButtonResource::init (widget); +} + +FltkComplexButtonResource::~FltkComplexButtonResource () +{ + delete viewsAndViews; +} + +void FltkComplexButtonResource::widgetCallback (::fltk::Widget *widget, + void *data) +{ + FltkComplexButtonResource *res = (FltkComplexButtonResource*)data; + + /* would be best not to send click pos. if the image could not be loaded */ + if (::fltk::event() == ::fltk::RELEASE && + ::fltk::event_button() == ::fltk::LeftButton) { + res->click_x = ::fltk::event_x(); + res->click_y = ::fltk::event_y(); + res->emitActivate (); + } else { + ((FltkViewBase*)res->lastFlatView)->handle(::fltk::event()); + } +} + +dw::core::Platform *FltkComplexButtonResource::createPlatform () +{ + return new FltkPlatform (); +} + +void FltkComplexButtonResource::attachView (FltkView *view) +{ + FltkResource::attachView (view); + + if (view->usesFltkWidgets ()) { + ViewAndView *viewAndView = new ViewAndView(); + viewAndView->topView = view; + viewAndView->flatView = lastFlatView; + viewsAndViews->append (viewAndView); + } +} + +void FltkComplexButtonResource::detachView (FltkView *view) +{ + FltkResource::detachView (view); + + for (Iterator <ViewAndView> it = viewsAndViews->iterator (); + it.hasNext(); ) { + ViewAndView *viewAndView = it.getNext (); + if (viewAndView->topView == view) { + viewsAndViews->removeRef (viewAndView); + return; + } + } + + fprintf (stderr, + "FltkComplexButtonResourceResource::detachView: View not " + "found.\n"); +} + +void FltkComplexButtonResource::sizeAllocate (core::Allocation *allocation) +{ + FltkResource::sizeAllocate (allocation); + + for (Iterator <ViewAndView> it = viewsAndViews->iterator (); + it.hasNext(); ) { + ViewAndView *viewAndView = it.getNext (); + ((FltkFlatView*)viewAndView->flatView)->resize ( + reliefXThickness (), + reliefYThickness (), + allocation->width - 2 * reliefXThickness (), + allocation->ascent + allocation->descent - 2 * reliefYThickness ()); + + ((FltkFlatView*)viewAndView->flatView)->parent ()->init_sizes (); + } +} + +void FltkComplexButtonResource::setLayout (dw::core::Layout *layout) +{ + for (Iterator <ViewAndView> it = viewsAndViews->iterator (); + it.hasNext(); ) { + ViewAndView *viewAndView = it.getNext (); + layout->attachView (viewAndView->flatView); + } +} + +int FltkComplexButtonResource::reliefXThickness () +{ + return relief ? RELIEF_X_THICKNESS : 0; +} + +int FltkComplexButtonResource::reliefYThickness () +{ + return relief ? RELIEF_Y_THICKNESS : 0; +} + + +::fltk::Widget *FltkComplexButtonResource::createNewWidget (core::Allocation + *allocation) +{ + ComplexButton *button = + new ComplexButton (allocation->x, allocation->y, allocation->width, + allocation->ascent + allocation->descent); + button->callback (widgetCallback, this); + button->when (::fltk::WHEN_RELEASE); + if (!relief) + button->box(::fltk::FLAT_BOX); + + FltkFlatView *flatView = + new FltkFlatView (allocation->x + reliefXThickness (), + allocation->y + reliefYThickness (), + allocation->width - 2 * reliefXThickness (), + allocation->ascent + allocation->descent + - 2 * reliefYThickness ()); + button->add (flatView); + + lastFlatView = flatView; + + if (layout) + layout->attachView (lastFlatView); + return button; +} + +// ---------------------------------------------------------------------- + +FltkEntryResource::FltkEntryResource (FltkPlatform *platform, int maxLength, + bool password): + FltkSpecificResource <dw::core::ui::EntryResource> (platform) +{ + this->maxLength = maxLength; + this->password = password; + + initText = NULL; + editable = false; + + init (platform); +} + +FltkEntryResource::~FltkEntryResource () +{ + if (initText) + delete initText; +} + +::fltk::Widget *FltkEntryResource::createNewWidget (core::Allocation + *allocation) +{ + ::fltk::Input *input = + password ? + new ::fltk::SecretInput (allocation->x, allocation->y, + allocation->width, + allocation->ascent + allocation->descent) : + new ::fltk::Input (allocation->x, allocation->y, allocation->width, + allocation->ascent + allocation->descent); + input->callback (widgetCallback, this); + input->when (::fltk::WHEN_ENTER_KEY_ALWAYS); + + if (viewsAndWidgets->isEmpty ()) { + // First widget created, attach the set text. + if (initText) + input->value (initText); + } else + input->value + (((::fltk::Input*)viewsAndWidgets->getFirst()->widget)->value ()); + + return input; +} + +void FltkEntryResource::sizeRequest (core::Requisition *requisition) +{ + if (style) { + FltkFont *font = (FltkFont*)style->font; + ::fltk::setfont(font->font,font->size); + requisition->width = + (int)::fltk::getwidth ("M", 1) + * (maxLength == UNLIMITED_MAX_LENGTH ? 10 : maxLength) + + 2 * RELIEF_X_THICKNESS; + requisition->ascent = font->ascent + RELIEF_Y_THICKNESS; + requisition->descent = font->descent + RELIEF_Y_THICKNESS; + } else { + requisition->width = 1; + requisition->ascent = 1; + requisition->descent = 0; + } +} + +void FltkEntryResource::widgetCallback (::fltk::Widget *widget, + void *data) +{ + /* The (::fltk::event_key() == ::fltk::ReturnKey) test + * is necessary because WHEN_ENTER_KEY also includes + * other events we're not interested in. For instance pressing + * The Back or Forward, buttons, or the first click on a rendered + * page. BUG: this must be investigated and reported to FLTK2 team + */ + printf ("when = %d\n", widget->when ()); + if ((widget->when () & ::fltk::WHEN_ENTER_KEY_ALWAYS) && + (::fltk::event_key() == ::fltk::ReturnKey)) + ((FltkEntryResource*)data)->emitActivate (); +} + +const char *FltkEntryResource::getText () +{ + if (viewsAndWidgets->isEmpty ()) + return initText; + else + return ((::fltk::Input*)viewsAndWidgets->getFirst()->widget)->value (); +} + +void FltkEntryResource::setText (const char *text) +{ + if (initText) + delete initText; + initText = strdup (text); + + for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator (); + it.hasNext(); ) { + ViewAndWidget *viewAndWidget = it.getNext (); + ((::fltk::Input*)viewAndWidget->widget)->value (initText); + } +} + +bool FltkEntryResource::isEditable () +{ + return editable; +} + +void FltkEntryResource::setEditable (bool editable) +{ + this->editable = editable; +} + +// ---------------------------------------------------------------------- + +FltkMultiLineTextResource::FltkMultiLineTextResource (FltkPlatform *platform, + int cols, int rows): + FltkSpecificResource <dw::core::ui::MultiLineTextResource> (platform) +{ + buffer = new ::fltk::TextBuffer; + editable = false; + + numCols = cols; + numRows = rows; + + // Check values. Upper bound check is left to the caller. + if (numCols < 1) { + fprintf (stderr, "WARNING: numCols = %d is set to 1.\n", numCols); + numCols = 1; + } + if (numRows < 1) { + fprintf (stderr, "WARNING: numRows = %d is set to 1.\n", numRows); + numRows = 1; + } + + init (platform); +} + +FltkMultiLineTextResource::~FltkMultiLineTextResource () +{ + /* Free memory avoiding a double-free of text buffers */ + for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator (); + it.hasNext(); ) { + ViewAndWidget *viewAndWidget = it.getNext (); + ((::fltk::TextEditor *) viewAndWidget->widget)->buffer (0); + } + delete buffer; +} + +::fltk::Widget *FltkMultiLineTextResource::createNewWidget (core::Allocation + *allocation) +{ + ::fltk::TextEditor *text = + new ::fltk::TextEditor (allocation->x, allocation->y, + allocation->width, + allocation->ascent + allocation->descent); + text->buffer (buffer); + return text; +} + +void FltkMultiLineTextResource::sizeRequest (core::Requisition *requisition) +{ + if (style) { + FltkFont *font = (FltkFont*)style->font; + ::fltk::setfont(font->font,font->size); + requisition->width = + (int)::fltk::getwidth ("X", 1) * numCols + + 2 * RELIEF_X_THICKNESS; + requisition->ascent = + font->ascent + RELIEF_Y_THICKNESS; + requisition->descent = + font->descent + + (font->ascent + font->descent) * (numRows - 1) + + RELIEF_Y_THICKNESS; + } else { + requisition->width = 1; + requisition->ascent = 1; + requisition->descent = 0; + } +} + +const char *FltkMultiLineTextResource::getText () +{ + return buffer->text (); +} + +void FltkMultiLineTextResource::setText (const char *text) +{ + buffer->text (text); +} + +bool FltkMultiLineTextResource::isEditable () +{ + return editable; +} + +void FltkMultiLineTextResource::setEditable (bool editable) +{ + this->editable = editable; +} + +// ---------------------------------------------------------------------- + +template <class I> +FltkToggleButtonResource<I>::FltkToggleButtonResource (FltkPlatform *platform, + bool activated): + FltkSpecificResource <I> (platform) +{ + initActivated = activated; +} + + +template <class I> +FltkToggleButtonResource<I>::~FltkToggleButtonResource () +{ +} + + +template <class I> +::fltk::Widget *FltkToggleButtonResource<I>::createNewWidget (core::Allocation + *allocation) +{ + ::fltk::Button *button = createNewButton (allocation); + + if (this->viewsAndWidgets->isEmpty ()) + button->value (initActivated); + else + button->value (((::fltk::Button*)this->viewsAndWidgets + ->getFirst()->widget)->value ()); + + return button; +} + + +template <class I> +void FltkToggleButtonResource<I>::sizeRequest (core::Requisition *requisition) +{ + /** \bug Random values. */ + requisition->width = 20; + requisition->ascent = 18; + requisition->descent = 5; +} + + +template <class I> +bool FltkToggleButtonResource<I>::FltkToggleButtonResource::isActivated () +{ + if (this->viewsAndWidgets->isEmpty ()) + return initActivated; + else + return + ((::fltk::Button*)this->viewsAndWidgets->getFirst()->widget) + ->value (); +} + + +template <class I> +void FltkToggleButtonResource<I>::setActivated (bool activated) +{ + initActivated = activated; + + for (Iterator <FltkResource::ViewAndWidget> it = + this->viewsAndWidgets->iterator (); + it.hasNext(); ) { + FltkResource::ViewAndWidget *viewAndWidget = it.getNext (); + ((::fltk::Button*)viewAndWidget->widget)->value (initActivated); + } +} + +// ---------------------------------------------------------------------- + +FltkCheckButtonResource::FltkCheckButtonResource (FltkPlatform *platform, + bool activated): + FltkToggleButtonResource<dw::core::ui::CheckButtonResource> (platform, + activated) +{ + init (platform); +} + + +FltkCheckButtonResource::~FltkCheckButtonResource () +{ +} + + +::fltk::Button *FltkCheckButtonResource::createNewButton (core::Allocation + *allocation) +{ + return + new ::fltk::CheckButton (allocation->x, allocation->y, allocation->width, + allocation->ascent + allocation->descent); +} + +// ---------------------------------------------------------------------- + +bool FltkRadioButtonResource::Group::FltkGroupIterator::hasNext () +{ + return it.hasNext (); +} + +dw::core::ui::RadioButtonResource +*FltkRadioButtonResource::Group::FltkGroupIterator::getNext () +{ + return (dw::core::ui::RadioButtonResource*)it.getNext (); +} + +void FltkRadioButtonResource::Group::FltkGroupIterator::unref () +{ + delete this; +} + + +FltkRadioButtonResource::Group::Group (FltkRadioButtonResource + *radioButtonResource) +{ + list = new container::typed::List <FltkRadioButtonResource> (false); + connect (radioButtonResource); +} + +FltkRadioButtonResource::Group::~Group () +{ + delete list; +} + +void FltkRadioButtonResource::Group::connect (FltkRadioButtonResource + *radioButtonResource) +{ + list->append (radioButtonResource); +} + +void FltkRadioButtonResource::Group::unconnect (FltkRadioButtonResource + *radioButtonResource) +{ + list->removeRef (radioButtonResource); + if (list->isEmpty ()) + delete this; +} + + +FltkRadioButtonResource::FltkRadioButtonResource (FltkPlatform *platform, + FltkRadioButtonResource + *groupedWith, + bool activated): + FltkToggleButtonResource<dw::core::ui::RadioButtonResource> (platform, + activated) +{ + init (platform); + + if (groupedWith) { + group = groupedWith->group; + group->connect (this); + } else + group = new Group (this); +} + + +FltkRadioButtonResource::~FltkRadioButtonResource () +{ + group->unconnect (this); +} + +dw::core::ui::RadioButtonResource::GroupIterator +*FltkRadioButtonResource::groupIterator () +{ + return group->groupIterator (); +} + +void FltkRadioButtonResource::widgetCallback (::fltk::Widget *widget, + void *data) +{ + if (widget->when () & ::fltk::WHEN_CHANGED) + ((FltkRadioButtonResource*)data)->buttonClicked (); +} + +void FltkRadioButtonResource::buttonClicked () +{ + for (Iterator <FltkRadioButtonResource> it = group->iterator (); + it.hasNext (); ) { + FltkRadioButtonResource *other = it.getNext (); + other->setActivated (other == this); + } +} + +::fltk::Button *FltkRadioButtonResource::createNewButton (core::Allocation + *allocation) +{ + /* + * Groups of fltk::RadioButton must be added to one fltk::Group, which is + * not possible in this context. For this, we do the grouping ourself, + * based on FltkRadioButtonResource::Group. + * + * What we actually need for this, is a widget, which behaves like a + * check button, but looks like a radio button. The first depends on the + * type, the second on the style. Since the type is simpler to change + * than the style, we create a radio button, and then change the type + * (instead of creating a check button, and changing the style). + */ + + ::fltk::Button *button = + new ::fltk::RadioButton (allocation->x, allocation->y, + allocation->width, + allocation->ascent + allocation->descent); + button->when (::fltk::WHEN_CHANGED); + button->callback (widgetCallback, this); + button->type (::fltk::Button::TOGGLE); + + return button; +} + +// ---------------------------------------------------------------------- + +template <class I> FltkSelectionResource<I>::Item::Item (Type type, + const char *name, + bool enabled, + bool selected) +{ + this->type = type; + this->name = name ? strdup (name) : NULL; + this->enabled = enabled; + initSelected = selected; +} + +template <class I> FltkSelectionResource<I>::Item::~Item () +{ + if (name) + delete name; +} + +template <class I> +::fltk::Item *FltkSelectionResource<I>::Item::createNewWidget (int index) +{ + ::fltk::Item *item = new ::fltk::Item (name); + item->user_data ((void *) index); + return item; +} + +template <class I> +::fltk::ItemGroup * +FltkSelectionResource<I>::Item::createNewGroupWidget () +{ + ::fltk::ItemGroup *itemGroup = new ::fltk::ItemGroup (name); + itemGroup->user_data ((void *) -1L); + return itemGroup; +} + + +template <class I> +FltkSelectionResource<I>::WidgetStack::WidgetStack (::fltk::Menu *widget) +{ + this->widget = widget; + this->stack = new Stack <TypedPointer < ::fltk::Menu> > (true); +} + +template <class I> FltkSelectionResource<I>::WidgetStack::~WidgetStack () +{ + delete stack; +} + + +template <class I> +FltkSelectionResource<I>::FltkSelectionResource (FltkPlatform *platform): + FltkSpecificResource<I> (platform) +{ + widgetStacks = new List <WidgetStack> (true); + allItems = new List <Item> (true); + items = new Vector <Item> (16, false); +} + +template <class I> FltkSelectionResource<I>::~FltkSelectionResource () +{ + delete widgetStacks; + delete allItems; + delete items; +} + +template <class I> dw::core::Iterator * +FltkSelectionResource<I>::iterator (dw::core::Content::Type mask, bool atEnd) +{ + /** \bug Implementation. */ + return new core::EmptyIterator (this->getEmbed (), mask, atEnd); +} + +template <class I> ::fltk::Widget * +FltkSelectionResource<I>::createNewWidget (core::Allocation *allocation) +{ + /** \todo Attributes (enabled, selected). */ + + ::fltk::Menu *menu = createNewMenu (allocation); + WidgetStack *widgetStack = new WidgetStack (menu); + widgetStack->stack->push (new TypedPointer < ::fltk::Menu> (menu)); + widgetStacks->append (widgetStack); + + + ::fltk::Menu *itemGroup; + ::fltk::Item *itemWidget; + + ::fltk::Group *currGroup = widgetStack->stack->getTop()->getTypedValue(); + + int index = 0; + for (Iterator <Item> it = allItems->iterator (); it.hasNext (); ) { + Item *item = it.getNext (); + switch (item->type) { + case Item::ITEM: + itemWidget = item->createNewWidget (index++); + currGroup->add (itemWidget); + break; + + case Item::START: + itemGroup = item->createNewGroupWidget (); + currGroup->add (itemGroup); + widgetStack->stack->push (new TypedPointer < ::fltk::Menu> (menu)); + currGroup = itemGroup; + break; + + case Item::END: + widgetStack->stack->pop (); + currGroup = widgetStack->stack->getTop()->getTypedValue(); + break; + } + } + + return menu; +} + +template <class I> +typename FltkSelectionResource<I>::Item * +FltkSelectionResource<I>::createNewItem (typename Item::Type type, + const char *name, + bool enabled, + bool selected) { + return new Item(type,name,enabled,selected); +} + +template <class I> void FltkSelectionResource<I>::addItem (const char *str, + bool enabled, + bool selected) +{ + int index = items->size (); + Item *item = createNewItem (Item::ITEM, str, enabled, selected); + items->put (item); + allItems->append (item); + + for (Iterator <WidgetStack> it = widgetStacks->iterator (); + it.hasNext(); ) { + WidgetStack *widgetStack = it.getNext (); + ::fltk::Item *itemWidget = item->createNewWidget (index); + widgetStack->stack->getTop()->getTypedValue()->add (itemWidget); + + if (!enabled) + itemWidget->deactivate (); + + if (selected) { + itemWidget->set_selected(); + if (setSelectedItems ()) { + // Handle multiple item selection. + int pos[widgetStack->stack->size ()]; + int i; + Iterator <TypedPointer < ::fltk::Menu> > it; + for (it = widgetStack->stack->iterator (), + i = widgetStack->stack->size () - 1; + it.hasNext (); + i--) { + TypedPointer < ::fltk::Menu> * p = it.getNext (); + pos[i] = p->getTypedValue()->children () - 1; + } + widgetStack->widget->set_item (pos, widgetStack->stack->size ()); + } + } + } +} + +template <class I> void FltkSelectionResource<I>::pushGroup (const char *name, + bool enabled) +{ + Item *item = createNewItem (Item::START, name, enabled); + allItems->append (item); + + for (Iterator <WidgetStack> it = widgetStacks->iterator (); + it.hasNext(); ) { + WidgetStack *widgetStack = it.getNext (); + ::fltk::ItemGroup *group = item->createNewGroupWidget (); + widgetStack->stack->getTop()->getTypedValue()->add (group); + widgetStack->stack->push (new TypedPointer < ::fltk::Menu> (group)); + if(!enabled) + group->deactivate (); + } +} + +template <class I> void FltkSelectionResource<I>::popGroup () +{ + Item *item = createNewItem (Item::END); + allItems->append (item); + + for (Iterator <WidgetStack> it = widgetStacks->iterator (); + it.hasNext(); ) { + WidgetStack *widgetStack = it.getNext (); + widgetStack->stack->pop (); + } +} + +template <class I> int FltkSelectionResource<I>::getNumberOfItems () +{ + return items->size (); +} + +template <class I> const char *FltkSelectionResource<I>::getItem (int index) +{ + return items->get(index)->name; +} + +template <class I> int FltkSelectionResource<I>::getMaxStringWidth () +{ + int width = 0, numberOfItems = getNumberOfItems (); + for (int i = 0; i < numberOfItems; i++) { + int len = (int)::fltk::getwidth (getItem(i)); + if (len > width) width = len; + } + return width; +} + +// ---------------------------------------------------------------------- + +FltkOptionMenuResource::FltkOptionMenuResource (FltkPlatform *platform): + FltkSelectionResource <dw::core::ui::OptionMenuResource> (platform), + selection(-1) +{ + init (platform); +} + +FltkOptionMenuResource::~FltkOptionMenuResource () +{ +} + + +::fltk::Menu *FltkOptionMenuResource::createNewMenu (core::Allocation + *allocation) +{ + ::fltk::Menu *menu = + new ::fltk::Choice (allocation->x, allocation->y, + allocation->width, + allocation->ascent + allocation->descent); + menu->callback(widgetCallback,this); + return menu; +} + +void FltkOptionMenuResource::widgetCallback (::fltk::Widget *widget, + void *data) +{ + ((FltkOptionMenuResource *) data)->selection = + (long) (((::fltk::Menu *) widget)->item()->user_data()); +} + +void FltkOptionMenuResource::sizeRequest (core::Requisition *requisition) +{ + if (style) { + FltkFont *font = (FltkFont*)style->font; + ::fltk::setfont(font->font,font->size); + int maxStringWidth = getMaxStringWidth (); + requisition->ascent = font->ascent + RELIEF_Y_THICKNESS; + requisition->descent = font->descent + RELIEF_Y_THICKNESS; + requisition->width = maxStringWidth + + (requisition->ascent + requisition->descent) * 4 / 5 + + 2 * RELIEF_X_THICKNESS; + } else { + requisition->width = 1; + requisition->ascent = 1; + requisition->descent = 0; + } +} + +void FltkOptionMenuResource::addItem (const char *str, + bool enabled, bool selected) +{ + FltkSelectionResource<dw::core::ui::OptionMenuResource>::addItem + (str,enabled,selected); + if (selected) + selection = (items->size ()) - 1; + + queueResize (true); +} + +bool FltkOptionMenuResource::isSelected (int index) +{ + return index == selection; +} + +// ---------------------------------------------------------------------- + +FltkListResource::FltkListResource (FltkPlatform *platform, + core::ui::ListResource::SelectionMode + selectionMode): + FltkSelectionResource <dw::core::ui::ListResource> (platform), + itemsSelected(8) +{ + init (platform); +} + +FltkListResource::~FltkListResource () +{ +} + + +::fltk::Menu *FltkListResource::createNewMenu (core::Allocation *allocation) +{ + ::fltk::Menu *menu = + new ::fltk::MultiBrowser (allocation->x, allocation->y, + allocation->width, + allocation->ascent + allocation->descent); + menu->callback(widgetCallback,this); + menu->when(::fltk::WHEN_CHANGED); + return menu; +} + +void FltkListResource::widgetCallback (::fltk::Widget *widget, void *data) +{ + ::fltk::Widget *fltkItem = ((::fltk::Menu *) widget)->item (); + int index = (long) (fltkItem->user_data ()); + if (index > -1) { + bool selected = fltkItem->selected (); + ((FltkListResource *) data)->itemsSelected.set (index, selected); + } +} + +void FltkListResource::addItem (const char *str, bool enabled, bool selected) +{ + FltkSelectionResource<dw::core::ui::ListResource>::addItem + (str,enabled,selected); + int index = itemsSelected.size (); + itemsSelected.increase (); + itemsSelected.set (index,selected); + queueResize (true); +} + +void FltkListResource::sizeRequest (core::Requisition *requisition) +{ + if (style) { + FltkFont *font = (FltkFont*)style->font; + ::fltk::setfont(font->font,font->size); + int maxStringWidth = getMaxStringWidth (); + requisition->ascent = font->ascent + RELIEF_Y_THICKNESS; + requisition->descent = + (getNumberOfItems () - 1) * (font->ascent) + font->descent; + requisition->width = maxStringWidth + + (font->ascent + font->descent) * 4 / 5 + + 2 * RELIEF_X_THICKNESS; + } else { + requisition->width = 1; + requisition->ascent = 1; + requisition->descent = 0; + } +} + +bool FltkListResource::isSelected (int index) +{ + return itemsSelected.get (index); +} + +} // namespace ui +} // namespace fltk +} // namespace dw +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkui.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,554 @@ +#ifndef __DW_FLTK_UI_HH__ +#define __DW_FLTK_UI_HH__ + +#ifndef __INCLUDED_FROM_DW_FLTK_CORE_HH__ +# error Do not include this file directly, use "fltkcore.hh" instead. +#endif + +#include <fltk/Button.h> +#include <fltk/Menu.h> +#include <fltk/TextBuffer.h> +#include <fltk/Item.h> +#include <fltk/ItemGroup.h> + +namespace dw { +namespace fltk { + +using namespace lout; + +/** + * \brief FLTK implementation of dw::core::ui. + * + * The design should be like this: + * + * \dot + * digraph G { + * node [shape=record, fontname=Helvetica, fontsize=10]; + * edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica, + * labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + * fontname=Helvetica; fontsize=10; + * + * subgraph cluster_core { + * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + * label="dw::core::ui"; + * + * Resource [color="#a0a0a0", URL="\ref dw::core::ui::Resource"]; + * LabelButtonResource [color="#a0a0a0", + * URL="\ref dw::core::ui::LabelButtonResource"]; + * EntryResource [color="#a0a0a0", + * URL="\ref dw::core::ui::EntryResource"]; + * } + * + * subgraph cluster_fltk { + * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + * label="dw::fltk::ui"; + * + * FltkResource [color="#a0a0a0", URL="\ref dw::fltk::ui::FltkResource"]; + * FltkLabelButtonResource + * [URL="\ref dw::fltk::ui::FltkLabelButtonResource"]; + * FltkEntryResource [URL="\ref dw::fltk::ui::FltkEntryResource"]; + * } + * + * Resource -> LabelButtonResource; + * Resource -> EntryResource; + * FltkResource -> FltkLabelButtonResource; + * FltkResource -> FltkEntryResource; + * Resource -> FltkResource; + * LabelButtonResource -> FltkLabelButtonResource; + * EntryResource -> FltkEntryResource; + * } + * \enddot + * + * <center>[\ref uml-legend "legend"]</center> + * + * where dw::fltk::ui::FltkResource provides some base funtionality for all + * conctrete FLTK implementations of sub-interfaces of dw::core::ui::Resource. + * However, this is not directly possible in C++, since the base class + * dw::core::ui::Resource is ambiguous for + * dw::fltk::ui::FltkLabelButtonResource. + * + * To solve this, we have to remove the depencency between + * dw::fltk::ui::FltkResource and dw::core::ui::Resource, instead, the part + * of dw::core::ui::Resource, which is implemented in + * dw::fltk::ui::FltkResource, must be explicitely delegated from + * dw::fltk::ui::FltkLabelButtonResourceto dw::fltk::ui::FltkResource: + * + * \dot + * digraph G { + * node [shape=record, fontname=Helvetica, fontsize=10]; + * edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica, + * labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + * fontname=Helvetica; fontsize=10; + * + * subgraph cluster_core { + * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + * label="dw::core::ui"; + * + * Resource [color="#a0a0a0", URL="\ref dw::core::ui::Resource"]; + * LabelButtonResource [color="#a0a0a0", + * URL="\ref dw::core::ui::LabelButtonResource"]; + * EntryResource [color="#a0a0a0", + * URL="\ref dw::core::ui::EntryResource"]; + * } + * + * subgraph cluster_fltk { + * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + * label="dw::fltk::ui"; + * + * FltkResource [color="#a0a0a0", URL="\ref dw::fltk::ui::FltkResource"]; + * FltkLabelButtonResource + * [URL="\ref dw::fltk::ui::FltkLabelButtonResource"]; + * FltkEntryResource [URL="\ref dw::fltk::ui::FltkEntryResource"]; + * } + * + * Resource -> LabelButtonResource; + * Resource -> EntryResource; + * FltkResource -> FltkLabelButtonResource; + * FltkResource -> FltkEntryResource; + * LabelButtonResource -> FltkLabelButtonResource; + * EntryResource -> FltkEntryResource; + * } + * \enddot + * + * <center>[\ref uml-legend "legend"]</center> + * + * To make this a bit simpler, we use templates: + * + * \dot + * digraph G { + * node [shape=record, fontname=Helvetica, fontsize=10]; + * edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica, + * labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + * fontname=Helvetica; fontsize=10; + * + * subgraph cluster_core { + * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + * label="dw::core::ui"; + * + * Resource [color="#a0a0a0", URL="\ref dw::core::ui::Resource"]; + * LabelButtonResource [color="#a0a0a0", + * URL="\ref dw::core::ui::LabelButtonResource"]; + * EntryResource [color="#a0a0a0", + * URL="\ref dw::core::ui::EntryResource"]; + * } + * + * subgraph cluster_fltk { + * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + * label="dw::fltk::ui"; + * + * FltkResource [color="#a0a0a0", URL="\ref dw::fltk::ui::FltkResource"]; + * FltkSpecificResource [color="#a0a0a0", + * fillcolor="#ffffc0", style="filled" + * URL="\ref dw::fltk::ui::FltkSpecificResource"]; + * FltkSpecificResource_button [color="#a0a0a0", + * label="FltkSpecificResource \<LabelButtonResource\>"]; + * FltkSpecificResource_entry [color="#a0a0a0", + * label="FltkSpecificResource \<EntryResource\>"]; + * FltkEntryResource [URL="\ref dw::fltk::ui::FltkEntryResource"]; + * FltkLabelButtonResource + * [URL="\ref dw::fltk::ui::FltkLabelButtonResource"]; + * } + * + * Resource -> LabelButtonResource; + * Resource -> EntryResource; + * FltkResource -> FltkSpecificResource; + * FltkSpecificResource -> FltkSpecificResource_button [arrowhead="open", + * arrowtail="none", + * style="dashed", + * color="#808000"]; + * FltkSpecificResource -> FltkSpecificResource_entry [arrowhead="open", + * arrowtail="none", + * style="dashed", + * color="#808000"]; + * LabelButtonResource -> FltkSpecificResource_button; + * EntryResource -> FltkSpecificResource_entry; + * FltkSpecificResource_button -> FltkLabelButtonResource; + * FltkSpecificResource_entry -> FltkEntryResource; + * } + * \enddot + * + * <center>[\ref uml-legend "legend"]</center> + */ +namespace ui { + +/** + * ... + */ +class FltkResource: public object::Object +{ +protected: + class ViewAndWidget: public object::Object + { + public: + FltkView *view; + ::fltk::Widget *widget; + }; + + container::typed::List <ViewAndWidget> *viewsAndWidgets; + core::Allocation allocation; + FltkPlatform *platform; + + core::style::Style *style; + + FltkResource (FltkPlatform *platform); + void init (FltkPlatform *platform); + virtual ::fltk::Widget *createNewWidget (core::Allocation *allocation) = 0; + + void setWidgetStyle (::fltk::Widget *widget, core::style::Style *style); +public: + ~FltkResource (); + + virtual void attachView (FltkView *view); + virtual void detachView (FltkView *view); + + void sizeAllocate (core::Allocation *allocation); + void draw (core::View *view, core::Rectangle *area); + + void setStyle (core::style::Style *style); + + bool isEnabled (); + void setEnabled (bool enabled); +}; + + +template <class I> class FltkSpecificResource: public I, public FltkResource +{ +public: + inline FltkSpecificResource (FltkPlatform *platform) : + FltkResource (platform) { } + + void sizeAllocate (core::Allocation *allocation); + void draw (core::View *view, core::Rectangle *area); + void setStyle (core::style::Style *style); + + bool isEnabled (); + void setEnabled (bool enabled); +}; + + +class FltkLabelButtonResource: + public FltkSpecificResource <dw::core::ui::LabelButtonResource> +{ +private: + const char *label; + + static void widgetCallback (::fltk::Widget *widget, void *data); + +protected: + ::fltk::Widget *createNewWidget (core::Allocation *allocation); + +public: + FltkLabelButtonResource (FltkPlatform *platform, const char *label); + ~FltkLabelButtonResource (); + + void sizeRequest (core::Requisition *requisition); + + const char *getLabel (); + void setLabel (const char *label); +}; + + +class FltkComplexButtonResource: + public FltkSpecificResource <dw::core::ui::ComplexButtonResource> +{ +private: + bool relief; + + static void widgetCallback (::fltk::Widget *widget, void *data); + +protected: + class ViewAndView: public object::Object + { + public: + FltkView *topView, *flatView; + }; + + FltkView *lastFlatView; + + container::typed::List <ViewAndView> *viewsAndViews; + + void attachView (FltkView *view); + void detachView (FltkView *view); + + void sizeAllocate (core::Allocation *allocation); + + dw::core::Platform *createPlatform (); + void setLayout (dw::core::Layout *layout); + + int reliefXThickness (); + int reliefYThickness (); + + ::fltk::Widget *createNewWidget (core::Allocation *allocation); + +public: + FltkComplexButtonResource (FltkPlatform *platform, dw::core::Widget *widget, + bool relief); + ~FltkComplexButtonResource (); +}; + + +/** + * \bug Maximal length not supported yet. + * \todo Text values are not synchronized (not needed in dillo). + */ +class FltkEntryResource: + public FltkSpecificResource <dw::core::ui::EntryResource> +{ +private: + int maxLength; + bool password; + const char *initText; + bool editable; + + static void widgetCallback (::fltk::Widget *widget, void *data); + +protected: + ::fltk::Widget *createNewWidget (core::Allocation *allocation); + +public: + FltkEntryResource (FltkPlatform *platform, int maxLength, bool password); + ~FltkEntryResource (); + + void sizeRequest (core::Requisition *requisition); + + const char *getText (); + void setText (const char *text); + bool isEditable (); + void setEditable (bool editable); +}; + + +class FltkMultiLineTextResource: + public FltkSpecificResource <dw::core::ui::MultiLineTextResource> +{ +private: + ::fltk::TextBuffer *buffer; + bool editable; + int numCols, numRows; + +protected: + ::fltk::Widget *createNewWidget (core::Allocation *allocation); + +public: + FltkMultiLineTextResource (FltkPlatform *platform, int cols, int rows); + ~FltkMultiLineTextResource (); + + void sizeRequest (core::Requisition *requisition); + + const char *getText (); + void setText (const char *text); + bool isEditable (); + void setEditable (bool editable); +}; + + +template <class I> class FltkToggleButtonResource: + public FltkSpecificResource <I> +{ +private: + bool initActivated; + +protected: + virtual ::fltk::Button *createNewButton (core::Allocation *allocation) = 0; + ::fltk::Widget *createNewWidget (core::Allocation *allocation); + +public: + FltkToggleButtonResource (FltkPlatform *platform, + bool activated); + ~FltkToggleButtonResource (); + + void sizeRequest (core::Requisition *requisition); + + bool isActivated (); + void setActivated (bool activated); +}; + + +class FltkCheckButtonResource: + public FltkToggleButtonResource <dw::core::ui::CheckButtonResource> +{ +protected: + ::fltk::Button *createNewButton (core::Allocation *allocation); + +public: + FltkCheckButtonResource (FltkPlatform *platform, + bool activated); + ~FltkCheckButtonResource (); +}; + + +class FltkRadioButtonResource: + public FltkToggleButtonResource <dw::core::ui::RadioButtonResource> +{ +private: + class Group + { + private: + class FltkGroupIterator: + public dw::core::ui::RadioButtonResource::GroupIterator + { + private: + container::typed::Iterator <FltkRadioButtonResource> it; + + public: + inline FltkGroupIterator (container::typed::List + <FltkRadioButtonResource> + *list) + { it = list->iterator (); } + + bool hasNext (); + dw::core::ui::RadioButtonResource *getNext (); + void unref (); + }; + + container::typed::List <FltkRadioButtonResource> *list; + + protected: + ~Group (); + + public: + Group (FltkRadioButtonResource *radioButtonResource); + + inline container::typed::Iterator <FltkRadioButtonResource> iterator () + { + return list->iterator (); + } + + inline dw::core::ui::RadioButtonResource::GroupIterator + *groupIterator () + { + return new FltkGroupIterator (list); + } + + void connect (FltkRadioButtonResource *radioButtonResource); + void unconnect (FltkRadioButtonResource *radioButtonResource); + }; + + Group *group; + + static void widgetCallback (::fltk::Widget *widget, void *data); + void buttonClicked (); + +protected: + ::fltk::Button *createNewButton (core::Allocation *allocation); + +public: + FltkRadioButtonResource (FltkPlatform *platform, + FltkRadioButtonResource *groupedWith, + bool activated); + ~FltkRadioButtonResource (); + + GroupIterator *groupIterator (); +}; + + +template <class I> class FltkSelectionResource: + public FltkSpecificResource <I> +{ +protected: + class Item: public object::Object + { + public: + enum Type { ITEM, START, END } type; + + const char *name; + bool enabled, initSelected; + + Item (Type type, const char *name = NULL, bool enabled = true, + bool selected = false); + ~Item (); + + ::fltk::Item *createNewWidget (int index); + ::fltk::ItemGroup *createNewGroupWidget (); + }; + + class WidgetStack: public object::Object + { + public: + ::fltk::Menu *widget; + container::typed::Stack <object::TypedPointer < ::fltk::Menu> > *stack; + + WidgetStack (::fltk::Menu *widget); + ~WidgetStack (); + }; + + container::typed::List <WidgetStack> *widgetStacks; + container::typed::List <Item> *allItems; + container::typed::Vector <Item> *items; + + Item *createNewItem (typename Item::Type type, + const char *name = NULL, + bool enabled = true, + bool selected = false); + + ::fltk::Widget *createNewWidget (core::Allocation *allocation); + virtual ::fltk::Menu *createNewMenu (core::Allocation *allocation) = 0; + virtual bool setSelectedItems() { return false; } + + int getMaxStringWidth (); + +public: + FltkSelectionResource (FltkPlatform *platform); + ~FltkSelectionResource (); + + dw::core::Iterator *iterator (dw::core::Content::Type mask, bool atEnd); + + void addItem (const char *str, bool enabled, bool selected); + + void pushGroup (const char *name, bool enabled); + void popGroup (); + + int getNumberOfItems (); + const char *getItem (int index); +}; + + +class FltkOptionMenuResource: + public FltkSelectionResource <dw::core::ui::OptionMenuResource> +{ +protected: + ::fltk::Menu *createNewMenu (core::Allocation *allocation); + virtual bool setSelectedItems() { return true; } + +private: + static void widgetCallback (::fltk::Widget *widget, void *data); + int selection; + +public: + FltkOptionMenuResource (FltkPlatform *platform); + ~FltkOptionMenuResource (); + + void addItem (const char *str, bool enabled, bool selected); + + void sizeRequest (core::Requisition *requisition); + bool isSelected (int index); +}; + +class FltkListResource: + public FltkSelectionResource <dw::core::ui::ListResource> +{ +protected: + ::fltk::Menu *createNewMenu (core::Allocation *allocation); + +private: + static void widgetCallback (::fltk::Widget *widget, void *data); + misc::SimpleVector <bool> itemsSelected; + +public: + FltkListResource (FltkPlatform *platform, + core::ui::ListResource::SelectionMode selectionMode); + ~FltkListResource (); + + void addItem (const char *str, bool enabled, bool selected); + + void sizeRequest (core::Requisition *requisition); + bool isSelected (int index); +}; + + +} // namespace ui +} // namespace fltk +} // namespace dw + + +#endif // __DW_FLTK_UI_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkviewbase.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,524 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "fltkviewport.hh" + +#include <fltk/draw.h> +#include <fltk/damage.h> +#include <fltk/layout.h> +#include <fltk/events.h> +#include <fltk/Cursor.h> +#include <fltk/run.h> + +#include <stdio.h> + +using namespace fltk; +using namespace lout::object; +using namespace lout::container::typed; + +namespace dw { +namespace fltk { + +::fltk::Image *FltkViewBase::backBuffer; +bool FltkViewBase::backBufferInUse; + +FltkViewBase::FltkViewBase (int x, int y, int w, int h, const char *label): + Group (x, y, w, h, label) +{ + canvasWidth = 1; + canvasHeight = 1; + bgColor = WHITE; + lastDraw = time(0); + drawDelay = 2; /* in seconds */ + mouse_x = mouse_y = 0; +#ifndef NO_DOUBLEBUFFER + if (!backBuffer) { + backBuffer = new Image (); + } +#endif +} + +FltkViewBase::~FltkViewBase () +{ + cancelQueueDraw (); +} + +void FltkViewBase::draw () +{ + int d = damage (); + + if ((d & DAMAGE_VALUE) && !(d & DAMAGE_EXPOSE)) { + container::typed::Iterator <core::Rectangle> it; + + for (it = drawRegion.rectangles (); it.hasNext (); ) { + drawRectangle (it.getNext (), true); + } + + drawRegion.clear (); + d &= ~DAMAGE_VALUE; + } + + if (d & DAMAGE_CHILD) { + drawChildWidgets (); + d &= ~DAMAGE_CHILD; + } + + if (d) { + dw::core::Rectangle rect ( + translateViewXToCanvasX (0), + translateViewYToCanvasY (0), + w (), + h ()); + + drawRectangle (&rect, false); + + if (! (d & DAMAGE_SCROLL)) { + drawRegion.clear (); + } + } +} + +void FltkViewBase::drawRectangle (const core::Rectangle *rect, + bool doubleBuffer) +{ + int offsetX = 0, offsetY = 0; + + /* fltk-clipping does not use widget coordinates */ + transform (offsetX, offsetY); + + ::fltk::Rectangle viewRect ( + translateCanvasXToViewX (rect->x) + offsetX, + translateCanvasYToViewY (rect->y) + offsetY, + rect->width, rect->height); + + ::fltk::intersect_with_clip (viewRect); + + viewRect.x (viewRect.x () - offsetX); + viewRect.y (viewRect.y () - offsetY); + + if (! viewRect.empty ()) { + dw::core::Rectangle r ( + translateViewXToCanvasX (viewRect.x ()), + translateViewYToCanvasY (viewRect.y ()), + viewRect.w (), + viewRect.h ()); + +#ifdef NO_DOUBLEBUFFER + push_clip (viewRect); +#endif + + if (doubleBuffer && backBuffer && !backBufferInUse) { + backBufferInUse = true; + { + GSave gsave; + + backBuffer->setsize (viewRect.w (), viewRect.h ()); + backBuffer->make_current (); + translate (-viewRect.x (), -viewRect.y ()); + + setcolor (bgColor); + fillrect (viewRect); + theLayout->expose (this, &r); + } + + backBuffer->draw (Rectangle (0, 0, viewRect.w (), viewRect.h ()), + viewRect); + + backBufferInUse = false; + } else { + setcolor (bgColor); + fillrect (viewRect); + theLayout->expose (this, &r); + } + +#ifdef NO_DOUBLEBUFFER + pop_clip (); +#endif + } +} + +void FltkViewBase::drawChildWidgets () { + for (int i = children () - 1; i >= 0; i--) { + Widget& w = *child(i); + if (w.damage() & DAMAGE_CHILD_LABEL) { + draw_outside_label(w); + w.set_damage(w.damage() & ~DAMAGE_CHILD_LABEL); + } + update_child(w); + } +} + +core::ButtonState getDwButtonState () +{ + int s1 = event_state (); + int s2 = (core::ButtonState)0; + + if(s1 & SHIFT) s2 |= core::SHIFT_MASK; + if(s1 & CTRL) s2 |= core::CONTROL_MASK; + if(s1 & ALT) s2 |= core::META_MASK; + if(s1 & BUTTON1) s2 |= core::BUTTON1_MASK; + if(s1 & BUTTON2) s2 |= core::BUTTON2_MASK; + if(s1 & BUTTON3) s2 |= core::BUTTON3_MASK; + + return (core::ButtonState)s2; +} + +int FltkViewBase::handle (int event) +{ + bool processed; + + /** + * \todo Consider, whether this from the FLTK documentation has any + * impacts: "To receive fltk::RELEASE events you must return non-zero + * when passed a fltk::PUSH event. " + */ + switch(event) { + case PUSH: + processed = + theLayout->buttonPress (this, event_clicks () + 1, + translateViewXToCanvasX (event_x ()), + translateViewYToCanvasY (event_y ()), + getDwButtonState (), event_button ()); + //printf ("PUSH => %s\n", processed ? "true" : "false"); + return processed ? true : Group::handle (event); + + case RELEASE: + processed = + theLayout->buttonRelease (this, event_clicks () + 1, + translateViewXToCanvasX (event_x ()), + translateViewYToCanvasY (event_y ()), + getDwButtonState (), event_button ()); + //printf ("RELEASE => %s\n", processed ? "true" : "false"); + return processed ? true : Group::handle (event); + + case MOVE: + mouse_x = event_x(); + mouse_y = event_y(); + processed = + theLayout->motionNotify (this, + translateViewXToCanvasX (mouse_x), + translateViewYToCanvasY (mouse_y), + getDwButtonState ()); + //printf ("MOVE => %s\n", processed ? "true" : "false"); + return processed ? true : Group::handle (event); + + case DRAG: + processed = + theLayout->motionNotify (this, + translateViewXToCanvasX (event_x ()), + translateViewYToCanvasY (event_y ()), + getDwButtonState ()); + //printf ("DRAG => %s\n", processed ? "true" : "false"); + return processed ? true : Group::handle (event); + + case ENTER: + theLayout->enterNotify (this, translateViewXToCanvasX (event_x ()), + translateViewYToCanvasY (event_y ()), + getDwButtonState ()); + return Group::handle (event); + + case LEAVE: + theLayout->leaveNotify (this, getDwButtonState ()); + return Group::handle (event); + + default: + return Group::handle (event); + } +} + +// ---------------------------------------------------------------------- + +void FltkViewBase::setLayout (core::Layout *layout) +{ + theLayout = layout; +} + +void FltkViewBase::setCanvasSize (int width, int ascent, int descent) +{ + canvasWidth = width; + canvasHeight = ascent + descent; +} + +void FltkViewBase::setCursor (core::style::Cursor cursor) +{ + static Cursor *mapDwToFltk[] = { + CURSOR_CROSS, + CURSOR_ARROW, + CURSOR_HAND, + CURSOR_MOVE, + CURSOR_WE, + CURSOR_NESW, + CURSOR_NWSE, + CURSOR_NS, + CURSOR_NWSE, + CURSOR_NESW, + CURSOR_NS, + CURSOR_WE, + CURSOR_INSERT, + CURSOR_WAIT, + CURSOR_HELP + }; + + /* + static char *cursorName[] = { + "CURSOR_CROSS", + "CURSOR_ARROW", + "CURSOR_HAND", + "CURSOR_MOVE", + "CURSOR_WE", + "CURSOR_NESW", + "CURSOR_NWSE", + "CURSOR_NS", + "CURSOR_NWSE", + "CURSOR_NESW", + "CURSOR_NS", + "CURSOR_WE", + "CURSOR_INSERT", + "CURSOR_WAIT", + "CURSOR_HELP" + }; + + printf ("Cursor changes to '%s'.\n", cursorName[cursor]); + */ + + /** \bug Does not work */ + this->cursor (mapDwToFltk[cursor]); +} + +void FltkViewBase::setBgColor (core::style::Color *color) +{ + bgColor = color ? + ((FltkColor*)color)->colors[dw::core::style::Color::SHADING_NORMAL] : + WHITE; +} + +void FltkViewBase::startDrawing (core::Rectangle *area) +{ +} + +void FltkViewBase::finishDrawing (core::Rectangle *area) +{ +} + +void FltkViewBase::queueDraw (core::Rectangle *area) +{ + drawRegion.addRectangle (area); + /** DAMAGE_VALUE is just an arbitrary value other than DAMAGE_EXPOSE here */ + redraw (DAMAGE_VALUE); +} + +static void drawTotalTimeout (void *data) +{ + FltkViewBase *view = (FltkViewBase*) data; + if (time(0) >= view->lastDraw + view->drawDelay) { + view->drawTotal (); + } else { + ::fltk::add_timeout (0.2f, drawTotalTimeout, data); + } +} + +void FltkViewBase::drawTotal () +{ + //static int calls = 0; + //printf(" FltkViewBase::drawTotal calls = %d\n", ++calls); + redraw (DAMAGE_EXPOSE); + lastDraw = time (0); + cancelQueueDraw (); +} + +void FltkViewBase::queueDrawTotal () +{ + drawTotal (); +} + +void FltkViewBase::cancelQueueDraw () +{ + ::fltk::remove_timeout (drawTotalTimeout, this); +} + +void FltkViewBase::drawPoint (core::style::Color *color, + core::style::Color::Shading shading, + int x, int y) +{ +} + +void FltkViewBase::drawLine (core::style::Color *color, + core::style::Color::Shading shading, + int x1, int y1, int x2, int y2) +{ + setcolor(((FltkColor*)color)->colors[shading]); + drawline (translateCanvasXToViewX (x1), translateCanvasYToViewY (y1), + translateCanvasXToViewX (x2), translateCanvasYToViewY (y2)); +} + +void FltkViewBase::drawRectangle (core::style::Color *color, + core::style::Color::Shading shading, + bool filled, + int x, int y, int width, int height) +{ + setcolor(((FltkColor*)color)->colors[shading]); + int x1 = translateCanvasXToViewX (x); + int y1 = translateCanvasYToViewY (y); + int x2 = translateCanvasXToViewX (x + width); + int y2 = translateCanvasYToViewY (y + height); + ::fltk::Rectangle rect (x1, y1, x2 - x1, y2 - y1); + if (filled) + fillrect (rect); + else + strokerect (rect); +} + +void FltkViewBase::drawArc (core::style::Color *color, + core::style::Color::Shading shading, bool filled, + int x, int y, int width, int height, + int angle1, int angle2) +{ + setcolor(((FltkColor*)color)->colors[shading]); + int x1 = translateCanvasXToViewX (x); + int y1 = translateCanvasYToViewY (y); + ::fltk::Rectangle rect (x1, y1, width, height); + addchord(rect, angle1, angle2); + closepath(); + if (filled) + fillpath(); + else + strokepath(); +} + +void FltkViewBase::drawPolygon (core::style::Color *color, + core::style::Color::Shading shading, + bool filled, int points[][2], int npoints) +{ + if (npoints > 0) { + for (int i = 0; i < npoints; i++) { + points[i][0] = translateCanvasXToViewX(points[i][0]); + points[i][1] = translateCanvasYToViewY(points[i][1]); + } + setcolor(((FltkColor*)color)->colors[shading]); + addvertices(npoints, points); + closepath(); + if (filled) + fillpath(); + else + strokepath(); + } +} + +core::View *FltkViewBase::getClippingView (int x, int y, int width, int height) +{ + push_clip (translateCanvasXToViewX (x), translateCanvasYToViewY (y), + width, height); + return this; +} + +void FltkViewBase::mergeClippingView (core::View *clippingView) +{ + pop_clip (); +} + +// ---------------------------------------------------------------------- + +FltkWidgetView::FltkWidgetView (int x, int y, int w, int h, + const char *label): + FltkViewBase (x, y, w, h, label) +{ +} + +FltkWidgetView::~FltkWidgetView () +{ +} + +void FltkWidgetView::layout () { + /** + * pass layout to child widgets. This is needed for complex fltk + * widgets as TextEditor. + * We can't use Group::layout() as that would rearrange the widgets. + */ + for (int i = children () - 1; i >= 0; i--) { + ::fltk::Widget *widget = child (i); + + if (widget->layout_damage ()) { + widget->layout (); + } + } +} + +void FltkWidgetView::drawText (core::style::Font *font, + core::style::Color *color, + core::style::Color::Shading shading, + int x, int y, const char *text, int len) +{ + FltkFont *ff = (FltkFont*)font; + setfont(ff->font, ff->size); + setcolor(((FltkColor*)color)->colors[shading]); + drawtext(text, len, + translateCanvasXToViewX (x), translateCanvasYToViewY (y)); +} + +void FltkWidgetView::drawImage (core::Imgbuf *imgbuf, int xRoot, int yRoot, + int x, int y, int width, int height) +{ + ((FltkImgbuf*)imgbuf)->draw (this, + translateCanvasXToViewX (xRoot), + translateCanvasYToViewY (yRoot), + x, y, width, height); +} + +bool FltkWidgetView::usesFltkWidgets () +{ + return true; +} + +void FltkWidgetView::addFltkWidget (::fltk::Widget *widget, + core::Allocation *allocation) +{ + allocateFltkWidget (widget, allocation); + add (widget); +} + +void FltkWidgetView::removeFltkWidget (::fltk::Widget *widget) +{ + remove (widget); +} + +void FltkWidgetView::allocateFltkWidget (::fltk::Widget *widget, + core::Allocation *allocation) +{ + widget->x (translateCanvasXToViewX (allocation->x)); + widget->y (translateCanvasYToViewY (allocation->y)); + widget->w (allocation->width); + widget->h (allocation->ascent + allocation->descent); + + /* widgets created tiny and later resized need this flag to display */ + uchar damage = widget->layout_damage (); + damage |= LAYOUT_XYWH; + widget->layout_damage (damage); +} + +void FltkWidgetView::drawFltkWidget (::fltk::Widget *widget, + core::Rectangle *area) +{ + draw_child (*widget); +} + +} // namespace fltk +} // namespace dw
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkviewbase.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,108 @@ +#ifndef __DW_FLTKVIEWBASE_HH__ +#define __DW_FLTKVIEWBASE_HH__ + +#include <time.h> // for time_t +#include <sys/time.h> // for time_t in FreeBSD + +#include <fltk/Group.h> +#include <fltk/Image.h> +#include <fltk/Scrollbar.h> + +#include "fltkcore.hh" + +namespace dw { +namespace fltk { + +class FltkViewBase: public FltkView, public ::fltk::Group +{ +private: + int bgColor; + core::Region drawRegion; + static ::fltk::Image *backBuffer; + static bool backBufferInUse; + + void drawRectangle (const core::Rectangle *rect, bool doubleBuffer); + void drawChildWidgets (); + +public: + time_t lastDraw; + time_t drawDelay; + +protected: + core::Layout *theLayout; + int canvasWidth, canvasHeight; + int mouse_x, mouse_y; + + virtual int translateViewXToCanvasX (int x) = 0; + virtual int translateViewYToCanvasY (int y) = 0; + virtual int translateCanvasXToViewX (int x) = 0; + virtual int translateCanvasYToViewY (int y) = 0; + +public: + FltkViewBase (int x, int y, int w, int h, const char *label = 0); + ~FltkViewBase (); + + void draw(); + int handle (int event); + + void setLayout (core::Layout *layout); + void setCanvasSize (int width, int ascent, int descent); + void setCursor (core::style::Cursor cursor); + void setBgColor (core::style::Color *color); + + void startDrawing (core::Rectangle *area); + void finishDrawing (core::Rectangle *area); + void queueDraw (core::Rectangle *area); + void queueDrawTotal (); + void drawTotal (); + void cancelQueueDraw (); + void drawPoint (core::style::Color *color, + core::style::Color::Shading shading, + int x, int y); + void drawLine (core::style::Color *color, + core::style::Color::Shading shading, + int x1, int y1, int x2, int y2); + void drawRectangle (core::style::Color *color, + core::style::Color::Shading shading, bool filled, + int x, int y, int width, int height); + void drawArc (core::style::Color *color, + core::style::Color::Shading shading, bool filled, + int x, int y, int width, int height, + int angle1, int angle2); + void drawPolygon (core::style::Color *color, + core::style::Color::Shading shading, + bool filled, int points[][2], int npoints); + + core::View *getClippingView (int x, int y, int width, int height); + void mergeClippingView (core::View *clippingView); +}; + + +class FltkWidgetView: public FltkViewBase +{ +public: + FltkWidgetView (int x, int y, int w, int h, const char *label = 0); + ~FltkWidgetView (); + + void layout(); + + void drawText (core::style::Font *font, + core::style::Color *color, + core::style::Color::Shading shading, + int x, int y, const char *text, int len); + void drawImage (core::Imgbuf *imgbuf, int xRoot, int yRoot, + int x, int y, int width, int height); + + bool usesFltkWidgets (); + void addFltkWidget (::fltk::Widget *widget, core::Allocation *allocation); + void removeFltkWidget (::fltk::Widget *widget); + void allocateFltkWidget (::fltk::Widget *widget, + core::Allocation *allocation); + void drawFltkWidget (::fltk::Widget *widget, core::Rectangle *area); +}; + +} // namespace fltk +} // namespace dw + +#endif // __DW_FLTKVIEWBASE_HH__ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkviewport.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,496 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "fltkviewport.hh" + +#include <fltk/draw.h> +#include <fltk/damage.h> +#include <fltk/events.h> + +#include <stdio.h> + +using namespace fltk; +using namespace lout::object; +using namespace lout::container::typed; + +namespace dw { +namespace fltk { + +FltkViewport::FltkViewport (int x, int y, int w, int h, const char *label): + FltkWidgetView (x, y, w, h, label) +{ + hscrollbar = new Scrollbar (0, 0, 1, 1); + hscrollbar->set_horizontal(); + hscrollbar->callback (hscrollbarCallback, this); + add (hscrollbar); + + vscrollbar = new Scrollbar (0, 0, 1, 1); + vscrollbar->set_vertical(); + vscrollbar->callback (vscrollbarCallback, this); + add (vscrollbar); + + scrollX = scrollY = scrollDX = scrollDY = 0; + dragScrolling = 0; + + gadgetOrientation[0] = GADGET_HORIZONTAL; + gadgetOrientation[1] = GADGET_HORIZONTAL; + gadgetOrientation[2] = GADGET_VERTICAL; + gadgetOrientation[3] = GADGET_HORIZONTAL; + + gadgets = + new container::typed::List <object::TypedPointer < ::fltk::Widget> > + (true); +} + +FltkViewport::~FltkViewport () +{ + delete gadgets; +} + +void FltkViewport::adjustScrollbarsAndGadgetsAllocation () +{ + int hdiff = 0, vdiff = 0; + int visibility = 0; + + if (hscrollbar->visible ()) + visibility |= 1; + if (vscrollbar->visible ()) + visibility |= 2; + + if (gadgets->size () > 0) { + switch (gadgetOrientation [visibility]) { + case GADGET_VERTICAL: + hdiff = SCROLLBAR_THICKNESS; + vdiff = SCROLLBAR_THICKNESS * gadgets->size (); + break; + + case GADGET_HORIZONTAL: + hdiff = SCROLLBAR_THICKNESS * gadgets->size (); + vdiff = SCROLLBAR_THICKNESS; + break; + } + } else { + hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + } + + hscrollbar->x (0); + hscrollbar->y (0 + h () - SCROLLBAR_THICKNESS); + hscrollbar->w (w () - hdiff); + hscrollbar->h (SCROLLBAR_THICKNESS); + + vscrollbar->x (0 + w () - SCROLLBAR_THICKNESS); + vscrollbar->y (0); + vscrollbar->h (h () - vdiff); + vscrollbar->w (SCROLLBAR_THICKNESS); + + int x = w () - SCROLLBAR_THICKNESS, y = h () - SCROLLBAR_THICKNESS; + for(Iterator <TypedPointer < ::fltk::Widget> > it = gadgets->iterator (); + it.hasNext (); ) { + ::fltk::Widget *widget = it.getNext()->getTypedValue (); + widget->x (0); + widget->y (0); + widget->w (SCROLLBAR_THICKNESS); + widget->h (SCROLLBAR_THICKNESS); + + switch (gadgetOrientation [visibility]) { + case GADGET_VERTICAL: + y -= SCROLLBAR_THICKNESS; + break; + + case GADGET_HORIZONTAL: + x -= SCROLLBAR_THICKNESS; + break; + } + } +} + +void FltkViewport::adjustScrollbarValues () +{ + hscrollbar->value (scrollX, hscrollbar->w (), 0, canvasWidth); + vscrollbar->value (scrollY, vscrollbar->h (), 0, canvasHeight); +} + +void FltkViewport::hscrollbarChanged () +{ + scroll (hscrollbar->value () - scrollX, 0); +} + +void FltkViewport::vscrollbarChanged () +{ + scroll (0, vscrollbar->value () - scrollY); +} + +void FltkViewport::vscrollbarCallback (Widget *vscrollbar, void *viewportPtr) +{ + ((FltkViewport*)viewportPtr)->vscrollbarChanged (); +} + +void FltkViewport::hscrollbarCallback (Widget *hscrollbar, void *viewportPtr) +{ + ((FltkViewport*)viewportPtr)->hscrollbarChanged (); +} + +// ---------------------------------------------------------------------- + +void FltkViewport::layout () +{ + theLayout->viewportSizeChanged (this, w(), h()); + adjustScrollbarsAndGadgetsAllocation (); + + FltkWidgetView::layout (); +} + +void FltkViewport::draw_area (void *data, const Rectangle& cr ) +{ + FltkViewport *vp = (FltkViewport*) data; + push_clip(cr); + + vp->FltkWidgetView::draw (); + + for(Iterator <TypedPointer < ::fltk::Widget> > it = vp->gadgets->iterator (); + it.hasNext (); ) { + ::fltk::Widget *widget = it.getNext()->getTypedValue (); + vp->draw_child (*widget); + } + + pop_clip(); + +} + +void FltkViewport::draw () +{ + int hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + int vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + Rectangle cr (0, 0, w () - hdiff, h () - vdiff); + int d = damage(); + + if (d & DAMAGE_SCROLL) { + set_damage (DAMAGE_SCROLL); + scrollrect(cr, -scrollDX, -scrollDY, draw_area, this); + d &= ~DAMAGE_SCROLL; + set_damage (d); + } + + if (d) { + draw_area(this, cr); + + if (d == DAMAGE_CHILD) { + if (hscrollbar->damage ()) + draw_child (*hscrollbar); + if (vscrollbar->damage ()) + draw_child (*vscrollbar); + } else { + draw_child (*hscrollbar); + draw_child (*vscrollbar); + } + } + + scrollDX = 0; + scrollDY = 0; +} + +int FltkViewport::handle (int event) +{ + //printf("FltkViewport::handle %d\n", event); + + if (hscrollbar->Rectangle::contains (event_x (), event_y ()) && + !(event_state() & (SHIFT | CTRL | ALT)) && + hscrollbar->send (event)) { + return 1; + } + + if (vscrollbar->Rectangle::contains (event_x (), event_y ()) && + vscrollbar->send (event)) { + return 1; + } + + switch(event) { + case ::fltk::FOCUS: + /** \bug Draw focus box. */ + return 1; + + case ::fltk::UNFOCUS: + /** \bug Undraw focus box. */ + return 1; + + case ::fltk::PUSH: + take_focus(); + if (::fltk::event_button() == ::fltk::MiddleButton) { + /* pass event so that middle click can open link in new window */ + if (FltkWidgetView::handle (event) == 0) { + dragScrolling = 1; + dragX = ::fltk::event_x(); + dragY = ::fltk::event_y(); + setCursor (core::style::CURSOR_MOVE); + } + return 1; + } + break; + + case ::fltk::DRAG: + if (::fltk::event_button() == ::fltk::MiddleButton) { + if (dragScrolling) { + scroll(dragX - ::fltk::event_x(), dragY - ::fltk::event_y()); + dragX = ::fltk::event_x(); + dragY = ::fltk::event_y(); + return 1; + } + } + break; + + case ::fltk:: MOUSEWHEEL: + return (event_dx() ? hscrollbar : vscrollbar)->handle(event); + break; + + case ::fltk::RELEASE: + if (::fltk::event_button() == ::fltk::MiddleButton) { + dragScrolling = 0; + setCursor (core::style::CURSOR_DEFAULT); + } + break; + + case ::fltk::ENTER: + /* could be the result of, e.g., closing another window. */ + mouse_x = ::fltk::event_x(); + mouse_y = ::fltk::event_y(); + positionChanged(); + break; + + case ::fltk::LEAVE: + mouse_x = mouse_y = -1; + break; + + case ::fltk::KEY: + /* tell fltk we want to receive these KEY events as SHORTCUT */ + switch (::fltk::event_key()) { + case PageUpKey: + case PageDownKey: + case SpaceKey: + case DownKey: + case UpKey: + case RightKey: + case LeftKey: + case HomeKey: + case EndKey: + return 0; + } + break; + + case ::fltk::SHORTCUT: + switch (::fltk::event_key()) { + case PageUpKey: + case 'b': + case 'B': + scroll (0, -vscrollbar->pagesize ()); + return 1; + + case PageDownKey: + case SpaceKey: + scroll (0, vscrollbar->pagesize ()); + return 1; + + case DownKey: + scroll (0, (int) vscrollbar->linesize ()); + return 1; + + case UpKey: + scroll (0, (int) -vscrollbar->linesize ()); + return 1; + + case RightKey: + scroll ((int) hscrollbar->linesize (), 0); + return 1; + + case LeftKey: + scroll ((int) -hscrollbar->linesize (), 0); + return 1; + + case HomeKey: + scrollTo (scrollX, 0); + return 1; + + case EndKey: + scrollTo (scrollX, canvasHeight); /* gets adjusted in scrollTo () */ + return 1; + } + } + + return FltkWidgetView::handle (event); +} + +// ---------------------------------------------------------------------- + +void FltkViewport::setCanvasSize (int width, int ascent, int descent) +{ + FltkWidgetView::setCanvasSize (width, ascent, descent); + adjustScrollbarValues (); +} + +/* + * This is used to simulate mouse motion (e.g., when scrolling). + */ +void FltkViewport::positionChanged () +{ + if (mouse_x != -1) + (void)theLayout->motionNotify (this, + translateViewXToCanvasX (mouse_x), + translateViewYToCanvasY (mouse_y), + (core::ButtonState)0); +} + +/* + * For scrollbars, this currently sets the same step to both vertical and + * horizontal. It may me differentiated if necessary. + */ +void FltkViewport::setScrollStep(int step) +{ + vscrollbar->linesize(step); + hscrollbar->linesize(step); +} + +bool FltkViewport::usesViewport () +{ + return true; +} + +int FltkViewport::getHScrollbarThickness () +{ + return SCROLLBAR_THICKNESS; +} + +int FltkViewport::getVScrollbarThickness () +{ + return SCROLLBAR_THICKNESS; +} + +void FltkViewport::scrollTo (int x, int y) +{ + int hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + int vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + + x = misc::min (x, canvasWidth - w() + hdiff); + x = misc::max (x, 0); + + y = misc::min (y, canvasHeight - h() + vdiff); + y = misc::max (y, 0); + + if (x == scrollX && y == scrollY) { + return; + } + + /* multiple calls to scroll can happen before a redraw occurs. + * scrollDX / scrollDY can therefore be non-zero here. + */ + updateCanvasWidgets (x - scrollX, y - scrollY); + scrollDX += x - scrollX; + scrollDY += y - scrollY; + + scrollX = x; + scrollY = y; + + adjustScrollbarValues (); + redraw (DAMAGE_SCROLL); + theLayout->scrollPosChanged (this, scrollX, scrollY); + positionChanged(); +} + +void FltkViewport::scroll (int dx, int dy) +{ + scrollTo (scrollX + dx, scrollY + dy); +} + +void FltkViewport::setViewportSize (int width, int height, + int hScrollbarThickness, + int vScrollbarThickness) +{ + if (hScrollbarThickness > 0) + hscrollbar->show (); + else + hscrollbar->hide (); + if (vScrollbarThickness > 0) + vscrollbar->show (); + else + vscrollbar->hide (); + + /* If no scrollbar, go to the beginning */ + scroll(hScrollbarThickness ? 0 : -scrollX, + vScrollbarThickness ? 0 : -scrollY); +} + +void FltkViewport::updateCanvasWidgets (int dx, int dy) +{ + // scroll all child widgets except scroll bars + for (int i = children () - 1; i > 0; i--) { + ::fltk::Widget *widget = child (i); + + if (widget == hscrollbar || widget == vscrollbar) + continue; + + widget->x (widget->x () - dx); + widget->y (widget->y () - dy); + } +} + +int FltkViewport::translateViewXToCanvasX (int x) +{ + return x + scrollX; +} + +int FltkViewport::translateViewYToCanvasY (int y) +{ + return y + scrollY; +} + +int FltkViewport::translateCanvasXToViewX (int x) +{ + return x - scrollX; +} + +int FltkViewport::translateCanvasYToViewY (int y) +{ + return y - scrollY; +} + +// ---------------------------------------------------------------------- + +void FltkViewport::setGadgetOrientation (bool hscrollbarVisible, + bool vscrollbarVisible, + FltkViewport::GadgetOrientation + gadgetOrientation) +{ + this->gadgetOrientation[(hscrollbarVisible ? 0 : 1) | + (vscrollbarVisible ? 0 : 2)] = gadgetOrientation; + adjustScrollbarsAndGadgetsAllocation (); +} + +void FltkViewport::addGadget (::fltk::Widget *gadget) +{ + /** \bug Reparent? */ + + gadgets->append (new TypedPointer < ::fltk::Widget> (gadget)); + adjustScrollbarsAndGadgetsAllocation (); +} + + +} // namespace fltk +} // namespace dw
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/fltkviewport.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,77 @@ +#ifndef __DW_FLTKVIEWPORT_HH__ +#define __DW_FLTKVIEWPORT_HH__ + +#include <fltk/Group.h> +#include <fltk/Scrollbar.h> + +#include "core.hh" +#include "fltkcore.hh" +#include "fltkviewbase.hh" + +namespace dw { +namespace fltk { + +class FltkViewport: public FltkWidgetView +{ +public: + enum GadgetOrientation { GADGET_VERTICAL, GADGET_HORIZONTAL }; + +private: + enum { SCROLLBAR_THICKNESS = 15 }; + + int scrollX, scrollY; + int scrollDX, scrollDY; + int dragScrolling, dragX, dragY; + + ::fltk::Scrollbar *vscrollbar, *hscrollbar; + + GadgetOrientation gadgetOrientation[4]; + container::typed::List <object::TypedPointer < ::fltk::Widget> > *gadgets; + + void adjustScrollbarsAndGadgetsAllocation (); + void adjustScrollbarValues (); + void hscrollbarChanged (); + void vscrollbarChanged (); + void positionChanged (); + + static void hscrollbarCallback (Widget *hscrollbar, void *viewportPtr); + static void vscrollbarCallback (Widget *vscrollbar, void *viewportPtr); + + void updateCanvasWidgets (int oldScrollX, int oldScrollY); + static void draw_area (void *data, const Rectangle& cr); + +protected: + int translateViewXToCanvasX (int x); + int translateViewYToCanvasY (int y); + int translateCanvasXToViewX (int x); + int translateCanvasYToViewY (int y); + +public: + FltkViewport (int x, int y, int w, int h, const char *label = 0); + ~FltkViewport (); + + void layout(); + void draw (); + int handle (int event); + + void setCanvasSize (int width, int ascent, int descent); + + bool usesViewport (); + int getHScrollbarThickness (); + int getVScrollbarThickness (); + void scroll(int dx, int dy); + void scrollTo (int x, int y); + void setViewportSize (int width, int height, + int hScrollbarThickness, int vScrollbarThickness); + void setScrollStep(int step); + + void setGadgetOrientation (bool hscrollbarVisible, bool vscrollbarVisible, + GadgetOrientation gadgetOrientation); + void addGadget (::fltk::Widget *gadget); +}; + +} // namespace fltk +} // namespace dw + +#endif // __DW_FLTKVIEWPORT_HH__ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/image.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,392 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "image.hh" +#include "../lout/misc.hh" + +namespace dw { + +using namespace lout; + +ImageMapsList::ImageMap::ImageMap () +{ + shapesAndLinks = new container::typed::List <ShapeAndLink> (true); + defaultLink = -1; +} + +ImageMapsList::ImageMap::~ImageMap () +{ + delete shapesAndLinks; +} + +void ImageMapsList::ImageMap::add (core::Shape *shape, int link) { + ShapeAndLink *shapeAndLink = new ShapeAndLink (); + shapeAndLink->shape = shape; + shapeAndLink->link = link; + shapesAndLinks->append (shapeAndLink); +} + +int ImageMapsList::ImageMap::link (int x, int y) { + container::typed::Iterator <ShapeAndLink> it; + int link = defaultLink; + + for (it = shapesAndLinks->iterator (); it.hasNext (); ) { + ShapeAndLink *shapeAndLink = it.getNext (); + + if (shapeAndLink->shape->isPointWithin (x, y)) { + link = shapeAndLink->link; + break; + } + } + + return link; +} + +ImageMapsList::ImageMapsList () +{ + imageMaps = new container::typed::HashTable <object::Object, ImageMap> + (true, true); + currentMap = NULL; +} + +ImageMapsList::~ImageMapsList () +{ + delete imageMaps; +} + +/** + * \brief Start a new map and make it the current one. + * + * This has to be called before dw::ImageMapsList::addShapeToCurrentMap. + * "key" is owned by the image map list, so a copy should be passed, when + * necessary. + */ +void ImageMapsList::startNewMap (object::Object *key) +{ + currentMap = new ImageMap (); + imageMaps->put (key, currentMap); +} + +/** + * \brief Add a shape to the current map- + * + * "shape" is owned by the image map list, so a copy should be passed, when + * necessary. + */ +void ImageMapsList::addShapeToCurrentMap (core::Shape *shape, int link) +{ + currentMap->add (shape, link); +} + +/** + * \brief Set default link for current map- + */ +void ImageMapsList::setCurrentMapDefaultLink (int link) +{ + currentMap->setDefaultLink (link); +} + +int ImageMapsList::link (object::Object *key, int x, int y) +{ + int link = -1; + ImageMap *map = imageMaps->get (key); + + if (map) + link = map->link (x, y); + + return link; +} + +// ---------------------------------------------------------------------- + +int Image::CLASS_ID = -1; + +Image::Image(const char *altText) +{ + registerName ("dw::Image", &CLASS_ID); + this->altText = altText ? strdup (altText) : NULL; + altTextWidth = -1; // not yet calculated + buffer = NULL; + clicking = false; + currLink = -1; + mapList = NULL; + mapKey = NULL; + isMap = false; +} + +Image::~Image() +{ + if (altText) + delete altText; + if (buffer) + buffer->unref (); +} + +void Image::sizeRequestImpl (core::Requisition *requisition) +{ + if (buffer) { + requisition->width = buffer->getRootWidth (); + requisition->ascent = buffer->getRootHeight (); + requisition->descent = 0; + } else { + if(altText && altText[0]) { + if (altTextWidth == -1) + altTextWidth = + layout->textWidth (getStyle()->font, altText, strlen (altText)); + + requisition->width = altTextWidth; + requisition->ascent = getStyle()->font->ascent; + requisition->descent = getStyle()->font->descent; + } else { + requisition->width = 0; + requisition->ascent = 0; + requisition->descent = 0; + } + } + + requisition->width += getStyle()->boxDiffWidth (); + requisition->ascent += getStyle()->boxOffsetY (); + requisition->descent += getStyle()->boxRestHeight (); +} + +void Image::sizeAllocateImpl (core::Allocation *allocation) +{ + core::Imgbuf *oldBuffer; + int dx, dy; + + /* if image is moved only */ + if (allocation->width == this->allocation.width && + allocation->ascent + allocation->descent == getHeight ()) + return; + + dx = getStyle()->boxDiffWidth (); + dy = getStyle()->boxDiffHeight (); +#if 0 + printf("boxDiffHeight = %d + %d, buffer=%p\n", + getStyle()->boxOffsetY(), getStyle()->boxRestHeight(), buffer); + printf("getContentWidth() = allocation.width - style->boxDiffWidth ()" + " = %d - %d = %d\n", + this->allocation.width, getStyle()->boxDiffWidth(), + this->allocation.width - getStyle()->boxDiffWidth()); + printf("getContentHeight() = getHeight() - style->boxDiffHeight ()" + " = %d - %d = %d\n", this->getHeight(), getStyle()->boxDiffHeight(), + this->getHeight() - getStyle()->boxDiffHeight()); +#endif + if (buffer != NULL && + /* It may be, that the image is allocated at zero content size. In this + * case, we simply wait. */ + getContentWidth () > 0 && getContentHeight () > 0) { + oldBuffer = buffer; + buffer = oldBuffer->getScaledBuf (allocation->width - dx, + allocation->ascent + + allocation->descent - dy); + oldBuffer->unref (); + } +} + +void Image::enterNotifyImpl (core::EventCrossing *event) +{ + // BUG: this is wrong for image maps, but the cursor position is unknown. + currLink = getStyle()->x_link; + + if (currLink != -1) { + (void) emitLinkEnter (currLink, -1, -1, -1); + } +} + +void Image::leaveNotifyImpl (core::EventCrossing *event) +{ + clicking = false; + + if (currLink != -1) { + currLink = -1; + (void) emitLinkEnter (-1, -1, -1, -1); + } +} + +bool Image::motionNotifyImpl (core::EventMotion *event) +{ + if (mapList) { + /* client-side image map */ + int newLink = mapList->link (mapKey, event->xWidget, event->yWidget); + if (newLink != currLink) { + currLink = newLink; + clicking = false; + setCursor(newLink == -1 ? core::style::CURSOR_DEFAULT : + core::style::CURSOR_POINTER); + (void) emitLinkEnter (newLink, -1, -1, -1); + } + } else if (isMap && currLink != -1) { + /* server-side image map */ + (void) emitLinkEnter (currLink, -1, event->xWidget, event->yWidget); + } + return true; +} + +bool Image::buttonPressImpl (core::EventButton *event) +{ + bool ret = false; + currLink = mapList ? mapList->link (mapKey, event->xWidget, event->yWidget): + getStyle()->x_link; + if (event->button == 3){ + (void)emitLinkPress(currLink, getStyle()->x_img, -1,-1,event); + ret = true; + } else if (event->button == 1 || currLink != -1){ + clicking = true; + ret = true; + } + return ret; +} + +bool Image::buttonReleaseImpl (core::EventButton *event) +{ + currLink = mapList ? mapList->link (mapKey, event->xWidget, event->yWidget): + getStyle()->x_link; + if (clicking) { + int x = isMap ? event->xWidget : -1; + int y = isMap ? event->yWidget : -1; + clicking = false; + emitLinkClick (currLink, getStyle()->x_img, x, y, event); + return true; + } + return false; +} + +void Image::draw (core::View *view, core::Rectangle *area) +{ + int dx, dy; + core::Rectangle content, intersection; + + drawWidgetBox (view, area, false); + + if (buffer) { + dx = getStyle()->boxOffsetX (); + dy = getStyle()->boxOffsetY (); + content.x = dx; + content.y = dy; + content.width = getContentWidth (); + content.height = getContentHeight (); + + if (area->intersectsWith (&content, &intersection)) + view->drawImage (buffer, + allocation.x + dx, allocation.y + dy, + intersection.x - dx, intersection.y - dy, + intersection.width, intersection.height); + } else { + if(altText && altText[0]) { + if (altTextWidth == -1) + altTextWidth = + layout->textWidth (getStyle()->font, altText, strlen (altText)); + + core::View *clippingView = NULL, *usedView = view; + if (allocation.width < altTextWidth || + allocation.ascent < getStyle()->font->ascent || + allocation.descent < getStyle()->font->descent) { + clippingView = usedView = + view->getClippingView (allocation.x + getStyle()->boxOffsetX (), + allocation.y + getStyle()->boxOffsetY (), + allocation.width + - getStyle()->boxDiffWidth (), + allocation.ascent + allocation.descent + - getStyle()->boxDiffHeight ()); + } + + usedView->drawText (getStyle()->font, getStyle()->color, + core::style::Color::SHADING_NORMAL, + allocation.x + getStyle()->boxOffsetX (), + allocation.y + getStyle()->boxOffsetY () + + getStyle()->font->ascent, + altText, strlen(altText)); + + if(clippingView) + view->mergeClippingView (clippingView); + } + } + + /** todo: draw selection */ +} + +core::Iterator *Image::iterator (core::Content::Type mask, bool atEnd) +{ + //return new core::TextIterator (this, mask, atEnd, altText); + /** \bug Not implemented. */ + return new core::EmptyIterator (this, mask, atEnd); +} + +void Image::setBuffer (core::Imgbuf *buffer, bool resize) +{ + core::Imgbuf *oldBuf = this->buffer; + + if (resize) + queueResize (0, true); + + // If the image has not yet been allocated, or is allocated at zero + // content size, the first part is useless. + if (wasAllocated () && getContentWidth () > 0 && getContentHeight () > 0) { + this->buffer = + buffer->getScaledBuf (getContentWidth (), getContentHeight ()); + } else { + this->buffer = buffer; + buffer->ref (); + } + + if (oldBuf) + oldBuf->unref (); +} + +void Image::drawRow (int row) +{ + core::Rectangle area; + + assert (buffer != NULL); + + buffer->getRowArea (row, &area); + if (area.width && area.height) + queueDrawArea (area.x + getStyle()->boxOffsetX (), + area.y + getStyle()->boxOffsetY (), + area.width, area.height); +} + + +/** + * \brief Sets image as server side image map. + */ +void Image::setIsMap () +{ + isMap = true; +} + + +/** + * \brief Sets image as client side image map. + * + * "list" is not owned by the image, the caller has to free it. "key" + * is owned by the image, if it is used by the caller afterwards, a copy + * should be passed. + */ +void Image::setUseMap (ImageMapsList *list, object::Object *key) +{ + mapList = list; + mapKey = key; +} + +} // namespace dw
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/image.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,161 @@ +#ifndef __DW_IMAGE_HH__ +#define __DW_IMAGE_HH__ + +#include "core.hh" + +namespace dw { + +/** + * \brief Represents a list of client-side image maps. + * + * All image maps of a HTML page (in the future, also image maps from + * different HTML pages) are stored in a list, which is passed to the + * image, so that it is possible to deal with maps, which are defined + * after the image within the HTML page. + * + * Maps are referred by instances of object::Object. These keys are + * typically URLs, so the type representing URLS should be derived from + * object::Object. + * + * \todo Some methods within the key class have to be implemented, this + * is not clear at this time. + */ +class ImageMapsList +{ +private: + class ImageMap: public lout::object::Object { + private: + class ShapeAndLink: public lout::object::Object { + public: + core::Shape *shape; + int link; + + ~ShapeAndLink () { if (shape) delete shape; }; + }; + + lout::container::typed::List <ShapeAndLink> *shapesAndLinks; + int defaultLink; + public: + ImageMap (); + ~ImageMap (); + + void add (core::Shape *shape, int link); + void setDefaultLink (int link) { defaultLink = link; }; + int link (int x, int y); + }; + + lout::container::typed::HashTable <lout::object::Object, ImageMap> + *imageMaps; + ImageMap *currentMap; + +public: + ImageMapsList (); + ~ImageMapsList (); + + void startNewMap (lout::object::Object *key); + void addShapeToCurrentMap (core::Shape *shape, int link); + void setCurrentMapDefaultLink (int link); + int link (lout::object::Object *key, int x, int y); +}; + +/** + * \brief Displays an instance of dw::core::Imgbuf. + * + * The dw::core::Imgbuf is automatically scaled, when needed, but dw::Image + * does not keep a reference on the root buffer. + * + * + * <h3>Signals</h3> + * + * For image maps, dw::Image uses the signals defined in + * dw::core::Widget::LinkReceiver. For client side image maps, -1 is + * passed for the coordinates, for server side image maps, the respective + * coordinates are used. See section "Image Maps" below. + * + * + * <h3>%Image Maps</h3> + * + * <h4>Client Side %Image Maps</h4> + * + * You must first create a list of image maps (dw::ImageMapList), which can + * be used for multiple images. The caller is responsible for freeing the + * dw::ImageMapList. + * + * Adding a map is done by dw::ImageMapsList::startNewMap. The key is an + * instance of a sub class of object::Object. In the context of HTML, this is + * a URL, which defines this map globally, by combining the URL of the + * document, this map is defined in, with the value of the attribute "name" of + * the \<MAP\> element, as a fragment. + * + * dw::ImageMapsList::addShapeToCurrentMap adds a shape to the current + * map. The \em link argument is a number, which is later passed to + * the dw::core::Widget::LinkReceiver. + * + * This map list is then, together with the key for the image, passed to + * dw::Image::setUseMap. For HTML, a URL with the value of the "ismap" + * attribute of \<IMG\> should be used. + * + * dw::Image will search the correct map, when needed. If it is not found + * at this time, but later defined, it will be found and used later. This is + * the case, when an HTML \<MAP\> is defined below the \<IMG\> in the + * document. + * + * Currently, only maps defined in the same document as the image may be + * used, since the dw::ImageMapsList is stored in the HTML link block, and + * contains only the image maps defined in the document. + * + * <h4>Server Side %Image Maps</h4> + * + * To use images for server side image maps, you must call + * dw::Image::setIsMap, and the dw::Image::style must contain a valid link + * (dw::core::style::Style::x_link). After this, motions and clicks are + * delegated to dw::core::Widget::LinkReceiver. + * + * \sa\ref dw-images-and-backgrounds + */ +class Image: public core::Widget +{ +private: + char *altText; + core::Imgbuf *buffer; + int altTextWidth; + bool clicking; + int currLink; + ImageMapsList *mapList; + Object *mapKey; + bool isMap; + +protected: + void sizeRequestImpl (core::Requisition *requisition); + void sizeAllocateImpl (core::Allocation *allocation); + + void draw (core::View *view, core::Rectangle *area); + + bool buttonPressImpl (core::EventButton *event); + bool buttonReleaseImpl (core::EventButton *event); + void enterNotifyImpl (core::EventCrossing *event); + void leaveNotifyImpl (core::EventCrossing *event); + bool motionNotifyImpl (core::EventMotion *event); + + //core::Iterator *iterator (Content::Type mask, bool atEnd); + +public: + static int CLASS_ID; + + Image(const char *altText); + ~Image(); + + core::Iterator *iterator (core::Content::Type mask, bool atEnd); + + inline core::Imgbuf *getBuffer () { return buffer; } + void setBuffer (core::Imgbuf *buffer, bool resize = false); + + void drawRow (int row); + + void setIsMap (); + void setUseMap (ImageMapsList *list, Object *key); +}; + +} // namespace dw + +#endif // __DW_IMAGE_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/imgbuf.hh Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,210 @@ +#ifndef __DW_IMGBUF_HH__ +#define __DW_IMGBUF_HH__ + +#ifndef __INCLUDED_FROM_DW_CORE_HH__ +# error Do not include this file directly, use "core.hh" instead. +#endif + +namespace dw { +namespace core { + +using namespace lout; + +/** + * \brief The platform independant interface for image buffers. + * + * %Image buffers depend on the platform (see \ref dw-images-and-backgrounds), + * but have this general, platform independant interface. The purpose of + * an image buffer is + * + * <ol> + * <li> storing the image data, + * <li> handling scaled versions of this buffer, and + * <li> drawing. + * </ol> + * + * The latter must be done independently from the window. + * + * <h3>Creating</h3> + * + * %Image buffers are created by calling dw::core::Platform::createImgbuf. + * + * <h3>Storing %Image Data</h3> + * + * dw::core::Imgbuf supports five image types, which are listed in the table + * below. The representation defines, how the colors are stored within + * the data, which is passed to dw::core::Imgbuf::copyRow. + * + * <table> + * <tr><th>Type (dw::core::Imgbuf::Type) <th>Bytes per + * Pixel <th>Representation + * <tr><td>dw::core::Imgbuf::RGB <td>3 <td>red, green, blue + * <tr><td>dw::core::Imgbuf::RGBA <td>4 <td>red, green, blue, alpha + * <tr><td>dw::core::Imgbuf::GRAY <td>1 <td>gray value + * <tr><td>dw::core::Imgbuf::INDEXED <td>1 <td>index to colormap + * <tr><td>dw::core::Imgbuf::INDEXED_ALPHA <td>1 <td>index to colormap + * </table> + * + * The last two types need a colormap, which is set by + * dw::core::Imgbuf::setCMap, which must be called before + * dw::core::Imgbuf::copyRow. This function expects the colors as 32 bit + * unsigned integers, which have the format 0xrrbbgg (for indexed + * images), or 0xaarrggbb (for indexed alpha), respectively. + * + * + * <h3>Scaling</h3> + * + * The buffer with the original size, which was created by + * dw::core::Platform::createImgbuf, is called root buffer. Imgbuf provides + * the ability to scale buffers. Generally, both root buffers, as well as + * scaled buffers, may be shared, memory management is done by reference + * counters. + * + * Via dw::core::Imgbuf::getScaledBuf, you can retrieve a scaled buffer. + * Generally, something like this must work always, in an efficient way: + * + * \code + * dw::core::Imgbuf *curBuf, *oldBuf; + * int width, heigt, + * // ... + * oldBuf = curBuf; + * curBuf = oldBuf->getScaledBuf(oldBuf, width, height); + * oldBuf->unref(); + * \endcode + * + * \em oldBuf may both be a root buffer, or a scaled buffer. + * + * The root buffer keeps a list of all children, and all methods + * operating on the image data (dw::core::Imgbuf::copyRow and + * dw::core::Imgbuf::setCMap) are delegated to the scaled buffers, when + * processed, and inherited, when a new scaled buffer is created. This + * means, that they must only be performed for the root buffer. + * + * A possible implementation could be (dw::fltk::FltkImgbuf does it this way): + * + * <ul> + * <li> If the method is called with an already scaled image buffer, this is + * delegated to the root buffer. + * + * <li> If the given size is the original size, the root buffer is + * returned, with an increased reference counter. + * + * <li> Otherwise, if this buffer has already been scaled to the given + * size, return this scaled buffer, with an increased reference + * counter. + * + * <li> Otherwise, return a new scaled buffer with reference counter 1. + * </ul> + * + * Special care is to be taken, when the root buffer is not used anymore, + * i.e. after dw::core::Imgbuf::unref the reference counter is 0, but there + * are still scaled buffers. Since all methods operating on the image data + * (dw::core::Imgbuf::copyRow and dw::core::Imgbuf::setCMap) are called for + * the root buffer, the root buffer is still needed, and so must not be + * deleted at this point. This is, how dw::fltk::FltkImgbuf solves this + * problem: + * + * <ul> + * <li> dw::fltk::FltkImgbuf::unref does, for root buffers, check, not only + * whether dw::fltk::FltkImgbuf::refCount is 0, but also, whether + * there are children left. When the latter is the case, the buffer + * is not deleted. + * + * <li> There is an additional check in dw::fltk::FltkImgbuf::detachScaledBuf, + * which deals with the case, that dw::fltk::FltkImgbuf::refCount is 0, + * and the last scaled buffer is removed. + * </ul> + * + * In the following example: + * + * \code + * dw::fltk::FltkPlatform *platform = new dw::fltk::FltkPlatform (); + * dw::core::Layout *layout = new dw::core::Layout (platform); + * + * dw::core::Imgbuf *rootbuf = + * layout->createImgbuf (dw::core::Imgbuf::RGB, 100, 100); + * dw::core::Imgbuf *scaledbuf = rootbuf->getScaledBuf (50, 50); + * rootbuf->unref (); + * scaledbuf->unref (); + * \endcode + * + * the root buffer is not deleted, when dw::core::Imgbuf::unref is called, + * since a scaled buffer is left. After calling dw::core::Imgbuf::unref for + * the scaled buffer, it is deleted, and after it, the root buffer. + * + * <h3>Drawing</h3> + * + * dw::core::Imgbuf provides no methods for drawing, instead, this is + * done by the views (implementation of dw::core::View). + * + * There are two situations, when drawing is necessary: + * + * <ol> + * <li> To react on expose events, the function dw::core::View::drawImage + * should be used, with the following parameters: + * <ul> + * <li> of course, the image buffer, + * <li> where the root of the image would be displayed (as \em xRoot + * and \em yRoot), and + * <li> the region within the image, which should be displayed (\em x, + * \em y, \em width, \em height). + * </ul> + * + * <li> When a row has been copied, it has to be drawn. To determine the + * area, which has to be drawn, the dw::core::Imgbuf::getRowArea + * should be used. The result can then passed + * to dw::core::View::drawImage. + * </ol> + * + * \sa \ref dw-images-and-backgrounds + */ +class Imgbuf: public object::Object, public lout::signal::ObservedObject +{ +public: + enum Type { RGB, RGBA, GRAY, INDEXED, INDEXED_ALPHA }; + + /* + * Methods called from the image decoding + */ + + virtual void setCMap (int *colors, int num_colors) = 0; + virtual void copyRow (int row, const byte *data) = 0; + virtual void newScan () = 0; + + /* + * Methods called from dw::Image + */ + + virtual Imgbuf* getScaledBuf (int width, int height) = 0; + virtual void getRowArea (int row, dw::core::Rectangle *area) = 0; + virtual int getRootWidth () = 0; + virtual int getRootHeight () = 0; + + /* + * Reference counting. + */ + + virtual void ref () = 0; + virtual void unref () = 0; + + /** + * \todo Comment + */ + virtual bool lastReference () = 0; + + + /** + * \todo Comment + */ + virtual void setDeleteOnUnref (bool deleteOnUnref) = 0; + + /** + * \todo Comment + */ + virtual bool isReferred () = 0; +}; + +} // namespace dw +} // namespace core + +#endif // __DW_IMGBUF_HH__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dw/iterator.cc Wed Sep 24 18:44:40 2008 +0200 @@ -0,0 +1,797 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "core.hh" +#include <limits.h> + +namespace dw { +namespace core { + +// -------------- +// Iterator +// -------------- + +Iterator::Iterator(Widget *widget, Content::Type mask, bool atEnd) +{ + this->widget = widget; + this->mask = mask; +} + +Iterator::Iterator(Iterator &it): object::Object (), misc::Comparable () +{ + widget = it.widget; + content = it.content; +} + +Iterator::~Iterator() +{ +} + +bool Iterator::equals (Object *other) +{ + Iterator *otherIt = (Iterator*)other; + return + this == otherIt || + (getWidget() == otherIt->getWidget() && compareTo(otherIt) == 0); +} + +/** + * \brief Delete the iterator. + * + * The desctructor is hidden, implementations may use optimizations for + * the allocation. (Will soon be the case for dw::core::EmptyIteratorFactory.) + */ +void Iterator::unref () +{ + delete this; +} + +/** + * \brief Scrolls the viewport, so that the region between \em it1 and + * \em it2 is seen, according to \em hpos and \em vpos. + * + * The parameters \em start and \em end have the same meaning as in + * dw::core::Iterator::getAllocation, \em start refers + * to \em it1, while \em end rerers to \em it2. + * + * If \em it1 and \em it2 point to the same location (see code), only + * \em it1 is regarded, and both belowstart and belowend refer to it. + */ +void Iterator::scrollTo (Iterator *it1, Iterator *it2, int start, int end, + HPosition hpos, VPosition vpos) +{ + Allocation alloc1, alloc2, alloc; + int x1, x2, y1, y2; + DeepIterator *eit1, *eit2, *eit3; + int curStart, curEnd, cmp; + bool atStart; + + if (it1->equals(it2)) { + it1->getAllocation (start, end, &alloc); + it1->getWidget()->getLayout()->scrollTo (hpos, vpos, alloc.x, alloc.y, + alloc.width, + alloc.ascent + alloc.descent); + } else { + // First, determine the rectangle all iterators from it1 and it2 + // allocate, i.e. the smallest rectangle containing all allocations of + // these iterators. + eit1 = new DeepIterator (it1); + eit2 = new DeepIterator (it2); + + x1 = INT_MAX; + x2 = INT_MIN; + y1 = INT_MAX; + y2 = INT_MIN; + + for (eit3 = (DeepIterator*)eit1->clone