diff --git a/.gitignore b/.gitignore index b8aa0e2a..02c34f37 100644 --- a/.gitignore +++ b/.gitignore @@ -32,12 +32,14 @@ Makefile.in /missing /stamp-h1 /test-driver +src/.depend src/.deps/ src/.libs/ examples/.deps/ examples/.libs/ examples/calculator examples/dialog +examples/busy examples/event-log examples/string-operations examples/background-color diff --git a/ChangeLog b/ChangeLog index f0701d49..4b93c1e1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,48 @@ +2020-09-11 Markus Gans + * Fixes a problem with mouse input in Cygwin in non-blocking read mode + +2020-09-08 Markus Gans + * Speed up the reaction time of the gpm mouse + * FListView now correctly adjusts the size of the scrollbar, + when expanding and collapsing by double-clicking + +2020-08-30 Markus Gans + * Adding Windows Terminal detection + +2020-08-15 Markus Gans + * The call of the function setNonBlockingRead() resulted in + a high CPU load in idle mode. + Thanks to Pavel Stehule for reporting this problem. + +2020-08-11 Markus Gans + * New callback backend was implemented. Callback functions with any + number of arguments are now possible. + +2020-07-19 Markus Gans + * API: Some method name changes: + FObject::delOwnTimer() -> FObject::delOwnTimers() + FObject::delAllTimer() -> FObject::delAllTimers() + FWidget::delCallbacks() -> FWidget::delAllCallbacks() + +2020-07-08 Markus Gans + * New data wrapper class FData + +2020-07-06 Markus Gans + * Add a document that describes how to create user themes + +2020-06-11 Markus Gans + * New widget FBusyIndicator to indicate background activity + * Added example/busy to demonstrate the functionality of this widget + +2020-06-07 Markus Gans + * The --log-file parameter stores log output to any file. The file + can be viewed directly on another terminal with "tail -f". + +2020-06-06 Markus Gans + * Now, the terminal is not initialized before the method show() + is called. Or you force it explicitly via the FApplication object. + * Simplification of FMouse::createMouseObject() + 2020-05-30 Markus Gans * With the two new methods FApplication::setDarkTheme() and FApplication::setDefaultTheme() you can now change the theme diff --git a/Makefile.am b/Makefile.am index 0b88c7dc..3931c23a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,3 +19,7 @@ docdir = ${datadir}/doc/${PACKAGE} doc_DATA = AUTHORS COPYING COPYING.LESSER ChangeLog test: check + +uninstall-hook: + if test -d ${docdir}; then rmdir ${docdir}; fi + diff --git a/README.md b/README.md index 20edef44..a4fbc267 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ ![FINAL CUT](logo/svg/finalcut-logo.svg) # Library for creating terminal applications with text-based widgets -The FINAL CUT is a C++ class library and widget toolkit with full mouse support for creating a [text-based user interface](https://en.wikipedia.org/wiki/Text-based_user_interface). The library supports the programmer to develop an application for the text console. It allows the simultaneous handling of multiple text windows on the screen. + +The FINAL CUT is a C++ class library and widget toolkit with full [mouse](doc/mouse-control.md#title-bar-actions-on-mouse-clicks) support for creating a [text-based user interface](https://en.wikipedia.org/wiki/Text-based_user_interface). The library supports the programmer to develop an application for the text console. It allows the simultaneous handling of multiple text windows on the screen. The structure of the Qt framework was originally the inspiration for the C++ class design of FINAL CUT. It provides common controls like dialog boxes, push buttons, check boxes, radio buttons, input lines, list boxes, status bars and so on. ## Building and code analysis + | | Badge | |-------------------:|:------| | *Latest release* | [![Latest Release](https://img.shields.io/github/release/gansm/finalcut.svg)](https://github.com/gansm/finalcut/releases) | @@ -18,6 +20,7 @@ The structure of the Qt framework was originally the inspiration for the C++ cla | *CodeFactor* | [![CodeFactor](https://www.codefactor.io/repository/github/gansm/finalcut/badge)](https://www.codefactor.io/repository/github/gansm/finalcut) | ## Installation + ```bash > git clone git://github.com/gansm/finalcut.git > cd finalcut @@ -28,6 +31,7 @@ The structure of the Qt framework was originally the inspiration for the C++ cla ``` ## Supported platforms + * Linux * FreeBSD * NetBSD @@ -37,6 +41,7 @@ The structure of the Qt framework was originally the inspiration for the C++ cla * Solaris ## First steps + See the [first steps](doc/first-steps.md#first-steps-with-the-final-cut-widget-toolkit) documentation for information on how to use the library. ## Some screenshots @@ -45,46 +50,38 @@ The FFileDialog widget with incremental file name search: ![FFileDialog](doc/fileopen-dialog.png) - The FINAL CUT FProgressbar widget: ![FProgressbar](doc/progress-bar.png) - Scrollable text in the FTextView widget: ![FTextView](doc/textview.png) - The Mandelbrot set example: ![Mandelbrot set](doc/Mandelbrot.png) +## newfont -newfont -------- A [graphical text font](fonts/) for X11 and the Linux console. ![ui example in newfont mode](doc/newfont1.png) - Newfont drive symbols: ![drive symbols](doc/newfont2.png) - The calculator example in newfont mode: ![calculator](doc/calculator.png) +## Benchmark -Benchmark ---------- Here you can find a test for [measuring the character speed](doc/benchmark.md#benchmark) in the terminal. +## Virtual terminal -Virtual terminal ----------------- FINAL CUT uses a virtual terminal to print character via an update method on the screen. It provides (as an overlying layer) virtual windows for the realization of window movements. The update methods only transfer differences to the virtual terminal or physical screen.
@@ -136,9 +133,7 @@ printf(...)
                                                ▀▀▀▀▀▀▀▀▀
 
- -Class digramm -------------- +## Class digramm
               1┌──────────────┐
@@ -177,11 +172,11 @@ Class digramm
    :          1┌───────────────┐   │    ┌─────────────┐
    ┌-----------┤ FMouseControl │   ├────┤ FTimerEvent │
    :           └───────────────┘   │    └─────────────┘
-   :          1┌─────────┐         │
-   ┌-----------┤ FSystem │         │
-   :           └─────────┘         │
-   :          *┌─────────┐         │
-   :  ┌--------┤ FString │         │       ┌──────────────┐
+   :          1┌─────────┐         │       ┌──────┐   ┌─────────┐
+   ┌-----------┤ FSystem │         │       │ FLog │◄──┤ FLogger │
+   :           └─────────┘         │       └──┬───┘   └─────────┘
+   :          *┌─────────┐         │          :1
+   :  ┌--------┤ FString │         │       ┌──┴───────────┐
    :  :        └─────────┘         │  ┌────┤ FApplication │
    :  :       *┌────────┐          │  │    └──────────────┘
    :  ┌--------┤ FPoint │          │  │    ┌────────┐
@@ -201,11 +196,11 @@ Class digramm
  │ FVTerm │◄──┐         :1            │    └──────────────┘   │  └──────────────┘
  └────────┘   │    ┌────┴────┐        │    ┌───────────────┐  │  ┌───────────┐
               ├────┤ FWidget │◄───────┼────┤ FToggleButton │◄─┼──┤ FCheckBox │
-┌─────────┐   │    └─────────┘        │    └───────────────┘  │  └───────────┘
-│ FObject │◄──┘                       │    ┌──────────────┐   │  ┌─────────┐
-└─────────┘                           ├────┤ FProgressbar │   └──┤ FSwitch │
-                                      │    └──────────────┘      └─────────┘
-                                      │    ┌────────────┐
+┌─────────┐   │    └────┬────┘        │    └───────────────┘  │  └───────────┘
+│ FObject │◄──┘         :1            │    ┌──────────────┐   │  ┌─────────┐
+└─────────┘      ┌──────┴────────┐    ├────┤ FProgressbar │   └──┤ FSwitch │
+                 │ FWidgetColors │    │    └──────────────┘      └─────────┘
+                 └───────────────┘    │    ┌────────────┐
                                       ├────┤ FScrollbar │
                                       │    └────────────┘
                                       │    ┌───────────┐
@@ -233,9 +228,9 @@ Class digramm
                                   └──┬──┬───┘  └─────────┘   │  ┌─────────────┐
                                      ▲  ▲                    └──┤ FMessageBox │
                                      │  │                       └─────────────┘
-                                     │  │      ┌──────────┐
-                                     │  └──────┤ FToolTip │
-                                     │         └──────────┘
+                                     │  │      ┌──────────┐  ┌────────────────┐
+                                     │  └──────┤ FToolTip │◄─┤ FBusyIndicator │
+                                     │         └──────────┘  └────────────────┘
                                      └───────────────┐          ┌──────────┐
                                                      │      ┌───┤ FMenuBar │
                                     ┌───────────┐    └──────┤   └──────────┘
@@ -254,15 +249,14 @@ Class digramm
                                                      └────────────────┘
 
-Frequently Asked Questions --------------------------- +## Frequently Asked Questions + For general questions about FINAL CUT, likely the answer is already included in the [FAQ](doc/faq.md#frequently-asked-questions). -Please send bug reports to --------------------------- +## Please send bug reports to + https://github.com/gansm/finalcut/issues -License -------- -GNU Lesser General Public License Version 3 LGPLv3 +## License +GNU Lesser General Public License Version 3 LGPLv3 diff --git a/configure.ac b/configure.ac index 47f6e80d..00d13fd6 100644 --- a/configure.ac +++ b/configure.ac @@ -86,12 +86,12 @@ AX_CHECK_COMPILE_FLAG([[-std=c++11]],, # use GPM (General Purpose Mouse) AC_ARG_WITH([gpm], [AS_HELP_STRING([--without-gpm], [Disable GPM mouse support])], - [with_gpm=no], + [], [with_gpm=yes]) -if test "x$with_gpm" = "xyes" +if test "x$with_gpm" != "xno" then AC_CHECK_LIB([gpm], - [main], + [Gpm_Open], [AC_DEFINE([HAVE_LIBGPM], 1, [Define to 1 if GPM mouse is enabled]) LIBS="$LIBS -lgpm"]) fi @@ -99,9 +99,9 @@ fi # profiling AC_ARG_WITH([profiler], [AS_HELP_STRING([--with-profiler], [build extra google profiler binaries])], - [with_profiler=yes], + [], [with_profiler=no]) -if test "x$with_profiler" = "xyes" +if test "x$with_profiler" != "xno" then AC_CHECK_LIB([profiler], [ProfilerFlush], @@ -111,14 +111,13 @@ fi # unit test AC_ARG_WITH([unit-test], [AS_HELP_STRING([--with-unit-test], [build unit tests])], - [with_unit_test=yes], + [], [with_unit_test=no]) -if test "x$with_unit_test" = "xyes" +if test "x$with_unit_test" != "xno" then AC_MSG_NOTICE(enabled cppunit test) - AM_PATH_CPPUNIT([1.12.0], - [], - [AC_MSG_ERROR([*** CppUnit not found! ***])]) + PKG_CHECK_MODULES(CPPUNIT, + [cppunit > 1.12.0]) AM_CONDITIONAL(CPPUNIT_TEST, [test "1" = "1"]) else AM_CONDITIONAL(CPPUNIT_TEST, [test "1" = "0"]) @@ -128,9 +127,9 @@ fi # code coverage AC_ARG_WITH([gcov], [AS_HELP_STRING([--with-gcov], [build for code coverage testing])], - [with_gcov=yes], + [], [with_gcov=no]) -if test "x$with_gcov" = "xyes" +if test "x$with_gcov" != "xno" then AC_CHECK_LIB([gcov], [main], diff --git a/debian/control b/debian/control index fdc3da05..072da752 100644 --- a/debian/control +++ b/debian/control @@ -27,7 +27,7 @@ Suggests: , ncurses-term , vim-common Description: Shared library for the final cut widget toolkit - The Final Cut is a class library and widget toolkit with full mouse + FINAL CUT is a class library and widget toolkit with full mouse support for creating a text-based user interface. The library supports the programmer to develop an application for the text console. It allows the simultaneous handling of multiple windows on the screen. @@ -50,7 +50,7 @@ Depends: , libtinfo-dev , libncurses5-dev Description: Developer's library for the final cut widget toolkit - The Final Cut is a class library and widget toolkit with full mouse + FINAL CUT is a class library and widget toolkit with full mouse support for creating a text-based user interface. The library supports the programmer to develop an application for the text console. It allows the simultaneous handling of multiple windows on the screen. @@ -74,7 +74,7 @@ Depends: , libtinfo-dev , libncurses5-dev Description: Test and example programs for the final cut widget toolkit - The Final Cut is a class library and widget toolkit with full mouse + FINAL CUT is a class library and widget toolkit with full mouse support for creating a text-based user interface. The library supports the programmer to develop an application for the text console. It allows the simultaneous handling of multiple windows on the screen. diff --git a/debian/copyright b/debian/copyright index 7330989e..11eb2172 100644 --- a/debian/copyright +++ b/debian/copyright @@ -7,13 +7,13 @@ Copyright: 2017, Markus Gans License: LGPL-3 License: LGPL-3 - The Final Cut is free software: you can redistribute it and/or modify + FINAL CUT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. . - The Final Cut is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of + FINAL CUT 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 Lesser General Public License for more details. . diff --git a/doc/Makefile.am b/doc/Makefile.am index 565853d0..d8ec9405 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -5,6 +5,7 @@ docdir = ${datadir}/doc/${PACKAGE} EXTRA_DIST = \ + benchmark.md \ build_openbsd.txt \ build_solaris.txt \ calendar-draft.png \ @@ -16,9 +17,21 @@ EXTRA_DIST = \ console_ioctl-manual.sh \ faq.md \ fileopen-dialog.png \ + final-cut-application-structure.svg \ first-steps.md \ + first-steps_callback-function.cpp.png \ + first-steps_callback-lambda.cpp.png \ + first-steps_callback-method.cpp.png \ + first-steps_dialog.cpp.png \ + first-steps_emit-signal.cpp.png \ + first-steps_memory.cpp.png \ + first-steps_scrollview.cpp.png \ + first-steps_size-adjustment.cpp.png \ + first-steps_timer.cpp.png \ + first-steps_user-event.cpp.png \ framebuffer.txt \ Mandelbrot.png \ + mouse-control.md \ ncurses.supp \ newfont1.png \ newfont2.png \ @@ -31,13 +44,24 @@ EXTRA_DIST = \ terminfo-manual.sh \ textview.png \ TODO \ + user-theme.md \ + user-theme.png \ + user-theme-bee-palette.svg \ + user-theme-fc16-dark-palette.svg \ + user-theme-fc16-palette.svg \ + user-theme-fc8-palette.svg \ + user-theme-vga-palette.svg \ vga.txt \ vt100_line_drawing_graphics.png \ virtual-terminal.txt \ + widget-coordinates.svg \ + widget-geometry.svg \ + widget-lengths.svg \ xterm.txt \ xgraphics doc_DATA = \ + benchmark.md \ build_openbsd.txt \ build_solaris.txt \ calendar-draft.png \ @@ -49,9 +73,21 @@ doc_DATA = \ console_ioctl-manual.sh \ faq.md \ fileopen-dialog.png \ + final-cut-application-structure.svg \ first-steps.md \ + first-steps_callback-function.cpp.png \ + first-steps_callback-lambda.cpp.png \ + first-steps_callback-method.cpp.png \ + first-steps_dialog.cpp.png \ + first-steps_emit-signal.cpp.png \ + first-steps_memory.cpp.png \ + first-steps_scrollview.cpp.png \ + first-steps_size-adjustment.cpp.png \ + first-steps_timer.cpp.png \ + first-steps_user-event.cpp.png \ framebuffer.txt \ Mandelbrot.png \ + mouse-control.md \ ncurses.supp \ newfont1.png \ newfont2.png \ @@ -64,8 +100,19 @@ doc_DATA = \ terminfo-manual.sh \ textview.png \ TODO \ + user-theme.md \ + user-theme.png \ + user-theme-bee-palette.svg \ + user-theme-fc16-dark-palette.svg \ + user-theme-fc16-palette.svg \ + user-theme-fc8-palette.svg \ + user-theme-vga-palette.svg \ vga.txt \ vt100_line_drawing_graphics.png \ virtual-terminal.txt \ + widget-coordinates.svg \ + widget-geometry.svg \ + widget-lengths.svg \ xterm.txt \ xgraphics + diff --git a/doc/class-diagram.txt b/doc/class-diagram.txt index 56bca269..a34f10e0 100644 --- a/doc/class-diagram.txt +++ b/doc/class-diagram.txt @@ -37,11 +37,11 @@ : 1┌───────────────┐ │ ┌─────────────┐ ┌-----------┤ FMouseControl │ ├────┤ FTimerEvent │ : └───────────────┘ │ └─────────────┘ - : 1┌─────────┐ │ - ┌-----------┤ FSystem │ │ - : └─────────┘ │ - : *┌─────────┐ │ - : ┌--------┤ FString │ │ ┌──────────────┐ + : 1┌─────────┐ │ ┌──────┐ ┌─────────┐ + ┌-----------┤ FSystem │ │ │ FLog │◄──┤ FLogger │ + : └─────────┘ │ └──┬───┘ └─────────┘ + : *┌─────────┐ │ :1 + : ┌--------┤ FString │ │ ┌──┴───────────┐ : : └─────────┘ │ ┌────┤ FApplication │ : : *┌────────┐ │ │ └──────────────┘ : ┌--------┤ FPoint │ │ │ ┌────────┐ @@ -61,11 +61,11 @@ │ FVTerm │◄──┐ :1 │ └──────────────┘ │ └──────────────┘ └────────┘ │ ┌────┴────┐ │ ┌───────────────┐ │ ┌───────────┐ ├────┤ FWidget │◄───────┼────┤ FToggleButton │◄─┼──┤ FCheckBox │ -┌─────────┐ │ └─────────┘ │ └───────────────┘ │ └───────────┘ -│ FObject │◄──┘ │ ┌──────────────┐ │ ┌─────────┐ -└─────────┘ ├────┤ FProgressbar │ └──┤ FSwitch │ - │ └──────────────┘ └─────────┘ - │ ┌────────────┐ +┌─────────┐ │ └────┬────┘ │ └───────────────┘ │ └───────────┘ +│ FObject │◄──┘ :1 │ ┌──────────────┐ │ ┌─────────┐ +└─────────┘ ┌──────┴────────┐ ├────┤ FProgressbar │ └──┤ FSwitch │ + │ FWidgetColors │ │ └──────────────┘ └─────────┘ + └───────────────┘ │ ┌────────────┐ ├────┤ FScrollbar │ │ └────────────┘ │ ┌───────────┐ @@ -93,9 +93,9 @@ └──┬──┬───┘ └─────────┘ │ ┌─────────────┐ ▲ ▲ └──┤ FMessageBox │ │ │ └─────────────┘ - │ │ ┌──────────┐ - │ └──────┤ FToolTip │ - │ └──────────┘ + │ │ ┌──────────┐ ┌────────────────┐ + │ └──────┤ FToolTip │◄─┤ FBusyIndicator │ + │ └──────────┘ └────────────────┘ └───────────────┐ ┌──────────┐ │ ┌───┤ FMenuBar │ ┌───────────┐ └──────┤ └──────────┘ diff --git a/doc/class_template.cpp b/doc/class_template.cpp index 0c1fc132..f7618712 100644 --- a/doc/class_template.cpp +++ b/doc/class_template.cpp @@ -1,17 +1,17 @@ /*********************************************************************** * fclassname.cpp - [brief description] * * * -* This file is part of the Final Cut widget toolkit * +* This file is part of the FINAL CUT widget toolkit * * * -* Copyright [year] [Maintainer] * +* Copyright [year] [Maintainer] * * * -* The Final Cut is free software; you can redistribute it and/or * -* modify it under the terms of the GNU Lesser General Public License * -* as published by the Free Software Foundation; either version 3 of * +* FINAL CUT is free software; you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * -* The Final Cut is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* FINAL CUT 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 Lesser General Public License for more details. * * * diff --git a/doc/class_template.h b/doc/class_template.h index 12c19272..c8352d65 100644 --- a/doc/class_template.h +++ b/doc/class_template.h @@ -1,17 +1,17 @@ /*********************************************************************** * fclassname.h - [brief description] * * * -* This file is part of the Final Cut widget toolkit * +* This file is part of the FINAL CUT widget toolkit * * * * Copyright [year] [Maintainer] * * * -* The Final Cut is free software; you can redistribute it and/or * -* modify it under the terms of the GNU Lesser General Public License * -* as published by the Free Software Foundation; either version 3 of * +* FINAL CUT is free software; you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * -* The Final Cut is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* FINAL CUT 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 Lesser General Public License for more details. * * * @@ -126,4 +126,3 @@ class FClassName #endif // FCLASSNAME_H - diff --git a/doc/faq.md b/doc/faq.md index edb0b5bc..47164336 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -6,7 +6,7 @@ Frequently Asked Questions What is FINAL CUT? ------------------ -The FINAL CUT is a [C++](https://en.wikipedia.org/wiki/C%2B%2B) class library +FINAL CUT is a [C++](https://en.wikipedia.org/wiki/C%2B%2B) class library and a widget toolkit with full mouse support for creating a text-based user interface. It's based on the Termcap library and has its own cursor optimization and window management. diff --git a/doc/first-steps.md b/doc/first-steps.md index f184b0dd..67c99515 100644 --- a/doc/first-steps.md +++ b/doc/first-steps.md @@ -11,6 +11,9 @@ Table of Contents - [Memory Management](#memory-management) - [Event Processing](#event-processing) - [Event handler reimplementation](#event-handler-reimplementation) + - [Event types](#available-event-types) + - [Timer event](#using-a-timer-event) + - [User event](#using-a-user-event) - [Signals and Callbacks](#signals-and-callbacks) - [Default signals](#the-final-cut-widgets-emit-the-following-default-signals) - [Callback function](#example-of-a-callback-function) @@ -245,16 +248,16 @@ Event Processing ---------------- Calling `FApplication::exec()` starts the FINAL CUT main event loop. -While the event loop is running, the system constantly checks whether +While the event loop is running, the system checks all the time whether an event has occurred and sends it to the application's currently focused -object. The events of the terminal such as keystrokes, mouse actions or -resizing the terminal are translated into `FEvent` objects and sent it to +object. The events of the terminal, such as keystrokes, mouse actions, or +terminal size changing, are translated into `FEvent` objects, and sent them to the active `FObject`. It is also possible to use `FApplication::sendEvent()` -or `FApplication::queueEvent()` to send your own events to an object. +or `FApplication::queueEvent()` to send a specific event to an object. `FObject`-derived objects process incoming events by reimplementing the -virtual method `event()`. The `FObject` itself calls only -`onTimer()` or `onUserEvent()` and ignores all other events. The +virtual method `event()`. The `FObject` itself can only call its own events +`onTimer()` and `onUserEvent()` and ignores all other events. The `FObject`-derived class `FWidget` also reimplements the `event()` method to handle further events. `FWidget` calls the `FWidget::onKeyPress` method when you press a key, or the `FWidget::onMouseDown` method when you click @@ -269,18 +272,18 @@ For example, the method `FEvent::type()` returns the type `fc::MouseDown_Event` when you press down a mouse button. Some event types have data that cannot store in an `FEvent` object. -For example, a click event of the mouse must store which button it -triggered where the mouse pointer was at that time. In classes derived +For example, a click event of the mouse must store which button is +triggered and where the mouse pointer was at that time. In classes derived from `FEvent`, such as `FMouseEvent()`, we store this data. Widgets get their events from the `event()` method inherited from FObject. The implementation of `event()` in `FWidget` forwards the most common event types to specific event handlers such as `FMouseEvent()`, `FKeyEvent()` or -`FResizeEvent()`. There are many other event types. It is also possible to -create own event types and send them to other objects. +`FResizeEvent()`. There are many other event types. You can create own event +types and send them to other objects and widgets. -**The FINAL CUT event types:** +### Available event types ### ```cpp enum events { @@ -312,6 +315,12 @@ enum events ``` +### Using a timer event ### + +The following example starts a periodic timer that triggers an `FTimerEvent()` +every 100 ms. The virtual method `onTimer()` is then called each time in the +same dialog object. + **File:** *timer.cpp* ```cpp #include @@ -375,6 +384,120 @@ g++ -O2 -lfinal -std=c++11 timer.cpp -o timer ``` +### Using a user event ### + +You can use the `FUserEvent()` to create a individual event and send it to a +specific object. If you want to create more than one user event, you can +specify an identification number (0 in the example below) to identify the +different events. This number can get later with `getUserId()`. + +User events should be generated in the main event loop. For this purpose, +the class `FApplication` provides the virtual method +`processExternalUserEvent()`. This method can be overwritten in a derived +class and filled with user code. + +The following example reads the average system load and creates a user event +when a value changes. This event sends the current values to an `FLabel` +widget and displays them in the terminal. + + +**File:** *user-event.cpp* +```cpp +#include +#include +#define _BSD_SOURCE 1 +#define _DEFAULT_SOURCE 1 + +using LoadAvg = double[3]; +using namespace finalcut; + +class extendedApplication : public FApplication +{ + public: + extendedApplication (const int& argc, char* argv[]) + : FApplication(argc, argv) + { } + + private: + void processExternalUserEvent() override + { + if ( getMainWidget() ) + { + if ( getloadavg(load_avg, 3) < 0 ) + FApplication::getLog()->error("Can't get load average values"); + + if ( last_avg[0] != load_avg[0] + || last_avg[1] != load_avg[1] + || last_avg[2] != load_avg[2] ) + { + FUserEvent user_event(fc::User_Event, 0); + user_event.setData (FDataPtr(&load_avg)); + FApplication::sendEvent (getMainWidget(), &user_event); + } + + for (std::size_t i = 0; i < 3; i++) + last_avg[i] = load_avg[i]; + } + } + + // Data member + LoadAvg load_avg{}, last_avg{}; +}; + + +class dialogWidget final : public FDialog +{ + public: + explicit dialogWidget (FWidget* parent = nullptr) + : FDialog{"User event", parent} + { + FDialog::setGeometry (FPoint{25, 5}, FSize{40, 6}); + loadavg_label.setGeometry (FPoint{2, 2}, FSize{36, 1}); + } + + private: + void onUserEvent (FUserEvent* ev) override + { + FDataPtr dataPtr = ev->getData(); + auto& lavg = *(reinterpret_cast(dataPtr)); + std::setlocale(LC_NUMERIC, "C"); + loadavg_label.clear(); + loadavg_label << "Load average: " << lavg[0] << ", " + << lavg[1] << ", " + << lavg[2] << " "; + loadavg_label.redraw(); + } + + FLabel loadavg_label{this}; +}; + + +int main (int argc, char* argv[]) +{ + extendedApplication app(argc, argv); + dialogWidget dialog(&app); + FWidget::setMainWidget(&dialog); + dialog.show(); + return app.exec(); +} +``` +
+ user-event.cpp +
Figure 5. User event generation
+
+

+ +*(Note: You can close the window with the mouse, +Shift+F10 or Ctrl+^)* + + +After entering the source code in *user-event.cpp* you can compile +the above program with gcc: +```cpp +g++ -O2 -lfinal -std=c++11 user-event.cpp -o user-event +``` + + Signals and Callbacks --------------------- @@ -387,46 +510,154 @@ clicked by a keyboard or mouse, it sends the string "clicked". A signal handler explicitly provided by Widget, in the form of a callback function or a callback method, can react to such a signal. -A callback function is always structured as follows: +A callback function has no return value and can have various arguments: ```cpp -void cb_function (FWidget* w, FDataPtr data) +void cb_function (FWidget* w, int* i, double* d, ...) {...} ``` The structure of a callback method is the same: ```cpp -void classname::cb_methode (FWidget* w, FDataPtr data) +void classname::cb_methode (FWidget* w, int* i, double* d, ...) {...} ``` We use the `addCallback()` method of the `FWidget` class to connect to other widget objects. -For calling functions and static methods: +1. For calling functions or static methods via a pointer: ```cpp +template::type = nullptr + , typename... Args> void FWidget::addCallback ( const FString& cb_signal - , FCallback cb_handler - , FDataPtr data ) + , Function&& cb_function + , Args&&... args) {...} ``` -For calling a member method of a specific instance: +2. For calling functions or static methods via a reference: ```cpp +template::type = nullptr + , typename... Args> void FWidget::addCallback ( const FString& cb_signal - , FWidget* cb_instance - , FMemberCallback cb_handler - , FDataPtr data ) + , Function& cb_function + , Args&&... args) {...} ``` -There are two macros `F_FUNCTION_CALLBACK` and `F_METHOD_CALLBACK` to avoid -having to deal with necessary type conversions. With `delCallback()` you can -remove a connection to a signal handler or a widget. Alternatively, you can -use `delCallbacks()` to remove all existing callbacks from an object. +3. For calling a member method of a specific instance: + +```cpp +template::type = nullptr + , typename MemberFunctionPointer::type = nullptr + , typename... Args> +void FWidget::addCallback ( const FString& cb_signal + , Object&& cb_instance + , Function&& cb_member + , Args&&... args) +{...} +``` + +4. For calling a std::bind call wrapper or a lambda expression: +```cpp +template::type = nullptr + , typename... Args> +void FWidget::addCallback ( const FString& cb_signal + , Function&& cb_function + , Args&&... args) +{...} +``` + +5. For calling a std::bind call wrapper to a specific instance: + +```cpp +template::type = nullptr + , typename ClassObject::type = nullptr + , typename... Args> +void FWidget::addCallback ( const FString& cb_signal + , Object&& cb_instance + , Function&& cb_function + , Args&&... args) +{...} +``` + +6. For calling a lambda function that has been stored in a variable +with the keyword auto: + +```cpp +template::type = nullptr + , typename... Args> +void FWidget::addCallback ( const FString& cb_signal + , Function& cb_function + , Args&&... args) +{...} +``` + +With `delCallback(...)` you can remove a connection to a signal handler +or a widget instance. Alternatively, you can use `delCallbacks()` to +remove all existing callbacks from an object. + +1. To delete functions or static methods callbacks via a pointer: + +```cpp +template::type = nullptr> +void FWidget::delCallback (FunctionPtr&& cb_func_ptr) +{...} +``` + +2. To delete functions or static methods callbacks via a reference: + +```cpp +template::type = nullptr> +void FWidget::delCallback (Function& cb_function) +{...} +``` + +3. To delete all callbacks from a specific instance: + +```cpp +template::type = nullptr> +void FWidget::delCallback (Object&& cb_instance) +{...} +``` + +4. To delete all callbacks of a signal: + +```cpp +void delCallback (const FString& cb_signal) +{...} +``` + +5. To delete all callbacks of a signal and specific instance: + +```cpp +template::type = nullptr> +void delCallback (const FString& cb_signal, Object&& cb_instance) +{...} +``` + +6. To delete all callbacks from a widget: + +```cpp +void delCallback() +{...} +``` ### The FINAL CUT widgets emit the following default signals ### @@ -486,10 +717,8 @@ use `delCallbacks()` to remove all existing callbacks from an object. using namespace finalcut; -void cb_changeText (FWidget* w, FDataPtr data) +void cb_changeText (const FButton& button, FLabel& label) { - FButton& button = *(static_cast(w)); - FLabel& label = *(static_cast(data)); label.clear(); label << "The " << button.getClassName() << " was pressed"; label.redraw(); @@ -512,9 +741,10 @@ int main (int argc, char* argv[]) // Connect the button signal "clicked" with the callback function button.addCallback ( - "clicked", - F_FUNCTION_CALLBACK (&cb_changeText), - &label + "clicked", // Callback signal + &cb_changeText, // Function pointer + std::cref(button), // First function argument + std::ref(label) // Second function argument ); FWidget::setMainWidget(&dialog); @@ -524,7 +754,7 @@ int main (int argc, char* argv[]) ```
callback-function.cpp -
Figure 5. Button with a callback function
+
Figure 6. Button with a callback function


@@ -560,11 +790,9 @@ int main (int argc, char* argv[]) // Connect the button signal "clicked" with the lambda expression button.addCallback ( - "clicked", - [] (FWidget* w, FDataPtr d) + "clicked", // Callback signal + [] (FButton& button, FDialog& dgl) // Lambda function { - FButton& button = *(static_cast(w)); - if ( button.getY() != 2 ) { button.setPos (FPoint{15, 2}); @@ -576,9 +804,10 @@ int main (int argc, char* argv[]) button.setText("&bottom"); } - static_cast(d)->redraw(); + dgl.redraw(); }, - &dialog + std::ref(button), // First function argument + std::ref(dialog) // Second function argument ); FWidget::setMainWidget(&dialog); @@ -588,7 +817,7 @@ int main (int argc, char* argv[]) ```
callback-lambda.cpp -
Figure 6. Button with lambda expression callback.
+
Figure 7. Button with lambda expression callback.


@@ -625,9 +854,10 @@ class dialogWidget : public FDialog // Connect the button signal "clicked" with the callback method button.addCallback ( - "clicked", - F_METHOD_CALLBACK (this, &FApplication::cb_exitApp), - nullptr + "clicked", // Callback signal + finalcut::getFApplication(), // Class instance + &finalcut::FApplication::cb_exitApp, // Method pointer + this // Function argument ); } @@ -646,7 +876,7 @@ int main (int argc, char* argv[]) ```
callback-method.cpp -
Figure 7. Button with a callback method
+
Figure 8. Button with a callback method


@@ -687,45 +917,22 @@ class dialogWidget : public FDialog label.setAlignment (fc::alignRight); label.setForegroundColor (fc::Black); plus.setGeometry (FPoint{3, 3}, size); - minus.setGeometry (FPoint{13, 3}, size); + minus.setGeometry (FPoint{3, 3} + FPoint{10, 0}, size); plus.setNoUnderline(); minus.setNoUnderline(); // Connect the button signal "clicked" with the callback method - plus.addCallback - ( - "clicked", - F_METHOD_CALLBACK (this, &dialogWidget::cb_plus) - ); - - minus.addCallback - ( - "clicked", - F_METHOD_CALLBACK (this, &dialogWidget::cb_minus) - ); + plus.addCallback ("clicked", this, &dialogWidget::cb_plus); + minus.addCallback ("clicked", this, &dialogWidget::cb_minus); // Connect own signals - addCallback - ( - "hot", - F_METHOD_CALLBACK (this, &dialogWidget::cb_set_red) - ); - - addCallback - ( - "regular", - F_METHOD_CALLBACK (this, &dialogWidget::cb_set_black) - ); - - addCallback - ( - "cold", - F_METHOD_CALLBACK (this, &dialogWidget::cb_set_blue) - ); + addCallback ("hot", this, &dialogWidget::cb_set_red); + addCallback ("regular", this, &dialogWidget::cb_set_black); + addCallback ("cold", this, &dialogWidget::cb_set_blue); } private: - void cb_plus (FWidget*, FDataPtr) + void cb_plus() { if ( t < 100 ) t++; @@ -738,7 +945,7 @@ class dialogWidget : public FDialog setTemperature(); } - void cb_minus (FWidget*, FDataPtr) + void cb_minus() { if ( t > -99 ) t--; @@ -751,17 +958,17 @@ class dialogWidget : public FDialog setTemperature(); } - void cb_set_blue (FWidget*, FDataPtr) + void cb_set_blue() { label.setForegroundColor (fc::Blue); } - void cb_set_black (FWidget*, FDataPtr) + void cb_set_black() { label.setForegroundColor (fc::Black); } - void cb_set_red (FWidget*, FDataPtr) + void cb_set_red() { label.setForegroundColor (fc::Red); } @@ -790,7 +997,7 @@ int main (int argc, char* argv[]) ```
emit-signal.cpp -
Figure 8. Callbacks with custom signals
+
Figure 9. Callbacks with custom signals


@@ -831,7 +1038,7 @@ If you want to ignore padding spaces, you must force this with the
widget coordinates -
Figure 9. Widget coordinates
+
Figure 10. Widget coordinates


@@ -881,7 +1088,7 @@ methods.
widget lengths -
Figure 10. Width and height of a widget
+
Figure 11. Width and height of a widget


@@ -934,7 +1141,7 @@ absolute geometry values as a `FRect` object, you can call the method
widget geometry -
Figure 11. Geometry of widgets
+
Figure 12. Geometry of widgets


@@ -994,7 +1201,7 @@ class dialogWidget : public FDialog button.setGeometry (FPoint{1, 1}, FSize{12, 1}, false); input.setGeometry (FPoint{2, 3}, FSize{12, 1}, false); // Set dialog geometry and calling adjustSize() - setGeometry (FPoint{25, 5}), FSize{40, 12}); + setGeometry (FPoint{25, 5}, FSize{40, 12}); setMinimumSize (FSize{25, 9}); } @@ -1068,7 +1275,7 @@ int main (int argc, char* argv[]) ```
size-adjustment.cpp -
Figure 12. Dynamic layout
+
Figure 13. Dynamic layout


@@ -1135,12 +1342,13 @@ class dialogWidget : public FDialog setGeometry (FPoint{28, 2}, FSize{24, 21}); scrollview.setGeometry(FPoint{1, 1}, FSize{22, 11}); scrollview.setScrollSize(FSize{60, 27}); - const auto& wc = getFWidgetColors(); - setColor (wc.label_inactive_fg, wc.dialog_bg); + // Attention: getColorTheme() requires an initialized terminal + const auto& wc = getColorTheme(); + setColor (wc->label_inactive_fg, wc->dialog_bg); scrollview.clearArea(); - FColorPair red (fc::LightRed, wc.dialog_bg); - FColorPair black (fc::Black, wc.dialog_bg); - FColorPair cyan (fc::Cyan, wc.dialog_bg); + FColorPair red (fc::LightRed, wc->dialog_bg); + FColorPair black (fc::Black, wc->dialog_bg); + FColorPair cyan (fc::Cyan, wc->dialog_bg); static std::vector d { @@ -1167,8 +1375,7 @@ class dialogWidget : public FDialog btn->addCallback ( "clicked", - F_METHOD_CALLBACK (this, &dialogWidget::cb_button), - static_cast(&std::get<2>(b)) + this, &dialogWidget::cb_button, std::get<2>(b) ); }; } @@ -1176,10 +1383,9 @@ class dialogWidget : public FDialog private: typedef std::tuple direction; - void cb_button (FWidget*, FDataPtr data) + void cb_button (const FPoint& p) { - FPoint* p = static_cast(data); - scrollview.scrollTo(*p); + scrollview.scrollTo(p); } FScrollView scrollview{this}; @@ -1188,6 +1394,7 @@ class dialogWidget : public FDialog int main (int argc, char* argv[]) { FApplication app(argc, argv); + app.initTerminal(); // Terminal initialization dialogWidget dialog(&app); FWidget::setMainWidget(&dialog); dialog.show(); @@ -1196,7 +1403,7 @@ int main (int argc, char* argv[]) ```
scrollview.cpp -
Figure 13. Dialog with a scrolling viewport
+
Figure 14. Dialog with a scrolling viewport


diff --git a/doc/first-steps_user-event.cpp.png b/doc/first-steps_user-event.cpp.png new file mode 100644 index 00000000..4e1c21d8 Binary files /dev/null and b/doc/first-steps_user-event.cpp.png differ diff --git a/doc/framebuffer.txt b/doc/framebuffer.txt index 4e11667a..8d6269a1 100644 --- a/doc/framebuffer.txt +++ b/doc/framebuffer.txt @@ -1,7 +1,7 @@ Framebuffer =========== -The Final Cut determines the used number of bits per pixel (bpp) +FINAL CUT determines the used number of bits per pixel (bpp) for Linux framebuffer console to determine whether 16 (or more) different background colors can be displayed. Therefore your user needs read-access to the framebuffer device (/dev/fb0 or /dev/fb/0). diff --git a/doc/mouse-control.md b/doc/mouse-control.md new file mode 100644 index 00000000..03ca4b70 --- /dev/null +++ b/doc/mouse-control.md @@ -0,0 +1,29 @@ +Title bar actions on mouse clicks +================================= + +The FINAL CUT title bar of dialog windows has different behaviors on mouse clicks. + + +Clicking on the title bar +------------------------- + +* A left-click activates and raises the window. After that, you can drag the window with the mouse. +* A middle-click activates and lower the window. +* A right-click activates the window and keeps its current position in the window stack. +* A double-click maximizes or restores the window size for a resizable dialog. + + +Clicking the title bar buttons +------------------------------ + +* Single-clicking on the title bar menu button opens the title bar menu. +* Double-clicking on the title bar menu button closes the dialog. +* Single-clicking on the zoom button maximizes the window size. +* Single-clicking on the unzoom button restores the window size. + + +Dialog resize corner +-------------------- + +If you click and drag the left mouse button in the lower right corner of the window, you can change the size of a resizable dialog. + diff --git a/doc/user-theme-bee-palette.svg b/doc/user-theme-bee-palette.svg new file mode 100644 index 00000000..90825aa4 --- /dev/null +++ b/doc/user-theme-bee-palette.svg @@ -0,0 +1,330 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + diff --git a/doc/user-theme-fc16-dark-palette.svg b/doc/user-theme-fc16-dark-palette.svg new file mode 100644 index 00000000..0d91e4d3 --- /dev/null +++ b/doc/user-theme-fc16-dark-palette.svg @@ -0,0 +1,330 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + diff --git a/doc/user-theme-fc16-palette.svg b/doc/user-theme-fc16-palette.svg new file mode 100644 index 00000000..7bcadf23 --- /dev/null +++ b/doc/user-theme-fc16-palette.svg @@ -0,0 +1,330 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + diff --git a/doc/user-theme-fc8-palette.svg b/doc/user-theme-fc8-palette.svg new file mode 100644 index 00000000..0578c6a1 --- /dev/null +++ b/doc/user-theme-fc8-palette.svg @@ -0,0 +1,194 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + diff --git a/doc/user-theme-vga-palette.svg b/doc/user-theme-vga-palette.svg new file mode 100644 index 00000000..e451e02c --- /dev/null +++ b/doc/user-theme-vga-palette.svg @@ -0,0 +1,330 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + diff --git a/doc/user-theme.md b/doc/user-theme.md new file mode 100644 index 00000000..fc59dd45 --- /dev/null +++ b/doc/user-theme.md @@ -0,0 +1,443 @@ +User Themes +=========== + +FINAL CUT supports color themes. That makes it possible to change the color +of all elements of a widget in the program. Also, you can adjust the color +palette to your preferences. If you want to switch back to the default +themes, you can always call the method `FApplication::setDefaultTheme()` +or `FApplication::setDarkTheme()` for the dark theme. + + +Widget Color Theme +------------------ + +FINAL CUT uses a default color scheme that the user can override in a +derived class of `FWidgetColors`. All widget colors are redefined in the +constructor by the method `setColorTheme()`. + +```cpp +class myWidgetColors final : public finalcut::FWidgetColors +{ + public: + myWidgetColors() + { + myWidgetColors::setColorTheme(); + } + + ~myWidgetColors() override + { } + + const finalcut::FString getClassName() const override + { + return "myWidgetColors"; + } + + void myWidgetColors() override + { + ... // Color definitions + } +}; +``` + +For setting the widget colors, it is recommended to call the method +`FWidget::setColorTheme()` via the `FApplication` object to create a +new instance of the theme and assign it to the application. + +```cpp +finalcut::FApplication app(argc, argv); +app.setColorTheme(); +``` + +In the following example, we will create the `BeeColorTheme`. For this +purpose, we will first create an include file that can be easily included +later in your application. + +**File:** *widget-color-theme.h* +```cpp +#ifndef WIDGETCOLORTHEME_H +#define WIDGETCOLORTHEME_H + +class BeeColorTheme final : public finalcut::FWidgetColors +{ + public: + BeeColorTheme() + { + BeeColorTheme::setColorTheme(); + } + + ~BeeColorTheme() override + { } + + const finalcut::FString getClassName() const override + { + return "BeeColorTheme"; + } + + void setColorTheme() override + { + term_fg = finalcut::fc::Black; + term_bg = finalcut::fc::LightBlue; + list_fg = finalcut::fc::Black; + list_bg = finalcut::fc::LightGray; + selected_list_fg = finalcut::fc::LightRed; + selected_list_bg = finalcut::fc::LightGray; + dialog_fg = finalcut::fc::Black; + dialog_resize_fg = finalcut::fc::Red; + dialog_emphasis_fg = finalcut::fc::Blue; + dialog_bg = finalcut::fc::LightGray; + error_box_fg = finalcut::fc::Black; + error_box_emphasis_fg = finalcut::fc::Red; + error_box_bg = finalcut::fc::Yellow; + tooltip_fg = finalcut::fc::Black; + tooltip_bg = finalcut::fc::Yellow; + shadow_fg = finalcut::fc::Black; + shadow_bg = finalcut::fc::LightGray; + current_element_focus_fg = finalcut::fc::White; + current_element_focus_bg = finalcut::fc::Green; + current_element_fg = finalcut::fc::LightGray; + current_element_bg = finalcut::fc::DarkGray; + current_inc_search_element_fg = finalcut::fc::Brown; + selected_current_element_focus_fg = finalcut::fc::LightRed; + selected_current_element_focus_bg = finalcut::fc::Green; + selected_current_element_fg = finalcut::fc::LightRed; + selected_current_element_bg = finalcut::fc::DarkGray; + label_fg = finalcut::fc::Black; + label_bg = finalcut::fc::LightGray; + label_inactive_fg = finalcut::fc::LightGray; + label_inactive_bg = finalcut::fc::DarkGray; + label_hotkey_fg = finalcut::fc::Red; + label_hotkey_bg = finalcut::fc::LightGray; + label_emphasis_fg = finalcut::fc::Blue; + label_ellipsis_fg = finalcut::fc::DarkGray; + inputfield_active_focus_fg = finalcut::fc::LightGray; + inputfield_active_focus_bg = finalcut::fc::Green; + inputfield_active_fg = finalcut::fc::Black; + inputfield_active_bg = finalcut::fc::Cyan ; + inputfield_inactive_fg = finalcut::fc::Black; + inputfield_inactive_bg = finalcut::fc::LightGray; + toggle_button_active_focus_fg = finalcut::fc::White; + toggle_button_active_focus_bg = finalcut::fc::Green; + toggle_button_active_fg = finalcut::fc::Black; + toggle_button_active_bg = finalcut::fc::LightGray; + toggle_button_inactive_fg = finalcut::fc::DarkGray; + toggle_button_inactive_bg = finalcut::fc::LightGray; + button_active_focus_fg = finalcut::fc::White; + button_active_focus_bg = finalcut::fc::Green; + button_active_fg = finalcut::fc::Black; + button_active_bg = finalcut::fc::Cyan; + button_inactive_fg = finalcut::fc::Cyan; + button_inactive_bg = finalcut::fc::LightGray; + button_hotkey_fg = finalcut::fc::Red; + titlebar_active_fg = finalcut::fc::White; + titlebar_active_bg = finalcut::fc::Blue; + titlebar_inactive_fg = finalcut::fc::LightGray; + titlebar_inactive_bg = finalcut::fc::DarkGray; + titlebar_button_fg = finalcut::fc::Black; + titlebar_button_bg = finalcut::fc::LightGray; + titlebar_button_focus_fg = finalcut::fc::LightGray; + titlebar_button_focus_bg = finalcut::fc::Black; + menu_active_focus_fg = finalcut::fc::White; + menu_active_focus_bg = finalcut::fc::Blue; + menu_active_fg = finalcut::fc::Black; + menu_active_bg = finalcut::fc::Yellow; + menu_inactive_fg = finalcut::fc::Cyan; + menu_inactive_bg = finalcut::fc::Yellow; + menu_hotkey_fg = finalcut::fc::Red; + menu_hotkey_bg = finalcut::fc::Yellow; + statusbar_fg = finalcut::fc::White; + statusbar_bg = finalcut::fc::DarkGray; + statusbar_hotkey_fg = finalcut::fc::LightRed; + statusbar_hotkey_bg = finalcut::fc::DarkGray; + statusbar_separator_fg = finalcut::fc::Black; + statusbar_active_fg = finalcut::fc::White; + statusbar_active_bg = finalcut::fc::Green; + statusbar_active_hotkey_fg = finalcut::fc::LightRed; + statusbar_active_hotkey_bg = finalcut::fc::Green; + scrollbar_fg = finalcut::fc::Black; + scrollbar_bg = finalcut::fc::Green; + scrollbar_button_fg = finalcut::fc::Black; + scrollbar_button_bg = finalcut::fc::Green; + scrollbar_button_inactive_fg = finalcut::fc::Cyan; + scrollbar_button_inactive_bg = finalcut::fc::LightGray; + progressbar_fg = finalcut::fc::Green; + progressbar_bg = finalcut::fc::DarkGray; + } +}; + +#endif // WIDGETCOLORTHEME_H +``` + + +Color Palette Theme +------------------- + +FINAL CUT has four color tables for the 16 standard colors in the terminal. +These are a redefinition of the 16 ANSI colors. You can address the colors +via indexes values from 0 to 15. They correspond to the following colors: + +| Index | Color name | +|:------:|:---------------------------| +| 0 | finalcut::fc::Black | +| 1 | finalcut::fc::Blue | +| 2 | finalcut::fc::Green | +| 3 | finalcut::fc::Cyan | +| 4 | finalcut::fc::Red | +| 5 | finalcut::fc::Magenta | +| 6 | finalcut::fc::Brown | +| 7 | finalcut::fc::LightGray | +| 8 | finalcut::fc::DarkGray | +| 9 | finalcut::fc::LightBlue | +| 10 | finalcut::fc::LightGreen | +| 11 | finalcut::fc::LightCyan | +| 12 | finalcut::fc::LightRed | +| 13 | finalcut::fc::LightMagenta | +| 14 | finalcut::fc::Yellow | +| 15 | finalcut::fc::White | + +You can define your color as an 8-bit value based on its red, green, and +blue components. To create a color palette, create a derived class of +`FColorPalette`. The constructor gets as argument the function to set +a palette color. This function must have the following structure: + +```cpp +setPalette(finalcut::FColor index, int red, int green, int blue); +``` + +A possible implementation could look as follows: + +```cpp +class myColorPalette final : public finalcut::FColorPalette +{ + public: + explicit myColorPalette (const FSetPalette& f) + : FColorPalette(f) + { } + + ~myColorPalette() + { } + + const finalcut::FString getClassName() const override + { + return "myColorPalette"; + } + + void setColorPalette() override + { + ... // Palette definitions + } + + void resetColorPalette() override + { + setVGAdefaultPalette(); + } +}; +``` +To set the colors of a palette theme, you should use the method +`FTerm::setColorPaletteTheme()`. This method creates a new instance and +saves it in the `FTerm` object. + +```cpp +finalcut::FTerm::setColorPaletteTheme(); +``` +The standard VGA palette is part of the `FColorPalette` class. To set it, +use the method `setVGAdefaultPalette()`. You can use it to reset the color +palette of terminals that cannot reset to default values with escape +sequences. +
+ VGA palette +
Figure 1. VGA palette
+
+

+ +The FINAL CUT eight-color palette `default8ColorPalette` is optimized for +the eight-color widget theme `default8ColorTheme`. It is for terminals +that cannot display more than eight colors. +
+ FINAL CUT 8-color palette +
Figure 2. FINAL CUT 8-color palette
+
+

+ +The FINAL CUT palette `default16ColorPalette` is the default 16-color +palette. It is optimized for the widget color theme `default16ColorTheme`. +
+ FINAL CUT 16-color palette +
Figure 3. FINAL CUT 16-color palette
+
+

+ +The second 16-color palette in FINAL CUT is for the dark theme. It was +adjusted for the widget color themes `default8ColorDarkTheme` and +`default16ColorDarkTheme`. +
+ FINAL CUT 16-color dark palette +
Figure 4. FINAL CUT 16-color dark palette
+
+

+ +In the following example, we want to create the palette them +`BeeColorPalette`. For this purpose, we generate an include file again, +in which we implement the new palette class. +
+ Bee palette +
Figure 6. Bee palette
+
+

+ +**File:** *color-palette-theme.h* +```cpp +#ifndef BEECOLORPALETTE_H +#define BEECOLORPALETTE_H + +class BeeColorPalette final : public finalcut::FColorPalette +{ + public: + explicit BeeColorPalette (const FSetPalette& f) + : FColorPalette(f) + { } + + ~BeeColorPalette() + { } + + const finalcut::FString getClassName() const override + { + return "BeeColorPalette"; + } + + void setColorPalette() override + { + setPalette (finalcut::fc::Black, 0x00, 0x00, 0x00); + setPalette (finalcut::fc::Blue, 0x23, 0x21, 0x2c); + setPalette (finalcut::fc::Green, 0x26, 0x93, 0x7c); + setPalette (finalcut::fc::Cyan, 0xcf, 0xb3, 0xa8); + setPalette (finalcut::fc::Red, 0xba, 0x1a, 0x1a); + setPalette (finalcut::fc::Magenta, 0xb2, 0x18, 0xb2); + setPalette (finalcut::fc::Brown, 0xe8, 0x87, 0x1f); + setPalette (finalcut::fc::LightGray, 0xff, 0xfb, 0xe4); + setPalette (finalcut::fc::DarkGray, 0x3a, 0x36, 0x37); + setPalette (finalcut::fc::LightBlue, 0xa5, 0xa5, 0xb1); + setPalette (finalcut::fc::LightGreen, 0x5e, 0xeb, 0x5c); + setPalette (finalcut::fc::LightCyan, 0x62, 0xbf, 0xf8); + setPalette (finalcut::fc::LightRed, 0xee, 0x44, 0x44); + setPalette (finalcut::fc::LightMagenta, 0xe9, 0xad, 0xff); + setPalette (finalcut::fc::Yellow, 0xf8, 0xef, 0xa6); + setPalette (finalcut::fc::White, 0xff, 0xff, 0xff); + } + + void resetColorPalette() override + { + setVGAdefaultPalette(); + } +}; + +#endif // BEECOLORPALETTE_H +``` + + +Use of Themes +------------- + +If you include the two include files above in your application, you can use +the widget color theme and the color palette theme. In the main function of +your application, the object instances of both classes are created and set. +
+ User theme example +
Figure 7. User theme example
+
+

+ +**File:** *theme.cpp* +```cpp +#include + +#include "widget-color-theme.h" +#include "color-palette-theme.h" + +using namespace finalcut; + +class dialogWidget final : public FDialog +{ + public: + explicit dialogWidget (FWidget* parent = nullptr) + : FDialog{"Theming test application", parent} + { + FDialog::setGeometry (FPoint{15, 5}, FSize{50, 9}); + Input.setGeometry (FPoint{2, 2}, FSize{39, 1}); + Input.setLabelText("File name:"); + Input.setLabelOrientation(FLineEdit::label_above); + Input.setStatusbarMessage("Enter a file name"); + Browse.setGeometry (FPoint{43, 2}, FSize{4, 1}); + Browse.addCallback + ( + "clicked", + this, &dialogWidget::cb_FileBrowse + ); + Apply.setGeometry (FPoint{24, 5}, FSize{10, 1}); + Apply.setStatusbarMessage("Apply settings"); + Quit.setGeometry (FPoint{37, 5}, FSize{10, 1}); + Quit.setStatusbarMessage("Exit the program"); + Quit.addCallback + ( + "clicked", + finalcut::getFApplication(), + &finalcut::FApplication::cb_exitApp, + this + ); + Open.addCallback + ( + "clicked", + this, &dialogWidget::cb_FileBrowse + ); + } + + private: + void cb_FileBrowse() + { + auto filename = FFileDialog::fileOpenChooser(this); + + if ( ! filename.isEmpty() ) + { + Input.setText(filename); + Input.redraw(); + } + } + + FMenuBar Menubar{this}; + FMenu File{"&File", &Menubar}; + FMenuItem New{"&New", &File}; + FMenuItem Open{"&Open...", &File}; + FMenu Edit{"&Edit", &Menubar}; + FMenuItem Undo{"&Undo", &Edit}; + FMenu Help{"&Help", &Menubar}; + FMenuItem About{"&About", &Help}; + FStatusBar Statusbar{this}; + FLineEdit Input{"input...", this}; + FButton Browse{"..", this}; + FButton Apply{"&Apply", this}; + FButton Quit{"&Quit", this}; +}; + +int main (int argc, char* argv[]) +{ + FApplication app(argc, argv); + + // Set the widget color theme + app.setColorTheme(); + + // Set the color palette theme + FTerm::setColorPaletteTheme(); + + dialogWidget dialog(&app); + FWidget::setMainWidget(&dialog); + dialog.show(); + return app.exec(); +} +``` + + +After entering the source code in *theme.cpp* you can compile +the above program with gcc: +```cpp +g++ -O2 -lfinal -std=c++11 theme.cpp -o theme +``` + diff --git a/doc/user-theme.png b/doc/user-theme.png new file mode 100644 index 00000000..47019aab Binary files /dev/null and b/doc/user-theme.png differ diff --git a/examples/7segment.cpp b/examples/7segment.cpp index 8cf9cdbb..89991113 100644 --- a/examples/7segment.cpp +++ b/examples/7segment.cpp @@ -1,17 +1,17 @@ /*********************************************************************** * 7segment.cpp - Seven-segment display * * * -* This file is part of the Final Cut widget toolkit * +* This file is part of the FINAL CUT widget toolkit * * * * Copyright 2012-2020 Markus Gans * * * -* The Final Cut is free software; you can redistribute it and/or * -* modify it under the terms of the GNU Lesser General Public License * -* as published by the Free Software Foundation; either version 3 of * +* FINAL CUT is free software; you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * -* The Final Cut is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* FINAL CUT 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 Lesser General Public License for more details. * * * @@ -100,18 +100,19 @@ SegmentView::SegmentView (finalcut::FWidget* parent) Input.addCallback ( "changed", - [] (const finalcut::FWidget*, FDataPtr data) + [] (SegmentView& dialog) { - auto dialog = static_cast(data); - dialog->redraw(); + dialog.redraw(); }, - this + std::ref(*this) ); Exit.addCallback ( "clicked", - F_METHOD_CALLBACK (this, &finalcut::FApplication::cb_exitApp) + finalcut::getFApplication(), + &finalcut::FApplication::cb_exitApp, + this ); } diff --git a/examples/Makefile.am b/examples/Makefile.am index 9514ec2b..e8a33ee2 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,5 +1,5 @@ #---------------------------------------------------------------------- -# Makefile.am - The Final Cut example programs +# Makefile.am - FINAL CUT example programs #---------------------------------------------------------------------- if ! CPPUNIT_TEST @@ -15,6 +15,7 @@ noinst_PROGRAMS = \ fullwidth-character \ 7segment \ choice \ + busy \ listbox \ listview \ checklist \ @@ -44,6 +45,7 @@ event_log_SOURCES = event-log.cpp fullwidth_character_SOURCES = fullwidth-character.cpp 7segment_SOURCES = 7segment.cpp choice_SOURCES = choice.cpp +busy_SOURCES = busy.cpp listbox_SOURCES = listbox.cpp listview_SOURCES = listview.cpp checklist_SOURCES = checklist.cpp diff --git a/examples/background-color.cpp b/examples/background-color.cpp index 60938a7e..0894b8ea 100644 --- a/examples/background-color.cpp +++ b/examples/background-color.cpp @@ -1,17 +1,17 @@ /*********************************************************************** * background-color.cpp - Sets the background color palette * * * -* This file is part of the Final Cut widget toolkit * +* This file is part of the FINAL CUT widget toolkit * * * * Copyright 2019-2020 Markus Gans * * * -* The Final Cut is free software; you can redistribute it and/or * -* modify it under the terms of the GNU Lesser General Public License * -* as published by the Free Software Foundation; either version 3 of * +* FINAL CUT is free software; you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * -* The Final Cut is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* FINAL CUT 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 Lesser General Public License for more details. * * * @@ -42,7 +42,7 @@ class Background final : public finalcut::FDialog using FDialog::setGeometry; // Typedef - typedef std::tuple RGB; + typedef std::tuple RGB; // Constructor explicit Background (finalcut::FWidget* = nullptr); @@ -58,8 +58,8 @@ class Background final : public finalcut::FDialog private: // Callback method - void cb_changed (const finalcut::FWidget*, const FDataPtr); - void cb_choice (const finalcut::FWidget*, const FDataPtr); + void cb_changed(); + void cb_choice(); // Data members finalcut::FComboBox color_choice{this}; @@ -148,7 +148,9 @@ Background::Background (finalcut::FWidget* parent) quit.addCallback ( "clicked", - F_METHOD_CALLBACK (this, &finalcut::FApplication::cb_exitApp) + finalcut::getFApplication(), + &finalcut::FApplication::cb_exitApp, + this ); for (const auto spinbox : {&red, &green, &blue}) @@ -156,7 +158,7 @@ Background::Background (finalcut::FWidget* parent) spinbox->addCallback ( "changed", - F_METHOD_CALLBACK (this, &Background::cb_changed) + this, &Background::cb_changed ); } @@ -165,7 +167,7 @@ Background::Background (finalcut::FWidget* parent) color_choice.addCallback ( signal, - F_METHOD_CALLBACK (this, &Background::cb_choice) + this, &Background::cb_choice ); } } @@ -175,7 +177,7 @@ Background::~Background() // destructor { } //---------------------------------------------------------------------- -void Background::cb_changed (const finalcut::FWidget*, const FDataPtr) +void Background::cb_changed() { if ( ! finalcut::FTerm::canChangeColorPalette() ) return; @@ -189,7 +191,7 @@ void Background::cb_changed (const finalcut::FWidget*, const FDataPtr) } //---------------------------------------------------------------------- -void Background::cb_choice (const finalcut::FWidget*, const FDataPtr) +void Background::cb_choice() { if ( ! finalcut::FTerm::canChangeColorPalette() ) return; @@ -217,8 +219,13 @@ void Background::cb_choice (const finalcut::FWidget*, const FDataPtr) int main (int argc, char* argv[]) { + // Create the application object finalcut::FApplication app(argc, argv); + // Force terminal initialization without calling show() + app.initTerminal(); + + // The following lines require an initialized terminal if ( finalcut::FTerm::canChangeColorPalette() ) app.setBackgroundColor(finalcut::fc::LightMagenta); diff --git a/examples/busy.cpp b/examples/busy.cpp new file mode 100644 index 00000000..24e3bf22 --- /dev/null +++ b/examples/busy.cpp @@ -0,0 +1,129 @@ +/*********************************************************************** +* busy.cpp - Shows the use of the FBusyIndicator * +* * +* This file is part of the FINAL CUT widget toolkit * +* * +* Copyright 2020 Markus Gans * +* * +* FINAL CUT is free software; you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation; either version 3 of * +* the License, or (at your option) any later version. * +* * +* FINAL CUT 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 Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with this program. If not, see * +* . * +***********************************************************************/ + +#include +using finalcut::FPoint; +using finalcut::FRect; +using finalcut::FSize; + +//---------------------------------------------------------------------- +// class Dialog +//---------------------------------------------------------------------- + +class Dialog final : public finalcut::FDialog +{ + public: + explicit Dialog (FWidget* parent = nullptr); + + private: + void adjustSize() override; + + // Event handler + void onTimer (finalcut::FTimerEvent*) override; + + // Callback method + void cb_start(); + + // Data members + finalcut::FSpinBox seconds{this}; + finalcut::FButton start{"&Start", this}; + finalcut::FButton quit{"&Quit", this}; + finalcut::FBusyIndicator busy_indicator{this}; +}; + +//---------------------------------------------------------------------- +Dialog::Dialog (FWidget* parent) + : finalcut::FDialog{parent} +{ + FDialog::setText ("Dialog"); + finalcut::FDialog::setGeometry (FPoint{26, 5}, FSize{28, 10}); + seconds.setGeometry (FPoint{10, 2}, FSize{10, 1}); + seconds.setLabelText ("Seconds"); + seconds.setRange (0, 60); + seconds.setValue (3); + start.setGeometry (FPoint{2, 6}, FSize{10, 1}); + quit.setGeometry (FPoint{15, 6}, FSize{10, 1}); + + // Add button callbacks + seconds.addCallback + ( + "activate", + this, &Dialog::cb_start + ); + + start.addCallback + ( + "clicked", + this, &Dialog::cb_start + ); + + quit.addCallback + ( + "clicked", + finalcut::getFApplication(), + &finalcut::FApplication::cb_exitApp, + this + ); +} + +//---------------------------------------------------------------------- +void Dialog::adjustSize() +{ + finalcut::FDialog::adjustSize(); + int X = int((getDesktopWidth() - getWidth()) / 2); + const int Y = 5; + + if ( X < 1 ) + X = 1; + + setPos (FPoint{X, Y}, false); +} + +//---------------------------------------------------------------------- +void Dialog::onTimer (finalcut::FTimerEvent*) +{ + delOwnTimers(); + busy_indicator.stop(); +} + +//---------------------------------------------------------------------- +void Dialog::cb_start() +{ + if ( seconds.getValue() < 1 ) + return; + + busy_indicator.start(); + addTimer(int(seconds.getValue() * 1000)); +} + +//---------------------------------------------------------------------- +// main part +//---------------------------------------------------------------------- + +int main (int argc, char* argv[]) +{ + finalcut::FApplication app(argc, argv); + Dialog dialog(&app); + finalcut::FWidget::setMainWidget(&dialog); + dialog.show(); + return app.exec(); +} diff --git a/examples/calculator.cpp b/examples/calculator.cpp index aff63430..8160f41e 100644 --- a/examples/calculator.cpp +++ b/examples/calculator.cpp @@ -1,17 +1,17 @@ /*********************************************************************** * calculator.cpp - A simple calculator with trigonometric functions * * * -* This file is part of the Final Cut widget toolkit * +* This file is part of the FINAL CUT widget toolkit * * * * Copyright 2016-2020 Markus Gans * * * -* The Final Cut is free software; you can redistribute it and/or * -* modify it under the terms of the GNU Lesser General Public License * -* as published by the Free Software Foundation; either version 3 of * +* FINAL CUT is free software; you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * -* The Final Cut is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* FINAL CUT 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 Lesser General Public License for more details. * * * @@ -119,13 +119,6 @@ class Calc final : public finalcut::FDialog // Destructor ~Calc() override; - // Event handlers - void onKeyPress (finalcut::FKeyEvent*) override; - void onClose (finalcut::FCloseEvent*) override; - - // Callback method - void cb_buttonClicked (const finalcut::FWidget*, FDataPtr); - private: // Typedef and Enumeration typedef std::function keyFunction; // Member function @@ -207,17 +200,24 @@ class Calc final : public finalcut::FDialog void sine (lDouble&); void cosine (lDouble&); void tangent (lDouble&); - bool isDataEntryKey (int); - bool isOperatorKey (int); + bool isDataEntryKey (int) const; + bool isOperatorKey (int) const; lDouble& getValue(); void setDisplay (lDouble); void setInfixOperator (char); void clearInfixOperator(); void calcInfixOperator(); void adjustSize() override; - const wchar_t* getButtonText (const std::size_t); + const wchar_t* getButtonText (const std::size_t) const; void mapKeyFunctions(); + // Event handlers + void onKeyPress (finalcut::FKeyEvent*) override; + void onClose (finalcut::FCloseEvent*) override; + + // Callback method + void cb_buttonClicked (Calc::button); + // Data members bool error{false}; bool arcus_mode{false}; @@ -230,7 +230,7 @@ class Calc final : public finalcut::FDialog char infix_operator{'\0'}; char last_infix_operator{'\0'}; finalcut::FString input{""}; - std::size_t button_no[Calc::NUM_OF_BUTTONS]{}; + button button_no[Calc::NUM_OF_BUTTONS]{}; struct stack_data { @@ -257,7 +257,7 @@ Calc::Calc (FWidget* parent) clearInfixOperator(); std::setlocale(LC_NUMERIC, "C"); - for (std::size_t key{0}; key < Calc::NUM_OF_BUTTONS; key++) + for (button key{Sine}; key < Calc::NUM_OF_BUTTONS; key = button(key + 1)) { auto btn = std::make_shared