Add a "user event" chapter to the first steps document
This commit is contained in:
parent
9845a022a3
commit
7749d28b92
|
@ -38,6 +38,7 @@ examples/.deps/
|
|||
examples/.libs/
|
||||
examples/calculator
|
||||
examples/dialog
|
||||
examples/busy
|
||||
examples/event-log
|
||||
examples/string-operations
|
||||
examples/background-color
|
||||
|
|
|
@ -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 <final/final.h>
|
||||
|
@ -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 <stdlib.h>
|
||||
#include <final/final.h>
|
||||
#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<LoadAvg*>(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();
|
||||
}
|
||||
```
|
||||
<figure class="image">
|
||||
<img src="first-steps_user-event.cpp.png" alt="user-event.cpp">
|
||||
<figcaption>Figure 5. User event generation</figcaption>
|
||||
</figure>
|
||||
<br /><br />
|
||||
|
||||
*(Note: You can close the window with the mouse,
|
||||
<kbd>Shift</kbd>+<kbd>F10</kbd> or <kbd>Ctrl</kbd>+<kbd>^</kbd>)*
|
||||
|
||||
|
||||
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[])
|
|||
```
|
||||
<figure class="image">
|
||||
<img src="first-steps_callback-function.cpp.png" alt="callback-function.cpp">
|
||||
<figcaption>Figure 5. Button with a callback function</figcaption>
|
||||
<figcaption>Figure 6. Button with a callback function</figcaption>
|
||||
</figure>
|
||||
<br /><br />
|
||||
|
||||
|
@ -588,7 +707,7 @@ int main (int argc, char* argv[])
|
|||
```
|
||||
<figure class="image">
|
||||
<img src="first-steps_callback-lambda.cpp.png" alt="callback-lambda.cpp">
|
||||
<figcaption>Figure 6. Button with lambda expression callback.</figcaption>
|
||||
<figcaption>Figure 7. Button with lambda expression callback.</figcaption>
|
||||
</figure>
|
||||
<br /><br />
|
||||
|
||||
|
@ -646,7 +765,7 @@ int main (int argc, char* argv[])
|
|||
```
|
||||
<figure class="image">
|
||||
<img src="first-steps_callback-method.cpp.png" alt="callback-method.cpp">
|
||||
<figcaption>Figure 7. Button with a callback method</figcaption>
|
||||
<figcaption>Figure 8. Button with a callback method</figcaption>
|
||||
</figure>
|
||||
<br /><br />
|
||||
|
||||
|
@ -790,7 +909,7 @@ int main (int argc, char* argv[])
|
|||
```
|
||||
<figure class="image">
|
||||
<img src="first-steps_emit-signal.cpp.png" alt="emit-signal.cpp">
|
||||
<figcaption>Figure 8. Callbacks with custom signals</figcaption>
|
||||
<figcaption>Figure 9. Callbacks with custom signals</figcaption>
|
||||
</figure>
|
||||
<br /><br />
|
||||
|
||||
|
@ -831,7 +950,7 @@ If you want to ignore padding spaces, you must force this with the
|
|||
|
||||
<figure class="image">
|
||||
<img src="widget-coordinates.svg" alt="widget coordinates">
|
||||
<figcaption>Figure 9. Widget coordinates</figcaption>
|
||||
<figcaption>Figure 10. Widget coordinates</figcaption>
|
||||
</figure>
|
||||
<br /><br />
|
||||
|
||||
|
@ -881,7 +1000,7 @@ methods.
|
|||
|
||||
<figure class="image">
|
||||
<img src="widget-lengths.svg" alt="widget lengths">
|
||||
<figcaption>Figure 10. Width and height of a widget</figcaption>
|
||||
<figcaption>Figure 11. Width and height of a widget</figcaption>
|
||||
</figure>
|
||||
<br /><br />
|
||||
|
||||
|
@ -934,7 +1053,7 @@ absolute geometry values as a `FRect` object, you can call the method
|
|||
|
||||
<figure class="image">
|
||||
<img src="widget-geometry.svg" alt="widget geometry">
|
||||
<figcaption>Figure 11. Geometry of widgets</figcaption>
|
||||
<figcaption>Figure 12. Geometry of widgets</figcaption>
|
||||
</figure>
|
||||
<br /><br />
|
||||
|
||||
|
@ -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[])
|
|||
```
|
||||
<figure class="image">
|
||||
<img src="first-steps_size-adjustment.cpp.png" alt="size-adjustment.cpp">
|
||||
<figcaption>Figure 12. Dynamic layout</figcaption>
|
||||
<figcaption>Figure 13. Dynamic layout</figcaption>
|
||||
</figure>
|
||||
<br /><br />
|
||||
|
||||
|
@ -1198,7 +1317,7 @@ int main (int argc, char* argv[])
|
|||
```
|
||||
<figure class="image">
|
||||
<img src="first-steps_scrollview.cpp.png" alt="scrollview.cpp">
|
||||
<figcaption>Figure 13. Dialog with a scrolling viewport</figcaption>
|
||||
<figcaption>Figure 14. Dialog with a scrolling viewport</figcaption>
|
||||
</figure>
|
||||
<br /><br />
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 586 B |
210
examples/busy
210
examples/busy
|
@ -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
|
Loading…
Reference in New Issue