diff --git a/.gitignore b/.gitignore index b8aa0e2a..a4813f98 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ examples/.deps/ examples/.libs/ examples/calculator examples/dialog +examples/busy examples/event-log examples/string-operations examples/background-color diff --git a/doc/first-steps.md b/doc/first-steps.md index f352f815..e4edfbf8 100644 --- a/doc/first-steps.md +++ b/doc/first-steps.md @@ -245,16 +245,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,15 +269,15 @@ 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:** @@ -312,6 +312,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 +381,119 @@ 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 --------------------- @@ -524,7 +643,7 @@ int main (int argc, char* argv[]) ```
callback-function.cpp -
Figure 5. Button with a callback function
+
Figure 6. Button with a callback function


@@ -588,7 +707,7 @@ int main (int argc, char* argv[]) ```
callback-lambda.cpp -
Figure 6. Button with lambda expression callback.
+
Figure 7. Button with lambda expression callback.


@@ -646,7 +765,7 @@ int main (int argc, char* argv[]) ```
callback-method.cpp -
Figure 7. Button with a callback method
+
Figure 8. Button with a callback method


@@ -790,7 +909,7 @@ int main (int argc, char* argv[]) ```
emit-signal.cpp -
Figure 8. Callbacks with custom signals
+
Figure 9. Callbacks with custom signals


@@ -831,7 +950,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 +1000,7 @@ methods.
widget lengths -
Figure 10. Width and height of a widget
+
Figure 11. Width and height of a widget


@@ -934,7 +1053,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 +1113,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 +1187,7 @@ int main (int argc, char* argv[]) ```
size-adjustment.cpp -
Figure 12. Dynamic layout
+
Figure 13. Dynamic layout


@@ -1198,7 +1317,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/examples/busy b/examples/busy deleted file mode 100755 index f53abfea..00000000 --- a/examples/busy +++ /dev/null @@ -1,210 +0,0 @@ -#! /bin/bash - -# busy - temporary wrapper script for .libs/busy -# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-2 -# -# The busy program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of the build directory. -# If it is, it will not operate correctly. - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -sed_quote_subst='s|\([`"$\\]\)|\\\1|g' - -# Be Bourne compatible -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac -fi -BIN_SH=xpg4; export BIN_SH # for Tru64 -DUALCASE=1; export DUALCASE # for MKS sh - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -relink_command="" - -# This environment variable determines our operation mode. -if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then - # install mode needs the following variables: - generated_by_libtool_version='2.4.6' - notinst_deplibs=' /usr/local/src/MyProgs/finalcut/src/.libs/libfinal.la' -else - # When we are sourced in execute mode, $file and $ECHO are already set. - if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then - file="$0" - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' -} - ECHO="printf %s\\n" - fi - -# Very basic option parsing. These options are (a) specific to -# the libtool wrapper, (b) are identical between the wrapper -# /script/ and the wrapper /executable/ that is used only on -# windows platforms, and (c) all begin with the string --lt- -# (application programs are unlikely to have options that match -# this pattern). -# -# There are only two supported options: --lt-debug and -# --lt-dump-script. There is, deliberately, no --lt-help. -# -# The first argument to this parsing function should be the -# script's ../libtool value, followed by no. -lt_option_debug= -func_parse_lt_options () -{ - lt_script_arg0=$0 - shift - for lt_opt - do - case "$lt_opt" in - --lt-debug) lt_option_debug=1 ;; - --lt-dump-script) - lt_dump_D=`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e 's%/[^/]*$%%'` - test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=. - lt_dump_F=`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e 's%^.*/%%'` - cat "$lt_dump_D/$lt_dump_F" - exit 0 - ;; - --lt-*) - $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2 - exit 1 - ;; - esac - done - - # Print the debug banner immediately: - if test -n "$lt_option_debug"; then - echo "busy:busy:$LINENO: libtool wrapper (GNU libtool) 2.4.6 Debian-2.4.6-2" 1>&2 - fi -} - -# Used when --lt-debug. Prints its arguments to stdout -# (redirection is the responsibility of the caller) -func_lt_dump_args () -{ - lt_dump_args_N=1; - for lt_arg - do - $ECHO "busy:busy:$LINENO: newargv[$lt_dump_args_N]: $lt_arg" - lt_dump_args_N=`expr $lt_dump_args_N + 1` - done -} - -# Core function for launching the target application -func_exec_program_core () -{ - - if test -n "$lt_option_debug"; then - $ECHO "busy:busy:$LINENO: newargv[0]: $progdir/$program" 1>&2 - func_lt_dump_args ${1+"$@"} 1>&2 - fi - exec "$progdir/$program" ${1+"$@"} - - $ECHO "$0: cannot exec $program $*" 1>&2 - exit 1 -} - -# A function to encapsulate launching the target application -# Strips options in the --lt-* namespace from $@ and -# launches target application with the remaining arguments. -func_exec_program () -{ - case " $* " in - *\ --lt-*) - for lt_wr_arg - do - case $lt_wr_arg in - --lt-*) ;; - *) set x "$@" "$lt_wr_arg"; shift;; - esac - shift - done ;; - esac - func_exec_program_core ${1+"$@"} -} - - # Parse options - func_parse_lt_options "$0" ${1+"$@"} - - # Find the directory that this script lives in. - thisdir=`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'` - test "x$thisdir" = "x$file" && thisdir=. - - # Follow symbolic links until we get to the real thisdir. - file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'` - while test -n "$file"; do - destdir=`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'` - - # If there was a directory component, then change thisdir. - if test "x$destdir" != "x$file"; then - case "$destdir" in - [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;; - *) thisdir="$thisdir/$destdir" ;; - esac - fi - - file=`$ECHO "$file" | /bin/sed 's%^.*/%%'` - file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'` - done - - # Usually 'no', except on cygwin/mingw when embedded into - # the cwrapper. - WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no - if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then - # special case for '.' - if test "$thisdir" = "."; then - thisdir=`pwd` - fi - # remove .libs from thisdir - case "$thisdir" in - *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /bin/sed 's%[\\/][^\\/]*$%%'` ;; - .libs ) thisdir=. ;; - esac - fi - - # Try to get the absolute directory name. - absdir=`cd "$thisdir" && pwd` - test -n "$absdir" && thisdir="$absdir" - - program='busy' - progdir="$thisdir/.libs" - - - if test -f "$progdir/$program"; then - # Add our own library path to LD_LIBRARY_PATH - LD_LIBRARY_PATH="/usr/local/src/MyProgs/finalcut/src/.libs:$LD_LIBRARY_PATH" - - # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH - # The second colon is a workaround for a bug in BeOS R4 sed - LD_LIBRARY_PATH=`$ECHO "$LD_LIBRARY_PATH" | /bin/sed 's/::*$//'` - - export LD_LIBRARY_PATH - - if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then - # Run the actual program with our arguments. - func_exec_program ${1+"$@"} - fi - else - # The program doesn't exist. - $ECHO "$0: error: '$progdir/$program' does not exist" 1>&2 - $ECHO "This script is just a wrapper for $program." 1>&2 - $ECHO "See the libtool documentation for more information." 1>&2 - exit 1 - fi -fi