pcp-gui-1.5.11/0000755000000000000000000000000012234612137010032 5ustar pcp-gui-1.5.11/GNUmakefile0000644000000000000000000000422312176111200012073 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # ifneq (,) This makefile requires GNU Make. endif TOPDIR = . -include $(TOPDIR)/src/include/builddefs CONFFILES = configure pcp-gui.lsm LSRCFILES = Makepkgs aclocal.m4 install-sh README VERSION \ configure.in pcp-gui.lsm.in LDIRT = config.log .dep config.status config.cache confdefs.h conftest* \ Logs/* built .census install.* install-dev.* *.gz \ install.manifest base_files.rpm docs_files.rpm conf_files LDIRDIRT = pcp-gui-* SUBDIRS = src qa m4 images doc man books debian build default :: default-pcp-gui pcp-gui : default-pcp-gui default-pcp-gui : configure-pcp-gui @for d in `echo $(SUBDIRS)`; do \ if test -d "$$d" ; then \ echo === $$d ===; \ $(MAKE) -C $$d default || exit $$?; \ fi; \ done install :: default-pcp-gui install-pcp-gui pack-pcp-gui : default-pcp-gui $(MAKE) -C build $@ install-pcp-gui : default-pcp-gui @for d in `echo $(SUBDIRS)`; do \ if test -d "$$d" ; then \ echo === $$d ===; \ $(MAKE) -C $$d install || exit $$?; \ fi; \ done $(INSTALL) -m 755 -d $(PKG_DOC_DIR) $(INSTALL) -m 644 pcp-gui.lsm README $(PKG_DOC_DIR) $(INSTALL) -m 755 -d $(PKG_BOOKS_DIR) $(INSTALL) -m 755 -d $(PKG_ICON_DIR) $(INSTALL) -m 755 -d $(PKG_DESKTOP_DIR) ifdef BUILDRULES include $(BUILDRULES) else # if src/include/builddefs doesn't exist, we are pristine (hence also clean) realclean distclean clean clobber: @true endif configure-pcp-gui: pcp-gui.lsm pcp-gui.lsm: configure pcp-gui.lsm.in ./configure configure : configure.in rm -fr config.cache autom4te.cache autoconf aclocal.m4: aclocal --acdir=`pwd`/m4 --output=$@ pcp-gui-1.5.11/Makepkgs0000755000000000000000000000665612176111200011525 0ustar #! /bin/sh # # Make whichever packages the system supports # # Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # LOGDIR=Logs clean=false verbose=false MAKE=${MAKE:-make} for opt in $* do case "$opt" in -clean|--clean) clean=true shift ;; -verbose|--verbose) verbose=true shift ;; -*) echo "Unknown option $opt" echo "Usage: Makepkgs [-clean] [-verbose]" exit 1 ;; *) break ;; esac done if [ $# = 0 ] ; then set -- pcp-gui fi test ! -d $LOGDIR && mkdir $LOGDIR rm -rf $LOGDIR/* > /dev/null 2>&1 tmp=/tmp/$$ trap "rm -f $tmp.*;" 0 1 2 3 15 if $clean; then echo "== clean, log is in $LOGDIR/clean" if $verbose ; then $MAKE clean 2>&1 | tee $LOGDIR/clean else $MAKE clean > $LOGDIR/clean 2>&1 || exit 1 fi if [ -f $tmp.failed ] ; then if ! $verbose ; then echo \"$MAKE clean\" failed, see log in $LOGDIR/clean tail $LOGDIR/clean fi exit 1 fi fi echo if [ ! -f ./configure ] then echo "== autoconf, log is in $LOGDIR/autoconf" autoconf 2>&1 >$LOGDIR/autoconf fi LOGF=$LOGDIR/pcp-gui . ./VERSION special=false ARCH=`uname -m | sed -e 's/i.86/ia32/'` VERS=`uname -s | cut -c-5` [ "$VERS" = MINGW ] && special=windows [ -f /etc/debian_version ] && special=debian if [ $special != false ] then LOGF=`pwd`/$LOGF if $verbose ; then $MAKE -j 1 configure-pcp-gui 2>&1 | tee -a $LOGF else $MAKE -j 1 configure-pcp-gui 2>&1 >> $LOGF fi echo echo "== src-link, log is in $LOGF" | tee -a $LOGF VERSION=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} SRCLINK_ROOT=`pwd`/pcp-gui-$VERSION if [ $special = debian ] ; then SRCLINK_ROOT=`pwd`/build/deb/pcp-gui-$VERSION fi export SRCLINK_ROOT rm -fr $SRCLINK_ROOT mkdir -p $SRCLINK_ROOT || exit 1 $MAKE -j 1 src-link-pcp-gui || exit 1 cd $SRCLINK_ROOT [ ! -f .census ] && touch .census if [ $special = debian ] then SUDO=${SUDO:-fakeroot} if $verbose ; then dpkg-buildpackage -r$SUDO | tee -a $LOGF else dpkg-buildpackage -r$SUDO >> $LOGF || exit 1 fi exit 0 fi # Fall through for MinGW (Win32) builds fi echo echo "== default, log is in $LOGF" if $verbose ; then st=`(($MAKE -j 1 default 2>&1; echo $? >&3) | tee $LOGF 1>&2) 3>&1` else $MAKE -j 1 default > $LOGF 2>&1; st=$? fi if [ $st -ne 0 ] ; then if ! $verbose ; then echo \"$MAKE default\" failed, see log in $LOGF tail $LOGF fi exit 1 fi rm -f files.rpm echo echo "== Packaging, log is in $LOGF" [ ! -f .census ] && touch .census if $verbose ; then ($MAKE -j 1 -C build pack 2>&1 || touch $tmp.failed) | tee -a $LOGF else ($MAKE -j 1 -C build pack 2>&1 || touch $tmp.failed) >> $LOGF fi if [ -f $tmp.failed ] ; then if ! $verbose ; then echo Packaging failed, see log in $LOGF tail $LOGF fi exit 1 else if ! $verbose ; then grep '^Wrote:' $LOGF | sed -e 's/\.\.\/\.\.\///' fi fi rm -f $tmp.failed exit 0 pcp-gui-1.5.11/aclocal.m40000644000000000000000000003145312176111200011666 0ustar # generated automatically by aclocal 1.11.1 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. # # Find format of installed man pages. # AC_DEFUN([AC_MANUAL_FORMAT], [ have_zipped_manpages=false have_bzip2ed_manpages=false eval export `grep PCP_MAN_DIR /etc/pcp.conf` if test -f "$PCP_MAN_DIR/man1/pcp.1.gz"; then have_zipped_manpages=true elif test -f "$PCP_MAN_DIR/man1/pcp.1.bz2"; then have_bzip2ed_manpages=true fi AC_SUBST(have_zipped_manpages) AC_SUBST(have_bzip2ed_manpages) ]) # # Generic macro, sets up all of the global packaging variables. # The following environment variables may be set to override defaults: # DEBUG OPTIMIZER MALLOCLIB PLATFORM DISTRIBUTION INSTALL_USER INSTALL_GROUP # BUILD_VERSION # AC_DEFUN([AC_PACKAGE_GLOBALS], [ pkg_name="$1" AC_SUBST(pkg_name) . ./VERSION pkg_major=$PKG_MAJOR pkg_minor=$PKG_MINOR pkg_revision=$PKG_REVISION pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} AC_SUBST(pkg_major) AC_SUBST(pkg_minor) AC_SUBST(pkg_revision) AC_SUBST(pkg_version) pkg_release=$PKG_BUILD test -z "$BUILD_VERSION" || pkg_release="$BUILD_VERSION" AC_SUBST(pkg_release) pkg_build_date=`date +%Y-%m-%d` AC_SUBST(pkg_build_date) DEBUG=${DEBUG:-'-DDEBUG'} dnl -DNDEBUG debug_build="$DEBUG" AC_SUBST(debug_build) OPTIMIZER=${OPTIMIZER:-'-g -O2'} opt_build="$OPTIMIZER" AC_SUBST(opt_build) pkg_user=`id -u -n root` test $? -eq 0 || pkg_user=`id -u -n` test -z "$INSTALL_USER" || pkg_user="$INSTALL_USER" AC_SUBST(pkg_user) pkg_group=`id -g -n root` test $? -eq 0 || pkg_group=`id -g -n` test -z "$INSTALL_GROUP" || pkg_group="$INSTALL_GROUP" AC_SUBST(pkg_group) pkg_distribution=unknown test -f /etc/SuSE-release && pkg_distribution=suse test -f /etc/fedora-release && pkg_distribution=fedora test -f /etc/redhat-release && pkg_distribution=redhat test -f /etc/debian_version && pkg_distribution=debian test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION" AC_SUBST(pkg_distribution) pkg_doc_dir=`eval echo $datadir` pkg_doc_dir=`eval echo $pkg_doc_dir/doc/pcp-gui` if test "`echo $pkg_doc_dir | sed 's;/.*\$;;'`" = NONE then if test -d /usr/share/doc then pkg_doc_dir=/usr/share/doc/pcp-gui else pkg_doc_dir=/usr/share/pcp-gui fi fi test -z "$DOCDIR" || pkg_doc_dir="$DOCDIR" AC_SUBST(pkg_doc_dir) pkg_books_dir=`eval echo $datadir` pkg_books_dir=`eval echo $pkg_books_dir/doc/pcp-doc` if test "`echo $pkg_books_dir | sed 's;/.*\$;;'`" = NONE then if test -d /usr/share/doc then pkg_books_dir=/usr/share/doc/pcp-doc else pkg_books_dir=/usr/share/pcp-doc fi fi test -z "$BOOKSDIR" || pkg_books_dir="$BOOKSDIR" AC_SUBST(pkg_books_dir) pkg_icon_dir=`eval echo $datadir` pkg_icon_dir=`eval echo $pkg_icon_dir/pixmaps` if test "`echo $pkg_icon_dir | sed 's;/.*\$;;'`" = NONE then if test -d /usr/share/doc then pkg_icon_dir=/usr/share/doc/pcp-gui/pixmaps else pkg_icon_dir=/usr/share/pcp-gui/pixmaps fi fi test -z "$ICONDIR" || pkg_icon_dir="$ICONDIR" AC_SUBST(pkg_icon_dir) ]) # # Check if we have a pcp/pmapi.h installed # AC_DEFUN([AC_PACKAGE_NEED_PMAPI_H], [ AC_CHECK_HEADERS(pcp/pmapi.h) if test $ac_cv_header_pcp_pmapi_h = no; then echo echo 'FATAL ERROR: could not find a valid header.' exit 1 fi ]) # # Check if we have a pcp/pmda.h installed # AC_DEFUN([AC_PACKAGE_NEED_PMDA_H], [ AC_CHECK_HEADERS([pcp/pmda.h], [], [], [[#include #include ]]) if test $ac_cv_header_pcp_pmda_h = no; then echo echo 'FATAL ERROR: could not find a valid header.' exit 1 fi ]) # # Check if we have the pmNewContext routine in libpcp # AC_DEFUN([AC_PACKAGE_NEED_LIBPCP], [ AC_CHECK_LIB(pcp, pmNewContext,, [ echo echo 'FATAL ERROR: could not find a PCP library (libpcp).' exit 1 ]) libpcp=-lpcp AC_SUBST(libpcp) ]) # # Check if we have the __pmSetProgname routine in libpcp # AC_DEFUN([AC_PACKAGE_HAVE_PM_SET_PROGNAME], [ AC_CHECK_LIB(pcp, __pmSetProgname, [ have_pm_set_progname=1 ], [ have_pm_set_progname=0 ]) AC_SUBST(have_pm_set_progname) ]) # # Check if we have the __pmPathSeparator routine in libpcp # AC_DEFUN([AC_PACKAGE_HAVE_PM_PATH_SEPARATOR], [ AC_CHECK_LIB(pcp, __pmPathSeparator, [ have_pm_path_separator=1 ], [ have_pm_path_separator=0 ]) AC_SUBST(have_pm_path_separator) ]) # # Check if we have the __pmtimevalNow routine in libpcp # AC_DEFUN([AC_PACKAGE_HAVE_PM_TIMEVAL_NOW], [ AC_CHECK_LIB(pcp, __pmtimevalNow, [ have_pm_timeval_now=1 ], [ have_pm_timeval_now=0 ]) AC_SUBST(have_pm_timeval_now) ]) # # Check if we have the PM_TYPE_EVENT macro in pmapi.h # AC_DEFUN([AC_PACKAGE_HAVE_PM_TYPE_EVENT], [ AC_CHECK_DECLS(PM_TYPE_EVENT, [], [], [[#include ]]) ]) # # Check if we have the PM_CTXFLAG_SECURE macro in pmapi.h # AC_DEFUN([AC_PACKAGE_HAVE_PM_CTXFLAG_SECURE], [ AC_CHECK_DECLS(PM_CTXFLAG_SECURE, [], [], [[#include ]]) ]) # # Check if we have the PM_CTXFLAG_AUTH macro in pmapi.h # AC_DEFUN([AC_PACKAGE_HAVE_PM_CTXFLAG_AUTH], [ AC_CHECK_DECLS(PM_CTXFLAG_AUTH, [], [], [[#include ]]) ]) # # Check if we have the pmdaMain routine in libpcp_pmda # AC_DEFUN([AC_PACKAGE_NEED_LIBPCP_PMDA], [ AC_CHECK_LIB(pcp_pmda, pmdaMain,, [ echo echo 'FATAL ERROR: could not find a PCP PMDA library (libpcp_pmda).' exit 1 ]) libpcp_pmda=-lpcp_pmda AC_SUBST(libpcp_pmda) ]) AC_DEFUN([AC_PACKAGE_NEED_QT_QMAKE], [ if test -x "$QTDIR/bin/qmake.exe"; then QMAKE="$QTDIR/bin/qmake.exe" fi if test -z "$QMAKE"; then AC_PATH_PROGS(QMAKE, [qmake-qt4 qmake],, [$QTDIR/bin:/usr/bin:/usr/lib64/qt4/bin:/usr/lib/qt4/bin]) fi qmake=$QMAKE AC_SUBST(qmake) AC_PACKAGE_NEED_UTILITY($1, "$qmake", qmake, [Qt make]) ]) AC_DEFUN([AC_PACKAGE_NEED_QT_VERSION4], [ AC_MSG_CHECKING([Qt version]) eval `$qmake --version | awk '/Using Qt version/ { ver=4; print $ver }' | awk -F. '{ major=1; minor=2; point=3; printf "export QT_MAJOR=%d QT_MINOR=%d QT_POINT=%d\n",$major,$minor,$point }'` if test "$QT_MAJOR" -lt 4 ; then echo echo FATAL ERROR: Qt version 4 does not seem to be installed. echo Cannot proceed with the Qt $QT_MAJOR installation found. exit 1 fi if test "$QT_MAJOR" -eq 4 -a "$QT_MINOR" -lt 4 ; then echo echo FATAL ERROR: Qt version 4.$QT_MINOR is too old. echo Qt version 4.4 or later is required. exit 1 fi AC_MSG_RESULT([$QT_MAJOR.$QT_MINOR.$QT_POINT]) ]) AC_DEFUN([AC_PACKAGE_NEED_QT_UIC], [ if test -z "$UIC"; then AC_PATH_PROGS(UIC, [uic-qt4 uic],, [$QTDIR/bin:/usr/bin:/usr/lib64/qt4/bin:/usr/lib/qt4/bin]) fi uic=$UIC AC_SUBST(uic) AC_PACKAGE_NEED_UTILITY($1, "$uic", uic, [Qt User Interface Compiler]) ]) AC_DEFUN([AC_PACKAGE_NEED_QT_MOC], [ if test -z "$MOC"; then AC_PATH_PROGS(MOC, [moc-qt4 moc],, [$QTDIR/bin:/usr/bin:/usr/lib64/qt4/bin:/usr/lib/qt4/bin]) fi moc=$MOC AC_SUBST(moc) AC_PACKAGE_NEED_UTILITY($1, "$uic", uic, [Qt Meta-Object Compiler]) ]) # # Check for specified utility (env var) - if unset, fail. # AC_DEFUN([AC_PACKAGE_NEED_UTILITY], [ if test -z "$2"; then echo echo FATAL ERROR: $3 does not seem to be installed. echo $1 cannot be built without a working $4 installation. exit 1 fi ]) # # Generic macro, sets up all of the global build variables. # The following environment variables may be set to override defaults: # MAKE TAR BZIP2 MAKEDEPEND AWK SED ECHO SORT RPMBUILD DPKG LEX YACC # AC_DEFUN([AC_PACKAGE_UTILITIES], [ AC_PROG_CXX AC_PACKAGE_NEED_UTILITY($1, "$CXX", cc, [C++ compiler]) if test -z "$MAKE"; then AC_PATH_PROG(MAKE, mingw32-make,, /mingw/bin:/usr/bin:/usr/local/bin) fi if test -z "$MAKE"; then AC_PATH_PROG(MAKE, gmake,, /usr/bin:/usr/local/bin) fi if test -z "$MAKE"; then AC_PATH_PROG(MAKE, make,, /usr/bin) fi make=$MAKE AC_SUBST(make) AC_PACKAGE_NEED_UTILITY($1, "$make", make, [GNU make]) if test -z "$TAR"; then AC_PATH_PROG(TAR, tar,, /bin:/usr/local/bin:/usr/bin) fi tar=$TAR AC_SUBST(tar) if test -z "$ZIP"; then AC_PATH_PROG(ZIP, gzip,, /bin:/usr/bin:/usr/local/bin) fi zip=$ZIP AC_SUBST(zip) if test -z "$BZIP2"; then AC_PATH_PROG(BZIP2, bzip2,, /bin:/usr/bin:/usr/local/bin) fi bzip2=$BZIP2 AC_SUBST(bzip2) if test -z "$MAKEDEPEND"; then AC_PATH_PROG(MAKEDEPEND, makedepend, /bin/true) fi makedepend=$MAKEDEPEND AC_SUBST(makedepend) if test -z "$AWK"; then AC_PATH_PROG(AWK, awk,, /bin:/usr/bin) fi awk=$AWK AC_SUBST(awk) if test -z "$SED"; then AC_PATH_PROG(SED, sed,, /bin:/usr/bin) fi sed=$SED AC_SUBST(sed) if test -z "$ECHO"; then AC_PATH_PROG(ECHO, echo,, /bin:/usr/bin) fi echo=$ECHO AC_SUBST(echo) if test -z "$SORT"; then AC_PATH_PROG(SORT, sort,, /bin:/usr/bin) fi sort=$SORT AC_SUBST(sort) dnl check if symbolic links are supported AC_PROG_LN_S dnl check if rpmbuild is available if test -z "$RPMBUILD" then AC_PATH_PROG(RPMBUILD, rpmbuild) fi rpmbuild=$RPMBUILD AC_SUBST(rpmbuild) dnl check if the dpkg program is available if test -z "$DPKG" then AC_PATH_PROG(DPKG, dpkg) fi dpkg=$DKPG AC_SUBST(dpkg) dnl Check for the MacOSX PackageMaker AC_MSG_CHECKING([for PackageMaker]) if test -z "$PACKAGE_MAKER" then devapps=/Developer/Applications darwin6=${devapps}/PackageMaker.app/Contents/MacOS darwin7=${devapps}/Utilities/PackageMaker.app/Contents/MacOS if test -x ${darwin6}/PackageMaker then package_maker=${darwin6}/PackageMaker AC_MSG_RESULT([ yes (darwin 6.x)]) elif test -x ${darwin7}/PackageMaker then AC_MSG_RESULT([ yes (darwin 7.x)]) package_maker=${darwin7}/PackageMaker else AC_MSG_RESULT([ no]) fi else package_maker="$PACKAGE_MAKER" fi AC_SUBST(package_maker) dnl check if the MacOSX hdiutil program is available test -z "$HDIUTIL" && AC_PATH_PROG(HDIUTIL, hdiutil) hdiutil=$HDIUTIL AC_SUBST(hdiutil) AC_ARG_WITH( [books], [AC_HELP_STRING([--with-books], [enable building of the PCP books (default is off)])], [do_books=$withval; PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --with-books=$withval"], [do_books=off]) dnl check if a toolchain is available for the books test -z "$PUBLICAN" && AC_PATH_PROG(PUBLICAN, publican) publican=$PUBLICAN AC_SUBST(publican) test -z "$DBLATEX" && AC_PATH_PROG(DBLATEX, dblatex) dblatex=$DBLATEX AC_SUBST(dblatex) test -z "$XMLTO" && AC_PATH_PROG(XMLTO, xmlto) xmlto=$XMLTO AC_SUBST(xmlto) book_toolchain="" if test "$do_books" = "check" -o "$do_books" = "yes" then if test "$BOOK_TOOLCHAIN" != "" then book_toolchain=$BOOK_TOOLCHAIN elif test "$DBLATEX" != "" then book_toolchain=dblatex elif test "$PUBLICAN" != "" then book_toolchain=publican elif test "$XMLTO" != "" then book_toolchain=xmlto elif test "$do_books" = "yes" then AC_MSG_ERROR(cannot enable books build - no toolchain found) fi fi AC_SUBST(book_toolchain) dnl check if user wants their own lex, yacc AC_PROG_YACC yacc=$YACC AC_SUBST(yacc) AC_PROG_LEX lex=$LEX AC_SUBST(lex) dnl extra check for lex and yacc as these are often not installed AC_MSG_CHECKING([if yacc is executable]) binary=`echo $yacc | awk '{cmd=1; print $cmd}'` binary=`which "$binary"` if test -x "$binary" then AC_MSG_RESULT([ yes]) else AC_MSG_RESULT([ no]) echo echo "FATAL ERROR: did not find a valid yacc executable." echo "You can either set \$YACC as the full path to yacc" echo "in the environment, or install a yacc/bison package." exit 1 fi AC_MSG_CHECKING([if lex is executable]) binary=`echo $lex | awk '{cmd=1; print $cmd}'` binary=`which "$binary"` if test -x "$binary" then AC_MSG_RESULT([ yes]) else AC_MSG_RESULT([ no]) echo echo "FATAL ERROR: did not find a valid lex executable." echo "You can either set \$LEX as the full path to lex" echo "in the environment, or install a lex/flex package." exit 1 fi ]) pcp-gui-1.5.11/install-sh0000755000000000000000000001547312176111204012042 0ustar #!/bin/sh # # Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA # # This script emulates bsd install and also recognises # two environment variables, with the following semanitcs :- # # $DIST_MANIFEST - if set, the name of the file to append manifest # information in the following format: # File : f mode owner group src target # Diretory: d mode owner group target # Symlink : l linkval target # # $DIST_ROOT - if set, prepend to target # # The sematics of all combinations of these two variables # are as follows: # # $DIST_MANIFEST? $DIST_ROOT? | Copy? Append Manifest? # -----------------------------+-------------------------- # not set not set | yes no # not set set | yes no # set not set | no yes # set set | yes yes _usage() { echo "Usage: $prog [-o owner] [-g group] [-m mode] -d directory" echo "or $prog [-o owner] [-g group] [-m mode] file directory/file" echo "or $prog [-o owner] [-g group] [-m mode] file file [file ...] directory" echo "or $prog -S file target (creates \"target\" symlink)" echo "" echo "The \$DIST_MANIFEST and \$DIST_ROOT environment variables affect the" echo "behaviour of this command - see comments in the script." echo "" exit 1 } _chown () { _st=255 if [ $# -eq 3 ] ; then chown $1:$2 $3 _st=$? if [ $_st -ne 0 ] ; then if [ $REAL_UID != '0' ] ; then if [ ! -f $DIST_ROOT/.chown.quite ] ; then echo '===============================================' echo Ownership of files under ${DIST_ROOT:-/} echo cannot be changed echo '===============================================' if [ -n "$DIST_ROOT" ] ; then touch $DIST_ROOT/.chown.quite fi fi _st=0 fi fi fi return $_st } _manifest () { echo $* | sed -e 's/\/\//\//g' >>${DIST_MANIFEST:-/dev/null} } ID=id # Test to use the functional id on Solaris test -f /usr/xpg4/bin/id && ID=/usr/xpg4/bin/id prog=`basename $0` HERE=`pwd` dflag=false Sflag=false DIRMODE=755 FILEMODE=644 OWNER=`$ID -u 2>/dev/null` GROUP=`$ID -g 2>/dev/null` if [ -z "$OWNER" -o -z "$GROUP" ] then # do it the hardway # OWNER=`$ID | sed -e 's/.*uid=[^(]*(//' -e 's/).*//'` GROUP=`$ID | sed -e 's/.*gid=[^(]*(//' -e 's/).*//'` fi REAL_UID=$OWNER # default is to install and don't append manifest INSTALL=true MANIFEST=: [ -n "$DIST_MANIFEST" -a -z "$DIST_ROOT" ] && INSTALL=false [ -n "$DIST_MANIFEST" ] && MANIFEST="_manifest" [ $# -eq 0 ] && _usage if $INSTALL then RM=rm; CP=cp; LN=ln; MKDIR=mkdir; CHMOD=chmod; CHOWN=_chown else RM=true; CP=true; LN=true; MKDIR=true; CHMOD=true; CHOWN=true fi [ -n "$DIST_ROOT" -a $REAL_UID -ne 0 ] && CHOWN=true while getopts "d:g:m:o:S:" c $* do case $c in d) dir=`echo $DIST_ROOT/$OPTARG | sed -e 's;//*;/;g'` dflag=true ;; g) GROUP=$OPTARG ;; m) DIRMODE=`expr $OPTARG` FILEMODE=$DIRMODE ;; o) OWNER=$OPTARG ;; S) symlink=$OPTARG Sflag=true ;; *) _usage ;; esac done shift `expr $OPTIND - 1` status=0 if $dflag then # # first usage # $MKDIR -p $dir status=$? if [ $status -eq 0 ] then $CHMOD $DIRMODE $dir status=$? fi if [ $status -eq 0 ] then $CHOWN $OWNER $GROUP $dir status=$? fi $MANIFEST d $DIRMODE $OWNER $GROUP `echo "$dir" | sed -e "s;^$DIST_ROOT;;"` elif $Sflag then # # fourth usage (symlink) # if [ $# -ne 1 ] then _usage else target=`echo $DIST_ROOT/$1 | sed -e 's;//*;/;g'` fi $RM -f $target dir=`dirname $target | sed -e 's;//*;/;g'` [ ! -d $dir ] && mkdir -p $dir $LN -s -f $symlink $target status=$? $MANIFEST l $symlink `echo "$target" | sed -e "s;^$DIST_ROOT;;"` else list="" dir="" if [ $# -eq 2 ] then # # second usage: install file dir/name # target 'name' is not necessarily the same as 'file' # (Note: install file dir is ambiguous and not supported # f=$1 dir=$DIST_ROOT/`dirname $2` dir=`echo $dir | sed -e 's;//*;/;g'` t_dir=`echo "$dir" | sed -e "s;^$DIST_ROOT;;" | sed -e 's;//*;/;g'` destfile=`basename $2` if [ -f $f -a -f $f.exe ] then # Cygwin hack ... executables present as foo and foo.exe, # the foo one is visible to test(1) and ls(1), but not to # cat(1)/cp(1) ... need to $RM/$CP the foo.exe one # if cat $f >/dev/null 2>&1 then : else f=$f.exe destfile=$destfile.exe fi fi [ ! -d $dir ] && mkdir -p $dir if [ -d $dir/$destfile ] then echo ERROR: unsupported install usage _usage exit 1 else $RM -f $dir/$destfile fi $CP $f $dir/$destfile status=$? if [ $status -eq 0 ] then [ ! -d $dir/$destfile ] && $CHMOD $FILEMODE $dir/$destfile status=$? if [ $status -eq 0 ] then $CHOWN $OWNER $GROUP $dir/$destfile status=$? fi $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f $t_dir/$destfile fi [ $status -ne 0 ] && break else # # third usage: install file file [file ...] directory # n=1 while [ $# -gt 0 ] do if [ $# -gt 1 ] then list="$list $1" else dir=`echo $DIST_ROOT/$1 | sed -e 's;//*;/;g'` fi shift done # At this stage, $list is the list of files to install # in $dir. We create $dir if necessary # t_dir is for the manifest, i.e. without $DIST_ROOT prefix t_dir=`echo "$dir" | sed -e "s;^$DIST_ROOT;;"` for f in $list do if [ -f $f -a -f $f.exe ] then # Cygwin hack ... executables present as foo and foo.exe, # the foo one is visible to test(1) and ls(1), but not to # cat(1)/cp(1) ... need to $RM/$CP the foo.exe one # if cat $f >/dev/null 2>&1 then : else f=$f.exe fi fi [ ! -d $dir ] && mkdir -p $dir $RM -f $dir/$f $CP $f $dir/$f status=$? if [ $status -eq 0 ] then $CHMOD $FILEMODE $dir/$f status=$? if [ $status -eq 0 ] then $CHOWN $OWNER $GROUP $dir/$f status=$? fi $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f $t_dir/$f fi [ $status -ne 0 ] && break done fi fi exit $status pcp-gui-1.5.11/README0000644000000000000000000000455212176111200010706 0ustar PCP GUI pmchart is designed to produce stripcharts from Performance Co-Pilot (PCP) performance metrics fetched from live sources (one or more pmcd hosts) and also historical sources (one or more PCP archives). pmtime is a graphical time controller utility that coordinates time updates and VCR-like playback for other utilities like pmchart and pmval. Instructions on building these tools can be found in doc/INSTALL. Consult http://oss.sgi.com/projects/pcp/ for additional details about these tools. === Planned for 2.0 === - Movable charts (drag & drop) - Chart gadget (with Y-axis - pmgadgets-like) - Bar gadget (horizonal/vertical - pmgadgets/gmemusage/grosview-like) - LED gadget (pmgadgets-like) - Label gadget (pmgadgets-like) - Value gadget (new - optionally use QLCDNumber) - Extended pmchart view format - chart positioning - gadget panels - "include " syntax (for Overview view, and people like Nigel generating their own 'composite' views) - support the pmgadgets configuration file syntax - Need to regenerate many screenshots (Tutorial/Manual) with whatever the final windows look like. === Wishlist TODO items === - Merge Qwt 5.1 sources. - The Qt-based metrics class needs: o A hash for metric instance values instead of an array (to support delete, and better support of dynamic indoms) - pmtime should send a message to all clients on show/hide (except for the client that explicitly requested the show/hide, if there was one) - this would let the clients correctly track whether it is visible/not (pmchart displays this state in the Options menu, and uses that state to decide whether a hide/show is needed). - Extend pmdumptext to use an abstracted pmtime class for pmtime VCR control. - Extend pmdumptext to allow input to drive pmtime remotely (will need to allow SET message from clients at any time, not just on initial exchange) and use this to automate QA of pmtime. - Write automated QA for Save View (need a new command line option), then with -C and -c, open (multiple) views, save, then verify. - pmquery window initial sizing and resizing could use improvement. - pmview code released by SGI - needs porting work www.coin3d.org have an Inventor-compatible API, Qt bindings, and support Mac/Windows/Linux - looks ideal for this. pcp-gui-1.5.11/VERSION0000644000000000000000000000016412234611044011077 0ustar # # This file is used by configure to get version information # PKG_MAJOR=1 PKG_MINOR=5 PKG_REVISION=11 PKG_BUILD=1 pcp-gui-1.5.11/configure.in0000644000000000000000000000232312176111202012333 0ustar AC_INIT(VERSION) AC_PREFIX_DEFAULT(/usr) AC_PACKAGE_GLOBALS(pcp-gui) AC_PACKAGE_UTILITIES(pcp-gui) AC_PACKAGE_NEED_QT_QMAKE AC_PACKAGE_NEED_QT_VERSION4 dnl Debug/release style build? (non-debug by default) qt_release=release test -z "$QT_RELEASE" || qt_release="$QT_RELEASE" AC_SUBST(qt_release) pcp_dir="" if test -n "$PCP_DIR"; then pcp_dir="$PCP_DIR" export CPPFLAGS="$CPPFLAGS -I$PCP_DIR/include -I$PCP_DIR/local/include" export CFLAGS="$CFLAGS -I$PCP_DIR/include -I$PCP_DIR/local/include" export LDFLAGS="$LDFLAGS -L$PCP_DIR/bin -L$PCP_DIR/local/bin -L$PCP_DIR/lib" export PATH="$PATH:$PCP_DIR/bin:$PCP_DIR/local/bin" fi AC_SUBST(pcp_dir) AC_PACKAGE_NEED_PMAPI_H AC_PACKAGE_NEED_LIBPCP AC_PACKAGE_HAVE_PM_TYPE_EVENT AC_PACKAGE_HAVE_PM_TIMEVAL_NOW AC_PACKAGE_HAVE_PM_SET_PROGNAME AC_PACKAGE_HAVE_PM_PATH_SEPARATOR AC_PACKAGE_HAVE_PM_CTXFLAG_SECURE AC_PACKAGE_HAVE_PM_CTXFLAG_AUTH AC_MANUAL_FORMAT AC_OUTPUT( \ src/include/builddefs \ src/include/version.h \ src/libqmc/libqmc.pro \ src/libqwt/libqwt.pro \ src/dumptext/pmdumptext.pro \ src/query/pmquery.info \ src/query/pmquery.pro \ src/chart/pmchart.info \ src/chart/pmchart.pro \ src/time/pmtime.info \ src/time/pmtime.pro \ pcp-gui.lsm ) pcp-gui-1.5.11/pcp-gui.lsm.in0000644000000000000000000000122612176111207012516 0ustar Begin4 Title: Performance Co-Pilot visualisation tools Version: @pkg_version@ Entered-date: @pkg_build_date@ Description: Visualisation tools for displaying PCP metric values. Keywords: performance, monitoring, system, distributed, visualisation Author: pcp@oss.sgi.com (Performance Co-Pilot Development Team) Maintained-by: pcp@oss.sgi.com (Performance Co-Pilot Development Team) Primary-site: ftp://oss.sgi.com/www/projects/pcp/download/ Alternate-site: Original-site: ftp://oss.sgi.com/www/projects/pcp/download/ Platforms: Linux, MacOSX, AIX, Solaris, FreeBSD, Windows Copying-policy: GPL (libraries are LGPL) End pcp-gui-1.5.11/src/0000755000000000000000000000000012234612131010613 5ustar pcp-gui-1.5.11/src/GNUmakefile0000644000000000000000000000030312176111211012657 0ustar TOPDIR = .. include $(TOPDIR)/src/include/builddefs SUBDIRS = include libqmc libqwt chart dumptext pmafm query snap time default install: $(SUBDIRS) $(SUBDIRS_MAKERULE) include $(BUILDRULES) pcp-gui-1.5.11/src/include/0000755000000000000000000000000012234612137012244 5ustar pcp-gui-1.5.11/src/include/GNUmakefile0000644000000000000000000000033412176111212014307 0ustar TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs HFILES = pmtime.h CONFFILES = builddefs version.h LSRCFILES = builddefs.in version.h.in buildmacros buildrules default install install-dev: include $(BUILDRULES) pcp-gui-1.5.11/src/include/pmtime.h0000644000000000000000000000636012176111212013706 0ustar /* * Copyright (c) 2006-2009, Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef PMTIME_H #define PMTIME_H #include class QIcon; class PmTime { public: typedef enum { StoppedState = 0, ForwardState = 1, BackwardState = 2, } State; typedef enum { StepMode = 0, NormalMode = 1, FastMode = 2, } Mode; typedef enum { NoSource = -1, HostSource = 0, ArchiveSource = 1, } Source; typedef enum { Set = (1<<0), // client -> server Step = (1<<1), // server -> clients TZ = (1<<2), // server -> clients VCRMode = (1<<3), // server -> clients VCRModeDrag = (1<<4), // server -> clients GUIShow = (1<<5), // client -> server GUIHide = (1<<6), // client -> server Bounds = (1<<7), // client -> server ACK = (1<<8), // client -> server (except handshake) } Command; static const unsigned int Magic = 0x54494D45; // "TIME" typedef struct { unsigned int magic; unsigned int length; PmTime::Command command; PmTime::Source source; PmTime::State state; PmTime::Mode mode; struct timeval delta; struct timeval position; struct timeval start; // archive only struct timeval end; // archive only unsigned char data[0]; // arbitrary length (e.g. $TZ) } Packet; typedef enum { ForwardOn, ForwardOff, StoppedOn, StoppedOff, BackwardOn, BackwardOff, FastForwardOn, FastForwardOff, FastBackwardOn, FastBackwardOff, StepForwardOn, StepForwardOff, StepBackwardOn, StepBackwardOff, IconCount } Icon; typedef enum { Milliseconds, Seconds, Minutes, Hours, Days, Weeks, } DeltaUnits; typedef enum { DebugApp = 0x1, DebugProtocol = 0x2, } DebugOptions; static const int BasePort = 43334; static const int FastModeDelay = 100; // milliseconds static const int DefaultDelta = 2; // seconds static QIcon *icon(PmTime::Icon); static double defaultSpeed(double delta) { return 2.0 * delta; } // num deltas per second static double minimumSpeed(double delta) { return 0.1 * delta; } // min deltas per second static double maximumSpeed(double delta) { return 1000.0 * delta; } // max deltas per second static void timevalAdd(struct timeval *a, struct timeval *b); static void timevalSub(struct timeval *a, struct timeval *b); static int timevalNonZero(struct timeval *a); static int timevalCompare(struct timeval *a, struct timeval *b); static void secondsToTimeval(double value, struct timeval *tv); static double secondsFromTimeval(struct timeval *tv); static double unitsToSeconds(double value, DeltaUnits units); static double secondsToUnits(double value, DeltaUnits units); static QString deltaString(double value, DeltaUnits units); static double deltaValue(QString delta, DeltaUnits units); }; #endif // PMTIME_H pcp-gui-1.5.11/src/include/builddefs.in0000644000000000000000000000373212213235215014535 0ustar # # Copyright (c) 2004-2006 Silicon Graphics, Inc. # All Rights Reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # @configure_input@ # ifndef _BUILDDEFS_INCLUDED_ _BUILDDEFS_INCLUDED_ = 1 include @pcp_dir@/etc/pcp.conf SHELL = /bin/sh LIBPCP = @libpcp@ PCP_DIR = @pcp_dir@ prefix = @prefix@ datadir = @datadir@ datarootdir = @datarootdir@ exec_prefix = @exec_prefix@ PKG_NAME = @pkg_name@ PKG_USER = @pkg_user@ PKG_GROUP = @pkg_group@ PKG_RELEASE = @pkg_release@ PKG_VERSION = @pkg_version@ PKG_MAJOR = @pkg_major@ PKG_MINOR = @pkg_minor@ PKG_REVISION = @pkg_revision@ PKG_PLATFORM = $(PCP_PLATFORM) PKG_DISTRIBUTION= @pkg_distribution@ PKG_BIN_DIR = $(PCP_BIN_DIR) PKG_MAN_DIR = $(PCP_MAN_DIR) PKG_DEMOS_DIR = $(PCP_DEMOS_DIR) PKG_BOOKS_DIR = @pkg_books_dir@ PKG_ICON_DIR = @pkg_icon_dir@ PKG_DOC_DIR = @pkg_doc_dir@ PKG_DESKTOP_DIR = $(datadir)/applications QMAKE = @qmake@ AWK = @awk@ SED = @sed@ TAR = @tar@ ZIP = @zip@ BZIP2 = @bzip2@ #NB: don't override $(MAKE); gnumake sets it well, propagating -j etc. #MAKE = @make@ LEX = @lex@ YACC = @yacc@ ECHO = @echo@ SORT = @sort@ LN_S = @LN_S@ RPMBUILD = @rpmbuild@ PACKAGE_MAKER = @package_maker@ HDIUTIL = @hdiutil@ DPKG = @dpkg@ XMLTO = @xmlto@ DBLATEX = @dblatex@ PUBLICAN = @publican@ BOOK_TOOLCHAIN = @book_toolchain@ QT_RELEASE = @qt_release@ HAVE_PM_SET_PROGNAME = @have_pm_set_progname@ HAVE_ZIPPED_MANPAGES = @have_zipped_manpages@ HAVE_BZIP2ED_MANPAGES = @have_bzip2ed_manpages@ include $(TOPDIR)/src/include/buildmacros endif # # For targets that should always be rebuilt, # define a target that is never up-to-date. # Targets needing this should depend on $(_FORCE) _FORCE = __force_build pcp-gui-1.5.11/src/include/version.h.in0000644000000000000000000000342012176111212014477 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2006-2010, Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * @configure_input@ */ #ifndef VERSION_H #define VERSION_H #include #define VERSION "@pkg_version@" #define HTMLDIR "@pkg_books_dir@/html" #define PM_USE_CONTEXT_LOCAL 1 #define HAVE_PM_SET_PROGNAME @have_pm_set_progname@ #if HAVE_PM_SET_PROGNAME == 0 #include extern char *pmProgname; static inline void __pmSetProgname(char *p) { pmProgname = basename(p); } #endif #define HAVE_PM_PATH_SEPARATOR @have_pm_path_separator@ #if HAVE_PM_PATH_SEPARATOR == 0 static inline int __pmPathSeparator(void) { return '/'; } #endif #define HAVE_PM_TIMEVAL_NOW @have_pm_timeval_now@ #if HAVE_PM_TIMEVAL_NOW == 0 #include static inline void __pmtimevalNow(struct timeval *t) { gettimeofday(t, NULL); } #endif #if HAVE_DECL_PM_TYPE_EVENT == 0 #define PM_TYPE_EVENT 9 static inline void pmUnpackEventRecords(pmResult **) { } static inline int pmFreeEventResult(pmValueSet *, int, pmResult ***) { return -ENOSYS; } #endif #if HAVE_DECL_PM_CTXFLAG_SECURE == 0 #define PM_CTXFLAG_SECURE (1U<<10) #define PM_CTXFLAG_COMPRESS (1U<<11) #define PM_CTXFLAG_RELAXED (1U<<12) #endif #if HAVE_DECL_PM_CTXFLAG_AUTH == 0 #define PM_CTXFLAG_AUTH (1U<<13) #endif #endif // VERSION_H pcp-gui-1.5.11/src/include/buildmacros0000644000000000000000000000442412213235215014472 0ustar # # Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. # BUILDRULES = $(TOPDIR)/src/include/buildrules MAKEOPTS = --no-print-directory # NB: don't use $(MAKEF), since that suppresses gnumake's subdir parallelization #MAKEF = $(MAKE) $(MAKEOPTS) SRCFILES = GNUmakefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES) ifdef PROJECT QTDIRDIRT = build debug release .obj .ui .moc .qrc *.xcodeproj *.app QTDIRT = *.a *.o ui_* moc_* qrc_* Info.plist Makefile* object_script.* endif DEPDIRT = dep dep.bak MANDIRT = *.[1-9].gz PODIRT = *.tmpo *.mo CDIRT = $(OBJECTS) $(LTOBJECTS) $(LTCOMMAND) $(LTLIBRARY) DIRT = $(LDIRT) $(DEPDIRT) $(MANDIRT) $(PODIRT) $(QTDIRT) $(CDIRT) DIRDIRT = $(LDIRDIRT) $(QTDIRDIRT) INSTALL = $(TOPDIR)/install-sh -o $(PKG_USER) -g $(PKG_GROUP) ifeq "$(PCP_PLATFORM)" "mingw" INSTALL_MAN = else INSTALL_MAN = \ @for d in $(MAN_PAGES); do \ first=true; \ for m in `$(AWK) \ '/^\.S[h|H] NAME/ {ok=1; next} ok {print; exit}' $$d \ | $(SED) \ -e 's/^\.Nm //' -e 's/,/ /g' -e 's/\\-.*//' \ -e 's/\\\f[0-9]//g' -e 's/ / /g;q'`; \ do \ [ -z "$$m" -o "$$m" = "\\" ] && continue; \ t=$(MAN_DEST)/$$m.$(MAN_SECTION); \ if $$first; then \ if $(HAVE_ZIPPED_MANPAGES); then \ $(ZIP) -9 -c $$d > $$d.gz; _sfx=.gz; \ fi; \ if $(HAVE_BZIP2ED_MANPAGES) ; then \ $(BZIP2) -c $$d > $$d.bz2; _sfx=.bz2; \ fi; \ u=$$m.$(MAN_SECTION)$$_sfx; \ echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx;\ $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ else \ echo $(INSTALL) -S $$u $${t}$$_sfx; \ $(INSTALL) -S $$u $${t}$$_sfx; \ fi; \ first=false; \ done; \ done endif SUBDIRS_MAKERULE = \ +for d in $(SUBDIRS) ""; do \ if test -d "$$d" -a ! -z "$$d"; then \ $(ECHO) === $$d ===; \ $(MAKE) $(MAKEOPTS) -C $$d $@ || exit $$?; \ fi; \ done MAN_MAKERULE = \ @for f in *.[12345678] ""; do \ if test ! -z "$$f"; then \ $(ZIP) --best -c < $$f > $$f.gz; \ fi; \ done SOURCE_MAKERULE = \ @test -z "$$DIR" && DIR="."; \ for f in $(SRCFILES) ""; do \ test -z "$$f" && break; \ test -L "$$f" || $(ECHO) $$DIR/$$f; \ done; \ for d in `echo $(SUBDIRS)` ""; do \ test -z "$$d" && break; \ if test -d "$$d"; then \ $(MAKE) $(MAKEOPTS) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \ fi; \ done pcp-gui-1.5.11/src/include/buildrules0000644000000000000000000001217012213235215014335 0ustar # # Copyright (c) 2007 Aconex. All Rights Reserved. # ifndef _BUILDRULES_INCLUDED_ _BUILDRULES_INCLUDED_ = 1 include $(TOPDIR)/src/include/builddefs clean clobber: @rm -f $(DIRT) @rm -fr $(DIRDIRT) $(SUBDIRS_MAKERULE) realclean distclean: clean rm -f $(TOPDIR)/src/include/builddefs \ $(TOPDIR)/src/include/version.h \ $(TOPDIR)/src/libqmc/libqmc.pro \ $(TOPDIR)/src/libqwt/libqwt.pro \ $(TOPDIR)/src/dumptext/pmdumptext.pro \ $(TOPDIR)/src/query/pmquery.pro \ $(TOPDIR)/src/chart/pmchart.pro \ $(TOPDIR)/src/time/pmtime.pro \ rm -f $(TOPDIR)/pcp-gui.lsm $(TOPDIR)/configure # Never blow away subdirs ifdef SUBDIRS .PRECIOUS: $(SUBDIRS) endif src-pcp-gui : $(SRCFILES) $(SUBDIRS) @test ! -z "$$SRC_ROOT" || ( echo '$$SRC_ROOT not set ... bozo!' ; echo "... generally unsafe to run make src-pcp-gui outside the Makepkgs script"; exit 1 ) @test -z "$$DIR" && DIR="."; \ for f in `echo $^`; do \ if test -d $$f ; then \ $(MAKE) $(MAKEOPTS) -j 1 DIR=$$DIR/$$f -C $$f $@ || exit $$?; \ else \ $(ECHO) $$DIR/$$f; \ fi; \ done src-link-pcp-gui : $(SRCFILES) $(CONFFILES) $(SUBDIRS) @test ! -z "$$SRCLINK_ROOT" || ( echo '$$SRCLINK_ROOT not set ... bozo!' ; echo "... generally unsafe to run make src-link-pcp-gui outside the Makepkgs script"; exit 1 ) @test -z "$$DIR" && DIR="."; \ for f in `echo $^`; do \ if test -d $$f ; then \ mkdir $$SRCLINK_ROOT/$$DIR/$$f || exit $$?; \ $(MAKE) $(MAKEOPTS) -j 1 DIR=$$DIR/$$f -C $$f $@ || exit $$?; \ else \ ln $$f $$SRCLINK_ROOT/$$DIR/$$f || exit $$?; \ fi; \ done ifeq ($(PKG_PLATFORM),darwin) QTMAKE = $(QMAKE) -spec macx-g++ && make -f Makefile MACBUILD = $(COMMAND).app/Contents BINARY = $(MACBUILD)/MacOS/$(COMMAND) LNMAKE = test ! -f $(BINARY) -o -L $(COMMAND) || $(LN_S) $(BINARY) $(COMMAND) WINDOW = mac endif ifeq ($(PKG_PLATFORM),mingw) QTMAKE = $(QMAKE) && $(MAKE) -f Makefile BINARY = $(QT_RELEASE)/$(COMMAND) LNMAKE = WINDOW = win endif ifeq "$(findstring $(PKG_PLATFORM),darwin mingw)" "" QTMAKE = +$(QMAKE) && $(MAKE) $(MAKEOPTS) -f Makefile BINARY = $(COMMAND) LNMAKE = WINDOW = x11 endif ifeq ($(PKG_PLATFORM),darwin) INSTALL_DIRECTORY_HIERARCHY=\ d=$(1); while [ "$$d" != "$(2)" -a "$$d" != "/" -a "$$d" != "." ] ; do \ echo $$d; d=`dirname $$d`; done | sort | while read id; do \ $(INSTALL) -m 755 -d $$id || exit 1; done INSTALL_QT_RESOURCES=\ printf "[Paths]\nPlugins=/Library/PCP/Plugins\n\n" > qt.conf; \ $(INSTALL) -m 644 qt.conf $(1)/qt.conf; \ rm qt.conf; \ find frameworks -type d -name qt_menu.nib | while read nib; do \ $(INSTALL) -m 755 -d $(1)/qt_menu.nib || exit 1; \ find $$nib -type f | while read nibs; do \ f=`basename $$nibs`; \ $(INSTALL) -m 644 $$nibs $(1)/qt_menu.nib/$$f || exit 1; \ done; \ done MAC_APPSUPPORT_DIR=/Library/PCP MAC_FRAMEWORKS_DIR=$(MAC_APPSUPPORT_DIR)/Frameworks # WARNING! # This rule modified the binary it was given, once modified the # binary cannot be used with this rule again. # If the binary is installed then it's important to call this # rule before calling install rule for the binary. INSTALL_QT_FRAMEWORKS=\ otool -L $(1) | awk '{if (NR != 1) {print $$1}}' |\ egrep 'Qt.*\.framework' | while read qt; do \ tdir=`dirname $$qt`; \ install_name_tool -change $$qt $(MAC_FRAMEWORKS_DIR)/$$qt $(1);\ $(call INSTALL_DIRECTORY_HIERARCHY,$(MAC_FRAMEWORKS_DIR)/$$tdir,/Library/PCP); \ mkdir -p frameworks/$$tdir || exit 1; \ fwqt="frameworks/$$qt"; \ cp /Library/Frameworks/$$qt frameworks/$$qt || exit 1; \ otool -L $$fwqt | awk '{if (NR != 1) {print $$1}}' |\ egrep 'Qt.*\.framework' | while read dep; do \ install_name_tool -change $$dep $(MAC_FRAMEWORKS_DIR)/$$dep $$fwqt;\ done; \ $(INSTALL) frameworks/$$qt $(MAC_FRAMEWORKS_DIR)/$$qt; \ if [ -d /Library/Frameworks/$$tdir/Resources ] ; then \ $(INSTALL) -d $(MAC_FRAMEWORKS_DIR)/$$tdir/Resources; \ (cd /Library/Frameworks/$$tdir; find Resources -type f) | \ while read rf; do \ rfpath="$$tdir/$$rf"; rfd=`dirname $$rfpath`; \ fwpath="frameworks/$$rfpath"; brfd=`basename $$rfd`; \ mkdir -p frameworks/$$rfd || exit 1; \ cp /Library/Frameworks/$$rfpath $$fwpath || exit 1; \ [ $$brfd != qt_menu.nib ] || continue; \ $(INSTALL) -d $(MAC_FRAMEWORKS_DIR)/$$rfd || exit 1; \ $(INSTALL) $$fwpath $(MAC_FRAMEWORKS_DIR)/$$rfpath;\ done \ fi; done endif ifdef ICONLINKS iconlinks: @for l in $(ICONLINKS) ; do \ if [ ! -L $$l -a ! -f $$l ] ; then \ $(LN_S) $(TOPDIR)/images/$$l $$l ; \ fi \ done endif ifdef WINDOWLINKS windowlinks: @for l in $(WINDOWLINKS) ; do \ if [ ! -L $$l -a ! -f $$l ] ; then \ $(LN_S) $(WINDOW)_$$l $$l ; \ fi \ done endif # Suffix rule to support transition for XML to PDF (books) %.pdf: %.xml ifeq ($(BOOK_TOOLCHAIN),publican) $(PUBLICAN) build --langs=en-US --formats=pdf endif ifeq ($(BOOK_TOOLCHAIN),xmlto) $(XMLTO) --with-fop pdf $^ endif ifeq ($(BOOK_TOOLCHAIN),dblatex) $(DBLATEX) --type pdf $^ endif source : $(SOURCE_MAKERULE) endif # _BUILDRULES_INCLUDED_ $(_FORCE): .PHONY : depend pcp-gui-1.5.11/src/libqmc/0000755000000000000000000000000012234612137012070 5ustar pcp-gui-1.5.11/src/libqmc/GNUmakefile0000644000000000000000000000046212176111212014135 0ustar TOPDIR = ../.. LIBRARY = libqmc PROJECT = $(LIBRARY).pro include $(TOPDIR)/src/include/builddefs HEADERS = $(shell echo qmc*.h) SOURCES = $(shell echo qmc*.cpp) CONFFILES = $(PROJECT) LSRCFILES = $(PROJECT).in $(SOURCES) $(HEADERS) default: $(PROJECT) $(QTMAKE) include $(BUILDRULES) install: default pcp-gui-1.5.11/src/libqmc/libqmc.pro.in0000644000000000000000000000055412176111212014463 0ustar TARGET = qmc TEMPLATE = lib VERSION = 1.0.0 INCLUDEPATH += . ../include win32:INCLUDEPATH += @pcp_dir@/include CONFIG += qt staticlib warn_on @qt_release@ QT -= gui HEADERS = qmc_context.h qmc_desc.h qmc_group.h \ qmc_indom.h qmc_metric.h qmc_source.h SOURCES = qmc_context.cpp qmc_desc.cpp qmc_group.cpp \ qmc_indom.cpp qmc_metric.cpp qmc_source.cpp pcp-gui-1.5.11/src/libqmc/qmc_context.cpp0000644000000000000000000002167112176111212015120 0ustar /* * Copyright (c) 2012 Red Hat. * Copyright (c) 2007-2008 Aconex. All Rights Reserved. * Copyright (c) 1997,2005 Silicon Graphics, Inc. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include QStringList *QmcContext::theStringList; QmcContext::QmcContext(QmcSource* source) { my.delta = 0.0; my.context = -1; my.source = source; my.needReconnect = false; if (my.source->status() >= 0) my.context = my.source->dupContext(); else my.context = my.source->status(); } QmcContext::~QmcContext() { while (my.metrics.isEmpty() == false) { delete my.metrics.takeFirst(); } QHashIterator descs(my.descCache); while (descs.hasNext()) { descs.next(); delete descs.value(); } while (my.indoms.isEmpty() == false) { delete my.indoms.takeFirst(); } if (my.context >= 0) my.source->delContext(my.context); } int QmcContext::lookupName(pmID pmid, QString **name) { char *value; int sts = 0; if (my.pmidCache.contains(pmid) == false) { if ((sts = pmNameID(pmid, &value)) >= 0) { *name = new QString(value); my.pmidCache.insert(pmid, *name); free(value); } } else { QString *np = my.pmidCache.value(pmid); if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcContext::lookupName: Matched id " << pmIDStr(pmid) << " to \"" << *np << "\"" << endl; } *name = np; } return sts; } int QmcContext::lookupPMID(const char *name, pmID& id) { QString key = name; int sts; if (my.nameCache.contains(key) == false) { if ((sts = pmLookupName(1, (char **)(&name), &id)) >= 0) my.nameCache.insert(key, id); } else { id = my.nameCache.value(key); if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcContext::lookupPMID: Matched \"" << name << "\" to id " << pmIDStr(id) << endl; } sts = 1; } return sts; } int QmcContext::lookupInDom(const char *name, uint_t& indom) { pmID pmid; int sts = lookupPMID(name, pmid); if (sts < 0) return sts; return lookupInDom(pmid, indom); } int QmcContext::lookupDesc(pmID pmid, QmcDesc **descriptor) { int sts; QmcDesc *descPtr; if (my.descCache.contains(pmid) == false) { descPtr = new QmcDesc(pmid); if (descPtr->status() < 0) { sts = descPtr->status(); delete descPtr; return sts; } my.descCache.insert(pmid, descPtr); if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcContext::lookupDesc: Add descriptor for " << pmIDStr(descPtr->id()) << endl; } } else { descPtr = my.descCache.value(pmid); if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcContext::lookupDesc: Reusing descriptor " << pmIDStr(descPtr->id()) << endl; } } *descriptor = descPtr; return 0; } int QmcContext::lookup(pmID pmid, QString **namePtr, QmcDesc **descPtr, QmcIndom **indomPtr) { uint_t indom; int sts; if ((sts = lookupName(pmid, namePtr)) < 0) return sts; if ((sts = lookupDesc(pmid, descPtr)) < 0) return sts; if ((sts = lookupInDom(pmid, indom)) < 0) return sts; *indomPtr = (indom == UINT_MAX) ? NULL : my.indoms[indom]; return 0; } int QmcContext::lookupInDom(pmID pmid, uint_t& indom) { QmcDesc *descPtr; int sts; if ((sts = lookupDesc(pmid, &descPtr)) < 0) return sts; return lookupInDom(descPtr, indom); } int QmcContext::lookupInDom(QmcDesc *descPtr, uint_t& indom) { int i, sts; QmcIndom *indomPtr; indom = UINT_MAX; if (descPtr->desc().indom != PM_INDOM_NULL) { for (i = 0; i < my.indoms.size(); i++) if (my.indoms[i]->id() == (int)descPtr->desc().indom) break; if (i == my.indoms.size()) { indomPtr = new QmcIndom(my.source->type(), *descPtr); if (indomPtr->status() < 0) { sts = indomPtr->status(); delete indomPtr; return sts; } my.indoms.append(indomPtr); indom = my.indoms.size() - 1; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcContext::lookupInDom: Add indom for " << pmInDomStr(indomPtr->id()) << endl; } } else { indomPtr = my.indoms[i]; indom = i; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcContext::lookupInDom: Reusing indom " << pmInDomStr(indomPtr->id()) << endl; } } } return 0; } int QmcContext::useTZ() { if (my.source->tzHandle() >= 0) return pmUseZone(my.source->tzHandle()); return 0; } QTextStream& operator<<(QTextStream &stream, const QmcContext &context) { stream << context.source().desc() << " has " << context.numMetrics() << " metrics"; return stream; } void QmcContext::dump(QTextStream &stream) { stream << "Context " << my.context << " has " << my.nameCache.size() << " metric names for source:" << endl; my.source->dump(stream); } void QmcContext::dumpMetrics(QTextStream &stream) { for (int i = 0; i < my.metrics.size(); i++) stream << " [" << i << "] " << my.metrics[i]->spec(false, true) << endl; } void QmcContext::addMetric(QmcMetric *metric) { pmID pmid; int i; my.metrics.append(metric); if (metric->status() >= 0) { pmid = metric->desc().desc().pmid; for (i = 0; i < my.pmids.size(); i++) if (my.pmids[i] == pmid) break; if (i == my.pmids.size()) my.pmids.append(pmid); metric->setIdIndex(i); } } int QmcContext::fetch(bool update) { int i, sts; pmResult *result; for (i = 0; i < my.metrics.size(); i++) { QmcMetric *metric = my.metrics[i]; if (metric->status() < 0) continue; metric->shiftValues(); } // Inform each indom that we are about to do a new fetch so any // indom changes are now irrelevant for (i = 0; i < my.indoms.size(); i++) my.indoms[i]->newFetch(); sts = pmUseContext(my.context); if (sts >= 0) { for (i = 0; i < my.indoms.size(); i++) { if (my.indoms[i]->diffProfile()) sts = my.indoms[i]->genProfile(); } } else if (pmDebug & DBG_TRACE_OPTFETCH) { QTextStream cerr(stderr); cerr << "QmcContext::fetch: Unable to switch to this context: " << pmErrStr(sts) << endl; } if (sts >= 0 && my.needReconnect) { sts = pmReconnectContext(my.context); if (sts >= 0) { my.needReconnect = false; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcContext::fetch: Reconnected context \"" << *my.source << endl; } } else if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcContext::fetch: Reconnect failed: " << pmErrStr(sts) << endl; } } if (sts >= 0 && my.pmids.size()) { if (pmDebug & DBG_TRACE_OPTFETCH) { QTextStream cerr(stderr); cerr << "QmcContext::fetch: fetching context " << *this << endl; } sts = pmFetch(my.pmids.size(), (pmID *)(my.pmids.toVector().data()), &result); if (sts >= 0) { my.previousTime = my.currentTime; my.currentTime = result->timestamp; my.delta = __pmtimevalSub(&my.currentTime, &my.previousTime); for (i = 0; i < my.metrics.size(); i++) { QmcMetric *metric = my.metrics[i]; if (metric->status() < 0) continue; Q_ASSERT((int)metric->idIndex() < result->numpmid); metric->extractValues(result->vset[metric->idIndex()]); } pmFreeResult(result); } else { if (pmDebug & DBG_TRACE_OPTFETCH) { QTextStream cerr(stderr); cerr << "QmcContext::fetch: pmFetch: " << pmErrStr(sts) << endl; } for (i = 0; i < my.metrics.size(); i++) { QmcMetric *metric = my.metrics[i]; if (metric->status() < 0) continue; metric->setError(sts); } if (sts == PM_ERR_IPC || sts == PM_ERR_TIMEOUT) my.needReconnect = true; } if (update) { if (pmDebug & DBG_TRACE_OPTFETCH) { QTextStream cerr(stderr); cerr << "QmcContext::fetch: Updating metrics" << endl; } for (i = 0; i < my.metrics.size(); i++) { QmcMetric *metric = my.metrics[i]; if (metric->status() < 0) continue; metric->update(); } } } else if (pmDebug & DBG_TRACE_OPTFETCH) { QTextStream cerr(stderr); cerr << "QmcContext::fetch: nothing to fetch" << endl; } return sts; } void QmcContext::dometric(const char *name) { theStringList->append(name); } int QmcContext::traverse(const char *name, QStringList &list) { int sts; theStringList = &list; theStringList->clear(); sts = pmTraversePMNS(name, QmcContext::dometric); if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); if (sts >= 0) { cerr << "QmcContext::traverse: Found " << list.size() << " names from " << name << endl; } else cerr << "QmcContext::traverse: Failed: " << pmErrStr(sts) << endl; } return sts; } pcp-gui-1.5.11/src/libqmc/qmc_desc.cpp0000644000000000000000000001046112176111212014345 0ustar /* * Copyright (c) 1998,2005 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2007 Aconex. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. */ #include #include QmcDesc::QmcDesc(pmID pmid) { my.pmid = pmid; my.scaleFlag = false; my.status = pmLookupDesc(my.pmid, &my.desc); if (my.status >= 0) { my.scaleUnits = my.desc.units; setUnitStrings(); } else if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcDesc::QmcDesc: unable to lookup " << pmIDStr(my.pmid) << ": " << pmErrStr(my.status) << endl; } } void QmcDesc::setUnitStrings() { const char *units = pmUnitsStr(&my.scaleUnits); const char *shortUnits = shortUnitsString(&my.scaleUnits); if (my.desc.sem == PM_SEM_COUNTER) { if (my.scaleFlag && my.scaleUnits.dimTime == 1 && my.scaleUnits.dimSpace == 0 && my.scaleUnits.dimCount == 0) { my.units = "Time Utilization"; my.shortUnits = "util"; } else { my.units = units; my.units.append(" / second"); my.shortUnits = shortUnits; my.shortUnits.append("/s"); } } else { if (units[0] == '\0') my.units = "none"; else my.units = units; if (shortUnits[0] == '\0') my.shortUnits = "none"; else my.shortUnits = shortUnits; } } void QmcDesc::setScaleUnits(const pmUnits &units) { my.scaleUnits = units; my.scaleFlag = true; setUnitStrings(); } const char * QmcDesc::shortUnitsString(pmUnits *pu) { const char *spaceString, *timeString, *countString; char sbuf[20], tbuf[20], cbuf[20]; static char buf[60]; char *p; spaceString = timeString = countString = NULL; buf[0] = '\0'; if (pu->dimSpace) { switch (pu->scaleSpace) { case PM_SPACE_BYTE: spaceString = "b"; break; case PM_SPACE_KBYTE: spaceString = "Kb"; break; case PM_SPACE_MBYTE: spaceString = "Mb"; break; case PM_SPACE_GBYTE: spaceString = "Gb"; break; case PM_SPACE_TBYTE: spaceString = "Tb"; break; default: sprintf(sbuf, "space-%d", pu->scaleSpace); spaceString = sbuf; break; } } if (pu->dimTime) { switch (pu->scaleTime) { case PM_TIME_NSEC: timeString = "ns"; break; case PM_TIME_USEC: timeString = "us"; break; case PM_TIME_MSEC: timeString = "msec"; break; case PM_TIME_SEC: timeString = "s"; break; case PM_TIME_MIN: timeString = "m"; break; case PM_TIME_HOUR: timeString = "h"; break; default: sprintf(tbuf, "time-%d", pu->scaleTime); timeString = tbuf; break; } } if (pu->dimCount) { switch (pu->scaleCount) { case 0: countString = "c"; break; case 1: countString = "cx10"; break; default: sprintf(cbuf, "cx10^%d", pu->scaleCount); countString = cbuf; break; } } p = buf; if (pu->dimSpace > 0) { if (pu->dimSpace == 1) sprintf(p, "%s", spaceString); else sprintf(p, "%s^%d", spaceString, pu->dimSpace); while (*p) p++; } if (pu->dimTime > 0) { if (pu->dimTime == 1) sprintf(p, "%s", timeString); else sprintf(p, "%s^%d", timeString, pu->dimTime); while (*p) p++; } if (pu->dimCount > 0) { if (pu->dimCount == 1) sprintf(p, "%s", countString); else sprintf(p, "%s^%d", countString, pu->dimCount); while (*p) p++; } if (pu->dimSpace < 0 || pu->dimTime < 0 || pu->dimCount < 0) { *p++ = '/'; if (pu->dimSpace < 0) { if (pu->dimSpace == -1) sprintf(p, "%s", spaceString); else sprintf(p, "%s^%d", spaceString, -pu->dimSpace); while (*p) p++; } if (pu->dimTime < 0) { if (pu->dimTime == -1) sprintf(p, "%s", timeString); else sprintf(p, "%s^%d", timeString, -pu->dimTime); while (*p) p++; } if (pu->dimCount < 0) { if (pu->dimCount == -1) sprintf(p, "%s", countString); else sprintf(p, "%s^%d", countString, -pu->dimCount); while (*p) p++; } } if (buf[0] == '\0') { if (pu->scaleCount == 1) sprintf(buf, "x10"); else if (pu->scaleCount != 0) sprintf(buf, "x10^%d", pu->scaleCount); } else *p = '\0'; return buf; } pcp-gui-1.5.11/src/libqmc/qmc_group.cpp0000644000000000000000000003156412176111212014572 0ustar /* * Copyright (c) 2013, Red Hat. * Copyright (c) 2007 Aconex. All Rights Reserved. * Copyright (c) 1997-2005 Silicon Graphics, Inc. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include int QmcGroup::tzLocal = -1; bool QmcGroup::tzLocalInit = false; QString QmcGroup::tzLocalString; QString QmcGroup::localHost; QmcGroup::QmcGroup(bool restrictArchives) { my.restrictArchives = restrictArchives; my.mode = PM_CONTEXT_HOST; my.use = -1; my.localSource = 0; my.tzFlag = unknownTZ; my.tzDefault = -1; my.tzUser = -1; my.tzGroupIndex = 0; my.timeEndReal = 0.0; // Get timezone from environment if (tzLocalInit == false) { char buf[MAXHOSTNAMELEN]; gethostname(buf, MAXHOSTNAMELEN); buf[MAXHOSTNAMELEN-1] = '\0'; localHost = buf; char *tz = __pmTimezone(); if (tz == NULL) pmprintf("%s: Warning: Unable to get timezone from environment\n", pmProgname); else { tzLocal = pmNewZone(tz); if (tzLocal < 0) pmprintf("%s: Warning: Timezone for localhost: %s\n", pmProgname, pmErrStr(tzLocal)); else { tzLocalString = tz; my.tzDefault = tzLocal; my.tzFlag = localTZ; } } tzLocalInit = true; } } QmcGroup::~QmcGroup() { for (int i = 0; i < my.contexts.size(); i++) if (my.contexts[i]) delete my.contexts[i]; } int QmcGroup::use(int type, const QString &theSource, int flags) { int sts = 0; unsigned int i; QString source(theSource); if (type == PM_CONTEXT_LOCAL) { for (i = 0; i < numContexts(); i++) if (my.contexts[i]->source().type() == type) break; } else if (type == PM_CONTEXT_ARCHIVE) { if (source == QString::null) { pmprintf("%s: Error: Archive context requires archive path\n", pmProgname); return PM_ERR_NOCONTEXT; } // This doesn't take into account {.N,.meta,.index,} ... but // then again, nor does pmNewContext. More work ... useful? for (i = 0; i < numContexts(); i++) { if (source == my.contexts[i]->source().source()) break; } } else { if (source == QString::null) { if (!defaultDefined()) { createLocalContext(); if (!defaultDefined()) { pmprintf("%s: Error: " "Cannot connect to PMCD on localhost: %s\n", pmProgname, pmErrStr(my.localSource->status())); return my.localSource->status(); } } source = my.contexts[0]->source().source(); } for (i = 0; i < numContexts(); i++) { if (source == my.contexts[i]->source().source()) break; } } if (i == numContexts()) { if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::use: No direct match for context \"" << source << "\" (type " << type << ")." << endl; } // Determine live or archive mode by the first source if (i == 0) my.mode = type; // If the assumed mode differs from the requested context type // we may need to map the host to an archive if (my.mode != type) { if (my.mode == PM_CONTEXT_HOST && type == PM_CONTEXT_ARCHIVE) { pmprintf("%s: Error: Archive \"%s\" requested " "after live mode was assumed.\n", pmProgname, (const char *)source.toAscii()); return PM_ERR_NOCONTEXT; } // If we are in archive mode, map hosts to archives of same host if (my.mode == PM_CONTEXT_ARCHIVE && type == PM_CONTEXT_HOST) { QString chop1 = source.remove(PM_LOG_MAXHOSTLEN-1, INT_MAX); for (i = 0; i < numContexts(); i++) { QString chop2 = my.contexts[i]->source().host(); chop2.remove(PM_LOG_MAXHOSTLEN-1, INT_MAX); if (chop1 == chop2) break; } if (i == numContexts()) { pmprintf("%s: Error: No archives were specified " "for host \"%s\"\n", pmProgname, (const char *)source.toAscii()); return PM_ERR_NOTARCHIVE; } } } } if (i == numContexts()) { if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::use: Creating new context for \"" << source << '\"' << endl; } QmcSource *src = QmcSource::getSource(type, source, flags, false); if (src == NULL) { pmprintf("%s: Error: No archives were specified for host \"%s\"\n", pmProgname, (const char *)source.toAscii()); return PM_ERR_NOTARCHIVE; } QmcContext *newContext = new QmcContext(src); if (newContext->handle() < 0) { sts = newContext->handle(); pmprintf("%s: Error: %s: %s\n", pmProgname, (const char *)source.toAscii(), pmErrStr(sts)); delete newContext; return sts; } // If we are in archive mode and are adding an archive, // make sure another archive for the same host does not exist if (my.restrictArchives && type == PM_CONTEXT_ARCHIVE) { for (i = 0; i < numContexts(); i++) // No need to restrict comparison here, both are from // log labels. if (my.contexts[i]->source().host() == newContext->source().host()) { pmprintf("%s: Error: Archives \"%s\" and \"%s\" are from " "the same host \"%s\"\n", pmProgname, my.contexts[i]->source().sourceAscii(), newContext->source().sourceAscii(), my.contexts[i]->source().hostAscii()); delete newContext; return PM_ERR_NOCONTEXT; } } my.contexts.append(newContext); my.use = my.contexts.size() - 1; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::use: Added context " << my.use << ": " << *newContext << endl; } } // We found a match, do we need to use a different context? else if (i != (unsigned int)my.use) { my.use = i; sts = useContext(); if (sts < 0) { pmprintf("%s: Error: Unable to use context to %s: %s\n", pmProgname, context()->source().sourceAscii(), pmErrStr(sts)); return sts; } if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::use: Using existing context " << my.use << " for " << context()->source().desc() << endl; } } else if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::use: Using current context " << my.use << " (handle = " << context()->handle() << ") for " << context()->source().desc() << endl; } return context()->handle(); } int QmcGroup::useTZ() { int sts = context()->useTZ(); if (sts >= 0) { my.tzDefault = context()->source().tzHandle(); my.tzFlag = groupTZ; my.tzGroupIndex = my.use; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::useTZ: Using timezone of " << context()->source().desc() << " (" << my.tzGroupIndex << ')' << endl; } } return sts; } int QmcGroup::useTZ(const QString &tz) { int sts = pmNewZone(tz.toAscii()); if (sts >= 0) { my.tzUser = sts; my.tzUserString = tz; my.tzFlag = userTZ; my.tzDefault = sts; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::useTZ: Switching timezones to \"" << tz << "\" (" << my.tzUserString << ')' << endl; } } return sts; } int QmcGroup::useLocalTZ() { if (tzLocal >= 0) { int sts = pmUseZone(tzLocal); if (sts > 0) { my.tzFlag = localTZ; my.tzDefault = tzLocal; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::useTZ: Using timezone of host \"localhost\"" << endl; } } return sts; } return tzLocal; } void QmcGroup::defaultTZ(QString &label, QString &tz) { if (my.tzFlag == userTZ) { label = my.tzUserString; tz = my.tzUserString; } else if (my.tzFlag == localTZ) { label = localHost; tz = tzLocalString; } else { label = my.contexts[my.tzGroupIndex]->source().host(); tz = my.contexts[my.tzGroupIndex]->source().timezone(); } } int QmcGroup::useDefaultTZ() { if (my.tzFlag == unknownTZ) return -1; return pmUseZone(my.tzDefault); } int QmcGroup::useDefault() { if (numContexts() == 0) createLocalContext(); if (numContexts() == 0) return my.localSource->status(); my.use = 0; return pmUseContext(context()->handle()); } void QmcGroup::createLocalContext() { if (numContexts() == 0) { QTextStream cerr(stderr); QmcSource *localSource = QmcSource::getSource(PM_CONTEXT_HOST, localHost, 0, false); if (localSource->status() < 0 && pmDebug & DBG_TRACE_PMC) cerr << "QmcGroup::createLocalContext: Default context to " << localSource->desc() << " failed: " << pmErrStr(localSource->status()) << endl; else if (pmDebug & DBG_TRACE_PMC) cerr << "QmcGroup::createLocalContext: Default context to " << localSource->desc() << endl; QmcContext *newContext = new QmcContext(localSource); my.contexts.append(newContext); my.use = my.contexts.size() - 1; } } void QmcGroup::updateBounds() { double newStart = DBL_MAX; double newEnd = 0.0; double startReal; double endReal; struct timeval startTv; struct timeval endTv; my.timeStart.tv_sec = 0; my.timeStart.tv_usec = 0; my.timeEnd = my.timeStart; for (unsigned int i = 0; i < numContexts(); i++) { if (my.contexts[i]->handle() >= 0 && my.contexts[i]->source().type() == PM_CONTEXT_ARCHIVE) { startTv = my.contexts[i]->source().start(); endTv = my.contexts[i]->source().end(); startReal = __pmtimevalToReal(&startTv); endReal = __pmtimevalToReal(&endTv); if (startReal < newStart) newStart = startReal; if (endReal > newEnd) newEnd = endReal; } } __pmtimevalFromReal(newStart, &my.timeStart); __pmtimevalFromReal(newEnd, &my.timeEnd); my.timeEndReal = newEnd; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::updateBounds: start = " << my.timeStart.tv_sec << '.' << my.timeStart.tv_usec << ", end = " << my.timeEnd.tv_sec << '.' << my.timeEnd.tv_usec << endl; } } void QmcGroup::dump(QTextStream &stream) { stream << "mode: "; switch(my.mode) { case PM_CONTEXT_LOCAL: stream << "local"; break; case PM_CONTEXT_HOST: stream << "live host"; break; case PM_CONTEXT_ARCHIVE: stream << "archive"; break; } stream << ", timezone: "; switch(my.tzFlag) { case QmcGroup::localTZ: stream << "local = \"" << tzLocalString; break; case QmcGroup::userTZ: stream << "user = \"" << my.tzUserString; break; case QmcGroup::groupTZ: stream << "group = \"" << my.contexts[my.tzGroupIndex]->source().timezone(); break; case QmcGroup::unknownTZ: stream << "unknown = \"???"; break; } stream << "\": " << endl; stream << " " << numContexts() << " contexts:" << endl; for (unsigned int i = 0; i < numContexts(); i++) { stream << " [" << i << "] " << *(my.contexts[i]) << endl; my.contexts[i]->dumpMetrics(stream); } } int QmcGroup::useContext() { int sts = 0; if ((context()->status() == 0) && (sts = pmUseContext(context()->handle())) < 0) pmprintf("%s: Error: Unable to reuse context to %s: %s\n", pmProgname, context()->source().sourceAscii(), pmErrStr(sts)); return sts; } QmcMetric * QmcGroup::addMetric(char const *string, double theScale, bool active) { QmcMetric *metric = new QmcMetric(this, string, theScale, active); if (metric->status() >= 0) metric->context()->addMetric(metric); return metric; } QmcMetric * QmcGroup::addMetric(pmMetricSpec *theMetric, double theScale, bool active) { QmcMetric *metric = new QmcMetric(this, theMetric, theScale, active); if (metric->status() >= 0) metric->context()->addMetric(metric); return metric; } int QmcGroup::fetch(bool update) { int sts = 0; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::fetch: " << numContexts() << " contexts" << endl; } for (unsigned int i = 0; i < numContexts(); i++) my.contexts[i]->fetch(update); if (numContexts()) sts = useContext(); if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::fetch: Done" << endl; } return sts; } int QmcGroup::setArchiveMode(int mode, const struct timeval *when, int interval) { int sts, result = 0; for (unsigned int i = 0; i < numContexts(); i++) { if (my.contexts[i]->source().type() != PM_CONTEXT_ARCHIVE) continue; sts = pmUseContext(my.contexts[i]->handle()); if (sts < 0) { pmprintf("%s: Error: Unable to switch to context for %s: %s\n", pmProgname, my.contexts[i]->source().sourceAscii(), pmErrStr(sts)); result = sts; continue; } sts = pmSetMode(mode, when, interval); if (sts < 0) { pmprintf("%s: Error: Unable to set context mode for %s: %s\n", pmProgname, my.contexts[i]->source().sourceAscii(), pmErrStr(sts)); result = sts; } } sts = useContext(); if (sts < 0) result = sts; return result; } pcp-gui-1.5.11/src/libqmc/qmc_indom.cpp0000644000000000000000000003062112176111212014535 0ustar /* * Copyright (c) 1997,2005 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2007 Aconex. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include #include #include #include QmcInstance::QmcInstance() { my.inst = PM_IN_NULL; my.refCount = 0; my.index = -1; my.active = false; } QmcInstance::QmcInstance(int id, const char* name) { my.inst = id; my.name = name; my.refCount = 0; my.index = -1; my.active = true; } void QmcInstance::deactivate(int nullIndex) { my.inst = PM_IN_NULL; my.name = ""; my.refCount = 0; my.index = nullIndex; my.active = false; } QmcInstance const& QmcInstance::operator=(QmcInstance const& rhs) { if (this != &rhs) { my.inst = rhs.inst(); my.name = rhs.name(); my.refCount = rhs.refCount(); my.index = rhs.index(); my.active = rhs.active(); } return *this; } QmcIndom::QmcIndom(int type, QmcDesc &desc) { int *instList; char **nameList; my.type = type; my.id = desc.desc().indom; my.profile = false; my.changed = false; my.updated = true; my.count = 0; my.nullCount = 0; my.nullIndex = UINT_MAX; my.numActive = 0; my.numActiveRef = 0; if (my.id == PM_INDOM_NULL) my.status = PM_ERR_INDOM; else if (my.type == PM_CONTEXT_HOST || my.type == PM_CONTEXT_LOCAL) my.status = pmGetInDom(my.id, &instList, &nameList); else if (my.type == PM_CONTEXT_ARCHIVE) my.status = pmGetInDomArchive(my.id, &instList, &nameList); else my.status = PM_ERR_NOCONTEXT; if (my.status > 0) { for (int i = 0; i < my.status; i++) my.instances.append(QmcInstance(instList[i], nameList[i])); my.numActive = my.status; free(instList); free(nameList); if (pmDebug & DBG_TRACE_INDOM) { QTextStream cerr(stderr); cerr << "QmcIndom::QmcIndom: indom "; } } else if (my.status < 0 && pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcIndom::QmcIndom: unable to lookup " << pmInDomStr(my.id) << " from " << (my.type == PM_CONTEXT_ARCHIVE ? "archive" : "host/local") << " source: " << pmErrStr(my.status) << endl; } } int QmcIndom::lookup(QString const &name) { int i; bool ok; QStringList list; for (i = 0; i < my.instances.size(); i++) { if (my.instances[i].null()) continue; if (my.instances[i].name().compare(name) == 0) { if (my.instances[i].refCount() == 0) { my.profile = true; my.count++; if (my.instances[i].active()) my.numActiveRef++; } my.instances[i].refCountInc(); return i; } } // Match up to the first space // Need this for proc and similiar agents for (i = 0; i < my.instances.size(); i++) { if (my.instances[i].null()) continue; list = my.instances[i].name().split(QChar(' ')); if (list.size() <= 1) continue; if (name.compare(list.at(0)) == 0) { if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcIndom::lookup: inst \"" << name << "\"(" << i << ") matched to \"" << my.instances[i].name() << "\"(" << i << ')' << endl; } if (my.instances[i].refCount() == 0) { my.profile = true; my.count++; if (my.instances[i].active()) my.numActiveRef++; } my.instances[i].refCountInc(); return i; } } // If the instance requested is numeric, then ignore leading // zeros in the instance up to the first space int nameNumber = name.toInt(&ok); // The requested instance is numeric if (ok) { for (i = 0; i < my.instances.size(); i++) { if (my.instances[i].null()) continue; list = my.instances[i].name().split(QChar(' ')); if (list.size() <= 1) continue; int instNumber = list.at(0).toInt(&ok); if (!ok) continue; if (instNumber == nameNumber) { if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcIndom::lookup: numerical inst \"" << name << " matched to \"" << my.instances[i].name() << "\"(" << i << ')' << endl; } if (my.instances[i].refCount() == 0) { my.profile = true; my.count++; if (my.instances[i].active()) my.numActiveRef++; } my.instances[i].refCountInc(); return i; } } } return -1; // we don't know about that instance } void QmcIndom::refAll(bool active) { my.numActiveRef = 0; for (int i = 0; i < my.instances.size(); i++) { if (my.instances[i].null() || (active && !my.instances[i].active())) continue; if (my.instances[i].refCount() == 0) my.profile = true; if (my.instances[i].active()) my.numActiveRef++; my.instances[i].refCountInc(); } my.count = my.instances.size() - my.nullCount; } void QmcIndom::removeRef(uint index) { Q_ASSERT(my.instances[index].refCount()); my.instances[index].refCountDec(); if (my.instances[index].refCount() == 0) { my.profile = true; my.count--; if (my.instances[index].active()) my.numActiveRef--; } } int QmcIndom::genProfile() { int i, j; int sts = 0; int *ptr = NULL; QVector list; const char *action = NULL; // If all instances are referenced or there are no instances // then request all instances if (my.numActiveRef == my.numActive || my.numActive == 0) { sts = pmAddProfile(my.id, 0, NULL); action = "ALL"; } // If the number of referenced instances is less than the number // of unreferenced active instances, then the smallest profile // is to add all the referenced instances else if (my.count < (my.numActive - my.numActiveRef)) { action = "ADD"; sts = pmDelProfile(my.id, 0, NULL); if (sts >= 0) { list.resize(my.count); for (i = 0, j = 0; i < my.instances.size(); i++) if (!my.instances[i].null() && my.instances[i].refCount()) list[j++] = my.instances[i].inst(); ptr = list.data(); sts = pmAddProfile(my.id, list.size(), ptr); } } // Delete those active instances that are not referenced else { action = "DELETE"; sts = pmAddProfile(my.id, 0, NULL); if (sts >= 0) { list.resize(my.instances.size() - my.count); for (i = 0, j = 0; i < my.instances.size(); i++) if (!my.instances[i].null() && my.instances[i].refCount() == 0 && my.instances[i].active()) list[j++] = my.instances[i].inst(); ptr = list.data(); sts = pmDelProfile(my.id, list.size(), ptr); } } if (pmDebug & (DBG_TRACE_PMC | DBG_TRACE_INDOM | DBG_TRACE_PROFILE)) { QTextStream cerr(stderr); cerr << "QmcIndom::genProfile: id = " << my.id << ", count = " << my.count << ", numInsts = " << numInsts() << ", active = " << my.numActive << ", activeRef = " << my.numActiveRef << ": " << action << " ptr = " << ptr; if (sts < 0) cerr << ", sts = " << sts << ": " << pmErrStr(sts); cerr << endl; } if (sts >= 0) my.profile = false; return sts; } void QmcIndom::dump(QTextStream &os) const { os << pmInDomStr(my.id) << ": " << numInsts() << " instances (" << my.nullCount << " NULL)" << endl; for (int i = 0; i < my.instances.size(); i++) if (!my.instances[i].null()) os << " [" << my.instances[i].inst() << "] = \"" << my.instances[i].name() << "\" (" << my.instances[i].refCount() << " refs) " << (my.instances[i].active() ? "active" : "inactive") << endl; else os << " NULL -> " << my.instances[i].index() << endl; } int QmcIndom::update() { int *instList; char **nameList; int i, j, count; int oldLen = my.instances.size(); uint oldNullCount = my.nullCount; int sts = 0; // If the indom has already been updated, just check that all instances // are referenced and remove any that have gone away. if (!my.changed || my.updated) { for (i = 0; i < oldLen; i++) { QmcInstance &inst = my.instances[i]; if (inst.refCount() || inst.null() || inst.active()) continue; inst.deactivate(my.nullIndex); my.nullIndex = i; my.nullCount++; my.profile = true; } if (pmDebug & DBG_TRACE_INDOM && my.nullCount != oldNullCount) { QTextStream cerr(stderr); cerr << "QmcIndom::update: Cleaning indom " << pmInDomStr(my.id) << ": Removed " << my.nullCount - oldNullCount << " instances" << endl; } return 0; } my.updated = true; if (my.type == PM_CONTEXT_ARCHIVE) return 0; if (my.type == PM_CONTEXT_HOST || my.type == PM_CONTEXT_LOCAL) sts = pmGetInDom(my.id, &instList, &nameList); my.numActive = 0; my.numActiveRef = 0; if (sts > 0) { count = sts; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcIndom::update: Updating indom " << pmInDomStr(my.id) << ": Got " << count << " instances (vs " << numInsts() << ")" << endl; } // Any instances which are not in the new indom AND are not // referenced can be removed for (i = 0; i < oldLen; i++) { QmcInstance &inst = my.instances[i]; inst.setActive(false); if (inst.refCount() || inst.null()) continue; j = 0; if (i < count && inst.inst() == instList[i]) { if (inst.name().compare(nameList[i]) == 0) continue; else j = count; } for (; j < count; j++) { if (inst.inst() == instList[j]) { if (inst.name().compare(nameList[j]) == 0) break; else j = count; } } // If j >= count, then instance i has either changed or gone away if (j >= count) { inst.deactivate(my.nullIndex); my.nullIndex = i; my.nullCount++; my.profile = true; } } for (i = 0; i < count; i++) { // Quick check to see if they are the same if (i < my.instances.size() && my.instances[i].inst() == instList[i] && my.instances[i].name().compare(nameList[i]) == 0) { if (pmDebug & DBG_TRACE_INDOM) { QTextStream cerr(stderr); cerr << "QmcIndom::update: Unchanged \"" << nameList[i] << "\"(" << instList[i] << ')' << endl; } my.instances[i].setActive(true); my.numActive++; if (my.instances[i].refCount()) my.numActiveRef++; continue; } for (j = 0; j < oldLen; j++) { if (my.instances[j].null()) continue; if (my.instances[j].inst() == instList[i]) { // Same instance and same external name but different // order, mark as active. If it has a different // external name just ignore it if (my.instances[j].name().compare(nameList[i]) == 0) { my.instances[j].setActive(true); my.numActive++; if (my.instances[j].refCount()) my.numActiveRef++; } else if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcIndom::update: Ignoring \"" << nameList[i] << "\" with identical internal identifier (" << instList[i] << ")" << endl; } break; } } if (j == oldLen) { if (pmDebug & DBG_TRACE_INDOM) { QTextStream cerr(stderr); cerr << "QmcIndom::update: Adding \"" << nameList[i] << "\"(" << instList[i] << ")" << endl; } if (my.nullCount) { uint newindex = my.instances[my.nullIndex].index(); my.instances[my.nullIndex] = QmcInstance(instList[i], nameList[i]); my.nullIndex = newindex; my.nullCount--; } else my.instances.append(QmcInstance(instList[i], nameList[i])); my.profile = true; my.numActive++; } } free(instList); free(nameList); if (pmDebug & DBG_TRACE_INDOM) { QTextStream cerr(stderr); if (my.instances.size() == oldLen && my.nullCount == oldNullCount) cerr << "QmcIndom::update: indom size unchanged" << endl; else { cerr << "QmcIndom::update: indom changed from " << oldLen - oldNullCount << " to " << numInsts() << endl; dump(cerr); } } } else { for (i = 0; i < my.instances.size(); i++) my.instances[i].setActive(false); if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); if (sts == 0) cerr << "QmcIndom::update: indom empty!" << endl; else cerr << "QmcIndom::update: unable to lookup " << pmInDomStr(my.id) << " from host/local source: " << pmErrStr(sts) << endl; } } return sts; } pcp-gui-1.5.11/src/libqmc/qmc_metric.cpp0000644000000000000000000007554212176111212014725 0ustar /* * Copyright (c) 1997,2005 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2007 Aconex. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. */ #include #include #include QmcMetricValue::QmcMetricValue() { my.value = 0.0; my.currentValue = 0.0; my.previousValue = 0.0; my.error = PM_ERR_VALUE; my.currentError = PM_ERR_VALUE; my.previousError = PM_ERR_VALUE; my.instance = PM_ERR_INST; } QmcMetricValue const& QmcMetricValue::operator=(QmcMetricValue const& rhs) { if (this != &rhs) { my.instance = rhs.my.instance; my.value = rhs.my.value; my.currentValue = rhs.my.currentValue; my.previousValue = rhs.my.previousValue; my.stringValue = rhs.my.stringValue; my.error = rhs.my.error; my.currentError = rhs.my.currentError; my.previousError = rhs.my.previousError; } return *this; } QmcMetric::QmcMetric(QmcGroup *group, const char *string, double scale, bool active) { pmMetricSpec *metricSpec; char *msg; my.status = 0; my.group = group; my.scale = scale; my.idIndex = UINT_MAX; my.indomIndex = UINT_MAX; my.contextIndex = UINT_MAX; my.explicitInst = false; my.active = active; my.status = pmParseMetricSpec(string, 0, NULL, &metricSpec, &msg); if (my.status < 0) { pmprintf("%s: Error: Unable to parse metric spec:\n%s\n", pmProgname, msg); my.name = QString::null; free(msg); } else { my.name = QString(metricSpec->metric); setup(group, metricSpec); free(metricSpec); } } QmcMetric::QmcMetric(QmcGroup *group, pmMetricSpec *metricSpec, double scale, bool active) { my.pmid = PM_ID_NULL; my.status = 0; my.name = QString(metricSpec->metric); my.group = group; my.scale = scale; my.contextIndex = UINT_MAX; my.idIndex = 0; my.indomIndex = UINT_MAX; my.explicitInst = false; my.active = active; setup(group, metricSpec); } void QmcMetric::setup(QmcGroup* group, pmMetricSpec *metricSpec) { if (my.status >= 0) setupDesc(group, metricSpec); if (my.status >= 0) setupIndom(metricSpec); if (my.status < 0) return; if (pmDebug & DBG_TRACE_PMC) dumpAll(); } QmcMetric::~QmcMetric() { if (hasInstances()) for (int i = 0; i < my.values.size(); i++) indom()->removeRef(my.values[i].instance()); } void QmcMetric::setupDesc(QmcGroup* group, pmMetricSpec *metricSpec) { int contextType = PM_CONTEXT_HOST; int descType; char *src = NULL; char *name = NULL; if (metricSpec->isarch == 1) contextType = PM_CONTEXT_ARCHIVE; else if (metricSpec->isarch == 2) contextType = PM_CONTEXT_LOCAL; QString source = QString(metricSpec->source); my.status = group->use(contextType, source); my.contextIndex = group->contextIndex(); if (my.status >= 0) { contextType = context()->source().type(); my.status = context()->lookupPMID(metricSpec->metric, my.pmid); if (my.status >= 0) my.status = context()->lookupInDom(my.pmid, my.indomIndex); if (my.status < 0) { name = strdup(nameAscii()); src = strdup(context()->source().sourceAscii()); pmprintf("%s: Error: %s%c%s: %s\n", pmProgname, contextType == PM_CONTEXT_LOCAL ? "@" : src, contextType == PM_CONTEXT_ARCHIVE ? '/' : ':', name, pmErrStr(my.status)); } } else pmprintf("%s: Error: %s: %s\n", pmProgname, context()->source().descAscii(), pmErrStr(my.status)); if (my.status >= 0) { descType = desc().desc().type; if (descType == PM_TYPE_NOSUPPORT) { my.status = PM_ERR_CONV; name = strdup(nameAscii()); src = strdup(context()->source().sourceAscii()); pmprintf("%s: Error: %s%c%s is not supported on %s\n", pmProgname, contextType == PM_CONTEXT_LOCAL ? "@" : src, (contextType == PM_CONTEXT_ARCHIVE ? '/' : ':'), name, context()->source().hostAscii()); } else if (descType == PM_TYPE_AGGREGATE || descType == PM_TYPE_AGGREGATE_STATIC || descType == PM_TYPE_UNKNOWN) { my.status = PM_ERR_CONV; name = strdup(nameAscii()); src = strdup(context()->source().sourceAscii()); pmprintf("%s: Error: %s%c%s has type \"%s\"," " which is not a number or a string\n", pmProgname, contextType == PM_CONTEXT_LOCAL ? "@" : src, (contextType == PM_CONTEXT_ARCHIVE ? '/' : ':'), name, pmTypeStr(descType)); } } if (name) free(name); if (src) free(src); } void QmcMetric::setupIndom(pmMetricSpec *metricSpec) { int i, j; QmcIndom *indomPtr = indom(); if (!hasIndom()) { if (metricSpec->ninst > 0) { my.status = PM_ERR_INST; dumpErr(metricSpec->inst[0]); } else setupValues(1); } else if (metricSpec->ninst) { Q_ASSERT(hasInstances()); setupValues(metricSpec->ninst); for (i = 0 ; i < metricSpec->ninst && my.status >= 0; i++) { j = indomPtr->lookup(metricSpec->inst[i]); if (j >= 0) my.values[i].setInstance(j); else { my.status = PM_ERR_INST; my.values[i].setInstance(PM_ERR_INST); dumpErr(metricSpec->inst[i]); } } my.explicitInst = true; } else { Q_ASSERT(hasInstances()); if (my.active) { setupValues(indomPtr->numActiveInsts()); indomPtr->refAll(my.active); for (i = 0, j = 0; i < indomPtr->listLen(); i++) if (!indomPtr->nullInst(i) && indomPtr->activeInst(i)) my.values[j++].setInstance(i); } else { setupValues(indomPtr->numInsts()); indomPtr->refAll(my.active); for (i = 0, j = 0; i < indomPtr->listLen(); i++) if (!indomPtr->nullInst(i)) my.values[j++].setInstance(i); } } } void QmcMetric::setupValues(int num) { int i, oldLen = my.values.size(); if (num == 0) my.values.clear(); else { if (my.values.size() > num) for (i = num; i < my.values.size(); i++) my.values.removeAt(i); for (i = oldLen; i < num; i++) my.values.append(QmcMetricValue()); } } QString QmcMetric::spec(bool srcFlag, bool instFlag, uint instance) const { QString str; int i, len = 4; if (srcFlag) len += context()->source().source().size(); len += name().size(); if (hasInstances() && instFlag) { if (instance != UINT_MAX) len += instName(instance).size() + 2; else for (i = 0; i < numInst(); i++) len += instName(i).size() + 4; } if (srcFlag) { str.append(context()->source().source()); if (context()->source().type() == PM_CONTEXT_ARCHIVE) str.append(QChar('/')); else str.append(QChar(':')); } str.append(name()); if (hasInstances() && instFlag) { str.append(QChar('[')); str.append(QChar('\"')); if (instance != UINT_MAX) str.append(instName(instance)); else if (numInst()) { str.append(instName(0)); for (i = 1; i < numInst(); i++) { str.append("\", \""); str.append(instName(i)); } } str.append("\"]"); } return str; } void QmcMetric::dumpSource(QTextStream &os) const { switch(context()->source().type()) { case PM_CONTEXT_LOCAL: os << "@:"; break; case PM_CONTEXT_HOST: os << context()->source().source() << ':'; break; case PM_CONTEXT_ARCHIVE: os << context()->source().source() << '/'; break; } } void QmcMetric::dumpValue(QTextStream &stream, uint inst) const { if (error(inst) < 0) stream << pmErrStr(error(inst)); else if (!real()) stream << stringValue(inst); else if (!event()) stream << value(inst) << " " << desc().units(); } void QmcMetric::dump(QTextStream &stream, bool srcFlag, uint instance) const { if (event()) dumpEventMetric(stream, srcFlag, instance); else dumpSampledMetric(stream, srcFlag, instance); } void QmcMetric::dumpSampledMetric(QTextStream &stream, bool srcFlag, uint instance) const { Q_ASSERT(!event()); stream << name(); if (srcFlag == true) dumpSource(stream); if (my.status < 0) stream << ": " << pmErrStr(my.status) << endl; else if (hasInstances()) { if (instance == UINT_MAX) { if (numInst() == 1) stream << ": 1 instance"; else stream << ": " << numInst() << " instances"; if (indom()->changed()) stream << " (indom has changed)"; stream << endl; for (int i = 0; i < numInst(); i++) { stream << " [" << instID(i) << " or \"" << instName(i) << "\" (" << my.values[i].instance() << ")] = "; dumpValue(stream, i); stream << endl; } } else { stream << '[' << instID(instance) << " or \"" << instName(instance) << "\" (" << my.values[instance].instance() << ")] = "; dumpValue(stream, instance); stream << endl; } } else { stream << " = "; dumpValue(stream, 0); stream << endl; } } QTextStream& operator<<(QTextStream &stream, const QmcMetric &metric) { metric.dumpSource(stream); stream << metric.name(); if (metric.numInst()) { stream << "[\"" << metric.instName(0); for (int i = 1; i < metric.numValues(); i++) stream << "\", \"" << metric.instName(i); stream << "\"]"; } return stream; } void QmcMetric::setScaleUnits(pmUnits const& units) { QmcContext *context = my.group->context(my.contextIndex); QmcDesc &desc = context->desc(my.pmid); desc.setScaleUnits(units); } int QmcMetric::update() { uint i, err = 0; uint num = numValues(); int sts; pmAtomValue ival, oval; double delta = context()->timeDelta(); static int wrap = -1; if (num == 0 || my.status < 0) return my.status; // PCP_COUNTER_WRAP in environment enables "counter wrap" logic if (wrap == -1) wrap = (getenv("PCP_COUNTER_WRAP") != NULL); for (i = 0; i < num; i++) { my.values[i].setError(my.values[i].currentError()); if (my.values[i].error() < 0) err++; if (pmDebug & DBG_TRACE_VALUE) { QTextStream cerr(stderr); if (my.values[i].error() < 0) cerr << "QmcMetric::update: " << spec(true, true, i) << ": " << pmErrStr(my.values[i].error()) << endl; } } if (!real()) return err; if (desc().desc().sem == PM_SEM_COUNTER) { for (i = 0; i < num; i++) { QmcMetricValue& value = my.values[i]; if (value.error() < 0) { // we already know we value.setValue(0.0); // don't have this value continue; } if (value.previousError() < 0) { // we need two values value.setValue(0.0); // for a rate value.setError(value.previousError()); err++; if (pmDebug & DBG_TRACE_VALUE) { QTextStream cerr(stderr); cerr << "QmcMetric::update: Previous: " << spec(true, true, i) << ": " << pmErrStr(value.error()) << endl; } continue; } value.setValue(value.currentValue() - value.previousValue()); // wrapped going forwards if (value.value() < 0 && delta > 0) { if (wrap) { switch(desc().desc().type) { case PM_TYPE_32: case PM_TYPE_U32: value.addValue((double)UINT_MAX+1); break; case PM_TYPE_64: case PM_TYPE_U64: value.addValue((double)ULONGLONG_MAX+1); break; } } else { // counter not monotonic value.setValue(0.0); // increasing value.setError(PM_ERR_VALUE); err++; continue; } } // wrapped going backwards else if (value.value() > 0 && delta < 0) { if (wrap) { switch(desc().desc().type) { case PM_TYPE_32: case PM_TYPE_U32: value.subValue((double)UINT_MAX+1); break; case PM_TYPE_64: case PM_TYPE_U64: value.subValue((double)ULONGLONG_MAX+1); break; } } else { // counter not monotonic value.setValue(0.0); // increasing value.setError(PM_ERR_VALUE); err++; continue; } } if (delta != 0) // sign of delta and v value.divValue(delta); // should be the same else value.setValue(0.0); // nothing can have happened } } else { for (i = 0; i < num; i++) { QmcMetricValue& value = my.values[i]; if (value.error() < 0) value.setValue(0.0); else value.setValue(value.currentValue()); } } if (my.scale != 0.0) { for (i = 0; i < num; i++) { if (my.values[i].error() >= 0) my.values[i].divValue(my.scale); } } if (desc().useScaleUnits()) { for (i = 0; i < num; i++) { if (my.values[i].error() < 0) continue; ival.d = my.values[i].value(); pmUnits units = desc().desc().units; sts = pmConvScale(PM_TYPE_DOUBLE, &ival, &units, &oval, (pmUnits *)&(desc().scaleUnits())); if (sts < 0) my.values[i].setError(sts); else { my.values[i].setValue(oval.d); if (pmDebug & DBG_TRACE_VALUE) { QTextStream cerr(stderr); cerr << "QmcMetric::update: scaled " << my.name << " from " << ival.d << " to " << oval.d << endl; } } } } return err; } void QmcMetric::dumpAll() const { QTextStream cerr(stderr); cerr << *this << " from " << context()->source().desc() << " with scale = " << my.scale << " and units = " << desc().units() << endl; } void QmcMetric::dumpErr() const { pmprintf("%s: Error: %s: %s\n", pmProgname, (const char *)spec(true).toAscii(), pmErrStr(my.status)); } // Instance list may not be valid, so pass inst as a string rather than // as an index void QmcMetric::dumpErr(const char *inst) const { pmprintf("%s: Error: %s[%s]: %s\n", pmProgname, (const char *)spec(true).toAscii(), inst, pmErrStr(my.status)); } const char * QmcMetric::formatNumber(double value) { static char buf[8]; if (value >= 0.0) { if (value > 99950000000000.0) strcpy(buf, " inf?"); else if (value > 99950000000.0) sprintf(buf, "%5.2fT", value / 1000000000000.0); else if (value > 99950000.0) sprintf(buf, "%5.2fG", value / 1000000000.0); else if (value > 99950.0) sprintf(buf, "%5.2fM", value / 1000000.0); else if (value > 99.95) sprintf(buf, "%5.2fK", value / 1000.0); else if (value > 0.005) sprintf(buf, "%5.2f ", value); else strcpy(buf, " 0.00 "); } else { if (value < -9995000000000.0) strcpy(buf, " -inf?"); else if (value < -9995000000.0) sprintf(buf, "%.2fT", value / 1000000000000.0); else if (value < -9995000.0) sprintf(buf, "%.2fG", value / 1000000000.0); else if (value < -9995.0) sprintf(buf, "%.2fM", value / 1000000.0); else if (value < -9.995) sprintf(buf, "%.2fK", value / 1000.0); else if (value < -0.005) sprintf(buf, "%.2f ", value); else strcpy(buf, " 0.00 "); } return buf; } void QmcMetric::shiftValues() { for (int i = 0; i < my.values.size(); i++) my.values[i].shiftValues(); } void QmcMetric::setError(int sts) { for (int i = 0; i < numValues(); i++) { QmcMetricValue &value = my.values[i]; value.setCurrentError(sts); } } void QmcMetric::extractValues(pmValueSet const* set) { int i, j, index, inst; pmValue const *value = NULL; bool found; QmcIndom *indomPtr = indom(); Q_ASSERT(set->pmid == desc().id()); if (set->numval > 0) { if (hasIndom()) { // If the number of instances are not the expected number // then mark the indom as changed if (!my.explicitInst && (my.values.size() != set->numval)) { if (pmDebug & DBG_TRACE_INDOM) { QTextStream cerr(stderr); cerr << "QmcMetric::extractValues: implicit indom " << pmInDomStr(indomPtr->id()) << " changed (" << set->numval << " != " << my.values.size() << ')' << endl; } indomPtr->hasChanged(); updateIndom(); } for (i = 0; i < numInst(); i++) { QmcMetricValue &valueRef = my.values[i]; inst = my.values[i].instance(); index = indomPtr->index(inst); found = false; // If the index is within range, try it first if (index >= 0 && index < set->numval) { value = &(set->vlist[index]); // Found it in the same spot as last time if (value->inst == indomPtr->inst(inst)) found = true; } // Search for it from the top for (j = 0; found == false && j < set->numval; j++) { if (set->vlist[j].inst == indomPtr->inst(inst)) { index = j; value = &(set->vlist[j]); indomPtr->setIndex(inst, j); found = true; } } if (found) { if (real()) extractNumericMetric(set, value, valueRef); else if (!event()) extractArrayMetric(set, value, valueRef); else extractEventMetric(set, index, valueRef); } else { // Cannot find it if (pmDebug & DBG_TRACE_OPTFETCH) { QTextStream cerr(stderr); cerr << "QmcMetric::extractValues: " << spec(true, true, i) << ": " << pmErrStr(PM_ERR_VALUE) << endl; } if (valueRef.previousError() != PM_ERR_VALUE) indomPtr->hasChanged(); valueRef.setCurrentError(PM_ERR_VALUE); } } } else if (set->numval == 1) { // We have no instances at this point in time if (my.values.size() == 0 && hasInstances()) indomPtr->hasChanged(); else { QmcMetricValue &valueRef = my.values[0]; value = &(set->vlist[0]); if (real()) extractNumericMetric(set, value, valueRef); else if (!event()) extractArrayMetric(set, value, valueRef); else extractEventMetric(set, 0, valueRef); } } else { // Did not expect any instances if (pmDebug & DBG_TRACE_OPTFETCH) { QTextStream cerr(stderr); cerr << "QmcMetric::extractValues: " << spec(true) << " is a singular metric but result contained " << set->numval << " values" << endl; } setError(PM_ERR_VALUE); } } else if (set->numval == 0) { if (!(hasInstances() && numInst() == 0)) { if (pmDebug & DBG_TRACE_OPTFETCH) { QTextStream cerr(stderr); cerr << "QmcMetric::extractValues: numval == 0: " << spec(true, false) << ": " << pmErrStr(PM_ERR_VALUE) << endl; } setError(PM_ERR_VALUE); if (hasInstances()) indomPtr->hasChanged(); } } else { if (pmDebug & DBG_TRACE_OPTFETCH) { QTextStream cerr(stderr); cerr << "QmcMetric::extractValues: numval < 0: " << spec(true, false) << ": " << pmErrStr(set->numval) << endl; } setError(set->numval); if (hasInstances()) indomPtr->hasChanged(); } } /* * Display-able aggregate (for diagnostics) - up to * first 16 characters displayed. Uses a similar * approach to that taken in pmPrintValue(). */ void QmcMetric::aggregateAsString(pmValue const *vp, char *buffer, int buflen) { char *p = &vp->value.pval->vbuf[0]; memset(buffer, '.', buflen); for (int i = 0; i < (buflen/2)-1; i++, p++) { if (i < vp->value.pval->vlen - PM_VAL_HDR_SIZE) sprintf(buffer + (i*2), "%02x", *p & 0xff); } buffer[buflen-1] = '\0'; } void QmcMetric::extractArrayMetric(pmValueSet const *set, pmValue const *vp, QmcMetricValue &valueRef) { pmAtomValue result; int sts, type = desc().desc().type; if (aggregate(type)) { char buffer[32]; aggregateAsString(vp, buffer, sizeof(buffer)); valueRef.setStringValue(buffer); } else if ((sts = pmExtractValue(set->valfmt, vp, type, &result, PM_TYPE_STRING)) >= 0) { valueRef.setStringValue(result.cp); if (result.cp) free(result.cp); } else { valueRef.setCurrentError(sts); } } void QmcMetric::extractNumericMetric(pmValueSet const *set, pmValue const *value, QmcMetricValue &valueRef) { pmAtomValue result; int sts; if ((sts = pmExtractValue(set->valfmt, value, desc().desc().type, &result, PM_TYPE_DOUBLE)) >= 0) valueRef.setCurrentValue(result.d); else valueRef.setCurrentError(sts); } void QmcMetricValue::extractEventRecords(QmcContext *context, int recordCount, pmResult **result) { pmID parameterID; pmID missedID = QmcEventRecord::eventMissed(); pmID flagsID = QmcEventRecord::eventFlags(); int i, p, r, parameterCount; my.eventRecords.resize(recordCount); for (r = 0; r < recordCount; r++) { QmcEventRecord &record = my.eventRecords[r]; // count is the size of my.parameter vector (less flags/missed) parameterCount = 0; for (i = 0; i < result[r]->numpmid; i++) { parameterID = result[r]->vset[i]->pmid; if (parameterID != flagsID && parameterID != missedID) parameterCount++; } // initialise this record record.setTimestamp(&result[r]->timestamp); record.setParameterCount(parameterCount); record.setMissed(0); record.setFlags(0); // i indexes into result[r], p indexes into my.parameter vector for (i = p = 0; i < result[r]->numpmid; i++) { pmValueSet *valueSet = result[r]->vset[i]; parameterID = valueSet->pmid; if (parameterID == flagsID) record.setFlags(valueSet->vlist[0].value.lval); else if (parameterID == missedID) record.setMissed(valueSet->vlist[0].value.lval); else record.setParameter(p++, parameterID, context, valueSet); } if (pmDebug & DBG_TRACE_VALUE) { QTextStream cerr(stderr); pmValueSet *valueSet = result[r]->vset[0]; record.dump(cerr, valueSet->vlist[0].inst, r); } } } void QmcMetric::extractEventMetric(pmValueSet const *valueSet, int index, QmcMetricValue &valueRef) { pmValueSet *values = (pmValueSet *)valueSet; pmResult **result; int sts; if ((sts = pmUnpackEventRecords(values, index, &result)) >= 0) { valueRef.extractEventRecords(context(), sts, result); pmFreeEventResult(result); } else { valueRef.setCurrentError(sts); } } int QmcEventRecord::setParameter(int index, pmID pmid, QmcContext *context, pmValueSet const *vsp) { QString *name; QmcDesc *desc; QmcIndom *indom; int sts, type; if (vsp->numval <= 0) // no value or an error return vsp->numval; if ((sts = context->lookup(pmid, &name, &desc, &indom)) < 0) return sts; QmcEventParameter ¶meter = my.parameters[index]; parameter.setPMID(pmid); parameter.setNamePtr(name); parameter.setDescPtr(desc); parameter.setIndomPtr(indom); parameter.setValueCount(vsp->numval); type = desc->desc().type; for (int i = 0; i < vsp->numval; i++) { pmAtomValue result; const pmValue *vp = &vsp->vlist[i]; QmcMetricValue *value = parameter.valuePtr(i); sts = PM_ERR_TYPE; // no nesting events if (QmcMetric::real(type) == true) { if ((sts = pmExtractValue(vsp->valfmt, vp, type, &result, PM_TYPE_DOUBLE)) >= 0) value->setCurrentValue(result.d); } else if (QmcMetric::aggregate(type) == true) { char buffer[32]; QmcMetric::aggregateAsString(vp, buffer, sizeof(buffer)); value->setStringValue(buffer); } else if (QmcMetric::event(type) == false) { if ((sts = pmExtractValue(vsp->valfmt, vp, type, &result, PM_TYPE_STRING)) >= 0) { value->setStringValue(result.cp); free(result.cp); } } value->setInstance(vp->inst); if (sts < 0) value->setCurrentError(sts); } return 0; } QString QmcEventRecord::parameterAsString(int index) const { QString identifier; if (index >= my.parameters.size()) return QString::null; int type = my.parameters[index].type(); if (QmcMetric::real(type)) return QString::number(my.parameters.at(index).value(0)); if (QmcMetric::event(type)) return QString::null; return my.parameters.at(index).stringValue(0); } QString QmcEventRecord::identifier() const { // // If the ID flag is set, the identifier is always the // first parameter. // if (my.flags & PM_EVENT_FLAG_ID) return parameterAsString(0); return QString::null; } QString QmcEventRecord::parent() const { // // If PARENT flag is set, then parent identifier is either // the first parameter (if no ID, bit wierd) or the second // (thats expected typical usage anyway). // if (my.flags & PM_EVENT_FLAG_PARENT) return parameterAsString((my.flags & PM_EVENT_FLAG_ID) != 0); return QString::null; } void QmcEventRecord::parameterSummary(QString &os, int instID) const { for (int i = 0; i < my.parameters.size(); i++) my.parameters.at(i).summary(os, instID); } void QmcEventParameter::summary(QString &os, int instID) const { pmDesc desc = my.desc->desc(); for (int i = 0; i < my.values.size(); i++) { QmcMetricValue const &value = my.values.at(i); os.append(" ").append(*my.name); if (desc.indom != PM_INDOM_NULL) { if (my.values.size() > 1) os.append("\n").append(" "); QString name = my.indom->name(instID); if (name == QString::null) os.append("[").append(instID).append("]"); else os.append("[\"").append(name).append("\"]"); } os.append(" "); if (QmcMetric::real(desc.type)) os.append(QString::number(value.currentValue())); else if (QmcMetric::aggregate(desc.type)) os.append("[").append(value.stringValue()).append("]"); else if (QmcMetric::event(desc.type) == false) os.append("\"").append(value.stringValue()).append("\""); os.append("\n"); } } void QmcEventParameter::setValueCount(int numInst) { my.values.resize(numInst); } QmcMetricValue * QmcEventParameter::valuePtr(int inst) { return &my.values[inst]; } int QmcEventParameter::type() const { return my.desc->desc().type; } double QmcEventParameter::value(int inst) const { return my.values[inst].currentValue(); } QString QmcEventParameter::stringValue(int inst) const { return my.values[inst].stringValue(); } void QmcEventParameter::dump(QTextStream &os, int instID) const { pmDesc desc = my.desc->desc(); for (int i = 0; i < my.values.size(); i++) { QmcMetricValue const &value = my.values.at(i); os << " " << *my.name; if (desc.indom != PM_INDOM_NULL) { if (my.values.size() > 1) os << endl << " "; QString name = my.indom->name(instID); if (name == QString::null) os << "[" << instID << "]"; else os << "[\"" << name << "\"]"; } os << " "; if (QmcMetric::real(desc.type)) os << value.currentValue(); else if (QmcMetric::aggregate(desc.type)) os << "[" << value.stringValue() << "]"; else if (QmcMetric::event(desc.type) == false) os << "\"" << value.stringValue() << "\""; os << endl; } } void QmcEventRecord::dump(QTextStream &os, int instID, uint recordID) const { os << " " << QmcSource::timeStringBrief(&my.timestamp); os << " --- event record [" << recordID << "]"; if (my.flags) { os.setIntegerBase(16); os << " flags 0x" << (uint)my.flags << " (" << pmEventFlagsStr(my.flags) << ")"; os.setIntegerBase(10); } os << " ---" << endl; if (my.flags & PM_EVENT_FLAG_MISSED) os << " ==> " << my.missed << " missed event records" << endl; for (int i = 0; i < my.parameters.size(); i++) my.parameters.at(i).dump(os, instID); } void QmcMetricValue::dumpEventRecords(QTextStream &os, int instID) const { os << my.eventRecords.size() << " event records" << endl; for (int i = 0; i < my.eventRecords.size(); i++) my.eventRecords.at(i).dump(os, instID, i); } void QmcMetric::dumpEventMetric(QTextStream &os, bool srcFlag, uint instance) const { Q_ASSERT(event()); for (int i = 0; i < my.values.size(); i++) { int instID; if (srcFlag == true) dumpSource(os); os << name(); instID = PM_IN_NULL; if (hasInstances()) { if (instance != UINT_MAX) instID = (int)instance; else instID = my.values[i].instance(); QString inst = instName(instID); if (inst == QString::null) os << "[" << instID << "]"; else os << "[\"" << inst << "\"]"; } os << ": "; my.values[i].dumpEventRecords(os, instID); } } pmID QmcEventRecord::eventMissed(void) { static pmID eventMissed = PM_IN_NULL; static const char *nameMissed[] = { "event.missed" }; if (eventMissed == PM_ID_NULL) if (pmLookupName(1, (char **)nameMissed, &eventMissed) < 0) eventMissed = PM_ID_NULL; return eventMissed; } pmID QmcEventRecord::eventFlags(void) { static pmID eventFlags = PM_IN_NULL; static const char *nameFlags[] = { "event.flags" }; if (eventFlags == PM_ID_NULL) if (pmLookupName(1, (char **)nameFlags, &eventFlags) < 0) eventFlags = PM_ID_NULL; return eventFlags; } bool QmcMetric::updateIndom(void) { int i = 0, j, oldNum = numInst(), newNum, newInst; QmcIndom *indomPtr = indom(); if (status() < 0 || !hasIndom()) return false; if (indomPtr->changed()) indomPtr->update(); my.explicitInst = false; newNum = my.active ? indomPtr->numActiveInsts() : indomPtr->numInsts(); // If the number of instances are the same then we know that no // modifications to the metric instance list is required as these // instances are all referenced in the indom // // If the instance list is only active instances, then we need to // check all the instances as the number may be the same // if (newNum == oldNum) { if (my.active) { for (i = 0; i < my.values.size(); i++) if (!indomPtr->activeInst(my.values[i].instance())) break; } if (!my.active || i == my.values.size()) { if (pmDebug & DBG_TRACE_INDOM) { QTextStream cerr(stderr); cerr << "QmcMetric::updateIndom: No change required" << endl; } return false; } } // Duplicate the current values // Replace the old index into the indom instance list with the // internal instance identifiers so that these can be correlated // if the order of instances changes QList oldValues = my.values; for (i = 0; i < oldNum; i++) { oldValues[i].setInstance(indomPtr->inst(my.values[i].instance())); indomPtr->removeRef(my.values[i].instance()); } setupValues(newNum); indomPtr->refAll(my.active); if (my.active) { for (i = 0, j = 0; i < indomPtr->listLen(); i++) if (!indomPtr->nullInst(i) && indomPtr->activeInst(i)) my.values[j++].setInstance(i); } else { for (i = 0, j = 0; i < indomPtr->listLen(); i++) if (!indomPtr->nullInst(i)) my.values[j++].setInstance(i); } // Copy values of instances that have not gone away // Note that their position may have changed for (i = 0; i < my.values.size(); i++) { if (i < oldValues.size() && indomPtr->inst(my.values[i].instance()) == oldValues[i].instance()) { newInst = my.values[i].instance(); my.values[i] = oldValues[i]; my.values[i].setInstance(newInst); continue; } for (j = 0; j < oldValues.size(); j++) if (indomPtr->inst(my.values[i].instance()) == oldValues[j].instance()) { newInst = my.values[i].instance(); my.values[i] = oldValues[j]; my.values[i].setInstance(newInst); break; } // Need to set all error flags to avoid problems with rate conversion if (j == oldValues.size()) my.values[i].setAllErrors(PM_ERR_VALUE); } if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcMetric::updateIndom: " << spec(true) << ": Had " << oldNum << " instances, now have " << numInst() << endl; } indomPtr->update(); return true; } int QmcMetric::addInst(QString const& name) { if (my.status < 0) return my.status; if (!hasInstances()) return PM_ERR_INDOM; int i = indom()->lookup(name); if (i >= 0) { setupValues(my.values.size() + 1); my.values.last().setInstance(i); } return i; } void QmcMetric::removeInst(uint index) { Q_ASSERT(hasInstances()); indom()->removeRef(my.values[index].instance()); my.values.removeAt(index); } pcp-gui-1.5.11/src/libqmc/qmc_source.cpp0000644000000000000000000002502612213235215014734 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2007 Aconex. All Rights Reserved. * Copyright (c) 1998,2005 Silicon Graphics, Inc. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. */ #include QString QmcSource::localHost; QList QmcSource::sourceList; QmcSource::QmcSource(int type, QString &source, int flags) { my.status = -1; my.flags = flags; my.type = type; my.tz = 0; my.dupFlag = false; if (localHost.length() == 0) { char buf[MAXHOSTNAMELEN]; gethostname(buf, MAXHOSTNAMELEN); buf[MAXHOSTNAMELEN-1] = '\0'; localHost = buf; } this->retryConnect(type, source); } void QmcSource::retryConnect(int type, QString &source) { int oldTZ; int oldContext; int offset; int sts; char *tzs; QString hostSpec; my.attrs = QString::null; switch(type) { case PM_CONTEXT_LOCAL: my.desc = "Local context"; my.host = my.source = localHost; my.proxy = ""; break; case PM_CONTEXT_HOST: my.desc = "host \""; my.desc.append(source); my.desc.append(QChar('\"')); my.host = source; my.proxy = getenv("PMPROXY_HOST"); if ((offset = my.host.indexOf('?')) >= 0) { my.attrs = my.host; my.attrs.remove(0, offset+1); my.host.truncate(offset); } if ((offset = my.host.indexOf('@')) >= 0) { my.proxy = my.host; my.proxy.remove(0, offset+1); } my.source = my.host; break; case PM_CONTEXT_ARCHIVE: my.desc = "archive \""; my.desc.append(source); my.desc.append(QChar('\"')); my.source = source; my.proxy = ""; break; } oldContext = pmWhichContext(); hostSpec = source; if (my.attrs != QString::null) hostSpec.append("?").append(my.attrs); my.status = pmNewContext(type | my.flags, (const char *)hostSpec.toAscii()); if (my.status >= 0) { my.handles.append(my.status); // Fetch the server-side host name for this context, properly as of pcp 3.8.3+. my.context_hostname = pmGetContextHostName (my.status); // NB: may leak memory if (my.context_hostname == "") // may be returned for errors or PM_CONTEXT_LOCAL my.context_hostname = localHost; if (my.type == PM_CONTEXT_ARCHIVE) { pmLogLabel lp; sts = pmGetArchiveLabel(&lp); if (sts < 0) { pmprintf("%s: Unable to obtain log label for \"%s\": %s\n", pmProgname, (const char *)my.desc.toAscii(), pmErrStr(sts)); my.host = "unknown?"; my.status = sts; goto done; } else { my.host = lp.ll_hostname; my.start = lp.ll_start; } sts = pmGetArchiveEnd(&my.end); if (sts < 0) { pmprintf("%s: Unable to determine end of \"%s\": %s\n", pmProgname, (const char *)my.desc.toAscii(), pmErrStr(sts)); my.status = sts; goto done; } } else { gettimeofday(&my.start, NULL); my.end = my.start; } if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcSource::QmcSource: Created context " << my.handles.last() << " to " << my.desc << endl; } oldTZ = pmWhichZone(&tzs); my.tz = pmNewContextZone(); if (my.tz < 0) pmprintf("%s: Warning: Unable to obtain timezone for %s: %s\n", pmProgname, (const char *)my.desc.toAscii(), pmErrStr(my.tz)); else { sts = pmWhichZone(&tzs); if (sts >= 0) my.timezone = tzs; else pmprintf("%s: Warning: Unable to obtain timezone for %s: %s\n", pmProgname, (const char *)my.desc.toAscii(), pmErrStr(sts)); } if (oldTZ >= 0) { sts = pmUseZone(oldTZ); if (sts < 0) { pmprintf("%s: Warning: Unable to switch timezones." " Using timezone for %s: %s\n", pmProgname, (const char *)my.desc.toAscii(), pmErrStr(sts)); } } } else if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcSource::QmcSource: Context to " << source << " failed: " << pmErrStr(my.status) << endl; } done: sourceList.append(this); if (oldContext >= 0) { sts = pmUseContext(oldContext); if (sts < 0) { pmprintf("%s: Warning: Unable to switch contexts." " Using context to %s: %s\n", pmProgname, (const char *)my.desc.toAscii(), pmErrStr(sts)); } } } QmcSource::~QmcSource() { int i; for (i = 0; i < sourceList.size(); i++) if (sourceList[i] == this) break; if (i < sourceList.size()) sourceList.removeAt(i); } QString QmcSource::timeString(const struct timeval *timeval) { QString timestring; char timebuf[32], *ddmm, *year; struct tm tmp; time_t secs = (time_t)timeval->tv_sec; ddmm = pmCtime(&secs, timebuf); ddmm[10] = '\0'; year = &ddmm[20]; year[4] = '\0'; pmLocaltime(&secs, &tmp); timestring.sprintf("%02d:%02d:%02d.%03d", tmp.tm_hour, tmp.tm_min, tmp.tm_sec, (int)(timeval->tv_usec/1000)); timestring.prepend(" "); timestring.prepend(ddmm); timestring.append(" "); timestring.append(year); return timestring; } QString QmcSource::timeStringBrief(const struct timeval *timeval) { QString timestring; struct tm tmp; time_t secs = (time_t)timeval->tv_sec; pmLocaltime(&secs, &tmp); timestring.sprintf("%02d:%02d:%02d.%03d", tmp.tm_hour, tmp.tm_min, tmp.tm_sec, (int)(timeval->tv_usec/1000)); return timestring; } bool QmcSource::compare(int type, QString &source, int flags) { if (this->type() != type) return false; if (this->flags() != flags) return false; return this->source() == source; } QmcSource* QmcSource::getSource(int type, QString &source, int flags, bool matchHosts) { int i; QmcSource *src = NULL; for (i = 0; i < sourceList.size(); i++) { src = sourceList[i]; if (matchHosts && type == PM_CONTEXT_HOST) { if (src->type() == PM_CONTEXT_ARCHIVE && src->host() == source) { if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcSource::getSource: Matched host " << source << " to archive " << src->source() << " (source " << i << ")" << endl; } break; } } else if (src->compare(type, source, flags)) { if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcSource::getSource: Matched " << source << " to source " << i << endl; } if (src->status() < 0) src->retryConnect(type, source); break; } } if (i == sourceList.size() && !(matchHosts == true && type == PM_CONTEXT_HOST)) { if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); if (type != PM_CONTEXT_LOCAL) cerr << "QmcSource::getSource: Creating new source for " << source << endl; else cerr << "QmcSource::getSource: Creating new local context" << endl; } src = new QmcSource(type, source, flags); } if (src == NULL && pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcSource::getSource: Unable to map host " << source << " to an arch context" << endl; } return src; } int QmcSource::dupContext() { int sts = 0; if (my.status < 0) return my.status; if (my.dupFlag == false && my.handles.size() == 1) { sts = pmUseContext(my.handles[0]); if (sts >= 0) { sts = my.handles[0]; my.dupFlag = true; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcSource::dupContext: Using original context for " << my.desc << endl; } } else pmprintf("%s: Error: Unable to switch to context for \"%s\": %s\n", pmProgname, (const char *)my.desc.toAscii(), pmErrStr(sts)); } else if (my.handles.size()) { sts = pmUseContext(my.handles[0]); if (sts >= 0) { sts = pmDupContext(); if (sts >= 0) { my.handles.append(sts); if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcSource::dupContext: " << my.desc << " duplicated, handle[" << my.handles.size() - 1 << "] = " << sts << endl; } } else pmprintf("%s: Error: " "Unable to duplicate context to \"%s\": %s\n", pmProgname, (const char *)my.desc.toAscii(), pmErrStr(sts)); } else pmprintf("%s: Error: Unable to switch to context for \"%s\": %s\n", pmProgname, (const char *)my.desc.toAscii(), pmErrStr(sts)); } // No active contexts, create a new context else { sts = pmNewContext(my.type, sourceAscii()); if (sts >= 0) { my.handles.append(sts); if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcSource::dupContext: new context to " << my.desc << " created, handle = " << sts << endl; } } } if (sts < 0 && pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcSource::dupContext: context to " << my.desc << " failed: " << pmErrStr(my.status) << endl; } return sts; } int QmcSource::delContext(int handle) { int i; int sts; for (i = 0; i < my.handles.size(); i++) if (my.handles[i] == handle) break; if (i == my.handles.size()) { if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcSource::delContext: Attempt to delete " << handle << " from list for " << my.desc << ", but it is not listed" << endl; } return PM_ERR_NOCONTEXT; } sts = pmDestroyContext(my.handles[i]); my.handles.removeAt(i); // If this is a valid source, but no more contexts remain, // then we should delete ourselves if (my.handles.size() == 0 && my.status >= 0) { if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcSource::delContext: No contexts remain, removing " << my.desc << endl; } delete this; } return sts; } QTextStream& operator<<(QTextStream &stream, const QmcSource &rhs) { stream << rhs.my.desc; return stream; } void QmcSource::dump(QTextStream &stream) { stream << " sts = " << my.status << ", type = " << my.type << ", source = " << my.source << endl << " host = " << my.host << ", timezone = " << my.timezone << ", tz hndl = " << my.tz << endl; if (my.status >= 0) stream << " start = " << timeString(&my.start) << ", end = " << timeString(&my.end) << ", dupFlag = " << (my.dupFlag == true ? "true" : "false") << endl << " " << my.handles.size() << " contexts: "; for (int i = 0; i < my.handles.size(); i++) stream << my.handles[i] << ' '; stream << endl; } void QmcSource::dumpList(QTextStream &stream) { stream << sourceList.size() << " sources:" << endl; for (int i = 0; i < sourceList.size(); i++) { stream << '[' << i << "] " << *(sourceList[i]) << endl; sourceList[i]->dump(stream); } } pcp-gui-1.5.11/src/libqmc/qmc.h0000644000000000000000000000113412176111212013011 0ustar /* * Copyright (c) 1998-2005 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2007 Aconex. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. */ #ifndef QMC_H #define QMC_H #include #include // // Classes // class QmcContext; class QmcDesc; class QmcGroup; class QmcIndom; class QmcMetric; class QmcSource; #endif // QMC_H pcp-gui-1.5.11/src/libqmc/qmc_context.h0000644000000000000000000000761212176111212014564 0ustar /* * Copyright (c) 2012 Red Hat. * Copyright (c) 2007 Aconex. All Rights Reserved. * Copyright (c) 1998-2005 Silicon Graphics, Inc. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. */ #ifndef QMC_CONTEXT_H #define QMC_CONTEXT_H #include #include #include #include #include #include #include #include class QmcContext { public: QmcContext(QmcSource *source); ~QmcContext(); int status() const // Is this a valid context? { return (my.context < 0) ? my.context : 0; } int handle() const // The PMAPI context handle { return my.context; } QmcSource const& source() const // Source description { return *my.source; } unsigned int numIDs() const // Number of unique pmIDs in use { return my.pmids.size(); } pmID id(unsigned int index) const // Access to each unique pmID { return my.pmids[index]; } QmcDesc const& desc(pmID pmid) const { return *(my.descCache.value(pmid)); } QmcDesc& desc(pmID pmid) // Access to each descriptor { return *(my.descCache.value(pmid)); } unsigned int numIndoms() const // Number of indom descriptors { return my.indoms.size(); } // requested from this context QmcIndom const& indom(unsigned int index) const { return *(my.indoms[index]); } QmcIndom& indom(unsigned int index) // Access to each indom { return *(my.indoms[index]); } // Lookup the pmid or indom (implies descriptor) for metric | int lookupPMID(const char *name, pmID& id); int lookupInDom(const char *name, unsigned int& indom); int lookupInDom(QmcDesc *desc, uint_t& indom); // Lookup various structures using the pmid int lookupInDom(pmID pmid, unsigned int& indom); int lookupName(pmID pmid, QString **name); int lookupDesc(pmID pmid, QmcDesc **desc); int lookup(pmID pmid, QString **name, QmcDesc **desc, QmcIndom **indom); int useTZ(); // Use this timezone unsigned int numMetrics() const // Number of metrics using this context { return my.metrics.size(); } QmcMetric const& metric(unsigned int index) const { return *(my.metrics[index]); } QmcMetric& metric(unsigned int index) // Get a handle to a metric { return *(my.metrics[index]); } void addMetric(QmcMetric* metric); // Add a metric using this context int fetch(bool update); // Fetch metrics using this context struct timeval const& timeStamp() const { return my.currentTime; } double timeDelta() const // Time since previous fetch { return my.delta; } int traverse(const char *name, QStringList &list); // Walk the namespace friend QTextStream &operator<<(QTextStream &stream, const QmcContext &rhs); void dump(QTextStream &stream); // Dump debugging information void dumpMetrics(QTextStream &stream); // Dump list of metrics private: struct { int context; // PMAPI Context handle bool needReconnect; // Need to reconnect the context QmcSource *source; // Handle to the source description QHash nameCache; // Reverse map from names to PMIDs QHash pmidCache;// Mapping between PMIDs and names QHash descCache;// Mapping between PMIDs and descs QList pmids; // List of valid PMIDs to be fetched QList indoms; // List of requested indoms QList metrics; // List of metrics using this context struct timeval currentTime; // Time of current fetch struct timeval previousTime; // Time of previous fetch double delta; // Time between fetches } my; static QStringList *theStringList; // List of metric names in traversal static void dometric(const char *); }; #endif // QMC_CONTEXT_H pcp-gui-1.5.11/src/libqmc/qmc_desc.h0000644000000000000000000000244512176111212014015 0ustar /* * Copyright (c) 1998-2005 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2007 Aconex. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. */ #ifndef QMC_DESC_H #define QMC_DESC_H #include #include class QmcDesc { public: QmcDesc(pmID pmid); int status() const { return my.status; } pmID id() const { return my.pmid; } pmDesc desc() const { return my.desc; } const pmDesc *descPtr() const { return &my.desc; } const QString units() const { return my.units; } const QString shortUnits() const { return my.shortUnits; } const pmUnits &scaleUnits() const { return my.scaleUnits; } void setScaleUnits(const pmUnits &units); // Are we using scaled units provided by a call to setScaleUnits? bool useScaleUnits() const { return my.scaleFlag; } private: struct { int status; pmID pmid; pmDesc desc; QString units; QString shortUnits; pmUnits scaleUnits; bool scaleFlag; } my; void setUnitStrings(); static const char *shortUnitsString(pmUnits *pu); }; #endif // QMC_DESC_H pcp-gui-1.5.11/src/libqmc/qmc_group.h0000644000000000000000000000650512176111212014234 0ustar /* * Copyright (c) 2013, Red Hat. * Copyright (c) 2007 Aconex. All Rights Reserved. * Copyright (c) 1998-2005 Silicon Graphics, Inc. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. */ #ifndef QMC_GROUP_H #define QMC_GROUP_H #include #include #include #include #include class QmcGroup { public: enum TimeZoneFlag { localTZ, userTZ, groupTZ, unknownTZ }; public: QmcGroup(bool restrictArchives = false); ~QmcGroup(); int mode() const { return my.mode; } unsigned int numContexts() const { return my.contexts.size(); } // Return a handle to the contexts QmcContext* context() const { return my.contexts[my.use]; } QmcContext* context(unsigned int index) const { return my.contexts[index]; } // Index to the active context unsigned int contextIndex() const { return my.use; } int use(int type, const QString &source, int flags = 0); int use(unsigned int index) { my.use = index; return useContext(); } bool defaultDefined() const { return (numContexts() > 0); } int useDefault(); void createLocalContext(); // Add a new metric to the group QmcMetric* addMetric(char const* str, double theScale = 0.0, bool active = false); QmcMetric* addMetric(pmMetricSpec* theMetric, double theScale = 0.0, bool active = false); // Fetch all the metrics in this group // By default, do all rate conversions and counter wraps int fetch(bool update = true); // Set the archive position and mode int setArchiveMode(int mode, const struct timeval *when, int interval); int useTZ(); // Use TZ of current context as default int useTZ(const QString &tz); // Use this TZ as default int useLocalTZ(); // Use local TZ as default void defaultTZ(QString &label, QString &tz); TimeZoneFlag defaultTZ() const { return my.tzFlag; } int useDefaultTZ(); struct timeval const& logStart() const { return my.timeStart; } struct timeval const& logEnd() const { return my.timeEnd; } void updateBounds(); // Determine the archive start and finish times void dump(QTextStream &os); private: struct { QList contexts; // List of all contexts in this group bool restrictArchives; // Only one archive per host int mode; // Default context type int use; // Context in use QmcSource *localSource; // Localhost source desc TimeZoneFlag tzFlag; // default TZ type int tzDefault; // handle to default TZ int tzUser; // handle to user defined TZ QString tzUserString; // user defined TZ; int tzGroupIndex; // index to group context used for // current timezone struct timeval timeStart; // Start of first archive struct timeval timeEnd; // End of last archive double timeEndReal; // End of last archive } my; // Timezone for localhost from environment static bool tzLocalInit; // got TZ from environment static int tzLocal; // handle to environment TZ static QString tzLocalString; // environment TZ string static QString localHost; // name of localhost int useContext(); }; #endif // QMC_GROUP_H pcp-gui-1.5.11/src/libqmc/qmc_indom.h0000644000000000000000000001112312176111212014176 0ustar /* * Copyright (c) 1997-2005 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2007 Aconex. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #ifndef QMC_INDOM_H #define QMC_INDOM_H #include #include #include #include class QmcInstance { public: QmcInstance(); QmcInstance(int id, const char* name); QmcInstance const& operator=(QmcInstance const&); void deactivate(int index); int inst() const { return my.inst; } bool null() const { return (my.inst == (int)PM_IN_NULL); } QString name() const { return my.name; } int refCount() const { return my.refCount; } int refCountInc() { return ++my.refCount; } int refCountDec() { return --my.refCount; } bool active() const { return my.active; } void setActive(bool active) { my.active = active; } int index() const { return my.index; } void setIndex(int index) { my.index = index; } private: struct { int inst; // Instance internal id QString name; // Instance external id int refCount; int index; // Index into pmResult of last fetch // May also be used to index the next NULL inst bool active; // Instance was listed in last indom lookup } my; }; class QmcIndom { public: QmcIndom(int type, QmcDesc &desc); int status() const { return my.status; } int id() const { return my.id; } int numInsts() const { return my.instances.size() - my.nullCount; } int numActiveInsts() const { return my.numActive; } // Length of instance list - some of the instances may be NULL hence // this may be larger than numInsts() int listLen() const { return my.instances.size(); } // Internal instance id for instance int inst(uint index) const { return my.instances[index].inst(); } // External instance name for instance const QString name(uint index) const { return my.instances[index].name(); } bool nullInst(uint index) const { return my.instances[index].null(); } // Was this instance listed in the last update? bool activeInst(uint index) const { return my.instances[index].active(); } // Is this instance referenced by any metrics? bool refInst(uint index) const { return my.instances[index].refCount()>0; } // Return index into table for instance with external // Also adds a reference to this instance for the profile int lookup(QString const& name); // Add a reference to all instances in this indom // Id is set, only reference active instances void refAll(bool active = false); // Remove a reference to an instance void removeRef(uint index); // Number of instances referenced uint refCount() const { return my.count; } // Was the indom different on the last fetch? bool changed() const { return my.changed; } // About to fetch, so mark this indom as unchanged void newFetch() { my.changed = false; my.updated = true; } // Mark that the indom was different in a previous fetch void hasChanged() { my.changed = true; my.updated = false; } int update(); // Update indom with latest instances // Has profile changed since last call to genProfile bool diffProfile() const { return my.profile; } int genProfile(); // Generate profile for current context // Likely index into pmResult for instance int index(uint inst) const { return my.instances[inst].index(); } void setIndex(uint inst, int index) { my.instances[inst].setIndex(index); } // Dump some debugging output for this indom void dump(QTextStream &os) const; private: struct { int status; int type; pmInDom id; QList instances; // Sparse list of instances bool profile; // Does the profile need to be updated bool changed; // Did indom change in the last fetch? bool updated; // Has the indom been updated? uint count; // Number of referenced instances uint nullCount; // Count of NULL instances uint nullIndex; // Index to first NULL instance uint numActive; // Number of active instances uint numActiveRef; // Number of active referenced insts } my; }; #endif // QMC_INDOM_H pcp-gui-1.5.11/src/libqmc/qmc_metric.h0000644000000000000000000002564412176111212014370 0ustar /* * Copyright (c) 2012-2013 Red Hat, Inc. * Copyright (c) 2007 Aconex. All Rights Reserved. * Copyright (c) 1998-2005 Silicon Graphics, Inc. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. */ #ifndef QMC_METRIC_H #define QMC_METRIC_H #include #include #include #include #include #include #include #include class QmcMetricValue; class QmcEventParameter { public: QmcEventParameter() { my.pmid = PM_ID_NULL; } void setPMID(pmID pmid) { my.pmid = pmid; } void setNamePtr(QString *name) { my.name = name; } void setDescPtr(QmcDesc *desc) { my.desc = desc; } void setIndomPtr(QmcIndom *indom) { my.indom = indom; } void setValueCount(int numInst); QmcMetricValue *valuePtr(int inst); int type() const; double value(int inst) const; QString stringValue(int inst) const; void summary(QString &os, int instID) const; void dump(QTextStream &os, int instID) const; private: struct { pmID pmid; // pmid for the parameter to an event QString *name; // direct pointer into external cache QmcDesc *desc; // direct pointer into external cache QmcIndom *indom; // direct pointer into external cache QVector values; } my; }; class QmcEventRecord { public: QmcEventRecord() { my.missed = my.flags = 0; } const struct timeval *timestamp() const { return &my.timestamp; } void setTimestamp(struct timeval *tv) { my.timestamp = *tv; } int flags() const { return my.flags; } void setFlags(int flags) { my.flags = flags; } int missed() const { return my.missed; } void setMissed(int missed) { my.missed = missed; } void setParameterCount(int numParams) { my.parameters.resize(numParams); } int setParameter(int n, pmID pmid, QmcContext *cp, pmValueSet const *vp); QString parent() const; QString identifier() const; void parameterSummary(QString &os, int instID) const; void dump(QTextStream &os, int instID, uint recordID) const; static pmID eventFlags(); static pmID eventMissed(); private: QString parameterAsString(int index) const; struct { struct timeval timestamp; int missed; int flags; QVector parameters; } my; }; class QmcMetricValue { public: QmcMetricValue(); QmcMetricValue const& operator=(QmcMetricValue const& rhs); int instance() const { return my.instance; } void setInstance(int instance) { my.instance = instance; } int error() const { return my.error; } void setError(int error) { my.error = error; } void setAllErrors(int error) { my.error = my.currentError = my.previousError = error; } double value() const { return my.value; } void setValue(double value) { my.value = value; } void divValue(double value) { my.value /= value; } void addValue(double value) { my.value += value; } void subValue(double value) { my.value -= value; } QString stringValue() const { return my.stringValue; } void setStringValue(const char *s) { my.stringValue = s; } int currentError() const { return my.currentError; } void setCurrentError(int error) { my.currentError = error; resetCurrentValue(); } double currentValue() const { return my.currentValue; } void setCurrentValue(double value) { my.currentValue = value; } int previousError() const { return my.previousError; } double previousValue() const { return my.previousValue; } void shiftValues() { my.previousValue = my.currentValue; my.previousError = my.currentError; my.currentError = 0; } QVector const &eventRecords() const { return my.eventRecords; } void extractEventRecords(QmcContext *context, int recordCount, pmResult **result); void dumpEventRecords(QTextStream &os, int instid) const; private: void resetCurrentValue() { my.currentValue = 0.0; my.stringValue = QString::null; my.eventRecords.clear(); } struct { int instance; int error; double value; double previousValue; double currentValue; int currentError; int previousError; QString stringValue; QVector eventRecords; } my; }; class QmcMetric { friend class QmcGroup; friend class QmcContext; public: QmcMetric(QmcGroup *group, const char *str, double theScale = 0.0, bool active = false); QmcMetric(QmcGroup *group, pmMetricSpec *theMetric, double theScale = 0.0, bool active = false); ~QmcMetric(); int status() const { return my.status; } pmID metricID() const { return my.pmid; } const QString name() const { return my.name; } char *nameAscii() const { return strdup((const char *)my.name.toAscii()); } QmcContext *context() const { return my.group->context(my.contextIndex); } const QmcDesc &desc() const { return context()->desc(my.pmid); } bool hasIndom() const { return desc().desc().indom != PM_INDOM_NULL; } bool hasInstances() const { return (my.status >= 0 && my.indomIndex < UINT_MAX); } // Were the instances explicitly listed? bool explicitInsts() const { return my.explicitInst; } // Are only active instances referenced bool activeInsts() const { return my.active; } int numInst() const { return (my.status >= 0 && my.indomIndex < UINT_MAX) ? my.values.size() : 0; } // How many values does it have (will not equal number of instances // if singular) int numValues() const { return (my.status >= 0) ? my.values.size() : 0; } // The metric indom QmcIndom *indom() const { return (my.indomIndex == UINT_MAX) ? NULL : &(my.group->context(my.contextIndex)->indom(my.indomIndex)); } // Internal instance id for instance int instID(int index) const { return my.group->context(my.contextIndex)->indom(my.indomIndex).inst(my.values[index].instance()); } // External instance name for instance const QString instName(int index) const { return my.group->context(my.contextIndex)->indom(my.indomIndex).name(my.values[index].instance()); } // Return the index for the instance in the indom list int instIndex(uint index) const { return my.values[index].instance(); } // Update the metric to include new instances // Returns true if the instance list changed // Metrics with implicit instances will be extended to include those // new instances. The position of instances may change. // If is set, only those instances in the latest indom will // be listed, other instances will be removed bool updateIndom(); int addInst(QString const& name); void removeInst(uint index); // Scaling modifier applied to metric values double scale() const { return my.scale; } // Metric has event records (as opposed to real/string/aggregate values) bool event() const { return event(desc().desc().type); } static bool event(int type) { return type == PM_TYPE_EVENT; } bool aggregate() const { return aggregate(desc().desc().type); } static void aggregateAsString(pmValue const *, char *, int); static bool aggregate(int type) { return type == PM_TYPE_AGGREGATE || type == PM_TYPE_AGGREGATE_STATIC; } // Metric has real values (as opposed to event/string/aggregate values) bool real() const { return real(desc().desc().type); } static bool real(int type) { return type > PM_TYPE_NOSUPPORT && type < PM_TYPE_STRING; } // Current rate-converted and scaled real value double value(int index) const { return my.values[index].value(); } double realValue(int index) const // Current rate-converted value { return my.values[index].value() * my.scale; } double currentValue(int index) const // Current raw value { return my.values[index].currentValue(); } QString stringValue(int index) const // Current string value { return my.values[index].stringValue(); } QVector const &eventRecords(int index) const { return my.values[index].eventRecords(); } int error(int index) const // Current error code (after rate-conversion) { return my.values[index].error(); } int currentError(int index) const // Current raw error code { return my.values[index].currentError(); } void shiftValues(); // Shift values in preparation for next fetch void setError(int sts); // Set error code for all instances void extractValues(pmValueSet const* set); // Extract values after a fetch uint contextIndex() const // Index for context in group list { return my.contextIndex; } // Index for metric into pmResult uint idIndex() const { return my.idIndex; } // Index for indom in context list uint indomIndex() const { return my.indomIndex; } // Set the canonical units void setScaleUnits(pmUnits const& units); // Generate a metric spec QString spec(bool srcFlag = false, bool instFlag = false, uint instance = UINT_MAX) const; // Dump out the metric and its current value(s) void dump(QTextStream &os, bool srcFlag = false, uint instance = UINT_MAX) const; // Dump out the current value void dumpValue(QTextStream &os, uint instance) const; // Dump out the metric source void dumpSource(QTextStream &os) const; // Format a value into a fixed width format static const char *formatNumber(double value); // Determine the current errors and rate-converted scaled values int update(); friend QTextStream &operator<<(QTextStream &os, const QmcMetric &metric); private: struct { pmID pmid; int status; QString name; QmcGroup *group; QList values; double scale; uint contextIndex; // Index into the context list for the group uint idIndex; // Index into the pmid list for the context. uint indomIndex; // Index into the indom list for the context. bool explicitInst; // Instances explicitly specified bool active; // Use only active implicit insts } my; void setup(QmcGroup *group, pmMetricSpec *theMetric); void setupDesc(QmcGroup *group, pmMetricSpec *theMetric); void setupIndom(pmMetricSpec *theMetric); void setupValues(int num); void extractNumericMetric(pmValueSet const *vset, pmValue const *v, QmcMetricValue &vref); void extractArrayMetric(pmValueSet const *vset, pmValue const *v, QmcMetricValue &vref); void extractEventMetric(pmValueSet const *vset, int index, QmcMetricValue &vref); void setIdIndex(uint index) { my.idIndex = index; } // Dump error messages void dumpAll() const; void dumpErr() const; void dumpErr(const char *inst) const; // Dump out different metric flavours and their current value(s) void dumpEventMetric(QTextStream &os, bool srcFlag = false, uint instance = UINT_MAX) const; void dumpSampledMetric(QTextStream &os, bool srcFlag = false, uint instance = UINT_MAX) const; }; #endif // QMC_METRIC_H pcp-gui-1.5.11/src/libqmc/qmc_source.h0000644000000000000000000000714212213235215014400 0ustar /* * Copyright (c) 2013 Red Hat, Inc. * Copyright (c) 2007 Aconex. All Rights Reserved. * Copyright (c) 1998,2005 Silicon Graphics, Inc. All Rights Reserved. * * This library 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 2.1 of the License, or * (at your option) any later version. */ #ifndef QMC_SOURCE_H #define QMC_SOURCE_H #include #include #include #include #include "version.h" class QmcSource { public: QmcSource(int type, QString &source, int flags = 0); ~QmcSource(); // Get the source description by searching the list of existing sources // and returning a new source only if required. // If matchHosts is true, then it will attempt to map a live context // to an archive source. If no matching archive context is found, // a NULL pointer is returned. static QmcSource* getSource(int type, QString &source, int flags = 0, bool matchHosts = false); int status() const { return my.status; } int flags() const { return my.flags; } int type() const { return my.type; } bool isArchive() const { return my.type == PM_CONTEXT_ARCHIVE; } QString source() const { return my.source; } char *sourceAscii() const { return strdup((const char*)my.source.toAscii()); } QString host() const { return my.host; } char *hostAscii() const { return strdup((const char *)my.host.toAscii()); } QString proxy() const { return my.proxy; } char *proxyAscii() const { return strdup((const char *)my.proxy.toAscii()); } int tzHandle() const { return my.tz; } QString timezone() const { return my.timezone; } struct timeval start() const { return my.start; } QString startTime() { return timeString(&my.start); } struct timeval end() const { return my.end; } QString endTime() { return timeString(&my.end); } QString desc() const { return my.desc; } char *descAscii() const { return strdup((const char *)my.desc.toAscii()); } QString context_hostname() const { return my.context_hostname; } // Number of active contexts to this source uint numContexts() const { return my.handles.size(); } // Create a new context to this source int dupContext(); // Delete context to this source int delContext(int handle); // Output the source friend QTextStream &operator<<(QTextStream &os, const QmcSource &rhs); // Dump all info about a source void dump(QTextStream &os); // Dump list of known sources static void dumpList(QTextStream &os); // Local host name (from gethostname(2)) static QString localHost; // Convert a time to a string (long and short forms) static QString timeString(const struct timeval *timeval); static QString timeStringBrief(const struct timeval *timeval); protected: // retry context/connection (e.g. if it failed in the constructor) void retryConnect(int type, QString &source); // compare two sources - static so getSource() can make use of it bool compare(int type, QString &source, int flags); private: struct { int status; int type; QString source; QString proxy; QString attrs; QString host; QString context_hostname; // from pmcd/archive, not from -h/-a argument QString desc; QString timezone; QList handles; // Contexts created for this source struct timeval start; struct timeval end; int tz; bool dupFlag; // Dup has been called and 1st context is in use int flags; } my; static QList sourceList; }; #endif // QMC_SOURCE_H pcp-gui-1.5.11/src/libqwt/0000755000000000000000000000000012234612137012123 5ustar pcp-gui-1.5.11/src/libqwt/GNUmakefile0000644000000000000000000000050412176111212014165 0ustar TOPDIR = ../.. LIBRARY = libqwt PROJECT = $(LIBRARY).pro include $(TOPDIR)/src/include/builddefs HEADERS = $(shell echo qwt*.h) SOURCES = $(shell echo qwt*.cpp) CONFFILES = $(PROJECT) LSRCFILES = $(PROJECT).in $(SOURCES) $(HEADERS) LDIRT = Makefile* default: $(PROJECT) $(QTMAKE) include $(BUILDRULES) install: default pcp-gui-1.5.11/src/libqwt/libqwt.pro.in0000644000000000000000000001036212176111212014547 0ustar TARGET = qwt TEMPLATE = lib VERSION = 6.0.2 CONFIG += qt staticlib warn_on @qt_release@ HEADERS += \ qwt.h \ qwt_abstract_scale_draw.h \ qwt_interval_symbol.h \ qwt_clipper.h \ qwt_color_map.h \ qwt_compat.h \ qwt_column_symbol.h \ qwt_interval.h \ qwt_dyngrid_layout.h \ qwt_global.h \ qwt_math.h \ qwt_magnifier.h \ qwt_null_paintdevice.h \ qwt_painter.h \ qwt_panner.h \ qwt_picker.h \ qwt_picker_machine.h \ qwt_point_3d.h \ qwt_point_polar.h \ qwt_round_scale_draw.h \ qwt_scale_div.h \ qwt_scale_draw.h \ qwt_scale_engine.h \ qwt_scale_map.h \ qwt_spline.h \ qwt_symbol.h \ qwt_system_clock.h \ qwt_text_engine.h \ qwt_text_label.h \ qwt_text.h SOURCES += \ qwt_abstract_scale_draw.cpp \ qwt_interval_symbol.cpp \ qwt_clipper.cpp \ qwt_color_map.cpp \ qwt_column_symbol.cpp \ qwt_interval.cpp \ qwt_dyngrid_layout.cpp \ qwt_math.cpp \ qwt_magnifier.cpp \ qwt_panner.cpp \ qwt_null_paintdevice.cpp \ qwt_painter.cpp \ qwt_picker.cpp \ qwt_round_scale_draw.cpp \ qwt_scale_div.cpp \ qwt_scale_draw.cpp \ qwt_scale_map.cpp \ qwt_spline.cpp \ qwt_text_engine.cpp \ qwt_text_label.cpp \ qwt_text.cpp \ qwt_event_pattern.cpp \ qwt_picker_machine.cpp \ qwt_point_3d.cpp \ qwt_point_polar.cpp \ qwt_scale_engine.cpp \ qwt_symbol.cpp \ qwt_system_clock.cpp # qwt plot HEADERS += \ qwt_curve_fitter.h \ qwt_event_pattern.h \ qwt_legend.h \ qwt_legend_item.h \ qwt_legend_itemmanager.h \ qwt_plot.h \ qwt_plot_renderer.h \ qwt_plot_curve.h \ qwt_plot_dict.h \ qwt_plot_directpainter.h \ qwt_plot_grid.h \ qwt_plot_histogram.h \ qwt_plot_item.h \ qwt_plot_intervalcurve.h \ qwt_plot_layout.h \ qwt_plot_marker.h \ qwt_plot_rasteritem.h \ qwt_plot_spectrogram.h \ qwt_plot_spectrocurve.h \ qwt_plot_scaleitem.h \ qwt_plot_seriesitem.h \ qwt_plot_canvas.h \ qwt_plot_panner.h \ qwt_plot_picker.h \ qwt_plot_zoomer.h \ qwt_plot_magnifier.h \ qwt_plot_rescaler.h \ qwt_raster_data.h \ qwt_matrix_raster_data.h \ qwt_sampling_thread.h \ qwt_series_data.h \ qwt_scale_widget.h SOURCES += \ qwt_curve_fitter.cpp \ qwt_legend.cpp \ qwt_legend_item.cpp \ qwt_plot.cpp \ qwt_plot_renderer.cpp \ qwt_plot_xml.cpp \ qwt_plot_axis.cpp \ qwt_plot_curve.cpp \ qwt_plot_dict.cpp \ qwt_plot_directpainter.cpp \ qwt_plot_grid.cpp \ qwt_plot_histogram.cpp \ qwt_plot_item.cpp \ qwt_plot_intervalcurve.cpp \ qwt_plot_spectrogram.cpp \ qwt_plot_spectrocurve.cpp \ qwt_plot_scaleitem.cpp \ qwt_plot_seriesitem.cpp \ qwt_plot_marker.cpp \ qwt_plot_layout.cpp \ qwt_plot_canvas.cpp \ qwt_plot_panner.cpp \ qwt_plot_rasteritem.cpp \ qwt_plot_picker.cpp \ qwt_plot_zoomer.cpp \ qwt_plot_magnifier.cpp \ qwt_plot_rescaler.cpp \ qwt_raster_data.cpp \ qwt_matrix_raster_data.cpp \ qwt_sampling_thread.cpp \ qwt_series_data.cpp \ qwt_scale_widget.cpp # svg # HEADERS += qwt_plot_svgitem.h # SOURCES += qwt_plot_svgitem.cpp # widgets HEADERS += \ qwt_abstract_slider.h \ qwt_abstract_scale.h \ qwt_arrow_button.h \ qwt_analog_clock.h \ qwt_compass.h \ qwt_compass_rose.h \ qwt_counter.h \ qwt_dial.h \ qwt_dial_needle.h \ qwt_double_range.h \ qwt_knob.h \ qwt_slider.h \ qwt_thermo.h \ qwt_wheel.h SOURCES += \ qwt_abstract_slider.cpp \ qwt_abstract_scale.cpp \ qwt_arrow_button.cpp \ qwt_analog_clock.cpp \ qwt_compass.cpp \ qwt_compass_rose.cpp \ qwt_counter.cpp \ qwt_dial.cpp \ qwt_dial_needle.cpp \ qwt_double_range.cpp \ qwt_knob.cpp \ qwt_slider.cpp \ qwt_thermo.cpp \ qwt_wheel.cpp pcp-gui-1.5.11/src/libqwt/qwt_abstract_scale.cpp0000644000000000000000000001542312176111212016472 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_abstract_scale.h" #include "qwt_scale_engine.h" #include "qwt_scale_draw.h" #include "qwt_scale_div.h" #include "qwt_scale_map.h" #include "qwt_interval.h" class QwtAbstractScale::PrivateData { public: PrivateData(): maxMajor( 5 ), maxMinor( 3 ), stepSize( 0.0 ), autoScale( true ) { scaleEngine = new QwtLinearScaleEngine; scaleDraw = new QwtScaleDraw(); } ~PrivateData() { delete scaleEngine; delete scaleDraw; } QwtScaleEngine *scaleEngine; QwtAbstractScaleDraw *scaleDraw; int maxMajor; int maxMinor; double stepSize; bool autoScale; }; /*! Constructor Creates a default QwtScaleDraw and a QwtLinearScaleEngine. Autoscaling is enabled, and the stepSize is initialized by 0.0. */ QwtAbstractScale::QwtAbstractScale() { d_data = new PrivateData; rescale( 0.0, 100.0 ); } //! Destructor QwtAbstractScale::~QwtAbstractScale() { delete d_data; } /*! \brief Specify a scale. Disable autoscaling and define a scale by an interval and a step size \param vmin lower limit of the scale interval \param vmax upper limit of the scale interval \param stepSize major step size \sa setAutoScale() */ void QwtAbstractScale::setScale( double vmin, double vmax, double stepSize ) { d_data->autoScale = false; d_data->stepSize = stepSize; rescale( vmin, vmax, stepSize ); } /*! \brief Specify a scale. Disable autoscaling and define a scale by an interval and a step size \param interval Interval \param stepSize major step size \sa setAutoScale() */ void QwtAbstractScale::setScale( const QwtInterval &interval, double stepSize ) { setScale( interval.minValue(), interval.maxValue(), stepSize ); } /*! \brief Specify a scale. Disable autoscaling and define a scale by a scale division \param scaleDiv Scale division \sa setAutoScale() */ void QwtAbstractScale::setScale( const QwtScaleDiv &scaleDiv ) { d_data->autoScale = false; if ( scaleDiv != d_data->scaleDraw->scaleDiv() ) { d_data->scaleDraw->setScaleDiv( scaleDiv ); scaleChange(); } } /*! Recalculate the scale division and update the scale draw. \param vmin Lower limit of the scale interval \param vmax Upper limit of the scale interval \param stepSize Major step size \sa scaleChange() */ void QwtAbstractScale::rescale( double vmin, double vmax, double stepSize ) { const QwtScaleDiv scaleDiv = d_data->scaleEngine->divideScale( vmin, vmax, d_data->maxMajor, d_data->maxMinor, stepSize ); if ( scaleDiv != d_data->scaleDraw->scaleDiv() ) { d_data->scaleDraw->setTransformation( d_data->scaleEngine->transformation() ); d_data->scaleDraw->setScaleDiv( scaleDiv ); scaleChange(); } } /*! \brief Advise the widget to control the scale range internally. Autoscaling is on by default. \sa setScale(), autoScale() */ void QwtAbstractScale::setAutoScale() { if ( !d_data->autoScale ) { d_data->autoScale = true; scaleChange(); } } /*! \return \c true if autoscaling is enabled */ bool QwtAbstractScale::autoScale() const { return d_data->autoScale; } /*! \brief Set the maximum number of major tick intervals. The scale's major ticks are calculated automatically such that the number of major intervals does not exceed ticks. The default value is 5. \param ticks maximal number of major ticks. \sa QwtAbstractScaleDraw */ void QwtAbstractScale::setScaleMaxMajor( int ticks ) { if ( ticks != d_data->maxMajor ) { d_data->maxMajor = ticks; updateScaleDraw(); } } /*! \brief Set the maximum number of minor tick intervals The scale's minor ticks are calculated automatically such that the number of minor intervals does not exceed ticks. The default value is 3. \param ticks \sa QwtAbstractScaleDraw */ void QwtAbstractScale::setScaleMaxMinor( int ticks ) { if ( ticks != d_data->maxMinor ) { d_data->maxMinor = ticks; updateScaleDraw(); } } /*! \return Max. number of minor tick intervals The default value is 3. */ int QwtAbstractScale::scaleMaxMinor() const { return d_data->maxMinor; } /*! \return Max. number of major tick intervals The default value is 5. */ int QwtAbstractScale::scaleMaxMajor() const { return d_data->maxMajor; } /*! \brief Set a scale draw scaleDraw has to be created with new and will be deleted in ~QwtAbstractScale or the next call of setAbstractScaleDraw. */ void QwtAbstractScale::setAbstractScaleDraw( QwtAbstractScaleDraw *scaleDraw ) { if ( scaleDraw == NULL || scaleDraw == d_data->scaleDraw ) return; if ( d_data->scaleDraw != NULL ) scaleDraw->setScaleDiv( d_data->scaleDraw->scaleDiv() ); delete d_data->scaleDraw; d_data->scaleDraw = scaleDraw; } /*! \return Scale draw \sa setAbstractScaleDraw() */ QwtAbstractScaleDraw *QwtAbstractScale::abstractScaleDraw() { return d_data->scaleDraw; } /*! \return Scale draw \sa setAbstractScaleDraw() */ const QwtAbstractScaleDraw *QwtAbstractScale::abstractScaleDraw() const { return d_data->scaleDraw; } void QwtAbstractScale::updateScaleDraw() { rescale( d_data->scaleDraw->scaleDiv().lowerBound(), d_data->scaleDraw->scaleDiv().upperBound(), d_data->stepSize ); } /*! \brief Set a scale engine The scale engine is responsible for calculating the scale division, and in case of auto scaling how to align the scale. scaleEngine has to be created with new and will be deleted in ~QwtAbstractScale or the next call of setScaleEngine. */ void QwtAbstractScale::setScaleEngine( QwtScaleEngine *scaleEngine ) { if ( scaleEngine != NULL && scaleEngine != d_data->scaleEngine ) { delete d_data->scaleEngine; d_data->scaleEngine = scaleEngine; } } /*! \return Scale engine \sa setScaleEngine() */ const QwtScaleEngine *QwtAbstractScale::scaleEngine() const { return d_data->scaleEngine; } /*! \return Scale engine \sa setScaleEngine() */ QwtScaleEngine *QwtAbstractScale::scaleEngine() { return d_data->scaleEngine; } /*! \brief Notify changed scale Dummy empty implementation, intended to be overloaded by derived classes */ void QwtAbstractScale::scaleChange() { } /*! \return abstractScaleDraw()->scaleMap() */ const QwtScaleMap &QwtAbstractScale::scaleMap() const { return d_data->scaleDraw->scaleMap(); } pcp-gui-1.5.11/src/libqwt/qwt_abstract_scale_draw.cpp0000644000000000000000000002256212176111212017511 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_abstract_scale_draw.h" #include "qwt_math.h" #include "qwt_text.h" #include "qwt_painter.h" #include "qwt_scale_map.h" #include #include #include #include class QwtAbstractScaleDraw::PrivateData { public: PrivateData(): spacing( 4.0 ), penWidth( 0 ), minExtent( 0.0 ) { components = QwtAbstractScaleDraw::Backbone | QwtAbstractScaleDraw::Ticks | QwtAbstractScaleDraw::Labels; tickLength[QwtScaleDiv::MinorTick] = 4.0; tickLength[QwtScaleDiv::MediumTick] = 6.0; tickLength[QwtScaleDiv::MajorTick] = 8.0; } ScaleComponents components; QwtScaleMap map; QwtScaleDiv scldiv; double spacing; double tickLength[QwtScaleDiv::NTickTypes]; int penWidth; double minExtent; QMap labelCache; }; /*! \brief Constructor The range of the scale is initialized to [0, 100], The spacing (distance between ticks and labels) is set to 4, the tick lengths are set to 4,6 and 8 pixels */ QwtAbstractScaleDraw::QwtAbstractScaleDraw() { d_data = new QwtAbstractScaleDraw::PrivateData; } //! Destructor QwtAbstractScaleDraw::~QwtAbstractScaleDraw() { delete d_data; } /*! En/Disable a component of the scale \param component Scale component \param enable On/Off \sa hasComponent() */ void QwtAbstractScaleDraw::enableComponent( ScaleComponent component, bool enable ) { if ( enable ) d_data->components |= component; else d_data->components &= ~component; } /*! Check if a component is enabled \sa enableComponent() */ bool QwtAbstractScaleDraw::hasComponent( ScaleComponent component ) const { return ( d_data->components & component ); } /*! Change the scale division \param sd New scale division */ void QwtAbstractScaleDraw::setScaleDiv( const QwtScaleDiv &sd ) { d_data->scldiv = sd; d_data->map.setScaleInterval( sd.lowerBound(), sd.upperBound() ); d_data->labelCache.clear(); } /*! Change the transformation of the scale \param transformation New scale transformation */ void QwtAbstractScaleDraw::setTransformation( QwtScaleTransformation *transformation ) { d_data->map.setTransformation( transformation ); } //! \return Map how to translate between scale and pixel values const QwtScaleMap &QwtAbstractScaleDraw::scaleMap() const { return d_data->map; } //! \return Map how to translate between scale and pixel values QwtScaleMap &QwtAbstractScaleDraw::scaleMap() { return d_data->map; } //! \return scale division const QwtScaleDiv& QwtAbstractScaleDraw::scaleDiv() const { return d_data->scldiv; } /*! \brief Specify the width of the scale pen \param width Pen width \sa penWidth() */ void QwtAbstractScaleDraw::setPenWidth( int width ) { if ( width < 0 ) width = 0; if ( width != d_data->penWidth ) d_data->penWidth = width; } /*! \return Scale pen width \sa setPenWidth() */ int QwtAbstractScaleDraw::penWidth() const { return d_data->penWidth; } /*! \brief Draw the scale \param painter The painter \param palette Palette, text color is used for the labels, foreground color for ticks and backbone */ void QwtAbstractScaleDraw::draw( QPainter *painter, const QPalette& palette ) const { painter->save(); QPen pen = painter->pen(); pen.setWidth( d_data->penWidth ); pen.setCosmetic( false ); painter->setPen( pen ); if ( hasComponent( QwtAbstractScaleDraw::Labels ) ) { painter->save(); painter->setPen( palette.color( QPalette::Text ) ); // ignore pen style const QList &majorTicks = d_data->scldiv.ticks( QwtScaleDiv::MajorTick ); for ( int i = 0; i < majorTicks.count(); i++ ) { const double v = majorTicks[i]; if ( d_data->scldiv.contains( v ) ) drawLabel( painter, v ); } painter->restore(); } if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) { painter->save(); QPen pen = painter->pen(); pen.setColor( palette.color( QPalette::WindowText ) ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); for ( int tickType = QwtScaleDiv::MinorTick; tickType < QwtScaleDiv::NTickTypes; tickType++ ) { const QList &ticks = d_data->scldiv.ticks( tickType ); for ( int i = 0; i < ticks.count(); i++ ) { const double v = ticks[i]; if ( d_data->scldiv.contains( v ) ) drawTick( painter, v, d_data->tickLength[tickType] ); } } painter->restore(); } if ( hasComponent( QwtAbstractScaleDraw::Backbone ) ) { painter->save(); QPen pen = painter->pen(); pen.setColor( palette.color( QPalette::WindowText ) ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); drawBackbone( painter ); painter->restore(); } painter->restore(); } /*! \brief Set the spacing between tick and labels The spacing is the distance between ticks and labels. The default spacing is 4 pixels. \param spacing Spacing \sa spacing() */ void QwtAbstractScaleDraw::setSpacing( double spacing ) { if ( spacing < 0 ) spacing = 0; d_data->spacing = spacing; } /*! \brief Get the spacing The spacing is the distance between ticks and labels. The default spacing is 4 pixels. \sa setSpacing() */ double QwtAbstractScaleDraw::spacing() const { return d_data->spacing; } /*! \brief Set a minimum for the extent The extent is calculated from the coomponents of the scale draw. In situations, where the labels are changing and the layout depends on the extent (f.e scrolling a scale), setting an upper limit as minimum extent will avoid jumps of the layout. \param minExtent Minimum extent \sa extent(), minimumExtent() */ void QwtAbstractScaleDraw::setMinimumExtent( double minExtent ) { if ( minExtent < 0.0 ) minExtent = 0.0; d_data->minExtent = minExtent; } /*! Get the minimum extent \sa extent(), setMinimumExtent() */ double QwtAbstractScaleDraw::minimumExtent() const { return d_data->minExtent; } /*! Set the length of the ticks \param tickType Tick type \param length New length \warning the length is limited to [0..1000] */ void QwtAbstractScaleDraw::setTickLength( QwtScaleDiv::TickType tickType, double length ) { if ( tickType < QwtScaleDiv::MinorTick || tickType > QwtScaleDiv::MajorTick ) { return; } if ( length < 0.0 ) length = 0.0; const double maxTickLen = 1000.0; if ( length > maxTickLen ) length = maxTickLen; d_data->tickLength[tickType] = length; } /*! Return the length of the ticks \sa setTickLength(), maxTickLength() */ double QwtAbstractScaleDraw::tickLength( QwtScaleDiv::TickType tickType ) const { if ( tickType < QwtScaleDiv::MinorTick || tickType > QwtScaleDiv::MajorTick ) { return 0; } return d_data->tickLength[tickType]; } /*! \return Length of the longest tick Useful for layout calculations \sa tickLength(), setTickLength() */ double QwtAbstractScaleDraw::maxTickLength() const { double length = 0.0; for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ ) length = qMax( length, d_data->tickLength[i] ); return length; } /*! \brief Convert a value into its representing label The value is converted to a plain text using QLocale::system().toString(value). This method is often overloaded by applications to have individual labels. \param value Value \return Label string. */ QwtText QwtAbstractScaleDraw::label( double value ) const { return QLocale().toString( value ); } /*! \brief Convert a value into its representing label and cache it. The conversion between value and label is called very often in the layout and painting code. Unfortunately the calculation of the label sizes might be slow (really slow for rich text in Qt4), so it's necessary to cache the labels. \param font Font \param value Value \return Tick label */ const QwtText &QwtAbstractScaleDraw::tickLabel( const QFont &font, double value ) const { QMap::const_iterator it = d_data->labelCache.find( value ); if ( it == d_data->labelCache.end() ) { QwtText lbl = label( value ); lbl.setRenderFlags( 0 ); lbl.setLayoutAttribute( QwtText::MinimumLayout ); ( void )lbl.textSize( font ); // initialize the internal cache it = d_data->labelCache.insert( value, lbl ); } return ( *it ); } /*! Invalidate the cache used by QwtAbstractScaleDraw::tickLabel The cache is invalidated, when a new QwtScaleDiv is set. If the labels need to be changed. while the same QwtScaleDiv is set, invalidateCache() needs to be called manually. */ void QwtAbstractScaleDraw::invalidateCache() { d_data->labelCache.clear(); } pcp-gui-1.5.11/src/libqwt/qwt_abstract_slider.cpp0000644000000000000000000003172612176111212016671 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_abstract_slider.h" #include "qwt_math.h" #include #include #if QT_VERSION < 0x040601 #define qFabs(x) ::fabs(x) #define qExp(x) ::exp(x) #endif class QwtAbstractSlider::PrivateData { public: PrivateData(): scrollMode( QwtAbstractSlider::ScrNone ), mouseOffset( 0.0 ), tracking( true ), tmrID( 0 ), updTime( 150 ), mass( 0.0 ), readOnly( false ) { } QwtAbstractSlider::ScrollMode scrollMode; double mouseOffset; int direction; int tracking; int tmrID; int updTime; int timerTick; QTime time; double speed; double mass; Qt::Orientation orientation; bool readOnly; }; /*! \brief Constructor \param orientation Orientation \param parent Parent widget */ QwtAbstractSlider::QwtAbstractSlider( Qt::Orientation orientation, QWidget *parent ): QWidget( parent, NULL ) { d_data = new QwtAbstractSlider::PrivateData; d_data->orientation = orientation; setFocusPolicy( Qt::TabFocus ); } //! Destructor QwtAbstractSlider::~QwtAbstractSlider() { if ( d_data->tmrID ) killTimer( d_data->tmrID ); delete d_data; } /*! En/Disable read only mode In read only mode the slider can't be controlled by mouse or keyboard. \param readOnly Enables in case of true \sa isReadOnly() */ void QwtAbstractSlider::setReadOnly( bool readOnly ) { d_data->readOnly = readOnly; update(); } /*! In read only mode the slider can't be controlled by mouse or keyboard. \return true if read only \sa setReadOnly() */ bool QwtAbstractSlider::isReadOnly() const { return d_data->readOnly; } /*! \brief Set the orientation. \param o Orientation. Allowed values are Qt::Horizontal and Qt::Vertical. */ void QwtAbstractSlider::setOrientation( Qt::Orientation o ) { d_data->orientation = o; } /*! \return Orientation \sa setOrientation() */ Qt::Orientation QwtAbstractSlider::orientation() const { return d_data->orientation; } //! Stop updating if automatic scrolling is active void QwtAbstractSlider::stopMoving() { if ( d_data->tmrID ) { killTimer( d_data->tmrID ); d_data->tmrID = 0; } } /*! \brief Specify the update interval for automatic scrolling \param t update interval in milliseconds \sa getScrollMode() */ void QwtAbstractSlider::setUpdateTime( int t ) { if ( t < 50 ) t = 50; d_data->updTime = t; } /*! Mouse press event handler \param e Mouse event */ void QwtAbstractSlider::mousePressEvent( QMouseEvent *e ) { if ( isReadOnly() ) { e->ignore(); return; } if ( !isValid() ) return; const QPoint &p = e->pos(); d_data->timerTick = 0; getScrollMode( p, d_data->scrollMode, d_data->direction ); stopMoving(); switch ( d_data->scrollMode ) { case ScrPage: case ScrTimer: d_data->mouseOffset = 0; d_data->tmrID = startTimer( qMax( 250, 2 * d_data->updTime ) ); break; case ScrMouse: d_data->time.start(); d_data->speed = 0; d_data->mouseOffset = getValue( p ) - value(); Q_EMIT sliderPressed(); break; default: d_data->mouseOffset = 0; d_data->direction = 0; break; } } //! Emits a valueChanged() signal if necessary void QwtAbstractSlider::buttonReleased() { if ( ( !d_data->tracking ) || ( value() != prevValue() ) ) Q_EMIT valueChanged( value() ); } /*! Mouse Release Event handler \param e Mouse event */ void QwtAbstractSlider::mouseReleaseEvent( QMouseEvent *e ) { if ( isReadOnly() ) { e->ignore(); return; } if ( !isValid() ) return; const double inc = step(); switch ( d_data->scrollMode ) { case ScrMouse: { setPosition( e->pos() ); d_data->direction = 0; d_data->mouseOffset = 0; if ( d_data->mass > 0.0 ) { const int ms = d_data->time.elapsed(); if ( ( qFabs( d_data->speed ) > 0.0 ) && ( ms < 50 ) ) d_data->tmrID = startTimer( d_data->updTime ); } else { d_data->scrollMode = ScrNone; buttonReleased(); } Q_EMIT sliderReleased(); break; } case ScrDirect: { setPosition( e->pos() ); d_data->direction = 0; d_data->mouseOffset = 0; d_data->scrollMode = ScrNone; buttonReleased(); break; } case ScrPage: { stopMoving(); if ( !d_data->timerTick ) QwtDoubleRange::incPages( d_data->direction ); d_data->timerTick = 0; buttonReleased(); d_data->scrollMode = ScrNone; break; } case ScrTimer: { stopMoving(); if ( !d_data->timerTick ) QwtDoubleRange::fitValue( value() + double( d_data->direction ) * inc ); d_data->timerTick = 0; buttonReleased(); d_data->scrollMode = ScrNone; break; } default: { d_data->scrollMode = ScrNone; buttonReleased(); } } } /*! Move the slider to a specified point, adjust the value and emit signals if necessary. */ void QwtAbstractSlider::setPosition( const QPoint &p ) { QwtDoubleRange::fitValue( getValue( p ) - d_data->mouseOffset ); } /*! \brief Enables or disables tracking. If tracking is enabled, the slider emits a valueChanged() signal whenever its value changes (the default behaviour). If tracking is disabled, the value changed() signal will only be emitted if:
  • the user releases the mouse button and the value has changed or
  • at the end of automatic scrolling.
Tracking is enabled by default. \param enable \c true (enable) or \c false (disable) tracking. */ void QwtAbstractSlider::setTracking( bool enable ) { d_data->tracking = enable; } /*! Mouse Move Event handler \param e Mouse event */ void QwtAbstractSlider::mouseMoveEvent( QMouseEvent *e ) { if ( isReadOnly() ) { e->ignore(); return; } if ( !isValid() ) return; if ( d_data->scrollMode == ScrMouse ) { setPosition( e->pos() ); if ( d_data->mass > 0.0 ) { double ms = double( d_data->time.elapsed() ); if ( ms < 1.0 ) ms = 1.0; d_data->speed = ( exactValue() - exactPrevValue() ) / ms; d_data->time.start(); } if ( value() != prevValue() ) Q_EMIT sliderMoved( value() ); } } /*! Wheel Event handler \param e Whell event */ void QwtAbstractSlider::wheelEvent( QWheelEvent *e ) { if ( isReadOnly() ) { e->ignore(); return; } if ( !isValid() ) return; QwtAbstractSlider::ScrollMode mode = ScrNone; int direction = 0; // Give derived classes a chance to say ScrNone getScrollMode( e->pos(), mode, direction ); if ( mode != QwtAbstractSlider::ScrNone ) { // Most mouse types work in steps of 15 degrees, in which case // the delta value is a multiple of 120 const int inc = e->delta() / 120; QwtDoubleRange::incPages( inc ); if ( value() != prevValue() ) Q_EMIT sliderMoved( value() ); } } /*! Handles key events - Key_Down, KeyLeft\n Decrement by 1 - Key_Up, Key_Right\n Increment by 1 \param e Key event \sa isReadOnly() */ void QwtAbstractSlider::keyPressEvent( QKeyEvent *e ) { if ( isReadOnly() ) { e->ignore(); return; } if ( !isValid() ) return; int increment = 0; switch ( e->key() ) { case Qt::Key_Down: if ( orientation() == Qt::Vertical ) increment = -1; break; case Qt::Key_Up: if ( orientation() == Qt::Vertical ) increment = 1; break; case Qt::Key_Left: if ( orientation() == Qt::Horizontal ) increment = -1; break; case Qt::Key_Right: if ( orientation() == Qt::Horizontal ) increment = 1; break; default:; e->ignore(); } if ( increment != 0 ) { QwtDoubleRange::incValue( increment ); if ( value() != prevValue() ) Q_EMIT sliderMoved( value() ); } } /*! Qt timer event \param e Timer event */ void QwtAbstractSlider::timerEvent( QTimerEvent * ) { const double inc = step(); switch ( d_data->scrollMode ) { case ScrMouse: { if ( d_data->mass > 0.0 ) { d_data->speed *= qExp( - double( d_data->updTime ) * 0.001 / d_data->mass ); const double newval = exactValue() + d_data->speed * double( d_data->updTime ); QwtDoubleRange::fitValue( newval ); // stop if d_data->speed < one step per second if ( qFabs( d_data->speed ) < 0.001 * qFabs( step() ) ) { d_data->speed = 0; stopMoving(); buttonReleased(); } } else stopMoving(); break; } case ScrPage: { QwtDoubleRange::incPages( d_data->direction ); if ( !d_data->timerTick ) { killTimer( d_data->tmrID ); d_data->tmrID = startTimer( d_data->updTime ); } break; } case ScrTimer: { QwtDoubleRange::fitValue( value() + double( d_data->direction ) * inc ); if ( !d_data->timerTick ) { killTimer( d_data->tmrID ); d_data->tmrID = startTimer( d_data->updTime ); } break; } default: { stopMoving(); break; } } d_data->timerTick = 1; } /*! Notify change of value This function can be reimplemented by derived classes in order to keep track of changes, i.e. repaint the widget. The default implementation emits a valueChanged() signal if tracking is enabled. */ void QwtAbstractSlider::valueChange() { if ( d_data->tracking ) Q_EMIT valueChanged( value() ); } /*! \brief Set the slider's mass for flywheel effect. If the slider's mass is greater then 0, it will continue to move after the mouse button has been released. Its speed decreases with time at a rate depending on the slider's mass. A large mass means that it will continue to move for a long time. Derived widgets may overload this function to make it public. \param val New mass in kg \bug If the mass is smaller than 1g, it is set to zero. The maximal mass is limited to 100kg. \sa mass() */ void QwtAbstractSlider::setMass( double val ) { if ( val < 0.001 ) d_data->mass = 0.0; else if ( val > 100.0 ) d_data->mass = 100.0; else d_data->mass = val; } /*! \return mass \sa setMass() */ double QwtAbstractSlider::mass() const { return d_data->mass; } /*! \brief Move the slider to a specified value This function can be used to move the slider to a value which is not an integer multiple of the step size. \param val new value \sa fitValue() */ void QwtAbstractSlider::setValue( double val ) { if ( d_data->scrollMode == ScrMouse ) stopMoving(); QwtDoubleRange::setValue( val ); } /*! \brief Set the slider's value to the nearest integer multiple of the step size. \param value Value \sa setValue(), incValue() */ void QwtAbstractSlider::fitValue( double value ) { if ( d_data->scrollMode == ScrMouse ) stopMoving(); QwtDoubleRange::fitValue( value ); } /*! \brief Increment the value by a specified number of steps \param steps number of steps \sa setValue() */ void QwtAbstractSlider::incValue( int steps ) { if ( d_data->scrollMode == ScrMouse ) stopMoving(); QwtDoubleRange::incValue( steps ); } /*! \sa mouseOffset() */ void QwtAbstractSlider::setMouseOffset( double offset ) { d_data->mouseOffset = offset; } /*! \sa setMouseOffset() */ double QwtAbstractSlider::mouseOffset() const { return d_data->mouseOffset; } //! sa ScrollMode int QwtAbstractSlider::scrollMode() const { return d_data->scrollMode; } pcp-gui-1.5.11/src/libqwt/qwt_analog_clock.cpp0000644000000000000000000001225712176111212016136 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_analog_clock.h" #include /*! Constructor \param parent Parent widget */ QwtAnalogClock::QwtAnalogClock( QWidget *parent ): QwtDial( parent ) { initClock(); } void QwtAnalogClock::initClock() { setWrapping( true ); setReadOnly( true ); setOrigin( 270.0 ); setRange( 0.0, 60.0 * 60.0 * 12.0 ); // seconds setScale( -1, 5, 60.0 * 60.0 ); setScaleComponents( QwtAbstractScaleDraw::Ticks | QwtAbstractScaleDraw::Labels ); setScaleTicks( 1, 0, 8 ); scaleDraw()->setSpacing( 8 ); QColor knobColor = palette().color( QPalette::Active, QPalette::Text ); knobColor = knobColor.dark( 120 ); QColor handColor; int width; for ( int i = 0; i < NHands; i++ ) { if ( i == SecondHand ) { width = 2; handColor = knobColor.dark( 120 ); } else { width = 8; handColor = knobColor; } QwtDialSimpleNeedle *hand = new QwtDialSimpleNeedle( QwtDialSimpleNeedle::Arrow, true, handColor, knobColor ); hand->setWidth( width ); d_hand[i] = NULL; setHand( ( Hand )i, hand ); } } //! Destructor QwtAnalogClock::~QwtAnalogClock() { for ( int i = 0; i < NHands; i++ ) delete d_hand[i]; } /*! Nop method, use setHand instead \sa setHand() */ void QwtAnalogClock::setNeedle( QwtDialNeedle * ) { // no op return; } /*! Set a clockhand \param hand Specifies the type of hand \param needle Hand \sa hand() */ void QwtAnalogClock::setHand( Hand hand, QwtDialNeedle *needle ) { if ( hand >= 0 || hand < NHands ) { delete d_hand[hand]; d_hand[hand] = needle; } } /*! \return Clock hand \param hd Specifies the type of hand \sa setHand() */ QwtDialNeedle *QwtAnalogClock::hand( Hand hd ) { if ( hd < 0 || hd >= NHands ) return NULL; return d_hand[hd]; } /*! \return Clock hand \param hd Specifies the type of hand \sa setHand() */ const QwtDialNeedle *QwtAnalogClock::hand( Hand hd ) const { return const_cast( this )->hand( hd ); } /*! \brief Set the current time This is the same as QwtAnalogClock::setTime(), but Qt < 3.0 can't handle default parameters for slots. */ void QwtAnalogClock::setCurrentTime() { setTime( QTime::currentTime() ); } /*! Set a time \param time Time to display */ void QwtAnalogClock::setTime( const QTime &time ) { if ( time.isValid() ) { setValue( ( time.hour() % 12 ) * 60.0 * 60.0 + time.minute() * 60.0 + time.second() ); } else setValid( false ); } /*! Find the scale label for a given value \param value Value \return Label */ QwtText QwtAnalogClock::scaleLabel( double value ) const { if ( qFuzzyCompare( value + 1.0, 1.0 ) ) value = 60.0 * 60.0 * 12.0; return QString::number( qRound( value / ( 60.0 * 60.0 ) ) ); } /*! \brief Draw the needle A clock has no single needle but three hands instead. drawNeedle translates value() into directions for the hands and calls drawHand(). \param painter Painter \param center Center of the clock \param radius Maximum length for the hands \param dir Dummy, not used. \param colorGroup ColorGroup \sa drawHand() */ void QwtAnalogClock::drawNeedle( QPainter *painter, const QPointF ¢er, double radius, double dir, QPalette::ColorGroup colorGroup ) const { Q_UNUSED( dir ); if ( isValid() ) { const double hours = value() / ( 60.0 * 60.0 ); const double minutes = ( value() - qFloor(hours) * 60.0 * 60.0 ) / 60.0; const double seconds = value() - qFloor(hours) * 60.0 * 60.0 - qFloor(minutes) * 60.0; double angle[NHands]; angle[HourHand] = 360.0 * hours / 12.0; angle[MinuteHand] = 360.0 * minutes / 60.0; angle[SecondHand] = 360.0 * seconds / 60.0; for ( int hand = 0; hand < NHands; hand++ ) { double d = angle[hand]; if ( direction() == Clockwise ) d = 360.0 - d; d -= origin(); drawHand( painter, ( Hand )hand, center, radius, d, colorGroup ); } } } /*! Draw a clock hand \param painter Painter \param hd Specify the type of hand \param center Center of the clock \param radius Maximum length for the hands \param direction Direction of the hand in degrees, counter clockwise \param cg ColorGroup */ void QwtAnalogClock::drawHand( QPainter *painter, Hand hd, const QPointF ¢er, double radius, double direction, QPalette::ColorGroup cg ) const { const QwtDialNeedle *needle = hand( hd ); if ( needle ) { if ( hd == HourHand ) radius = qRound( 0.8 * radius ); needle->draw( painter, center, radius, direction, cg ); } } pcp-gui-1.5.11/src/libqwt/qwt_arrow_button.cpp0000644000000000000000000002012312176111212016236 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_arrow_button.h" #include "qwt_math.h" #include #include #include #include #include static const int MaxNum = 3; static const int Margin = 2; static const int Spacing = 1; class QwtArrowButton::PrivateData { public: int num; Qt::ArrowType arrowType; }; static QStyleOptionButton styleOpt( const QwtArrowButton* btn ) { QStyleOptionButton option; option.init( btn ); option.features = QStyleOptionButton::None; if ( btn->isFlat() ) option.features |= QStyleOptionButton::Flat; if ( btn->menu() ) option.features |= QStyleOptionButton::HasMenu; if ( btn->autoDefault() || btn->isDefault() ) option.features |= QStyleOptionButton::AutoDefaultButton; if ( btn->isDefault() ) option.features |= QStyleOptionButton::DefaultButton; if ( btn->isDown() ) option.state |= QStyle::State_Sunken; if ( !btn->isFlat() && !btn->isDown() ) option.state |= QStyle::State_Raised; return option; } /*! \param num Number of arrows \param arrowType see Qt::ArowType in the Qt docs. \param parent Parent widget */ QwtArrowButton::QwtArrowButton( int num, Qt::ArrowType arrowType, QWidget *parent ): QPushButton( parent ) { d_data = new PrivateData; d_data->num = qBound( 1, num, MaxNum ); d_data->arrowType = arrowType; setAutoRepeat( true ); setAutoDefault( false ); switch ( d_data->arrowType ) { case Qt::LeftArrow: case Qt::RightArrow: setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); break; default: setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding ); } } //! Destructor QwtArrowButton::~QwtArrowButton() { delete d_data; d_data = NULL; } /*! \brief The direction of the arrows */ Qt::ArrowType QwtArrowButton::arrowType() const { return d_data->arrowType; } /*! \brief The number of arrows */ int QwtArrowButton::num() const { return d_data->num; } /*! \return the bounding rect for the label */ QRect QwtArrowButton::labelRect() const { const int m = Margin; QRect r = rect(); r.setRect( r.x() + m, r.y() + m, r.width() - 2 * m, r.height() - 2 * m ); if ( isDown() ) { QStyleOptionButton option = styleOpt( this ); const int ph = style()->pixelMetric( QStyle::PM_ButtonShiftHorizontal, &option, this ); const int pv = style()->pixelMetric( QStyle::PM_ButtonShiftVertical, &option, this ); r.translate( ph, pv ); } return r; } /*! Paint event handler \param event Paint event */ void QwtArrowButton::paintEvent( QPaintEvent *event ) { QPushButton::paintEvent( event ); QPainter painter( this ); drawButtonLabel( &painter ); } /*! \brief Draw the button label \param painter Painter \sa The Qt Manual on QPushButton */ void QwtArrowButton::drawButtonLabel( QPainter *painter ) { const bool isVertical = d_data->arrowType == Qt::UpArrow || d_data->arrowType == Qt::DownArrow; const QRect r = labelRect(); QSize boundingSize = labelRect().size(); if ( isVertical ) boundingSize.transpose(); const int w = ( boundingSize.width() - ( MaxNum - 1 ) * Spacing ) / MaxNum; QSize arrow = arrowSize( Qt::RightArrow, QSize( w, boundingSize.height() ) ); if ( isVertical ) arrow.transpose(); QRect contentsSize; // aligned rect where to paint all arrows if ( d_data->arrowType == Qt::LeftArrow || d_data->arrowType == Qt::RightArrow ) { contentsSize.setWidth( d_data->num * arrow.width() + ( d_data->num - 1 ) * Spacing ); contentsSize.setHeight( arrow.height() ); } else { contentsSize.setWidth( arrow.width() ); contentsSize.setHeight( d_data->num * arrow.height() + ( d_data->num - 1 ) * Spacing ); } QRect arrowRect( contentsSize ); arrowRect.moveCenter( r.center() ); arrowRect.setSize( arrow ); painter->save(); for ( int i = 0; i < d_data->num; i++ ) { drawArrow( painter, arrowRect, d_data->arrowType ); int dx = 0; int dy = 0; if ( isVertical ) dy = arrow.height() + Spacing; else dx = arrow.width() + Spacing; arrowRect.translate( dx, dy ); } painter->restore(); if ( hasFocus() ) { QStyleOptionFocusRect option; option.init( this ); option.backgroundColor = palette().color( QPalette::Window ); style()->drawPrimitive( QStyle::PE_FrameFocusRect, &option, painter, this ); } } /*! Draw an arrow int a bounding rect \param painter Painter \param r Rectangle where to paint the arrow \param arrowType Arrow type */ void QwtArrowButton::drawArrow( QPainter *painter, const QRect &r, Qt::ArrowType arrowType ) const { QPolygon pa( 3 ); switch ( arrowType ) { case Qt::UpArrow: pa.setPoint( 0, r.bottomLeft() ); pa.setPoint( 1, r.bottomRight() ); pa.setPoint( 2, r.center().x(), r.top() ); break; case Qt::DownArrow: pa.setPoint( 0, r.topLeft() ); pa.setPoint( 1, r.topRight() ); pa.setPoint( 2, r.center().x(), r.bottom() ); break; case Qt::RightArrow: pa.setPoint( 0, r.topLeft() ); pa.setPoint( 1, r.bottomLeft() ); pa.setPoint( 2, r.right(), r.center().y() ); break; case Qt::LeftArrow: pa.setPoint( 0, r.topRight() ); pa.setPoint( 1, r.bottomRight() ); pa.setPoint( 2, r.left(), r.center().y() ); break; default: break; } painter->save(); painter->setPen( palette().color( QPalette::ButtonText ) ); painter->setBrush( palette().brush( QPalette::ButtonText ) ); painter->drawPolygon( pa ); painter->restore(); } /*! \return a size hint */ QSize QwtArrowButton::sizeHint() const { const QSize hint = minimumSizeHint(); return hint.expandedTo( QApplication::globalStrut() ); } /*! \brief Return a minimum size hint */ QSize QwtArrowButton::minimumSizeHint() const { const QSize asz = arrowSize( Qt::RightArrow, QSize() ); QSize sz( 2 * Margin + ( MaxNum - 1 ) * Spacing + MaxNum * asz.width(), 2 * Margin + asz.height() ); if ( d_data->arrowType == Qt::UpArrow || d_data->arrowType == Qt::DownArrow ) sz.transpose(); QStyleOption styleOption; styleOption.init( this ); sz = style()->sizeFromContents( QStyle::CT_PushButton, &styleOption, sz, this ); return sz; } /*! Calculate the size for a arrow that fits into a rect of a given size \param arrowType Arrow type \param boundingSize Bounding size \return Size of the arrow */ QSize QwtArrowButton::arrowSize( Qt::ArrowType arrowType, const QSize &boundingSize ) const { QSize bs = boundingSize; if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow ) bs.transpose(); const int MinLen = 2; const QSize sz = bs.expandedTo( QSize( MinLen, 2 * MinLen - 1 ) ); // minimum int w = sz.width(); int h = 2 * w - 1; if ( h > sz.height() ) { h = sz.height(); w = ( h + 1 ) / 2; } QSize arrSize( w, h ); if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow ) arrSize.transpose(); return arrSize; } /*! \brief autoRepeat for the space keys */ void QwtArrowButton::keyPressEvent( QKeyEvent *event ) { if ( event->isAutoRepeat() && event->key() == Qt::Key_Space ) Q_EMIT clicked(); QPushButton::keyPressEvent( event ); } pcp-gui-1.5.11/src/libqwt/qwt_clipper.cpp0000644000000000000000000002737512176111212015167 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_clipper.h" #include "qwt_point_polar.h" #include #if QT_VERSION < 0x040601 #define qAtan(x) ::atan(x) #endif namespace QwtClip { // some templates used for inlining template class LeftEdge; template class RightEdge; template class TopEdge; template class BottomEdge; template class PointBuffer; } template class QwtClip::LeftEdge { public: inline LeftEdge( Value x1, Value, Value, Value ): d_x1( x1 ) { } inline bool isInside( const Point &p ) const { return p.x() >= d_x1; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() ); return Point( d_x1, ( Value ) ( p2.y() + ( d_x1 - p2.x() ) * dy ) ); } private: const Value d_x1; }; template class QwtClip::RightEdge { public: inline RightEdge( Value, Value x2, Value, Value ): d_x2( x2 ) { } inline bool isInside( const Point &p ) const { return p.x() <= d_x2; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() ); return Point( d_x2, ( Value ) ( p2.y() + ( d_x2 - p2.x() ) * dy ) ); } private: const Value d_x2; }; template class QwtClip::TopEdge { public: inline TopEdge( Value, Value, Value y1, Value ): d_y1( y1 ) { } inline bool isInside( const Point &p ) const { return p.y() >= d_y1; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() ); return Point( ( Value )( p2.x() + ( d_y1 - p2.y() ) * dx ), d_y1 ); } private: const Value d_y1; }; template class QwtClip::BottomEdge { public: inline BottomEdge( Value, Value, Value, Value y2 ): d_y2( y2 ) { } inline bool isInside( const Point &p ) const { return p.y() <= d_y2; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() ); return Point( ( Value )( p2.x() + ( d_y2 - p2.y() ) * dx ), d_y2 ); } private: const Value d_y2; }; template class QwtClip::PointBuffer { public: PointBuffer( int capacity = 0 ): m_capacity( 0 ), m_size( 0 ), m_buffer( NULL ) { if ( capacity > 0 ) reserve( capacity ); } ~PointBuffer() { if ( m_buffer ) qFree( m_buffer ); } inline void setPoints( int numPoints, const Point *points ) { reserve( numPoints ); m_size = numPoints; qMemCopy( m_buffer, points, m_size * sizeof( Point ) ); } inline void reset() { m_size = 0; } inline int size() const { return m_size; } inline Point *data() const { return m_buffer; } inline Point &operator[]( int i ) { return m_buffer[i]; } inline const Point &operator[]( int i ) const { return m_buffer[i]; } inline void add( const Point &point ) { if ( m_capacity <= m_size ) reserve( m_size + 1 ); m_buffer[m_size++] = point; } private: inline void reserve( int size ) { if ( m_capacity == 0 ) m_capacity = 1; while ( m_capacity < size ) m_capacity *= 2; m_buffer = ( Point * ) qRealloc( m_buffer, m_capacity * sizeof( Point ) ); } int m_capacity; int m_size; Point *m_buffer; }; using namespace QwtClip; template class QwtPolygonClipper { public: QwtPolygonClipper( const Rect &clipRect ): d_clipRect( clipRect ) { } Polygon clipPolygon( const Polygon &polygon, bool closePolygon ) const { #if 0 if ( d_clipRect.contains( polygon.boundingRect() ) ) return polygon; #endif PointBuffer points1; PointBuffer points2( qMin( 256, polygon.size() ) ); points1.setPoints( polygon.size(), polygon.data() ); clipEdge< LeftEdge >( closePolygon, points1, points2 ); clipEdge< RightEdge >( closePolygon, points2, points1 ); clipEdge< TopEdge >( closePolygon, points1, points2 ); clipEdge< BottomEdge >( closePolygon, points2, points1 ); Polygon p; p.resize( points1.size() ); qMemCopy( p.data(), points1.data(), points1.size() * sizeof( Point ) ); return p; } private: template inline void clipEdge( bool closePolygon, PointBuffer &points, PointBuffer &clippedPoints ) const { clippedPoints.reset(); if ( points.size() < 2 ) { if ( points.size() == 1 ) clippedPoints.add( points[0] ); return; } const Edge edge( d_clipRect.x(), d_clipRect.x() + d_clipRect.width(), d_clipRect.y(), d_clipRect.y() + d_clipRect.height() ); int lastPos, start; if ( closePolygon ) { start = 0; lastPos = points.size() - 1; } else { start = 1; lastPos = 0; if ( edge.isInside( points[0] ) ) clippedPoints.add( points[0] ); } const uint nPoints = points.size(); for ( uint i = start; i < nPoints; i++ ) { const Point &p1 = points[i]; const Point &p2 = points[lastPos]; if ( edge.isInside( p1 ) ) { if ( edge.isInside( p2 ) ) { clippedPoints.add( p1 ); } else { clippedPoints.add( edge.intersection( p1, p2 ) ); clippedPoints.add( p1 ); } } else { if ( edge.isInside( p2 ) ) { clippedPoints.add( edge.intersection( p1, p2 ) ); } } lastPos = i; } } const Rect d_clipRect; }; class QwtCircleClipper { public: QwtCircleClipper( const QRectF &r ); QVector clipCircle( const QPointF &, double radius ) const; private: enum Edge { Left, Top, Right, Bottom, NEdges }; QList cuttingPoints( Edge, const QPointF &pos, double radius ) const; double toAngle( const QPointF &, const QPointF & ) const; const QRectF d_rect; }; QwtCircleClipper::QwtCircleClipper( const QRectF &r ): d_rect( r ) { } QVector QwtCircleClipper::clipCircle( const QPointF &pos, double radius ) const { QList points; for ( int edge = 0; edge < NEdges; edge++ ) points += cuttingPoints( ( Edge )edge, pos, radius ); QVector intv; if ( points.size() <= 0 ) { QRectF cRect( 0, 0, 2 * radius, 2 * radius ); cRect.moveCenter( pos ); if ( d_rect.contains( cRect ) ) intv += QwtInterval( 0.0, 2 * M_PI ); } else { QList angles; for ( int i = 0; i < points.size(); i++ ) angles += toAngle( pos, points[i] ); qSort( angles ); const int in = d_rect.contains( qwtPolar2Pos( pos, radius, angles[0] + ( angles[1] - angles[0] ) / 2 ) ); if ( in ) { for ( int i = 0; i < angles.size() - 1; i += 2 ) intv += QwtInterval( angles[i], angles[i+1] ); } else { for ( int i = 1; i < angles.size() - 1; i += 2 ) intv += QwtInterval( angles[i], angles[i+1] ); intv += QwtInterval( angles.last(), angles.first() ); } } return intv; } double QwtCircleClipper::toAngle( const QPointF &from, const QPointF &to ) const { if ( from.x() == to.x() ) return from.y() <= to.y() ? M_PI / 2.0 : 3 * M_PI / 2.0; const double m = qAbs( ( to.y() - from.y() ) / ( to.x() - from.x() ) ); double angle = qAtan( m ); if ( to.x() > from.x() ) { if ( to.y() > from.y() ) angle = 2 * M_PI - angle; } else { if ( to.y() > from.y() ) angle = M_PI + angle; else angle = M_PI - angle; } return angle; } QList QwtCircleClipper::cuttingPoints( Edge edge, const QPointF &pos, double radius ) const { QList points; if ( edge == Left || edge == Right ) { const double x = ( edge == Left ) ? d_rect.left() : d_rect.right(); if ( qAbs( pos.x() - x ) < radius ) { const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.x() - x ) ); const double m_y1 = pos.y() + off; if ( m_y1 >= d_rect.top() && m_y1 <= d_rect.bottom() ) points += QPointF( x, m_y1 ); const double m_y2 = pos.y() - off; if ( m_y2 >= d_rect.top() && m_y2 <= d_rect.bottom() ) points += QPointF( x, m_y2 ); } } else { const double y = ( edge == Top ) ? d_rect.top() : d_rect.bottom(); if ( qAbs( pos.y() - y ) < radius ) { const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.y() - y ) ); const double x1 = pos.x() + off; if ( x1 >= d_rect.left() && x1 <= d_rect.right() ) points += QPointF( x1, y ); const double m_x2 = pos.x() - off; if ( m_x2 >= d_rect.left() && m_x2 <= d_rect.right() ) points += QPointF( m_x2, y ); } } return points; } /*! Sutherland-Hodgman polygon clipping \param clipRect Clip rectangle \param polygon Polygon \param closePolygon True, when the polygon is closed \return Clipped polygon */ QPolygon QwtClipper::clipPolygon( const QRect &clipRect, const QPolygon &polygon, bool closePolygon ) { QwtPolygonClipper clipper( clipRect ); return clipper.clipPolygon( polygon, closePolygon ); } /*! Sutherland-Hodgman polygon clipping \param clipRect Clip rectangle \param polygon Polygon \param closePolygon True, when the polygon is closed \return Clipped polygon */ QPolygonF QwtClipper::clipPolygonF( const QRectF &clipRect, const QPolygonF &polygon, bool closePolygon ) { QwtPolygonClipper clipper( clipRect ); return clipper.clipPolygon( polygon, closePolygon ); } /*! Circle clipping clipCircle() devides a circle into intervals of angles representing arcs of the circle. When the circle is completely inside the clip rectangle an interval [0.0, 2 * M_PI] is returned. \param clipRect Clip rectangle \param center Center of the circle \param radius Radius of the circle \return Arcs of the circle */ QVector QwtClipper::clipCircle( const QRectF &clipRect, const QPointF ¢er, double radius ) { QwtCircleClipper clipper( clipRect ); return clipper.clipCircle( center, radius ); } pcp-gui-1.5.11/src/libqwt/qwt_color_map.cpp0000644000000000000000000002356712176111212015503 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_color_map.h" #include "qwt_math.h" #include "qwt_interval.h" #include class QwtLinearColorMap::ColorStops { public: ColorStops() { _stops.reserve( 256 ); } void insert( double pos, const QColor &color ); QRgb rgb( QwtLinearColorMap::Mode, double pos ) const; QVector stops() const; private: class ColorStop { public: ColorStop(): pos( 0.0 ), rgb( 0 ) { }; ColorStop( double p, const QColor &c ): pos( p ), rgb( c.rgb() ) { r = qRed( rgb ); g = qGreen( rgb ); b = qBlue( rgb ); } double pos; QRgb rgb; int r, g, b; }; inline int findUpper( double pos ) const; QVector _stops; }; void QwtLinearColorMap::ColorStops::insert( double pos, const QColor &color ) { // Lookups need to be very fast, insertions are not so important. // Anyway, a balanced tree is what we need here. TODO ... if ( pos < 0.0 || pos > 1.0 ) return; int index; if ( _stops.size() == 0 ) { index = 0; _stops.resize( 1 ); } else { index = findUpper( pos ); if ( index == _stops.size() || qAbs( _stops[index].pos - pos ) >= 0.001 ) { _stops.resize( _stops.size() + 1 ); for ( int i = _stops.size() - 1; i > index; i-- ) _stops[i] = _stops[i-1]; } } _stops[index] = ColorStop( pos, color ); } inline QVector QwtLinearColorMap::ColorStops::stops() const { QVector positions( _stops.size() ); for ( int i = 0; i < _stops.size(); i++ ) positions[i] = _stops[i].pos; return positions; } inline int QwtLinearColorMap::ColorStops::findUpper( double pos ) const { int index = 0; int n = _stops.size(); const ColorStop *stops = _stops.data(); while ( n > 0 ) { const int half = n >> 1; const int middle = index + half; if ( stops[middle].pos <= pos ) { index = middle + 1; n -= half + 1; } else n = half; } return index; } inline QRgb QwtLinearColorMap::ColorStops::rgb( QwtLinearColorMap::Mode mode, double pos ) const { if ( pos <= 0.0 ) return _stops[0].rgb; if ( pos >= 1.0 ) return _stops[ _stops.size() - 1 ].rgb; const int index = findUpper( pos ); if ( mode == FixedColors ) { return _stops[index-1].rgb; } else { const ColorStop &s1 = _stops[index-1]; const ColorStop &s2 = _stops[index]; const double ratio = ( pos - s1.pos ) / ( s2.pos - s1.pos ); const int r = s1.r + qRound( ratio * ( s2.r - s1.r ) ); const int g = s1.g + qRound( ratio * ( s2.g - s1.g ) ); const int b = s1.b + qRound( ratio * ( s2.b - s1.b ) ); return qRgb( r, g, b ); } } //! Constructor QwtColorMap::QwtColorMap( Format format ): d_format( format ) { } //! Destructor QwtColorMap::~QwtColorMap() { } /*! Build and return a color map of 256 colors The color table is needed for rendering indexed images in combination with using colorIndex(). \param interval Range for the values \return A color table, that can be used for a QImage */ QVector QwtColorMap::colorTable( const QwtInterval &interval ) const { QVector table( 256 ); if ( interval.isValid() ) { const double step = interval.width() / ( table.size() - 1 ); for ( int i = 0; i < table.size(); i++ ) table[i] = rgb( interval, interval.minValue() + step * i ); } return table; } class QwtLinearColorMap::PrivateData { public: ColorStops colorStops; QwtLinearColorMap::Mode mode; }; /*! Build a color map with two stops at 0.0 and 1.0. The color at 0.0 is Qt::blue, at 1.0 it is Qt::yellow. \param format Preferred format of the color map */ QwtLinearColorMap::QwtLinearColorMap( QwtColorMap::Format format ): QwtColorMap( format ) { d_data = new PrivateData; d_data->mode = ScaledColors; setColorInterval( Qt::blue, Qt::yellow ); } /*! Build a color map with two stops at 0.0 and 1.0. \param color1 Color used for the minimum value of the value interval \param color2 Color used for the maximum value of the value interval \param format Preferred format of the coor map */ QwtLinearColorMap::QwtLinearColorMap( const QColor &color1, const QColor &color2, QwtColorMap::Format format ): QwtColorMap( format ) { d_data = new PrivateData; d_data->mode = ScaledColors; setColorInterval( color1, color2 ); } //! Destructor QwtLinearColorMap::~QwtLinearColorMap() { delete d_data; } /*! \brief Set the mode of the color map FixedColors means the color is calculated from the next lower color stop. ScaledColors means the color is calculated by interpolating the colors of the adjacent stops. \sa mode() */ void QwtLinearColorMap::setMode( Mode mode ) { d_data->mode = mode; } /*! \return Mode of the color map \sa setMode() */ QwtLinearColorMap::Mode QwtLinearColorMap::mode() const { return d_data->mode; } /*! Set the color range Add stops at 0.0 and 1.0. \param color1 Color used for the minimum value of the value interval \param color2 Color used for the maximum value of the value interval \sa color1(), color2() */ void QwtLinearColorMap::setColorInterval( const QColor &color1, const QColor &color2 ) { d_data->colorStops = ColorStops(); d_data->colorStops.insert( 0.0, color1 ); d_data->colorStops.insert( 1.0, color2 ); } /*! Add a color stop The value has to be in the range [0.0, 1.0]. F.e. a stop at position 17.0 for a range [10.0,20.0] must be passed as: (17.0 - 10.0) / (20.0 - 10.0) \param value Value between [0.0, 1.0] \param color Color stop */ void QwtLinearColorMap::addColorStop( double value, const QColor& color ) { if ( value >= 0.0 && value <= 1.0 ) d_data->colorStops.insert( value, color ); } /*! Return all positions of color stops in increasing order */ QVector QwtLinearColorMap::colorStops() const { return d_data->colorStops.stops(); } /*! \return the first color of the color range \sa setColorInterval() */ QColor QwtLinearColorMap::color1() const { return QColor( d_data->colorStops.rgb( d_data->mode, 0.0 ) ); } /*! \return the second color of the color range \sa setColorInterval() */ QColor QwtLinearColorMap::color2() const { return QColor( d_data->colorStops.rgb( d_data->mode, 1.0 ) ); } /*! Map a value of a given interval into a rgb value \param interval Range for all values \param value Value to map into a rgb value */ QRgb QwtLinearColorMap::rgb( const QwtInterval &interval, double value ) const { if ( qIsNaN(value) ) return qRgba(0, 0, 0, 0); const double width = interval.width(); double ratio = 0.0; if ( width > 0.0 ) ratio = ( value - interval.minValue() ) / width; return d_data->colorStops.rgb( d_data->mode, ratio ); } /*! Map a value of a given interval into a color index, between 0 and 255 \param interval Range for all values \param value Value to map into a color index */ unsigned char QwtLinearColorMap::colorIndex( const QwtInterval &interval, double value ) const { const double width = interval.width(); if ( qIsNaN(value) || width <= 0.0 || value <= interval.minValue() ) return 0; if ( value >= interval.maxValue() ) return ( unsigned char )255; const double ratio = ( value - interval.minValue() ) / width; unsigned char index; if ( d_data->mode == FixedColors ) index = ( unsigned char )( ratio * 255 ); // always floor else index = ( unsigned char )qRound( ratio * 255 ); return index; } class QwtAlphaColorMap::PrivateData { public: QColor color; QRgb rgb; }; /*! Constructor \param color Color of the map */ QwtAlphaColorMap::QwtAlphaColorMap( const QColor &color ): QwtColorMap( QwtColorMap::RGB ) { d_data = new PrivateData; d_data->color = color; d_data->rgb = color.rgb() & qRgba( 255, 255, 255, 0 ); } //! Destructor QwtAlphaColorMap::~QwtAlphaColorMap() { delete d_data; } /*! Set the color \param color Color \sa color() */ void QwtAlphaColorMap::setColor( const QColor &color ) { d_data->color = color; d_data->rgb = color.rgb(); } /*! \return the color \sa setColor() */ QColor QwtAlphaColorMap::color() const { return d_data->color; } /*! \brief Map a value of a given interval into a alpha value alpha := (value - interval.minValue()) / interval.width(); \param interval Range for all values \param value Value to map into a rgb value \return rgb value, with an alpha value */ QRgb QwtAlphaColorMap::rgb( const QwtInterval &interval, double value ) const { const double width = interval.width(); if ( !qIsNaN(value) && width >= 0.0 ) { const double ratio = ( value - interval.minValue() ) / width; int alpha = qRound( 255 * ratio ); if ( alpha < 0 ) alpha = 0; if ( alpha > 255 ) alpha = 255; return d_data->rgb | ( alpha << 24 ); } return d_data->rgb; } /*! Dummy function, needed to be implemented as it is pure virtual in QwtColorMap. Color indices make no sense in combination with an alpha channel. \return Always 0 */ unsigned char QwtAlphaColorMap::colorIndex( const QwtInterval &, double ) const { return 0; } pcp-gui-1.5.11/src/libqwt/qwt_column_symbol.cpp0000644000000000000000000001526612176111212016407 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_column_symbol.h" #include "qwt_math.h" #include "qwt_painter.h" #include #include static void drawBox( QPainter *p, const QRectF &rect, const QPalette &pal, double lw ) { if ( lw > 0.0 ) { if ( rect.width() == 0.0 ) { p->setPen( pal.dark().color() ); p->drawLine( rect.topLeft(), rect.bottomLeft() ); return; } if ( rect.height() == 0.0 ) { p->setPen( pal.dark().color() ); p->drawLine( rect.topLeft(), rect.topRight() ); return; } lw = qMin( lw, rect.height() / 2.0 - 1.0 ); lw = qMin( lw, rect.width() / 2.0 - 1.0 ); const QRectF outerRect = rect.adjusted( 0, 0, 1, 1 ); QPolygonF polygon( outerRect ); if ( outerRect.width() > 2 * lw && outerRect.height() > 2 * lw ) { const QRectF innerRect = outerRect.adjusted( lw, lw, -lw, -lw ); polygon = polygon.subtracted( innerRect ); } p->setPen( Qt::NoPen ); p->setBrush( pal.dark() ); p->drawPolygon( polygon ); } const QRectF windowRect = rect.adjusted( lw, lw, -lw + 1, -lw + 1 ); if ( windowRect.isValid() ) p->fillRect( windowRect, pal.window() ); } static void drawPanel( QPainter *painter, const QRectF &rect, const QPalette &pal, double lw ) { if ( lw > 0.0 ) { if ( rect.width() == 0.0 ) { painter->setPen( pal.window().color() ); painter->drawLine( rect.topLeft(), rect.bottomLeft() ); return; } if ( rect.height() == 0.0 ) { painter->setPen( pal.window().color() ); painter->drawLine( rect.topLeft(), rect.topRight() ); return; } lw = qMin( lw, rect.height() / 2.0 - 1.0 ); lw = qMin( lw, rect.width() / 2.0 - 1.0 ); const QRectF outerRect = rect.adjusted( 0, 0, 1, 1 ); const QRectF innerRect = outerRect.adjusted( lw, lw, -lw, -lw ); QPolygonF lines[2]; lines[0] += outerRect.bottomLeft(); lines[0] += outerRect.topLeft(); lines[0] += outerRect.topRight(); lines[0] += innerRect.topRight(); lines[0] += innerRect.topLeft(); lines[0] += innerRect.bottomLeft(); lines[1] += outerRect.topRight(); lines[1] += outerRect.bottomRight(); lines[1] += outerRect.bottomLeft(); lines[1] += innerRect.bottomLeft(); lines[1] += innerRect.bottomRight(); lines[1] += innerRect.topRight(); painter->setPen( Qt::NoPen ); painter->setBrush( pal.light() ); painter->drawPolygon( lines[0] ); painter->setBrush( pal.dark() ); painter->drawPolygon( lines[1] ); } painter->fillRect( rect.adjusted( lw, lw, -lw + 1, -lw + 1 ), pal.window() ); } class QwtColumnSymbol::PrivateData { public: PrivateData(): style( QwtColumnSymbol::Box ), frameStyle( QwtColumnSymbol::Raised ), lineWidth( 2 ) { palette = QPalette( Qt::gray ); } QwtColumnSymbol::Style style; QwtColumnSymbol::FrameStyle frameStyle; QPalette palette; int lineWidth; }; /*! Constructor \param style Style of the symbol \sa setStyle(), style(), Style */ QwtColumnSymbol::QwtColumnSymbol( Style style ) { d_data = new PrivateData(); d_data->style = style; } //! Destructor QwtColumnSymbol::~QwtColumnSymbol() { delete d_data; } /*! Specify the symbol style \param style Style \sa style(), setPalette() */ void QwtColumnSymbol::setStyle( Style style ) { d_data->style = style; } /*! \return Current symbol style \sa setStyle() */ QwtColumnSymbol::Style QwtColumnSymbol::style() const { return d_data->style; } /*! Assign a palette for the symbol \param palette Palette \sa palette(), setStyle() */ void QwtColumnSymbol::setPalette( const QPalette &palette ) { d_data->palette = palette; } /*! \return Current palette \sa setPalette() */ const QPalette& QwtColumnSymbol::palette() const { return d_data->palette; } /*! Set the frame, that is used for the Box style. \param frameStyle Frame style \sa frameStyle(), setLineWidth(), setStyle() */ void QwtColumnSymbol::setFrameStyle( FrameStyle frameStyle ) { d_data->frameStyle = frameStyle; } /*! \return Current frame style, that is used for the Box style. \sa setFrameStyle(), lineWidth(), setStyle() */ QwtColumnSymbol::FrameStyle QwtColumnSymbol::frameStyle() const { return d_data->frameStyle; } /*! Set the line width of the frame, that is used for the Box style. \param width Width \sa lineWidth(), setFrameStyle() */ void QwtColumnSymbol::setLineWidth( int width ) { if ( width < 0 ) width = 0; d_data->lineWidth = width; } /*! \return Line width of the frame, that is used for the Box style. \sa setLineWidth(), frameStyle(), setStyle() */ int QwtColumnSymbol::lineWidth() const { return d_data->lineWidth; } /*! Draw the symbol depending on its style. \param painter Painter \param rect Directed rectangle \sa drawBox() */ void QwtColumnSymbol::draw( QPainter *painter, const QwtColumnRect &rect ) const { painter->save(); switch ( d_data->style ) { case QwtColumnSymbol::Box: { drawBox( painter, rect ); break; } default:; } painter->restore(); } /*! Draw the symbol when it is in Box style. \param painter Painter \param rect Directed rectangle \sa draw() */ void QwtColumnSymbol::drawBox( QPainter *painter, const QwtColumnRect &rect ) const { QRectF r = rect.toRect(); if ( QwtPainter::roundingAlignment( painter ) ) { r.setLeft( qRound( r.left() ) ); r.setRight( qRound( r.right() ) ); r.setTop( qRound( r.top() ) ); r.setBottom( qRound( r.bottom() ) ); } switch ( d_data->frameStyle ) { case QwtColumnSymbol::Raised: { ::drawPanel( painter, r, d_data->palette, d_data->lineWidth ); break; } case QwtColumnSymbol::Plain: { ::drawBox( painter, r, d_data->palette, d_data->lineWidth ); break; } default: { painter->fillRect( r, d_data->palette.window() ); } } } pcp-gui-1.5.11/src/libqwt/qwt_compass.cpp0000644000000000000000000001570512176111212015170 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_compass.h" #include "qwt_compass_rose.h" #include "qwt_math.h" #include "qwt_scale_draw.h" #include "qwt_painter.h" #include "qwt_dial_needle.h" #include #include #include class QwtCompass::PrivateData { public: PrivateData(): rose( NULL ) { } ~PrivateData() { delete rose; } QwtCompassRose *rose; QMap labelMap; }; /*! \brief Constructor \param parent Parent widget Create a compass widget with a scale, no needle and no rose. The default origin is 270.0 with no valid value. It accepts mouse and keyboard inputs and has no step size. The default mode is QwtDial::RotateNeedle. */ QwtCompass::QwtCompass( QWidget* parent ): QwtDial( parent ) { initCompass(); } //! Destructor QwtCompass::~QwtCompass() { delete d_data; } void QwtCompass::initCompass() { d_data = new PrivateData; // Only labels, no backbone, no ticks setScaleComponents( QwtAbstractScaleDraw::Labels ); setOrigin( 270.0 ); setWrapping( true ); d_data->labelMap.insert( 0.0, QString::fromLatin1( "N" ) ); d_data->labelMap.insert( 45.0, QString::fromLatin1( "NE" ) ); d_data->labelMap.insert( 90.0, QString::fromLatin1( "E" ) ); d_data->labelMap.insert( 135.0, QString::fromLatin1( "SE" ) ); d_data->labelMap.insert( 180.0, QString::fromLatin1( "S" ) ); d_data->labelMap.insert( 225.0, QString::fromLatin1( "SW" ) ); d_data->labelMap.insert( 270.0, QString::fromLatin1( "W" ) ); d_data->labelMap.insert( 315.0, QString::fromLatin1( "NW" ) ); #if 0 d_data->labelMap.insert( 22.5, QString::fromLatin1( "NNE" ) ); d_data->labelMap.insert( 67.5, QString::fromLatin1( "NEE" ) ); d_data->labelMap.insert( 112.5, QString::fromLatin1( "SEE" ) ); d_data->labelMap.insert( 157.5, QString::fromLatin1( "SSE" ) ); d_data->labelMap.insert( 202.5, QString::fromLatin1( "SSW" ) ); d_data->labelMap.insert( 247.5, QString::fromLatin1( "SWW" ) ); d_data->labelMap.insert( 292.5, QString::fromLatin1( "NWW" ) ); d_data->labelMap.insert( 337.5, QString::fromLatin1( "NNW" ) ); #endif } /*! Draw the contents of the scale \param painter Painter \param center Center of the content circle \param radius Radius of the content circle */ void QwtCompass::drawScaleContents( QPainter *painter, const QPointF ¢er, double radius ) const { QPalette::ColorGroup cg; if ( isEnabled() ) cg = hasFocus() ? QPalette::Active : QPalette::Inactive; else cg = QPalette::Disabled; double north = origin(); if ( isValid() ) { if ( mode() == RotateScale ) north -= value(); } const int margin = 4; drawRose( painter, center, radius - margin, 360.0 - north, cg ); } /*! Draw the compass rose \param painter Painter \param center Center of the compass \param radius of the circle, where to paint the rose \param north Direction pointing north, in degrees counter clockwise \param cg Color group */ void QwtCompass::drawRose( QPainter *painter, const QPointF ¢er, double radius, double north, QPalette::ColorGroup cg ) const { if ( d_data->rose ) d_data->rose->draw( painter, center, radius, north, cg ); } /*! Set a rose for the compass \param rose Compass rose \warning The rose will be deleted, when a different rose is set or in ~QwtCompass \sa rose() */ void QwtCompass::setRose( QwtCompassRose *rose ) { if ( rose != d_data->rose ) { if ( d_data->rose ) delete d_data->rose; d_data->rose = rose; update(); } } /*! \return rose \sa setRose() */ const QwtCompassRose *QwtCompass::rose() const { return d_data->rose; } /*! \return rose \sa setRose() */ QwtCompassRose *QwtCompass::rose() { return d_data->rose; } /*! Handles key events Beside the keys described in QwtDial::keyPressEvent numbers from 1-9 (without 5) set the direction according to their position on the num pad. \sa isReadOnly() */ void QwtCompass::keyPressEvent( QKeyEvent *kev ) { if ( isReadOnly() ) return; #if 0 if ( kev->key() == Key_5 ) { invalidate(); // signal ??? return; } #endif double newValue = value(); if ( kev->key() >= Qt::Key_1 && kev->key() <= Qt::Key_9 ) { if ( mode() != RotateNeedle || kev->key() == Qt::Key_5 ) return; switch ( kev->key() ) { case Qt::Key_6: newValue = 180.0 * 0.0; break; case Qt::Key_3: newValue = 180.0 * 0.25; break; case Qt::Key_2: newValue = 180.0 * 0.5; break; case Qt::Key_1: newValue = 180.0 * 0.75; break; case Qt::Key_4: newValue = 180.0 * 1.0; break; case Qt::Key_7: newValue = 180.0 * 1.25; break; case Qt::Key_8: newValue = 180.0 * 1.5; break; case Qt::Key_9: newValue = 180.0 * 1.75; break; } newValue -= origin(); setValue( newValue ); } else { QwtDial::keyPressEvent( kev ); } } /*! \return map, mapping values to labels \sa setLabelMap() */ const QMap &QwtCompass::labelMap() const { return d_data->labelMap; } /*! \return map, mapping values to labels \sa setLabelMap() */ QMap &QwtCompass::labelMap() { return d_data->labelMap; } /*! \brief Set a map, mapping values to labels \param map value to label map The values of the major ticks are found by looking into this map. The default map consists of the labels N, NE, E, SE, S, SW, W, NW. \warning The map will have no effect for values that are no major tick values. Major ticks can be changed by QwtScaleDraw::setScale \sa labelMap(), scaleDraw(), setScale() */ void QwtCompass::setLabelMap( const QMap &map ) { d_data->labelMap = map; } /*! Map a value to a corresponding label \param value Value that will be mapped \return Label, or QString::null label() looks in a map for a corresponding label for value or return an null text. \sa labelMap(), setLabelMap() */ QwtText QwtCompass::scaleLabel( double value ) const { if ( qFuzzyCompare( value + 1.0, 1.0 ) ) value = 0.0; if ( value < 0.0 ) value += 360.0; if ( d_data->labelMap.contains( value ) ) return d_data->labelMap[value]; return QwtText(); } pcp-gui-1.5.11/src/libqwt/qwt_compass_rose.cpp0000644000000000000000000001464312176111212016220 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_compass_rose.h" #include "qwt_point_polar.h" #include "qwt_painter.h" #include static QPointF qwtIntersection( QPointF p11, QPointF p12, QPointF p21, QPointF p22 ) { const QLineF line1( p11, p12 ); const QLineF line2( p21, p22 ); QPointF pos; if ( line1.intersect( line2, &pos ) == QLineF::NoIntersection ) return QPointF(); return pos; } class QwtSimpleCompassRose::PrivateData { public: PrivateData(): width( 0.2 ), numThorns( 8 ), numThornLevels( -1 ), shrinkFactor( 0.9 ) { } double width; int numThorns; int numThornLevels; double shrinkFactor; }; /*! Constructor \param numThorns Number of thorns \param numThornLevels Number of thorn levels */ QwtSimpleCompassRose::QwtSimpleCompassRose( int numThorns, int numThornLevels ) { d_data = new PrivateData(); d_data->numThorns = numThorns; d_data->numThornLevels = numThornLevels; const QColor dark( 128, 128, 255 ); const QColor light( 192, 255, 255 ); QPalette palette; palette.setColor( QPalette::Dark, dark ); palette.setColor( QPalette::Light, light ); setPalette( palette ); } //! Destructor QwtSimpleCompassRose::~QwtSimpleCompassRose() { delete d_data; } /*! Set the Factor how to shrink the thorns with each level The default value is 0.9. \sa shrinkFactor() */ void QwtSimpleCompassRose::setShrinkFactor( double factor ) { d_data->shrinkFactor = factor; } /*! \return Factor how to shrink the thorns with each level \sa setShrinkFactor() */ double QwtSimpleCompassRose::shrinkFactor() const { return d_data->shrinkFactor; } /*! Draw the rose \param painter Painter \param center Center point \param radius Radius of the rose \param north Position \param cg Color group */ void QwtSimpleCompassRose::draw( QPainter *painter, const QPointF ¢er, double radius, double north, QPalette::ColorGroup cg ) const { QPalette pal = palette(); pal.setCurrentColorGroup( cg ); drawRose( painter, pal, center, radius, north, d_data->width, d_data->numThorns, d_data->numThornLevels, d_data->shrinkFactor ); } /*! Draw the rose \param painter Painter \param palette Palette \param center Center of the rose \param radius Radius of the rose \param north Position pointing to north \param width Width of the rose \param numThorns Number of thorns \param numThornLevels Number of thorn levels \param shrinkFactor Factor to shrink the thorns with each level */ void QwtSimpleCompassRose::drawRose( QPainter *painter, const QPalette &palette, const QPointF ¢er, double radius, double north, double width, int numThorns, int numThornLevels, double shrinkFactor ) { if ( numThorns < 4 ) numThorns = 4; if ( numThorns % 4 ) numThorns += 4 - numThorns % 4; if ( numThornLevels <= 0 ) numThornLevels = numThorns / 4; if ( shrinkFactor >= 1.0 ) shrinkFactor = 1.0; if ( shrinkFactor <= 0.5 ) shrinkFactor = 0.5; painter->save(); painter->setPen( Qt::NoPen ); for ( int j = 1; j <= numThornLevels; j++ ) { double step = qPow( 2.0, j ) * M_PI / numThorns; if ( step > M_PI_2 ) break; double r = radius; for ( int k = 0; k < 3; k++ ) { if ( j + k < numThornLevels ) r *= shrinkFactor; } double leafWidth = r * width; if ( 2.0 * M_PI / step > 32 ) leafWidth = 16; const double origin = north / 180.0 * M_PI; for ( double angle = origin; angle < 2.0 * M_PI + origin; angle += step ) { const QPointF p = qwtPolar2Pos( center, r, angle ); const QPointF p1 = qwtPolar2Pos( center, leafWidth, angle + M_PI_2 ); const QPointF p2 = qwtPolar2Pos( center, leafWidth, angle - M_PI_2 ); const QPointF p3 = qwtPolar2Pos( center, r, angle + step / 2.0 ); const QPointF p4 = qwtPolar2Pos( center, r, angle - step / 2.0 ); QPainterPath darkPath; darkPath.moveTo( center ); darkPath.lineTo( p ); darkPath.lineTo( qwtIntersection( center, p3, p1, p ) ); painter->setBrush( palette.brush( QPalette::Dark ) ); painter->drawPath( darkPath ); QPainterPath lightPath; lightPath.moveTo( center ); lightPath.lineTo( p ); lightPath.lineTo( qwtIntersection( center, p4, p2, p ) ); painter->setBrush( palette.brush( QPalette::Light ) ); painter->drawPath( lightPath ); } } painter->restore(); } /*! Set the width of the rose heads. Lower value make thinner heads. The range is limited from 0.03 to 0.4. \param width Width */ void QwtSimpleCompassRose::setWidth( double width ) { d_data->width = width; if ( d_data->width < 0.03 ) d_data->width = 0.03; if ( d_data->width > 0.4 ) d_data->width = 0.4; } //! \sa setWidth() double QwtSimpleCompassRose::width() const { return d_data->width; } /*! Set the number of thorns on one level The number is aligned to a multiple of 4, with a minimum of 4 \param numThorns Number of thorns \sa numThorns(), setNumThornLevels() */ void QwtSimpleCompassRose::setNumThorns( int numThorns ) { if ( numThorns < 4 ) numThorns = 4; if ( numThorns % 4 ) numThorns += 4 - numThorns % 4; d_data->numThorns = numThorns; } /*! \return Number of thorns \sa setNumThorns(), setNumThornLevels() */ int QwtSimpleCompassRose::numThorns() const { return d_data->numThorns; } /*! Set the of thorns levels \param numThornLevels Number of thorns levels \sa setNumThorns(), numThornLevels() */ void QwtSimpleCompassRose::setNumThornLevels( int numThornLevels ) { d_data->numThornLevels = numThornLevels; } /*! \return Number of thorn levels \sa setNumThorns(), setNumThornLevels() */ int QwtSimpleCompassRose::numThornLevels() const { return d_data->numThornLevels; } pcp-gui-1.5.11/src/libqwt/qwt_counter.cpp0000644000000000000000000003301012176111212015167 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_arrow_button.h" #include "qwt_math.h" #include "qwt_counter.h" #include #include #include #include #include class QwtCounter::PrivateData { public: PrivateData(): editable( true ) { increment[Button1] = 1; increment[Button2] = 10; increment[Button3] = 100; } QwtArrowButton *buttonDown[ButtonCnt]; QwtArrowButton *buttonUp[ButtonCnt]; QLineEdit *valueEdit; int increment[ButtonCnt]; int numButtons; bool editable; }; /*! The default number of buttons is set to 2. The default increments are: \li Button 1: 1 step \li Button 2: 10 steps \li Button 3: 100 steps \param parent */ QwtCounter::QwtCounter( QWidget *parent ): QWidget( parent ) { initCounter(); } void QwtCounter::initCounter() { d_data = new PrivateData; QHBoxLayout *layout = new QHBoxLayout( this ); layout->setSpacing( 0 ); layout->setMargin( 0 ); for ( int i = ButtonCnt - 1; i >= 0; i-- ) { QwtArrowButton *btn = new QwtArrowButton( i + 1, Qt::DownArrow, this ); btn->setFocusPolicy( Qt::NoFocus ); btn->installEventFilter( this ); layout->addWidget( btn ); connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) ); connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) ); d_data->buttonDown[i] = btn; } d_data->valueEdit = new QLineEdit( this ); d_data->valueEdit->setReadOnly( false ); d_data->valueEdit->setValidator( new QDoubleValidator( d_data->valueEdit ) ); layout->addWidget( d_data->valueEdit ); connect( d_data->valueEdit, SIGNAL( editingFinished() ), SLOT( textChanged() ) ); layout->setStretchFactor( d_data->valueEdit, 10 ); for ( int i = 0; i < ButtonCnt; i++ ) { QwtArrowButton *btn = new QwtArrowButton( i + 1, Qt::UpArrow, this ); btn->setFocusPolicy( Qt::NoFocus ); btn->installEventFilter( this ); layout->addWidget( btn ); connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) ); connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) ); d_data->buttonUp[i] = btn; } setNumButtons( 2 ); setRange( 0.0, 1.0, 0.001 ); setValue( 0.0 ); setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); setFocusProxy( d_data->valueEdit ); setFocusPolicy( Qt::StrongFocus ); } //! Destructor QwtCounter::~QwtCounter() { delete d_data; } //! Set from lineedit void QwtCounter::textChanged() { if ( !d_data->editable ) return; bool converted = false; const double value = d_data->valueEdit->text().toDouble( &converted ); if ( converted ) setValue( value ); } /** \brief Allow/disallow the user to manually edit the value \param editable true enables editing \sa editable() */ void QwtCounter::setEditable( bool editable ) { if ( editable == d_data->editable ) return; d_data->editable = editable; d_data->valueEdit->setReadOnly( !editable ); } //! returns whether the line edit is edatble. (default is yes) bool QwtCounter::editable() const { return d_data->editable; } /*! Handle PolishRequest events \param event Event */ bool QwtCounter::event( QEvent *event ) { if ( event->type() == QEvent::PolishRequest ) { const int w = d_data->valueEdit->fontMetrics().width( "W" ) + 8; for ( int i = 0; i < ButtonCnt; i++ ) { d_data->buttonDown[i]->setMinimumWidth( w ); d_data->buttonUp[i]->setMinimumWidth( w ); } } return QWidget::event( event ); } /*! Handle key events - Ctrl + Qt::Key_Home\n Step to minValue() - Ctrl + Qt::Key_End\n Step to maxValue() - Qt::Key_Up\n Increment by incSteps(QwtCounter::Button1) - Qt::Key_Down\n Decrement by incSteps(QwtCounter::Button1) - Qt::Key_PageUp\n Increment by incSteps(QwtCounter::Button2) - Qt::Key_PageDown\n Decrement by incSteps(QwtCounter::Button2) - Shift + Qt::Key_PageUp\n Increment by incSteps(QwtCounter::Button3) - Shift + Qt::Key_PageDown\n Decrement by incSteps(QwtCounter::Button3) \param event Key event */ void QwtCounter::keyPressEvent ( QKeyEvent *event ) { bool accepted = true; switch ( event->key() ) { case Qt::Key_Home: { if ( event->modifiers() & Qt::ControlModifier ) setValue( minValue() ); else accepted = false; break; } case Qt::Key_End: { if ( event->modifiers() & Qt::ControlModifier ) setValue( maxValue() ); else accepted = false; break; } case Qt::Key_Up: { incValue( d_data->increment[0] ); break; } case Qt::Key_Down: { incValue( -d_data->increment[0] ); break; } case Qt::Key_PageUp: case Qt::Key_PageDown: { int increment = d_data->increment[0]; if ( d_data->numButtons >= 2 ) increment = d_data->increment[1]; if ( d_data->numButtons >= 3 ) { if ( event->modifiers() & Qt::ShiftModifier ) increment = d_data->increment[2]; } if ( event->key() == Qt::Key_PageDown ) increment = -increment; incValue( increment ); break; } default: { accepted = false; } } if ( accepted ) { event->accept(); return; } QWidget::keyPressEvent ( event ); } /*! Handle wheel events \param event Wheel event */ void QwtCounter::wheelEvent( QWheelEvent *event ) { event->accept(); if ( d_data->numButtons <= 0 ) return; int increment = d_data->increment[0]; if ( d_data->numButtons >= 2 ) { if ( event->modifiers() & Qt::ControlModifier ) increment = d_data->increment[1]; } if ( d_data->numButtons >= 3 ) { if ( event->modifiers() & Qt::ShiftModifier ) increment = d_data->increment[2]; } for ( int i = 0; i < d_data->numButtons; i++ ) { if ( d_data->buttonDown[i]->geometry().contains( event->pos() ) || d_data->buttonUp[i]->geometry().contains( event->pos() ) ) { increment = d_data->increment[i]; } } const int wheel_delta = 120; int delta = event->delta(); if ( delta >= 2 * wheel_delta ) delta /= 2; // Never saw an abs(delta) < 240 incValue( delta / wheel_delta * increment ); } /*! Specify the number of steps by which the value is incremented or decremented when a specified button is pushed. \param button Button index \param nSteps Number of steps \sa incSteps() */ void QwtCounter::setIncSteps( QwtCounter::Button button, int nSteps ) { if ( button >= 0 && button < ButtonCnt ) d_data->increment[button] = nSteps; } /*! \return the number of steps by which a specified button increments the value or 0 if the button is invalid. \param button Button index \sa setIncSteps() */ int QwtCounter::incSteps( QwtCounter::Button button ) const { if ( button >= 0 && button < ButtonCnt ) return d_data->increment[button]; return 0; } /*! \brief Set a new value Calls QwtDoubleRange::setValue and does all visual updates. \param value New value \sa QwtDoubleRange::setValue() */ void QwtCounter::setValue( double value ) { QwtDoubleRange::setValue( value ); showNum( this->value() ); updateButtons(); } /*! \brief Notify a change of value */ void QwtCounter::valueChange() { if ( isValid() ) showNum( value() ); else d_data->valueEdit->setText( QString::null ); updateButtons(); if ( isValid() ) Q_EMIT valueChanged( value() ); } /*! \brief Update buttons according to the current value When the QwtCounter under- or over-flows, the focus is set to the smallest up- or down-button and counting is disabled. Counting is re-enabled on a button release event (mouse or space bar). */ void QwtCounter::updateButtons() { if ( isValid() ) { // 1. save enabled state of the smallest down- and up-button // 2. change enabled state on under- or over-flow for ( int i = 0; i < QwtCounter::ButtonCnt; i++ ) { d_data->buttonDown[i]->setEnabled( value() > minValue() ); d_data->buttonUp[i]->setEnabled( value() < maxValue() ); } } else { for ( int i = 0; i < QwtCounter::ButtonCnt; i++ ) { d_data->buttonDown[i]->setEnabled( false ); d_data->buttonUp[i]->setEnabled( false ); } } } /*! \brief Specify the number of buttons on each side of the label \param numButtons Number of buttons */ void QwtCounter::setNumButtons( int numButtons ) { if ( numButtons < 0 || numButtons > QwtCounter::ButtonCnt ) return; for ( int i = 0; i < QwtCounter::ButtonCnt; i++ ) { if ( i < numButtons ) { d_data->buttonDown[i]->show(); d_data->buttonUp[i]->show(); } else { d_data->buttonDown[i]->hide(); d_data->buttonUp[i]->hide(); } } d_data->numButtons = numButtons; } /*! \return The number of buttons on each side of the widget. */ int QwtCounter::numButtons() const { return d_data->numButtons; } /*! Display number string \param number Number */ void QwtCounter::showNum( double number ) { QString text; text.setNum( number ); const int cursorPos = d_data->valueEdit->cursorPosition(); d_data->valueEdit->setText( text ); d_data->valueEdit->setCursorPosition( cursorPos ); } //! Button clicked void QwtCounter::btnClicked() { for ( int i = 0; i < ButtonCnt; i++ ) { if ( d_data->buttonUp[i] == sender() ) incValue( d_data->increment[i] ); if ( d_data->buttonDown[i] == sender() ) incValue( -d_data->increment[i] ); } } //! Button released void QwtCounter::btnReleased() { Q_EMIT buttonReleased( value() ); } /*! \brief Notify change of range This function updates the enabled property of all buttons contained in QwtCounter. */ void QwtCounter::rangeChange() { updateButtons(); } //! A size hint QSize QwtCounter::sizeHint() const { QString tmp; int w = tmp.setNum( minValue() ).length(); int w1 = tmp.setNum( maxValue() ).length(); if ( w1 > w ) w = w1; w1 = tmp.setNum( minValue() + step() ).length(); if ( w1 > w ) w = w1; w1 = tmp.setNum( maxValue() - step() ).length(); if ( w1 > w ) w = w1; tmp.fill( '9', w ); QFontMetrics fm( d_data->valueEdit->font() ); w = fm.width( tmp ) + 2; if ( d_data->valueEdit->hasFrame() ) w += 2 * style()->pixelMetric( QStyle::PM_DefaultFrameWidth ); // Now we replace default sizeHint contribution of d_data->valueEdit by // what we really need. w += QWidget::sizeHint().width() - d_data->valueEdit->sizeHint().width(); const int h = qMin( QWidget::sizeHint().height(), d_data->valueEdit->minimumSizeHint().height() ); return QSize( w, h ); } //! returns the step size double QwtCounter::step() const { return QwtDoubleRange::step(); } /*! Set the step size \param stepSize Step size \sa QwtDoubleRange::setStep() */ void QwtCounter::setStep( double stepSize ) { QwtDoubleRange::setStep( stepSize ); } //! returns the minimum value of the range double QwtCounter::minValue() const { return QwtDoubleRange::minValue(); } /*! Set the minimum value of the range \param value Minimum value \sa setMaxValue(), minValue() */ void QwtCounter::setMinValue( double value ) { setRange( value, maxValue(), step() ); } //! returns the maximum value of the range double QwtCounter::maxValue() const { return QwtDoubleRange::maxValue(); } /*! Set the maximum value of the range \param value Maximum value \sa setMinValue(), maxVal() */ void QwtCounter::setMaxValue( double value ) { setRange( minValue(), value, step() ); } /*! Set the number of increment steps for button 1 \param nSteps Number of steps */ void QwtCounter::setStepButton1( int nSteps ) { setIncSteps( Button1, nSteps ); } //! returns the number of increment steps for button 1 int QwtCounter::stepButton1() const { return incSteps( Button1 ); } /*! Set the number of increment steps for button 2 \param nSteps Number of steps */ void QwtCounter::setStepButton2( int nSteps ) { setIncSteps( Button2, nSteps ); } //! returns the number of increment steps for button 2 int QwtCounter::stepButton2() const { return incSteps( Button2 ); } /*! Set the number of increment steps for button 3 \param nSteps Number of steps */ void QwtCounter::setStepButton3( int nSteps ) { setIncSteps( Button3, nSteps ); } //! returns the number of increment steps for button 3 int QwtCounter::stepButton3() const { return incSteps( Button3 ); } //! \return Current value double QwtCounter::value() const { return QwtDoubleRange::value(); } pcp-gui-1.5.11/src/libqwt/qwt_curve_fitter.cpp0000644000000000000000000002203512176111212016216 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_curve_fitter.h" #include "qwt_math.h" #include "qwt_spline.h" #include #include #if QT_VERSION < 0x040601 #define qFabs(x) ::fabs(x) #endif //! Constructor QwtCurveFitter::QwtCurveFitter() { } //! Destructor QwtCurveFitter::~QwtCurveFitter() { } class QwtSplineCurveFitter::PrivateData { public: PrivateData(): fitMode( QwtSplineCurveFitter::Auto ), splineSize( 250 ) { } QwtSpline spline; QwtSplineCurveFitter::FitMode fitMode; int splineSize; }; //! Constructor QwtSplineCurveFitter::QwtSplineCurveFitter() { d_data = new PrivateData; } //! Destructor QwtSplineCurveFitter::~QwtSplineCurveFitter() { delete d_data; } /*! Select the algorithm used for building the spline \param mode Mode representing a spline algorithm \sa fitMode() */ void QwtSplineCurveFitter::setFitMode( FitMode mode ) { d_data->fitMode = mode; } /*! \return Mode representing a spline algorithm \sa setFitMode() */ QwtSplineCurveFitter::FitMode QwtSplineCurveFitter::fitMode() const { return d_data->fitMode; } /*! Assign a spline \param spline Spline \sa spline() */ void QwtSplineCurveFitter::setSpline( const QwtSpline &spline ) { d_data->spline = spline; d_data->spline.reset(); } /*! \return Spline \sa setSpline() */ const QwtSpline &QwtSplineCurveFitter::spline() const { return d_data->spline; } /*! \return Spline \sa setSpline() */ QwtSpline &QwtSplineCurveFitter::spline() { return d_data->spline; } /*! Assign a spline size ( has to be at least 10 points ) \param splineSize Spline size \sa splineSize() */ void QwtSplineCurveFitter::setSplineSize( int splineSize ) { d_data->splineSize = qMax( splineSize, 10 ); } /*! \return Spline size \sa setSplineSize() */ int QwtSplineCurveFitter::splineSize() const { return d_data->splineSize; } /*! Find a curve which has the best fit to a series of data points \param points Series of data points \return Curve points */ QPolygonF QwtSplineCurveFitter::fitCurve( const QPolygonF &points ) const { const int size = points.size(); if ( size <= 2 ) return points; FitMode fitMode = d_data->fitMode; if ( fitMode == Auto ) { fitMode = Spline; const QPointF *p = points.data(); for ( int i = 1; i < size; i++ ) { if ( p[i].x() <= p[i-1].x() ) { fitMode = ParametricSpline; break; } }; } if ( fitMode == ParametricSpline ) return fitParametric( points ); else return fitSpline( points ); } QPolygonF QwtSplineCurveFitter::fitSpline( const QPolygonF &points ) const { d_data->spline.setPoints( points ); if ( !d_data->spline.isValid() ) return points; QPolygonF fittedPoints( d_data->splineSize ); const double x1 = points[0].x(); const double x2 = points[int( points.size() - 1 )].x(); const double dx = x2 - x1; const double delta = dx / ( d_data->splineSize - 1 ); for ( int i = 0; i < d_data->splineSize; i++ ) { QPointF &p = fittedPoints[i]; const double v = x1 + i * delta; const double sv = d_data->spline.value( v ); p.setX( v ); p.setY( sv ); } d_data->spline.reset(); return fittedPoints; } QPolygonF QwtSplineCurveFitter::fitParametric( const QPolygonF &points ) const { int i; const int size = points.size(); QPolygonF fittedPoints( d_data->splineSize ); QPolygonF splinePointsX( size ); QPolygonF splinePointsY( size ); const QPointF *p = points.data(); QPointF *spX = splinePointsX.data(); QPointF *spY = splinePointsY.data(); double param = 0.0; for ( i = 0; i < size; i++ ) { const double x = p[i].x(); const double y = p[i].y(); if ( i > 0 ) { const double delta = qSqrt( qwtSqr( x - spX[i-1].y() ) + qwtSqr( y - spY[i-1].y() ) ); param += qMax( delta, 1.0 ); } spX[i].setX( param ); spX[i].setY( x ); spY[i].setX( param ); spY[i].setY( y ); } d_data->spline.setPoints( splinePointsX ); if ( !d_data->spline.isValid() ) return points; const double deltaX = splinePointsX[size - 1].x() / ( d_data->splineSize - 1 ); for ( i = 0; i < d_data->splineSize; i++ ) { const double dtmp = i * deltaX; fittedPoints[i].setX( d_data->spline.value( dtmp ) ); } d_data->spline.setPoints( splinePointsY ); if ( !d_data->spline.isValid() ) return points; const double deltaY = splinePointsY[size - 1].x() / ( d_data->splineSize - 1 ); for ( i = 0; i < d_data->splineSize; i++ ) { const double dtmp = i * deltaY; fittedPoints[i].setY( d_data->spline.value( dtmp ) ); } return fittedPoints; } class QwtWeedingCurveFitter::PrivateData { public: PrivateData(): tolerance( 1.0 ) { } double tolerance; }; class QwtWeedingCurveFitter::Line { public: Line( int i1 = 0, int i2 = 0 ): from( i1 ), to( i2 ) { } int from; int to; }; /*! Constructor \param tolerance Tolerance \sa setTolerance(), tolerance() */ QwtWeedingCurveFitter::QwtWeedingCurveFitter( double tolerance ) { d_data = new PrivateData; setTolerance( tolerance ); } //! Destructor QwtWeedingCurveFitter::~QwtWeedingCurveFitter() { delete d_data; } /*! Assign the tolerance The tolerance is the maximum distance, that is accaptable between the original curve and the smoothed curve. Increasing the tolerance will reduce the number of the resulting points. \param tolerance Tolerance \sa tolerance() */ void QwtWeedingCurveFitter::setTolerance( double tolerance ) { d_data->tolerance = qMax( tolerance, 0.0 ); } /*! \return Tolerance \sa setTolerance() */ double QwtWeedingCurveFitter::tolerance() const { return d_data->tolerance; } /*! \param points Series of data points \return Curve points */ QPolygonF QwtWeedingCurveFitter::fitCurve( const QPolygonF &points ) const { QStack stack; stack.reserve( 500 ); const QPointF *p = points.data(); const int nPoints = points.size(); QVector usePoint( nPoints, false ); double distToSegment; stack.push( Line( 0, nPoints - 1 ) ); while ( !stack.isEmpty() ) { const Line r = stack.pop(); // initialize line segment const double vecX = p[r.to].x() - p[r.from].x(); const double vecY = p[r.to].y() - p[r.from].y(); const double vecLength = qSqrt( vecX * vecX + vecY * vecY ); const double unitVecX = ( vecLength != 0.0 ) ? vecX / vecLength : 0.0; const double unitVecY = ( vecLength != 0.0 ) ? vecY / vecLength : 0.0; double maxDist = 0.0; int nVertexIndexMaxDistance = r.from + 1; for ( int i = r.from + 1; i < r.to; i++ ) { //compare to anchor const double fromVecX = p[i].x() - p[r.from].x(); const double fromVecY = p[i].y() - p[r.from].y(); const double fromVecLength = qSqrt( fromVecX * fromVecX + fromVecY * fromVecY ); if ( fromVecX * unitVecX + fromVecY * unitVecY < 0.0 ) { distToSegment = fromVecLength; } if ( fromVecX * unitVecX + fromVecY * unitVecY < 0.0 ) { distToSegment = fromVecLength; } else { const double toVecX = p[i].x() - p[r.to].x(); const double toVecY = p[i].y() - p[r.to].y(); const double toVecLength = qSqrt( toVecX * toVecX + toVecY * toVecY ); const double s = toVecX * ( -unitVecX ) + toVecY * ( -unitVecY ); if ( s < 0.0 ) distToSegment = toVecLength; else { distToSegment = qSqrt( qFabs( toVecLength * toVecLength - s * s ) ); } } if ( maxDist < distToSegment ) { maxDist = distToSegment; nVertexIndexMaxDistance = i; } } if ( maxDist <= d_data->tolerance ) { usePoint[r.from] = true; usePoint[r.to] = true; } else { stack.push( Line( r.from, nVertexIndexMaxDistance ) ); stack.push( Line( nVertexIndexMaxDistance, r.to ) ); } } int cnt = 0; QPolygonF stripped( nPoints ); for ( int i = 0; i < nPoints; i++ ) { if ( usePoint[i] ) stripped[cnt++] = p[i]; } stripped.resize( cnt ); return stripped; } pcp-gui-1.5.11/src/libqwt/qwt_dial.cpp0000644000000000000000000006567212176111212014444 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_dial.h" #include "qwt_dial_needle.h" #include "qwt_math.h" #include "qwt_scale_engine.h" #include "qwt_scale_map.h" #include "qwt_painter.h" #include #include #include #include #include #include #include #include #include #include #if QT_VERSION < 0x040601 #define qAtan(x) ::atan(x) #endif class QwtDial::PrivateData { public: PrivateData(): frameShadow( Sunken ), lineWidth( 0 ), mode( RotateNeedle ), direction( Clockwise ), origin( 90.0 ), minScaleArc( 0.0 ), maxScaleArc( 0.0 ), scaleDraw( 0 ), maxMajIntv( 36 ), maxMinIntv( 10 ), scaleStep( 0.0 ), needle( 0 ) { } ~PrivateData() { delete scaleDraw; delete needle; } Shadow frameShadow; int lineWidth; QwtDial::Mode mode; QwtDial::Direction direction; double origin; double minScaleArc; double maxScaleArc; QwtDialScaleDraw *scaleDraw; int maxMajIntv; int maxMinIntv; double scaleStep; QwtDialNeedle *needle; static double previousDir; }; double QwtDial::PrivateData::previousDir = -1.0; /*! Constructor \param parent Parent dial widget */ QwtDialScaleDraw::QwtDialScaleDraw( QwtDial *parent ): d_parent( parent ), d_penWidth( 1.0 ) { } /*! Set the pen width used for painting the scale \param penWidth Pen width \sa penWidth(), QwtDial::drawScale() */ void QwtDialScaleDraw::setPenWidth( double penWidth ) { d_penWidth = qMax( penWidth, 0.0 ); } /*! \return Pen width used for painting the scale \sa setPenWidth, QwtDial::drawScale() */ double QwtDialScaleDraw::penWidth() const { return d_penWidth; } /*! Call QwtDial::scaleLabel of the parent dial widget. \param value Value to display \sa QwtDial::scaleLabel() */ QwtText QwtDialScaleDraw::label( double value ) const { if ( d_parent == NULL ) return QwtRoundScaleDraw::label( value ); return d_parent->scaleLabel( value ); } /*! \brief Constructor \param parent Parent widget Create a dial widget with no scale and no needle. The default origin is 90.0 with no valid value. It accepts mouse and keyboard inputs and has no step size. The default mode is QwtDial::RotateNeedle. */ QwtDial::QwtDial( QWidget* parent ): QwtAbstractSlider( Qt::Horizontal, parent ) { initDial(); } void QwtDial::initDial() { d_data = new PrivateData; setFocusPolicy( Qt::TabFocus ); QPalette p = palette(); for ( int i = 0; i < QPalette::NColorGroups; i++ ) { const QPalette::ColorGroup colorGroup = ( QPalette::ColorGroup )i; // Base: background color of the circle inside the frame. // WindowText: background color of the circle inside the scale p.setColor( colorGroup, QPalette::WindowText, p.color( colorGroup, QPalette::Base ) ); } setPalette( p ); d_data->scaleDraw = new QwtDialScaleDraw( this ); d_data->scaleDraw->setRadius( 0 ); setScaleArc( 0.0, 360.0 ); // scale as a full circle setRange( 0.0, 360.0, 1.0, 10 ); // degrees as default } //! Destructor QwtDial::~QwtDial() { delete d_data; } /*! Sets the frame shadow value from the frame style. \param shadow Frame shadow \sa setLineWidth(), QFrame::setFrameShadow() */ void QwtDial::setFrameShadow( Shadow shadow ) { if ( shadow != d_data->frameShadow ) { d_data->frameShadow = shadow; if ( lineWidth() > 0 ) update(); } } /*! \return Frame shadow /sa setFrameShadow(), lineWidth(), QFrame::frameShadow */ QwtDial::Shadow QwtDial::frameShadow() const { return d_data->frameShadow; } /*! Sets the line width \param lineWidth Line width \sa setFrameShadow() */ void QwtDial::setLineWidth( int lineWidth ) { if ( lineWidth < 0 ) lineWidth = 0; if ( d_data->lineWidth != lineWidth ) { d_data->lineWidth = lineWidth; update(); } } /*! \return Line width of the frame \sa setLineWidth(), frameShadow(), lineWidth() */ int QwtDial::lineWidth() const { return d_data->lineWidth; } /*! \return bounding rect of the circle inside the frame \sa setLineWidth(), scaleInnerRect(), boundingRect() */ QRectF QwtDial::innerRect() const { const double lw = lineWidth(); return boundingRect().adjusted( lw, lw, -lw, -lw ); } /*! \return bounding rect of the dial including the frame \sa setLineWidth(), scaleInnerRect(), innerRect() */ QRectF QwtDial::boundingRect() const { const QRectF cr = contentsRect(); const double dim = qMin( cr.width(), cr.height() ); QRectF inner( 0, 0, dim, dim ); inner.moveCenter( cr.center() ); return inner; } /*! \return rect inside the scale \sa setLineWidth(), boundingRect(), innerRect() */ QRectF QwtDial::scaleInnerRect() const { QRectF rect = innerRect(); if ( d_data->scaleDraw ) { double scaleDist = qCeil( d_data->scaleDraw->extent( font() ) ); scaleDist++; // margin rect.adjust( scaleDist, scaleDist, -scaleDist, -scaleDist ); } return rect; } /*! \brief Change the mode of the meter. \param mode New mode The value of the meter is indicated by the difference between north of the scale and the direction of the needle. In case of QwtDial::RotateNeedle north is pointing to the origin() and the needle is rotating, in case of QwtDial::RotateScale, the needle points to origin() and the scale is rotating. The default mode is QwtDial::RotateNeedle. \sa mode(), setValue(), setOrigin() */ void QwtDial::setMode( Mode mode ) { if ( mode != d_data->mode ) { d_data->mode = mode; update(); } } /*! \return mode of the dial. The value of the dial is indicated by the difference between the origin and the direction of the needle. In case of QwtDial::RotateNeedle the scale arc is fixed to the origin() and the needle is rotating, in case of QwtDial::RotateScale, the needle points to origin() and the scale is rotating. The default mode is QwtDial::RotateNeedle. \sa setMode(), origin(), setScaleArc(), value() */ QwtDial::Mode QwtDial::mode() const { return d_data->mode; } /*! Sets whether it is possible to step the value from the highest value to the lowest value and vice versa to on. \param wrapping en/disables wrapping \sa wrapping(), QwtDoubleRange::periodic() \note The meaning of wrapping is like the wrapping property of QSpinBox, but not like it is used in QDial. */ void QwtDial::setWrapping( bool wrapping ) { setPeriodic( wrapping ); } /*! wrapping() holds whether it is possible to step the value from the highest value to the lowest value and vice versa. \sa setWrapping(), QwtDoubleRange::setPeriodic() \note The meaning of wrapping is like the wrapping property of QSpinBox, but not like it is used in QDial. */ bool QwtDial::wrapping() const { return periodic(); } /*! Set the direction of the dial (clockwise/counterclockwise) \param direction Direction \sa direction() */ void QwtDial::setDirection( Direction direction ) { if ( direction != d_data->direction ) { d_data->direction = direction; update(); } } /*! \return Direction of the dial The default direction of a dial is QwtDial::Clockwise \sa setDirection() */ QwtDial::Direction QwtDial::direction() const { return d_data->direction; } /*! Paint the dial \param event Paint event */ void QwtDial::paintEvent( QPaintEvent *event ) { QPainter painter( this ); painter.setClipRegion( event->region() ); QStyleOption opt; opt.init(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); painter.setRenderHint( QPainter::Antialiasing, true ); painter.save(); drawContents( &painter ); painter.restore(); painter.save(); drawFrame( &painter ); painter.restore(); if ( hasFocus() ) drawFocusIndicator( &painter ); } /*! Draw a dotted round circle, if !isReadOnly() \param painter Painter */ void QwtDial::drawFocusIndicator( QPainter *painter ) const { if ( !isReadOnly() ) { QRectF focusRect = innerRect(); const int margin = 2; focusRect.adjust( margin, margin, -margin, -margin ); QColor color = palette().color( QPalette::Base ); if ( color.isValid() ) { const QColor gray( Qt::gray ); int h, s, v; color.getHsv( &h, &s, &v ); color = ( v > 128 ) ? gray.dark( 120 ) : gray.light( 120 ); } else color = Qt::darkGray; painter->save(); painter->setBrush( Qt::NoBrush ); painter->setPen( QPen( color, 0, Qt::DotLine ) ); painter->drawEllipse( focusRect ); painter->restore(); } } /*! Draw the frame around the dial \param painter Painter \sa lineWidth(), frameShadow() */ void QwtDial::drawFrame( QPainter *painter ) { if ( lineWidth() <= 0 ) return; const double lw2 = 0.5 * lineWidth(); QRectF r = boundingRect(); r.adjust( lw2, lw2, -lw2, -lw2 ); QPen pen; switch ( d_data->frameShadow ) { case QwtDial::Raised: case QwtDial::Sunken: { QColor c1 = palette().color( QPalette::Light ); QColor c2 = palette().color( QPalette::Dark ); if ( d_data->frameShadow == QwtDial::Sunken ) qSwap( c1, c2 ); QLinearGradient gradient( r.topLeft(), r.bottomRight() ); gradient.setColorAt( 0.0, c1 ); #if 0 gradient.setColorAt( 0.3, c1 ); gradient.setColorAt( 0.7, c2 ); #endif gradient.setColorAt( 1.0, c2 ); pen = QPen( gradient, lineWidth() ); break; } default: // Plain { pen = QPen( palette().brush( QPalette::Dark ), lineWidth() ); } } painter->save(); painter->setPen( pen ); painter->setBrush( Qt::NoBrush ); painter->drawEllipse( r ); painter->restore(); } /*! \brief Draw the contents inside the frame QPalette::Window is the background color outside of the frame. QPalette::Base is the background color inside the frame. QPalette::WindowText is the background color inside the scale. \param painter Painter \sa boundingRect(), innerRect(), scaleInnerRect(), QWidget::setPalette() */ void QwtDial::drawContents( QPainter *painter ) const { if ( testAttribute( Qt::WA_NoSystemBackground ) || palette().brush( QPalette::Base ) != palette().brush( QPalette::Window ) ) { const QRectF br = boundingRect(); painter->save(); painter->setPen( Qt::NoPen ); painter->setBrush( palette().brush( QPalette::Base ) ); painter->drawEllipse( br ); painter->restore(); } const QRectF insideScaleRect = scaleInnerRect(); if ( palette().brush( QPalette::WindowText ) != palette().brush( QPalette::Base ) ) { painter->save(); painter->setPen( Qt::NoPen ); painter->setBrush( palette().brush( QPalette::WindowText ) ); painter->drawEllipse( insideScaleRect ); painter->restore(); } const QPointF center = insideScaleRect.center(); const double radius = 0.5 * insideScaleRect.width(); double direction = d_data->origin; if ( isValid() ) { direction = d_data->minScaleArc; if ( maxValue() > minValue() && d_data->maxScaleArc > d_data->minScaleArc ) { const double ratio = ( value() - minValue() ) / ( maxValue() - minValue() ); direction += ratio * ( d_data->maxScaleArc - d_data->minScaleArc ); } if ( d_data->direction == QwtDial::CounterClockwise ) direction = d_data->maxScaleArc - ( direction - d_data->minScaleArc ); direction += d_data->origin; if ( direction >= 360.0 ) direction -= 360.0; else if ( direction < 0.0 ) direction += 360.0; } double origin = d_data->origin; if ( mode() == RotateScale ) { origin -= direction - d_data->origin; direction = d_data->origin; } painter->save(); drawScale( painter, center, radius, origin, d_data->minScaleArc, d_data->maxScaleArc ); painter->restore(); painter->save(); drawScaleContents( painter, center, radius ); painter->restore(); if ( isValid() ) { QPalette::ColorGroup cg; if ( isEnabled() ) cg = hasFocus() ? QPalette::Active : QPalette::Inactive; else cg = QPalette::Disabled; painter->save(); drawNeedle( painter, center, radius, direction, cg ); painter->restore(); } } /*! Draw the needle \param painter Painter \param center Center of the dial \param radius Length for the needle \param direction Direction of the needle in degrees, counter clockwise \param cg ColorGroup */ void QwtDial::drawNeedle( QPainter *painter, const QPointF ¢er, double radius, double direction, QPalette::ColorGroup cg ) const { if ( d_data->needle ) { direction = 360.0 - direction; // counter clockwise d_data->needle->draw( painter, center, radius, direction, cg ); } } /*! Draw the scale \param painter Painter \param center Center of the dial \param radius Radius of the scale \param origin Origin of the scale \param minArc Minimum of the arc \param maxArc Minimum of the arc \sa QwtRoundScaleDraw::setAngleRange() */ void QwtDial::drawScale( QPainter *painter, const QPointF ¢er, double radius, double origin, double minArc, double maxArc ) const { if ( d_data->scaleDraw == NULL ) return; origin -= 270.0; // hardcoded origin of QwtScaleDraw double angle = maxArc - minArc; if ( angle > 360.0 ) angle = ::fmod( angle, 360.0 ); minArc += origin; if ( minArc < -360.0 ) minArc = ::fmod( minArc, 360.0 ); maxArc = minArc + angle; if ( maxArc > 360.0 ) { // QwtRoundScaleDraw::setAngleRange accepts only values // in the range [-360.0..360.0] minArc -= 360.0; maxArc -= 360.0; } if ( d_data->direction == QwtDial::CounterClockwise ) qSwap( minArc, maxArc ); painter->setFont( font() ); d_data->scaleDraw->setAngleRange( minArc, maxArc ); d_data->scaleDraw->setRadius( qFloor( radius ) ); d_data->scaleDraw->moveCenter( center ); QPalette pal = palette(); const QColor textColor = pal.color( QPalette::Text ); pal.setColor( QPalette::WindowText, textColor ); //ticks, backbone painter->setPen( QPen( textColor, d_data->scaleDraw->penWidth() ) ); painter->setBrush( Qt::red ); d_data->scaleDraw->draw( painter, pal ); } /*! Draw the contents inside the scale Paints nothing. \param painter Painter \param center Center of the contents circle \param radius Radius of the contents circle */ void QwtDial::drawScaleContents( QPainter *painter, const QPointF ¢er, double radius ) const { Q_UNUSED(painter); Q_UNUSED(center); Q_UNUSED(radius); } /*! Set a needle for the dial Qwt is missing a set of good looking needles. Contributions are very welcome. \param needle Needle \warning The needle will be deleted, when a different needle is set or in ~QwtDial() */ void QwtDial::setNeedle( QwtDialNeedle *needle ) { if ( needle != d_data->needle ) { if ( d_data->needle ) delete d_data->needle; d_data->needle = needle; update(); } } /*! \return needle \sa setNeedle() */ const QwtDialNeedle *QwtDial::needle() const { return d_data->needle; } /*! \return needle \sa setNeedle() */ QwtDialNeedle *QwtDial::needle() { return d_data->needle; } //! QwtDoubleRange update hook void QwtDial::rangeChange() { updateScale(); } /*! Update the scale with the current attributes \sa setScale() */ void QwtDial::updateScale() { if ( d_data->scaleDraw ) { QwtLinearScaleEngine scaleEngine; const QwtScaleDiv scaleDiv = scaleEngine.divideScale( minValue(), maxValue(), d_data->maxMajIntv, d_data->maxMinIntv, d_data->scaleStep ); d_data->scaleDraw->setTransformation( scaleEngine.transformation() ); d_data->scaleDraw->setScaleDiv( scaleDiv ); } } //! Return the scale draw QwtDialScaleDraw *QwtDial::scaleDraw() { return d_data->scaleDraw; } //! Return the scale draw const QwtDialScaleDraw *QwtDial::scaleDraw() const { return d_data->scaleDraw; } /*! Set an individual scale draw \param scaleDraw Scale draw \warning The previous scale draw is deleted */ void QwtDial::setScaleDraw( QwtDialScaleDraw *scaleDraw ) { if ( scaleDraw != d_data->scaleDraw ) { if ( d_data->scaleDraw ) delete d_data->scaleDraw; d_data->scaleDraw = scaleDraw; updateScale(); update(); } } /*! Change the intervals of the scale \param maxMajIntv Maximum for the number of major steps \param maxMinIntv Maximum number of minor steps \param step Step size \sa QwtScaleEngine::divideScale() */ void QwtDial::setScale( int maxMajIntv, int maxMinIntv, double step ) { d_data->maxMajIntv = maxMajIntv; d_data->maxMinIntv = maxMinIntv; d_data->scaleStep = step; updateScale(); } /*! A wrapper method for accessing the scale draw. \param components Scale components \sa QwtAbstractScaleDraw::enableComponent() */ void QwtDial::setScaleComponents( QwtAbstractScaleDraw::ScaleComponents components ) { if ( components == 0 ) setScaleDraw( NULL ); QwtDialScaleDraw *sd = d_data->scaleDraw; if ( sd == NULL ) return; sd->enableComponent( QwtAbstractScaleDraw::Backbone, components & QwtAbstractScaleDraw::Backbone ); sd->enableComponent( QwtAbstractScaleDraw::Ticks, components & QwtAbstractScaleDraw::Ticks ); sd->enableComponent( QwtAbstractScaleDraw::Labels, components & QwtAbstractScaleDraw::Labels ); } /*! Assign length and width of the ticks \param minLen Length of the minor ticks \param medLen Length of the medium ticks \param majLen Length of the major ticks \param penWidth Width of the pen for all ticks \sa QwtAbstractScaleDraw::setTickLength(), QwtDialScaleDraw::setPenWidth() */ void QwtDial::setScaleTicks( int minLen, int medLen, int majLen, int penWidth ) { QwtDialScaleDraw *sd = d_data->scaleDraw; if ( sd ) { sd->setTickLength( QwtScaleDiv::MinorTick, minLen ); sd->setTickLength( QwtScaleDiv::MediumTick, medLen ); sd->setTickLength( QwtScaleDiv::MajorTick, majLen ); sd->setPenWidth( penWidth ); } } /*! Find the label for a value \param value Value \return label */ QwtText QwtDial::scaleLabel( double value ) const { if ( value == -0.0 ) value = 0.0; return QString::number( value ); } //! \return Lower limit of the scale arc double QwtDial::minScaleArc() const { return d_data->minScaleArc; } //! \return Upper limit of the scale arc double QwtDial::maxScaleArc() const { return d_data->maxScaleArc; } /*! \brief Change the origin The origin is the angle where scale and needle is relative to. \param origin New origin \sa origin() */ void QwtDial::setOrigin( double origin ) { d_data->origin = origin; update(); } /*! The origin is the angle where scale and needle is relative to. \return Origin of the dial \sa setOrigin() */ double QwtDial::origin() const { return d_data->origin; } /*! Change the arc of the scale \param minArc Lower limit \param maxArc Upper limit */ void QwtDial::setScaleArc( double minArc, double maxArc ) { if ( minArc != 360.0 && minArc != -360.0 ) minArc = ::fmod( minArc, 360.0 ); if ( maxArc != 360.0 && maxArc != -360.0 ) maxArc = ::fmod( maxArc, 360.0 ); d_data->minScaleArc = qMin( minArc, maxArc ); d_data->maxScaleArc = qMax( minArc, maxArc ); if ( d_data->maxScaleArc - d_data->minScaleArc > 360.0 ) d_data->maxScaleArc = d_data->minScaleArc + 360.0; update(); } //! QwtDoubleRange update hook void QwtDial::valueChange() { update(); QwtAbstractSlider::valueChange(); } /*! \return Size hint */ QSize QwtDial::sizeHint() const { int sh = 0; if ( d_data->scaleDraw ) sh = qCeil( d_data->scaleDraw->extent( font() ) ); const int d = 6 * sh + 2 * lineWidth(); QSize hint( d, d ); if ( !isReadOnly() ) hint = hint.expandedTo( QApplication::globalStrut() ); return hint; } /*! \brief Return a minimum size hint \warning The return value of QwtDial::minimumSizeHint() depends on the font and the scale. */ QSize QwtDial::minimumSizeHint() const { int sh = 0; if ( d_data->scaleDraw ) sh = qCeil( d_data->scaleDraw->extent( font() ) ); const int d = 3 * sh + 2 * lineWidth(); return QSize( d, d ); } static double line2Degrees( const QPointF &p1, const QPointF &p2 ) { const QPointF p = p2 - p1; double angle; if ( p.x() == 0.0 ) { angle = ( p.y() <= 0.0 ) ? M_PI_2 : 3 * M_PI_2; } else { angle = qAtan( double( -p.y() ) / double( p.x() ) ); if ( p.x() < 0.0 ) angle += M_PI; if ( angle < 0.0 ) angle += 2 * M_PI; } return 360.0 - angle * 180.0 / M_PI; } /*! Find the value for a given position \param pos Position \return Value */ double QwtDial::getValue( const QPoint &pos ) { if ( d_data->maxScaleArc == d_data->minScaleArc || maxValue() == minValue() ) return minValue(); double dir = line2Degrees( innerRect().center(), pos ) - d_data->origin; if ( dir < 0.0 ) dir += 360.0; if ( mode() == RotateScale ) dir = 360.0 - dir; // The position might be in the area that is outside the scale arc. // We need the range of the scale if it was a complete circle. const double completeCircle = 360.0 / ( d_data->maxScaleArc - d_data->minScaleArc ) * ( maxValue() - minValue() ); double posValue = minValue() + completeCircle * dir / 360.0; if ( scrollMode() == ScrMouse ) { if ( d_data->previousDir >= 0.0 ) // valid direction { // We have to find out whether the mouse is moving // clock or counter clockwise bool clockWise = false; const double angle = dir - d_data->previousDir; if ( ( angle >= 0.0 && angle <= 180.0 ) || angle < -180.0 ) clockWise = true; if ( clockWise ) { if ( dir < d_data->previousDir && mouseOffset() > 0.0 ) { // We passed 360 -> 0 setMouseOffset( mouseOffset() - completeCircle ); } if ( wrapping() ) { if ( posValue - mouseOffset() > maxValue() ) { // We passed maxValue and the value will be set // to minValue. We have to adjust the mouseOffset. setMouseOffset( posValue - minValue() ); } } else { if ( posValue - mouseOffset() > maxValue() || value() == maxValue() ) { // We fix the value at maxValue by adjusting // the mouse offset. setMouseOffset( posValue - maxValue() ); } } } else { if ( dir > d_data->previousDir && mouseOffset() < 0.0 ) { // We passed 0 -> 360 setMouseOffset( mouseOffset() + completeCircle ); } if ( wrapping() ) { if ( posValue - mouseOffset() < minValue() ) { // We passed minValue and the value will be set // to maxValue. We have to adjust the mouseOffset. setMouseOffset( posValue - maxValue() ); } } else { if ( posValue - mouseOffset() < minValue() || value() == minValue() ) { // We fix the value at minValue by adjusting // the mouse offset. setMouseOffset( posValue - minValue() ); } } } } d_data->previousDir = dir; } return posValue; } /*! See QwtAbstractSlider::getScrollMode() \param pos point where the mouse was pressed \retval scrollMode The scrolling mode \retval direction direction: 1, 0, or -1. \sa QwtAbstractSlider::getScrollMode() */ void QwtDial::getScrollMode( const QPoint &pos, QwtAbstractSlider::ScrollMode &scrollMode, int &direction ) const { direction = 0; scrollMode = QwtAbstractSlider::ScrNone; const QRegion region( innerRect().toRect(), QRegion::Ellipse ); if ( region.contains( pos ) && pos != innerRect().center() ) { scrollMode = QwtAbstractSlider::ScrMouse; d_data->previousDir = -1.0; } } /*! Handles key events - Key_Down, KeyLeft\n Decrement by 1 - Key_Prior\n Decrement by pageSize() - Key_Home\n Set the value to minValue() - Key_Up, KeyRight\n Increment by 1 - Key_Next\n Increment by pageSize() - Key_End\n Set the value to maxValue() \param event Key event \sa isReadOnly() */ void QwtDial::keyPressEvent( QKeyEvent *event ) { if ( isReadOnly() ) { event->ignore(); return; } if ( !isValid() ) return; const double previousValue = value(); switch ( event->key() ) { case Qt::Key_Down: case Qt::Key_Left: QwtDoubleRange::incValue( -1 ); break; case Qt::Key_PageUp: QwtDoubleRange::incValue( -pageSize() ); break; case Qt::Key_Home: setValue( minValue() ); break; case Qt::Key_Up: case Qt::Key_Right: QwtDoubleRange::incValue( 1 ); break; case Qt::Key_PageDown: QwtDoubleRange::incValue( pageSize() ); break; case Qt::Key_End: setValue( maxValue() ); break; default:; event->ignore(); } if ( value() != previousValue ) Q_EMIT sliderMoved( value() ); } pcp-gui-1.5.11/src/libqwt/qwt_dial_needle.cpp0000644000000000000000000002576412176111212015756 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_dial_needle.h" #include "qwt_global.h" #include "qwt_math.h" #include "qwt_painter.h" #include #include #if QT_VERSION < 0x040601 #define qFastSin(x) qSin(x) #define qFastCos(x) qCos(x) #endif static void qwtDrawStyle1Needle( QPainter *painter, const QPalette &palette, QPalette::ColorGroup colorGroup, double length ) { const double r[] = { 0.4, 0.3, 1, 0.8, 1, 0.3, 0.4 }; const double a[] = { -45, -20, -15, 0, 15, 20, 45 }; QPainterPath path; for ( int i = 0; i < 7; i++ ) { const double angle = a[i] / 180.0 * M_PI; const double radius = r[i] * length; const double x = radius * qFastCos( angle ); const double y = radius * qFastSin( angle ); path.lineTo( x, -y ); } painter->setPen( Qt::NoPen ); painter->setBrush( palette.brush( colorGroup, QPalette::Light ) ); painter->drawPath( path ); } static void qwtDrawStyle2Needle( QPainter *painter, const QPalette &palette, QPalette::ColorGroup colorGroup, double length ) { const double ratioX = 0.7; const double ratioY = 0.3; QPainterPath path1; path1.lineTo( ratioX * length, 0.0 ); path1.lineTo( length, ratioY * length ); QPainterPath path2; path2.lineTo( ratioX * length, 0.0 ); path2.lineTo( length, -ratioY * length ); painter->setPen( Qt::NoPen ); painter->setBrush( palette.brush( colorGroup, QPalette::Light ) ); painter->drawPath( path1 ); painter->setBrush( palette.brush( colorGroup, QPalette::Dark ) ); painter->drawPath( path2 ); } static void qwtDrawShadedPointer( QPainter *painter, const QColor &lightColor, const QColor &darkColor, double length, double width ) { const double peak = qMax( length / 10.0, 5.0 ); const double knobWidth = width + 8; QRectF knobRect( 0, 0, knobWidth, knobWidth ); knobRect.moveCenter( QPointF(0, 0) ); QPainterPath path1; path1.lineTo( 0.0, 0.5 * width ); path1.lineTo( length - peak, 0.5 * width ); path1.lineTo( length, 0.0 ); path1.lineTo( 0.0, 0.0 ); QPainterPath arcPath1; arcPath1.arcTo( knobRect, 0.0, -90.0 ); path1 = path1.united( arcPath1 ); QPainterPath path2; path2.lineTo( 0.0, -0.5 * width ); path2.lineTo( length - peak, -0.5 * width ); path2.lineTo( length, 0.0 ); path2.lineTo( 0.0, 0.0 ); QPainterPath arcPath2; arcPath2.arcTo( knobRect, 0.0, 90.0 ); path2 = path2.united( arcPath2 ); painter->setPen( Qt::NoPen ); painter->setBrush( lightColor ); painter->drawPath( path1 ); painter->setBrush( darkColor ); painter->drawPath( path2 ); } static void qwtDrawArrowNeedle( QPainter *painter, const QPalette &palette, QPalette::ColorGroup colorGroup, double length, double width ) { if ( width <= 0 ) width = qMax( length * 0.06, 9.0 ); const double peak = qMax( 2.0, 0.4 * width ); QPainterPath path; path.moveTo( 0.0, 0.5 * width ); path.lineTo( length - peak, 0.3 * width ); path.lineTo( length, 0.0 ); path.lineTo( length - peak, -0.3 * width ); path.lineTo( 0.0, -0.5 * width ); QRectF br = path.boundingRect(); QPalette pal( palette.color( QPalette::Mid ) ); QColor c1 = pal.color( QPalette::Light ); QColor c2 = pal.color( QPalette::Dark ); QLinearGradient gradient( br.topLeft(), br.bottomLeft() ); gradient.setColorAt( 0.0, c1 ); gradient.setColorAt( 0.5, c1 ); gradient.setColorAt( 0.5001, c2 ); gradient.setColorAt( 1.0, c2 ); QPen pen( gradient, 1 ); pen.setJoinStyle( Qt::MiterJoin ); painter->setPen( pen ); painter->setBrush( palette.brush( colorGroup, QPalette::Mid ) ); painter->drawPath( path ); } static void qwtDrawTriangleNeedle( QPainter *painter, const QPalette &palette, QPalette::ColorGroup colorGroup, double length ) { const double width = qRound( length / 3.0 ); QPainterPath path[4]; path[0].lineTo( length, 0.0 ); path[0].lineTo( 0.0, width / 2 ); path[1].lineTo( length, 0.0 ); path[1].lineTo( 0.0, -width / 2 ); path[2].lineTo( -length, 0.0 ); path[2].lineTo( 0.0, width / 2 ); path[3].lineTo( -length, 0.0 ); path[3].lineTo( 0.0, -width / 2 ); const int colorOffset = 10; const QColor darkColor = palette.color( colorGroup, QPalette::Dark ); const QColor lightColor = palette.color( colorGroup, QPalette::Light ); QColor color[4]; color[0] = darkColor.light( 100 + colorOffset ); color[1] = darkColor.dark( 100 + colorOffset ); color[2] = lightColor.light( 100 + colorOffset ); color[3] = lightColor.dark( 100 + colorOffset ); painter->setPen( Qt::NoPen ); for ( int i = 0; i < 4; i++ ) { painter->setBrush( color[i] ); painter->drawPath( path[i] ); } } //! Constructor QwtDialNeedle::QwtDialNeedle(): d_palette( QApplication::palette() ) { } //! Destructor QwtDialNeedle::~QwtDialNeedle() { } /*! Sets the palette for the needle. \param palette New Palette */ void QwtDialNeedle::setPalette( const QPalette &palette ) { d_palette = palette; } /*! \return the palette of the needle. */ const QPalette &QwtDialNeedle::palette() const { return d_palette; } /*! Draw the needle \param painter Painter \param center Center of the dial, start position for the needle \param length Length of the needle \param direction Direction of the needle, in degrees counter clockwise \param colorGroup Color group, used for painting */ void QwtDialNeedle::draw( QPainter *painter, const QPointF ¢er, double length, double direction, QPalette::ColorGroup colorGroup ) const { painter->save(); painter->translate( center ); painter->rotate( -direction ); drawNeedle( painter, length, colorGroup ); painter->restore(); } //! Draw the knob void QwtDialNeedle::drawKnob( QPainter *painter, double width, const QBrush &brush, bool sunken ) const { QPalette palette( brush.color() ); QColor c1 = palette.color( QPalette::Light ); QColor c2 = palette.color( QPalette::Dark ); if ( sunken ) qSwap( c1, c2 ); QRectF rect( 0.0, 0.0, width, width ); rect.moveCenter( painter->combinedTransform().map( QPointF() ) ); QLinearGradient gradient( rect.topLeft(), rect.bottomRight() ); gradient.setColorAt( 0.0, c1 ); gradient.setColorAt( 0.3, c1 ); gradient.setColorAt( 0.7, c2 ); gradient.setColorAt( 1.0, c2 ); painter->save(); painter->resetTransform(); painter->setPen( QPen( gradient, 1 ) ); painter->setBrush( brush ); painter->drawEllipse( rect ); painter->restore(); } /*! Constructor \param style Style \param hasKnob With/Without knob \param mid Middle color \param base Base color */ QwtDialSimpleNeedle::QwtDialSimpleNeedle( Style style, bool hasKnob, const QColor &mid, const QColor &base ): d_style( style ), d_hasKnob( hasKnob ), d_width( -1 ) { QPalette palette; palette.setColor( QPalette::Mid, mid ); palette.setColor( QPalette::Base, base ); setPalette( palette ); } /*! Set the width of the needle \param width Width \sa width() */ void QwtDialSimpleNeedle::setWidth( double width ) { d_width = width; } /*! \return the width of the needle \sa setWidth() */ double QwtDialSimpleNeedle::width() const { return d_width; } /*! Draw the needle \param painter Painter \param length Length of the needle \param colorGroup Color group, used for painting */ void QwtDialSimpleNeedle::drawNeedle( QPainter *painter, double length, QPalette::ColorGroup colorGroup ) const { double knobWidth = 0.0; double width = d_width; if ( d_style == Arrow ) { if ( width <= 0.0 ) width = qMax(length * 0.06, 6.0); qwtDrawArrowNeedle( painter, palette(), colorGroup, length, width ); knobWidth = qMin( width * 2.0, 0.2 * length ); } else { if ( width <= 0.0 ) width = 5.0; QPen pen ( palette().brush( colorGroup, QPalette::Mid ), width ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); painter->drawLine( QPointF( 0.0, 0.0 ), QPointF( length, 0.0 ) ); knobWidth = qMax( width * 3.0, 5.0 ); } if ( d_hasKnob && knobWidth > 0.0 ) { drawKnob( painter, knobWidth, palette().brush( colorGroup, QPalette::Base ), false ); } } //! Constructor QwtCompassMagnetNeedle::QwtCompassMagnetNeedle( Style style, const QColor &light, const QColor &dark ): d_style( style ) { QPalette palette; palette.setColor( QPalette::Light, light ); palette.setColor( QPalette::Dark, dark ); palette.setColor( QPalette::Base, Qt::gray ); setPalette( palette ); } /*! Draw the needle \param painter Painter \param length Length of the needle \param colorGroup Color group, used for painting */ void QwtCompassMagnetNeedle::drawNeedle( QPainter *painter, double length, QPalette::ColorGroup colorGroup ) const { if ( d_style == ThinStyle ) { const double width = qMax( length / 6.0, 3.0 ); const int colorOffset = 10; const QColor light = palette().color( colorGroup, QPalette::Light ); const QColor dark = palette().color( colorGroup, QPalette::Dark ); qwtDrawShadedPointer( painter, dark.light( 100 + colorOffset ), dark.dark( 100 + colorOffset ), length, width ); painter->rotate( 180.0 ); qwtDrawShadedPointer( painter, light.light( 100 + colorOffset ), light.dark( 100 + colorOffset ), length, width ); const QBrush baseBrush = palette().brush( colorGroup, QPalette::Base ); drawKnob( painter, width, baseBrush, true ); } else { qwtDrawTriangleNeedle( painter, palette(), colorGroup, length ); } } /*! Constructor \param style Arrow style \param light Light color \param dark Dark color */ QwtCompassWindArrow::QwtCompassWindArrow( Style style, const QColor &light, const QColor &dark ): d_style( style ) { QPalette palette; palette.setColor( QPalette::Light, light ); palette.setColor( QPalette::Dark, dark ); setPalette( palette ); } /*! Draw the needle \param painter Painter \param length Length of the needle \param colorGroup Color group, used for painting */ void QwtCompassWindArrow::drawNeedle( QPainter *painter, double length, QPalette::ColorGroup colorGroup ) const { if ( d_style == Style1 ) qwtDrawStyle1Needle( painter, palette(), colorGroup, length ); else qwtDrawStyle2Needle( painter, palette(), colorGroup, length ); } pcp-gui-1.5.11/src/libqwt/qwt_double_range.cpp0000644000000000000000000002327312176111212016150 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_double_range.h" #include "qwt_math.h" #if QT_VERSION < 0x040601 #define qFabs(x) ::fabs(x) #endif class QwtDoubleRange::PrivateData { public: PrivateData(): minValue( 0.0 ), maxValue( 0.0 ), step( 1.0 ), pageSize( 1 ), isValid( false ), value( 0.0 ), exactValue( 0.0 ), exactPrevValue( 0.0 ), prevValue( 0.0 ), periodic( false ) { } double minValue; double maxValue; double step; int pageSize; bool isValid; double value; double exactValue; double exactPrevValue; double prevValue; bool periodic; }; /*! The range is initialized to [0.0, 100.0], the step size to 1.0, and the value to 0.0. */ QwtDoubleRange::QwtDoubleRange() { d_data = new PrivateData(); } //! Destroys the QwtDoubleRange QwtDoubleRange::~QwtDoubleRange() { delete d_data; } //! Set the value to be valid/invalid void QwtDoubleRange::setValid( bool isValid ) { if ( isValid != d_data->isValid ) { d_data->isValid = isValid; valueChange(); } } //! Indicates if the value is valid bool QwtDoubleRange::isValid() const { return d_data->isValid; } void QwtDoubleRange::setNewValue( double value, bool align ) { d_data->prevValue = d_data->value; const double vmin = qMin( d_data->minValue, d_data->maxValue ); const double vmax = qMax( d_data->minValue, d_data->maxValue ); if ( value < vmin ) { if ( d_data->periodic && vmin != vmax ) { d_data->value = value + ::ceil( ( vmin - value ) / ( vmax - vmin ) ) * ( vmax - vmin ); } else d_data->value = vmin; } else if ( value > vmax ) { if ( ( d_data->periodic ) && ( vmin != vmax ) ) { d_data->value = value - ::ceil( ( value - vmax ) / ( vmax - vmin ) ) * ( vmax - vmin ); } else d_data->value = vmax; } else { d_data->value = value; } d_data->exactPrevValue = d_data->exactValue; d_data->exactValue = d_data->value; if ( align ) { if ( d_data->step != 0.0 ) { d_data->value = d_data->minValue + qRound( ( d_data->value - d_data->minValue ) / d_data->step ) * d_data->step; } else d_data->value = d_data->minValue; const double minEps = 1.0e-10; // correct rounding error at the border if ( qFabs( d_data->value - d_data->maxValue ) < minEps * qAbs( d_data->step ) ) d_data->value = d_data->maxValue; // correct rounding error if value = 0 if ( qFabs( d_data->value ) < minEps * qAbs( d_data->step ) ) d_data->value = 0.0; } if ( !d_data->isValid || d_data->prevValue != d_data->value ) { d_data->isValid = true; valueChange(); } } /*! \brief Adjust the value to the closest point in the step raster. \param x value \warning The value is clipped when it lies outside the range. When the range is QwtDoubleRange::periodic, it will be mapped to a point in the interval such that \verbatim new value := x + n * (max. value - min. value)\endverbatim with an integer number n. */ void QwtDoubleRange::fitValue( double x ) { setNewValue( x, true ); } /*! \brief Set a new value without adjusting to the step raster \param x new value \warning The value is clipped when it lies outside the range. When the range is QwtDoubleRange::periodic, it will be mapped to a point in the interval such that \verbatim new value := x + n * (max. value - min. value)\endverbatim with an integer number n. */ void QwtDoubleRange::setValue( double x ) { setNewValue( x, false ); } /*! \brief Specify range and step size \param vmin lower boundary of the interval \param vmax higher boundary of the interval \param vstep step width \param pageSize page size in steps \warning \li A change of the range changes the value if it lies outside the new range. The current value will *not* be adjusted to the new step raster. \li vmax < vmin is allowed. \li If the step size is left out or set to zero, it will be set to 1/100 of the interval length. \li If the step size has an absurd value, it will be corrected to a better one. */ void QwtDoubleRange::setRange( double vmin, double vmax, double vstep, int pageSize ) { const bool rchg = ( d_data->maxValue != vmax || d_data->minValue != vmin ); if ( rchg ) { d_data->minValue = vmin; d_data->maxValue = vmax; } // look if the step width has an acceptable // value or otherwise change it. setStep( vstep ); // limit page size const int max = int( qAbs( ( d_data->maxValue - d_data->minValue ) / d_data->step ) ); d_data->pageSize = qBound( 0, pageSize, max ); // If the value lies out of the range, it // will be changed. Note that it will not be adjusted to // the new step width. setNewValue( d_data->value, false ); // call notifier after the step width has been // adjusted. if ( rchg ) rangeChange(); } /*! \brief Change the step raster \param vstep new step width \warning The value will \e not be adjusted to the new step raster. */ void QwtDoubleRange::setStep( double vstep ) { const double intv = d_data->maxValue - d_data->minValue; double newStep; if ( vstep == 0.0 ) { const double defaultRelStep = 1.0e-2; newStep = intv * defaultRelStep; } else { if ( ( intv > 0.0 && vstep < 0.0 ) || ( intv < 0.0 && vstep > 0.0 ) ) newStep = -vstep; else newStep = vstep; const double minRelStep = 1.0e-10; if ( qFabs( newStep ) < qFabs( minRelStep * intv ) ) newStep = minRelStep * intv; } if ( newStep != d_data->step ) { d_data->step = newStep; stepChange(); } } /*! \brief Make the range periodic When the range is periodic, the value will be set to a point inside the interval such that \verbatim point = value + n * width \endverbatim if the user tries to set a new value which is outside the range. If the range is nonperiodic (the default), values outside the range will be clipped. \param tf true for a periodic range */ void QwtDoubleRange::setPeriodic( bool tf ) { d_data->periodic = tf; } /*! \brief Increment the value by a specified number of steps \param nSteps Number of steps to increment \warning As a result of this operation, the new value will always be adjusted to the step raster. */ void QwtDoubleRange::incValue( int nSteps ) { if ( isValid() ) setNewValue( d_data->value + double( nSteps ) * d_data->step, true ); } /*! \brief Increment the value by a specified number of pages \param nPages Number of pages to increment. A negative number decrements the value. \warning The Page size is specified in the constructor. */ void QwtDoubleRange::incPages( int nPages ) { if ( isValid() ) { const double off = d_data->step * d_data->pageSize * nPages; setNewValue( d_data->value + off, true ); } } /*! \brief Notify a change of value This virtual function is called whenever the value changes. The default implementation does nothing. */ void QwtDoubleRange::valueChange() { } /*! \brief Notify a change of the range This virtual function is called whenever the range changes. The default implementation does nothing. */ void QwtDoubleRange::rangeChange() { } /*! \brief Notify a change of the step size This virtual function is called whenever the step size changes. The default implementation does nothing. */ void QwtDoubleRange::stepChange() { } /*! \return the step size \sa setStep(), setRange() */ double QwtDoubleRange::step() const { return qAbs( d_data->step ); } /*! \brief Returns the value of the second border of the range maxValue returns the value which has been specified as the second parameter in QwtDoubleRange::setRange. \sa setRange() */ double QwtDoubleRange::maxValue() const { return d_data->maxValue; } /*! \brief Returns the value at the first border of the range minValue returns the value which has been specified as the first parameter in setRange(). \sa setRange() */ double QwtDoubleRange::minValue() const { return d_data->minValue; } /*! \brief Returns true if the range is periodic \sa setPeriodic() */ bool QwtDoubleRange::periodic() const { return d_data->periodic; } //! Returns the page size in steps. int QwtDoubleRange::pageSize() const { return d_data->pageSize; } //! Returns the current value. double QwtDoubleRange::value() const { return d_data->value; } /*! \brief Returns the exact value The exact value is the value which QwtDoubleRange::value would return if the value were not adjusted to the step raster. It differs from the current value only if fitValue() or incValue() have been used before. This function is intended for internal use in derived classes. */ double QwtDoubleRange::exactValue() const { return d_data->exactValue; } //! Returns the exact previous value double QwtDoubleRange::exactPrevValue() const { return d_data->exactPrevValue; } //! Returns the previous value double QwtDoubleRange::prevValue() const { return d_data->prevValue; } pcp-gui-1.5.11/src/libqwt/qwt_dyngrid_layout.cpp0000644000000000000000000003251012176111212016551 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_dyngrid_layout.h" #include "qwt_math.h" #include #include class QwtDynGridLayout::PrivateData { public: PrivateData(): isDirty( true ) { } void updateLayoutCache(); mutable QList itemList; uint maxCols; uint numRows; uint numCols; Qt::Orientations expanding; bool isDirty; QVector itemSizeHints; }; void QwtDynGridLayout::PrivateData::updateLayoutCache() { itemSizeHints.resize( itemList.count() ); int index = 0; for ( QList::iterator it = itemList.begin(); it != itemList.end(); ++it, index++ ) { itemSizeHints[ index ] = ( *it )->sizeHint(); } isDirty = false; } /*! \param parent Parent widget \param margin Margin \param spacing Spacing */ QwtDynGridLayout::QwtDynGridLayout( QWidget *parent, int margin, int spacing ): QLayout( parent ) { init(); setSpacing( spacing ); setMargin( margin ); } /*! \param spacing Spacing */ QwtDynGridLayout::QwtDynGridLayout( int spacing ) { init(); setSpacing( spacing ); } /*! Initialize the layout with default values. */ void QwtDynGridLayout::init() { d_data = new QwtDynGridLayout::PrivateData; d_data->maxCols = d_data->numRows = d_data->numCols = 0; d_data->expanding = 0; } //! Destructor QwtDynGridLayout::~QwtDynGridLayout() { for ( int i = 0; i < d_data->itemList.size(); i++ ) delete d_data->itemList[i]; delete d_data; } //! Invalidate all internal caches void QwtDynGridLayout::invalidate() { d_data->isDirty = true; QLayout::invalidate(); } /*! Limit the number of columns. \param maxCols upper limit, 0 means unlimited \sa maxCols() */ void QwtDynGridLayout::setMaxCols( uint maxCols ) { d_data->maxCols = maxCols; } /*! Return the upper limit for the number of columns. 0 means unlimited, what is the default. \sa setMaxCols() */ uint QwtDynGridLayout::maxCols() const { return d_data->maxCols; } //! Adds item to the next free position. void QwtDynGridLayout::addItem( QLayoutItem *item ) { d_data->itemList.append( item ); invalidate(); } /*! \return true if this layout is empty. */ bool QwtDynGridLayout::isEmpty() const { return d_data->itemList.isEmpty(); } /*! \return number of layout items */ uint QwtDynGridLayout::itemCount() const { return d_data->itemList.count(); } /*! Find the item at a spcific index \param index Index \sa takeAt() */ QLayoutItem *QwtDynGridLayout::itemAt( int index ) const { if ( index < 0 || index >= d_data->itemList.count() ) return NULL; return d_data->itemList.at( index ); } /*! Find the item at a spcific index and remove it from the layout \param index Index \sa itemAt() */ QLayoutItem *QwtDynGridLayout::takeAt( int index ) { if ( index < 0 || index >= d_data->itemList.count() ) return NULL; d_data->isDirty = true; return d_data->itemList.takeAt( index ); } //! \return Number of items in the layout int QwtDynGridLayout::count() const { return d_data->itemList.count(); } /*! Set whether this layout can make use of more space than sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only one dimension, while Qt::Vertical | Qt::Horizontal means that it wants to grow in both dimensions. The default value is 0. \param expanding Or'd orientations \sa expandingDirections() */ void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding ) { d_data->expanding = expanding; } /*! Returns whether this layout can make use of more space than sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only one dimension, while Qt::Vertical | Qt::Horizontal means that it wants to grow in both dimensions. \sa setExpandingDirections() */ Qt::Orientations QwtDynGridLayout::expandingDirections() const { return d_data->expanding; } /*! Reorganizes columns and rows and resizes managed items within the rectangle rect. \param rect Layout geometry */ void QwtDynGridLayout::setGeometry( const QRect &rect ) { QLayout::setGeometry( rect ); if ( isEmpty() ) return; d_data->numCols = columnsForWidth( rect.width() ); d_data->numRows = itemCount() / d_data->numCols; if ( itemCount() % d_data->numCols ) d_data->numRows++; QList itemGeometries = layoutItems( rect, d_data->numCols ); int index = 0; for ( QList::iterator it = d_data->itemList.begin(); it != d_data->itemList.end(); ++it ) { ( *it )->setGeometry( itemGeometries[index] ); index++; } } /*! Calculate the number of columns for a given width. It tries to use as many columns as possible (limited by maxCols()) \param width Available width for all columns \sa maxCols(), setMaxCols() */ uint QwtDynGridLayout::columnsForWidth( int width ) const { if ( isEmpty() ) return 0; uint maxCols = itemCount(); if ( d_data->maxCols > 0 ) maxCols = qMin( d_data->maxCols, maxCols ); if ( maxRowWidth( maxCols ) <= width ) return maxCols; for ( uint numCols = 2; numCols <= maxCols; numCols++ ) { const int rowWidth = maxRowWidth( numCols ); if ( rowWidth > width ) return numCols - 1; } return 1; // At least 1 column } /*! Calculate the width of a layout for a given number of columns. \param numCols Given number of columns \param itemWidth Array of the width hints for all items */ int QwtDynGridLayout::maxRowWidth( int numCols ) const { int col; QVector colWidth( numCols ); for ( col = 0; col < numCols; col++ ) colWidth[col] = 0; if ( d_data->isDirty ) d_data->updateLayoutCache(); for ( int index = 0; index < d_data->itemSizeHints.count(); index++ ) { col = index % numCols; colWidth[col] = qMax( colWidth[col], d_data->itemSizeHints[int( index )].width() ); } int rowWidth = 2 * margin() + ( numCols - 1 ) * spacing(); for ( col = 0; col < numCols; col++ ) rowWidth += colWidth[col]; return rowWidth; } /*! \return the maximum width of all layout items */ int QwtDynGridLayout::maxItemWidth() const { if ( isEmpty() ) return 0; if ( d_data->isDirty ) d_data->updateLayoutCache(); int w = 0; for ( int i = 0; i < d_data->itemSizeHints.count(); i++ ) { const int itemW = d_data->itemSizeHints[i].width(); if ( itemW > w ) w = itemW; } return w; } /*! Calculate the geometries of the layout items for a layout with numCols columns and a given rect. \param rect Rect where to place the items \param numCols Number of columns \return item geometries */ QList QwtDynGridLayout::layoutItems( const QRect &rect, uint numCols ) const { QList itemGeometries; if ( numCols == 0 || isEmpty() ) return itemGeometries; uint numRows = itemCount() / numCols; if ( numCols % itemCount() ) numRows++; if ( numRows == 0 ) return itemGeometries; QVector rowHeight( numRows ); QVector colWidth( numCols ); layoutGrid( numCols, rowHeight, colWidth ); bool expandH, expandV; expandH = expandingDirections() & Qt::Horizontal; expandV = expandingDirections() & Qt::Vertical; if ( expandH || expandV ) stretchGrid( rect, numCols, rowHeight, colWidth ); const int maxCols = d_data->maxCols; d_data->maxCols = numCols; const QRect alignedRect = alignmentRect( rect ); d_data->maxCols = maxCols; const int xOffset = expandH ? 0 : alignedRect.x(); const int yOffset = expandV ? 0 : alignedRect.y(); QVector colX( numCols ); QVector rowY( numRows ); const int xySpace = spacing(); rowY[0] = yOffset + margin(); for ( uint r = 1; r < numRows; r++ ) rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace; colX[0] = xOffset + margin(); for ( uint c = 1; c < numCols; c++ ) colX[c] = colX[c-1] + colWidth[c-1] + xySpace; const int itemCount = d_data->itemList.size(); for ( int i = 0; i < itemCount; i++ ) { const int row = i / numCols; const int col = i % numCols; QRect itemGeometry( colX[col], rowY[row], colWidth[col], rowHeight[row] ); itemGeometries.append( itemGeometry ); } return itemGeometries; } /*! Calculate the dimensions for the columns and rows for a grid of numCols columns. \param numCols Number of columns. \param rowHeight Array where to fill in the calculated row heights. \param colWidth Array where to fill in the calculated column widths. */ void QwtDynGridLayout::layoutGrid( uint numCols, QVector& rowHeight, QVector& colWidth ) const { if ( numCols <= 0 ) return; if ( d_data->isDirty ) d_data->updateLayoutCache(); for ( int index = 0; index < d_data->itemSizeHints.count(); index++ ) { const int row = index / numCols; const int col = index % numCols; const QSize &size = d_data->itemSizeHints[int( index )]; rowHeight[row] = ( col == 0 ) ? size.height() : qMax( rowHeight[row], size.height() ); colWidth[col] = ( row == 0 ) ? size.width() : qMax( colWidth[col], size.width() ); } } /*! \return true: QwtDynGridLayout implements heightForWidth. \sa heightForWidth() */ bool QwtDynGridLayout::hasHeightForWidth() const { return true; } /*! \return The preferred height for this layout, given the width w. \sa hasHeightForWidth() */ int QwtDynGridLayout::heightForWidth( int width ) const { if ( isEmpty() ) return 0; const uint numCols = columnsForWidth( width ); uint numRows = itemCount() / numCols; if ( itemCount() % numCols ) numRows++; QVector rowHeight( numRows ); QVector colWidth( numCols ); layoutGrid( numCols, rowHeight, colWidth ); int h = 2 * margin() + ( numRows - 1 ) * spacing(); for ( uint row = 0; row < numRows; row++ ) h += rowHeight[row]; return h; } /*! Stretch columns in case of expanding() & QSizePolicy::Horizontal and rows in case of expanding() & QSizePolicy::Vertical to fill the entire rect. Rows and columns are stretched with the same factor. \sa setExpanding(), expanding() */ void QwtDynGridLayout::stretchGrid( const QRect &rect, uint numCols, QVector& rowHeight, QVector& colWidth ) const { if ( numCols == 0 || isEmpty() ) return; bool expandH, expandV; expandH = expandingDirections() & Qt::Horizontal; expandV = expandingDirections() & Qt::Vertical; if ( expandH ) { int xDelta = rect.width() - 2 * margin() - ( numCols - 1 ) * spacing(); for ( uint col = 0; col < numCols; col++ ) xDelta -= colWidth[col]; if ( xDelta > 0 ) { for ( uint col = 0; col < numCols; col++ ) { const int space = xDelta / ( numCols - col ); colWidth[col] += space; xDelta -= space; } } } if ( expandV ) { uint numRows = itemCount() / numCols; if ( itemCount() % numCols ) numRows++; int yDelta = rect.height() - 2 * margin() - ( numRows - 1 ) * spacing(); for ( uint row = 0; row < numRows; row++ ) yDelta -= rowHeight[row]; if ( yDelta > 0 ) { for ( uint row = 0; row < numRows; row++ ) { const int space = yDelta / ( numRows - row ); rowHeight[row] += space; yDelta -= space; } } } } /*! Return the size hint. If maxCols() > 0 it is the size for a grid with maxCols() columns, otherwise it is the size for a grid with only one row. \sa maxCols(), setMaxCols() */ QSize QwtDynGridLayout::sizeHint() const { if ( isEmpty() ) return QSize(); uint numCols = itemCount(); if ( d_data->maxCols > 0 ) numCols = qMin( d_data->maxCols, numCols ); uint numRows = itemCount() / numCols; if ( itemCount() % numCols ) numRows++; QVector rowHeight( numRows ); QVector colWidth( numCols ); layoutGrid( numCols, rowHeight, colWidth ); int h = 2 * margin() + ( numRows - 1 ) * spacing(); for ( uint row = 0; row < numRows; row++ ) h += rowHeight[row]; int w = 2 * margin() + ( numCols - 1 ) * spacing(); for ( uint col = 0; col < numCols; col++ ) w += colWidth[col]; return QSize( w, h ); } /*! \return Number of rows of the current layout. \sa numCols() \warning The number of rows might change whenever the geometry changes */ uint QwtDynGridLayout::numRows() const { return d_data->numRows; } /*! \return Number of columns of the current layout. \sa numRows() \warning The number of columns might change whenever the geometry changes */ uint QwtDynGridLayout::numCols() const { return d_data->numCols; } pcp-gui-1.5.11/src/libqwt/qwt_event_pattern.cpp0000644000000000000000000001516412176111212016400 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_event_pattern.h" #include /*! Constructor \sa MousePatternCode, KeyPatternCode */ QwtEventPattern::QwtEventPattern(): d_mousePattern( MousePatternCount ), d_keyPattern( KeyPatternCount ) { initKeyPattern(); initMousePattern( 3 ); } //! Destructor QwtEventPattern::~QwtEventPattern() { } /*! Set default mouse patterns, depending on the number of mouse buttons \param numButtons Number of mouse buttons ( <= 3 ) \sa MousePatternCode */ void QwtEventPattern::initMousePattern( int numButtons ) { const int altButton = Qt::AltModifier; const int controlButton = Qt::ControlModifier; const int shiftButton = Qt::ShiftModifier; d_mousePattern.resize( MousePatternCount ); switch ( numButtons ) { case 1: { setMousePattern( MouseSelect1, Qt::LeftButton ); setMousePattern( MouseSelect2, Qt::LeftButton, controlButton ); setMousePattern( MouseSelect3, Qt::LeftButton, altButton ); break; } case 2: { setMousePattern( MouseSelect1, Qt::LeftButton ); setMousePattern( MouseSelect2, Qt::RightButton ); setMousePattern( MouseSelect3, Qt::LeftButton, altButton ); break; } default: { setMousePattern( MouseSelect1, Qt::LeftButton ); setMousePattern( MouseSelect2, Qt::RightButton ); setMousePattern( MouseSelect3, Qt::MidButton ); } } for ( int i = 0; i < 3; i++ ) { setMousePattern( MouseSelect4 + i, d_mousePattern[MouseSelect1 + i].button, d_mousePattern[MouseSelect1 + i].state | shiftButton ); } } /*! Set default mouse patterns. \sa KeyPatternCode */ void QwtEventPattern::initKeyPattern() { d_keyPattern.resize( KeyPatternCount ); setKeyPattern( KeySelect1, Qt::Key_Return ); setKeyPattern( KeySelect2, Qt::Key_Space ); setKeyPattern( KeyAbort, Qt::Key_Escape ); setKeyPattern( KeyLeft, Qt::Key_Left ); setKeyPattern( KeyRight, Qt::Key_Right ); setKeyPattern( KeyUp, Qt::Key_Up ); setKeyPattern( KeyDown, Qt::Key_Down ); setKeyPattern( KeyRedo, Qt::Key_Plus ); setKeyPattern( KeyUndo, Qt::Key_Minus ); setKeyPattern( KeyHome, Qt::Key_Escape ); } /*! Change one mouse pattern \param pattern Index of the pattern \param button Button \param state State \sa QMouseEvent */ void QwtEventPattern::setMousePattern( uint pattern, int button, int state ) { if ( pattern < ( uint )d_mousePattern.count() ) { d_mousePattern[int( pattern )].button = button; d_mousePattern[int( pattern )].state = state; } } /*! Change one key pattern \param pattern Index of the pattern \param key Key \param state State \sa QKeyEvent */ void QwtEventPattern::setKeyPattern( uint pattern, int key, int state ) { if ( pattern < ( uint )d_keyPattern.count() ) { d_keyPattern[int( pattern )].key = key; d_keyPattern[int( pattern )].state = state; } } //! Change the mouse event patterns void QwtEventPattern::setMousePattern( const QVector &pattern ) { d_mousePattern = pattern; } //! Change the key event patterns void QwtEventPattern::setKeyPattern( const QVector &pattern ) { d_keyPattern = pattern; } //! Return mouse patterns const QVector & QwtEventPattern::mousePattern() const { return d_mousePattern; } //! Return key patterns const QVector & QwtEventPattern::keyPattern() const { return d_keyPattern; } //! Return ,ouse patterns QVector &QwtEventPattern::mousePattern() { return d_mousePattern; } //! Return Key patterns QVector &QwtEventPattern::keyPattern() { return d_keyPattern; } /*! \brief Compare a mouse event with an event pattern. A mouse event matches the pattern when both have the same button value and in the state value the same key flags(Qt::KeyButtonMask) are set. \param pattern Index of the event pattern \param event Mouse event \return true if matches \sa keyMatch() */ bool QwtEventPattern::mouseMatch( uint pattern, const QMouseEvent *event ) const { bool ok = false; if ( event && pattern < ( uint )d_mousePattern.count() ) ok = mouseMatch( d_mousePattern[int( pattern )], event ); return ok; } /*! \brief Compare a mouse event with an event pattern. A mouse event matches the pattern when both have the same button value and in the state value the same key flags(Qt::KeyButtonMask) are set. \param pattern Mouse event pattern \param event Mouse event \return true if matches \sa keyMatch() */ bool QwtEventPattern::mouseMatch( const MousePattern &pattern, const QMouseEvent *event ) const { if ( event->button() != pattern.button ) return false; const bool matched = ( event->modifiers() & Qt::KeyboardModifierMask ) == ( int )( pattern.state & Qt::KeyboardModifierMask ); return matched; } /*! \brief Compare a key event with an event pattern. A key event matches the pattern when both have the same key value and in the state value the same key flags (Qt::KeyButtonMask) are set. \param pattern Index of the event pattern \param event Key event \return true if matches \sa mouseMatch() */ bool QwtEventPattern::keyMatch( uint pattern, const QKeyEvent *event ) const { bool ok = false; if ( event && pattern < ( uint )d_keyPattern.count() ) ok = keyMatch( d_keyPattern[int( pattern )], event ); return ok; } /*! \brief Compare a key event with an event pattern. A key event matches the pattern when both have the same key value and in the state value the same key flags (Qt::KeyButtonMask) are set. \param pattern Key event pattern \param event Key event \return true if matches \sa mouseMatch() */ bool QwtEventPattern::keyMatch( const KeyPattern &pattern, const QKeyEvent *event ) const { if ( event->key() != pattern.key ) return false; const bool matched = ( event->modifiers() & Qt::KeyboardModifierMask ) == ( int )( pattern.state & Qt::KeyboardModifierMask ); return matched; } pcp-gui-1.5.11/src/libqwt/qwt_interval.cpp0000644000000000000000000001765012176111212015350 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_interval.h" #include "qwt_math.h" #include /*! \brief Normalize the limits of the interval If maxValue() < minValue() the limits will be inverted. \return Normalized interval \sa isValid(), inverted() */ QwtInterval QwtInterval::normalized() const { if ( d_minValue > d_maxValue ) { return inverted(); } if ( d_minValue == d_maxValue && d_borderFlags == ExcludeMinimum ) { return inverted(); } return *this; } /*! Invert the limits of the interval \return Inverted interval \sa normalized() */ QwtInterval QwtInterval::inverted() const { BorderFlags borderFlags = IncludeBorders; if ( d_borderFlags & ExcludeMinimum ) borderFlags |= ExcludeMaximum; if ( d_borderFlags & ExcludeMaximum ) borderFlags |= ExcludeMinimum; return QwtInterval( d_maxValue, d_minValue, borderFlags ); } /*! Test if a value is inside an interval \param value Value \return true, if value >= minValue() && value <= maxValue() */ bool QwtInterval::contains( double value ) const { if ( !isValid() ) return false; if ( value < d_minValue || value > d_maxValue ) return false; if ( value == d_minValue && d_borderFlags & ExcludeMinimum ) return false; if ( value == d_maxValue && d_borderFlags & ExcludeMaximum ) return false; return true; } //! Unite 2 intervals QwtInterval QwtInterval::unite( const QwtInterval &other ) const { /* If one of the intervals is invalid return the other one. If both are invalid return an invalid default interval */ if ( !isValid() ) { if ( !other.isValid() ) return QwtInterval(); else return other; } if ( !other.isValid() ) return *this; QwtInterval united; BorderFlags flags = IncludeBorders; // minimum if ( d_minValue < other.minValue() ) { united.setMinValue( d_minValue ); flags &= d_borderFlags & ExcludeMinimum; } else if ( other.minValue() < d_minValue ) { united.setMinValue( other.minValue() ); flags &= other.borderFlags() & ExcludeMinimum; } else // d_minValue == other.minValue() { united.setMinValue( d_minValue ); flags &= ( d_borderFlags & other.borderFlags() ) & ExcludeMinimum; } // maximum if ( d_maxValue > other.maxValue() ) { united.setMaxValue( d_maxValue ); flags &= d_borderFlags & ExcludeMaximum; } else if ( other.maxValue() > d_maxValue ) { united.setMaxValue( other.maxValue() ); flags &= other.borderFlags() & ExcludeMaximum; } else // d_maxValue == other.maxValue() ) { united.setMaxValue( d_maxValue ); flags &= d_borderFlags & other.borderFlags() & ExcludeMaximum; } united.setBorderFlags( flags ); return united; } //! Intersect 2 intervals QwtInterval QwtInterval::intersect( const QwtInterval &other ) const { if ( !other.isValid() || !isValid() ) return QwtInterval(); QwtInterval i1 = *this; QwtInterval i2 = other; // swap i1/i2, so that the minimum of i1 // is smaller then the minimum of i2 if ( i1.minValue() > i2.minValue() ) { qSwap( i1, i2 ); } else if ( i1.minValue() == i2.minValue() ) { if ( i1.borderFlags() & ExcludeMinimum ) qSwap( i1, i2 ); } if ( i1.maxValue() < i2.minValue() ) { return QwtInterval(); } if ( i1.maxValue() == i2.minValue() ) { if ( i1.borderFlags() & ExcludeMaximum || i2.borderFlags() & ExcludeMinimum ) { return QwtInterval(); } } QwtInterval intersected; BorderFlags flags = IncludeBorders; intersected.setMinValue( i2.minValue() ); flags |= i2.borderFlags() & ExcludeMinimum; if ( i1.maxValue() < i2.maxValue() ) { intersected.setMaxValue( i1.maxValue() ); flags |= i1.borderFlags() & ExcludeMaximum; } else if ( i2.maxValue() < i1.maxValue() ) { intersected.setMaxValue( i2.maxValue() ); flags |= i2.borderFlags() & ExcludeMaximum; } else // i1.maxValue() == i2.maxValue() { intersected.setMaxValue( i1.maxValue() ); flags |= i1.borderFlags() & i2.borderFlags() & ExcludeMaximum; } intersected.setBorderFlags( flags ); return intersected; } //! Unites this interval with the given interval. QwtInterval& QwtInterval::operator|=( const QwtInterval & interval ) { *this = *this | interval; return *this; } //! Intersects this interval with the given interval. QwtInterval& QwtInterval::operator&=( const QwtInterval & interval ) { *this = *this & interval; return *this; } /*! Test if two intervals overlap */ bool QwtInterval::intersects( const QwtInterval &other ) const { if ( !isValid() || !other.isValid() ) return false; QwtInterval i1 = *this; QwtInterval i2 = other; // swap i1/i2, so that the minimum of i1 // is smaller then the minimum of i2 if ( i1.minValue() > i2.minValue() ) { qSwap( i1, i2 ); } else if ( i1.minValue() == i2.minValue() && i1.borderFlags() & ExcludeMinimum ) { qSwap( i1, i2 ); } if ( i1.maxValue() > i2.minValue() ) { return true; } if ( i1.maxValue() == i2.minValue() ) { return !( ( i1.borderFlags() & ExcludeMaximum ) || ( i2.borderFlags() & ExcludeMinimum ) ); } return false; } /*! Adjust the limit that is closer to value, so that value becomes the center of the interval. \param value Center \return Interval with value as center */ QwtInterval QwtInterval::symmetrize( double value ) const { if ( !isValid() ) return *this; const double delta = qMax( qAbs( value - d_maxValue ), qAbs( value - d_minValue ) ); return QwtInterval( value - delta, value + delta ); } /*! Limit the interval, keeping the border modes \param lowerBound Lower limit \param upperBound Upper limit \return Limited interval */ QwtInterval QwtInterval::limited( double lowerBound, double upperBound ) const { if ( !isValid() || lowerBound > upperBound ) return QwtInterval(); double minValue = qMax( d_minValue, lowerBound ); minValue = qMin( minValue, upperBound ); double maxValue = qMax( d_maxValue, lowerBound ); maxValue = qMin( maxValue, upperBound ); return QwtInterval( minValue, maxValue, d_borderFlags ); } /*! Extend the interval If value is below minValue, value becomes the lower limit. If value is above maxValue, value becomes the upper limit. extend has no effect for invalid intervals \param value Value \sa isValid() */ QwtInterval QwtInterval::extend( double value ) const { if ( !isValid() ) return *this; return QwtInterval( qMin( value, d_minValue ), qMax( value, d_maxValue ), d_borderFlags ); } /*! Extend an interval \param value Value \return Reference of the extended interval \sa extend() */ QwtInterval& QwtInterval::operator|=( double value ) { *this = *this | value; return *this; } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<( QDebug debug, const QwtInterval &interval ) { const int flags = interval.borderFlags(); debug.nospace() << "QwtInterval(" << ( ( flags & QwtInterval::ExcludeMinimum ) ? "]" : "[" ) << interval.minValue() << "," << interval.maxValue() << ( ( flags & QwtInterval::ExcludeMaximum ) ? "[" : "]" ) << ")"; return debug.space(); } #endif pcp-gui-1.5.11/src/libqwt/qwt_interval_symbol.cpp0000644000000000000000000001663412176111212016736 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_interval_symbol.h" #include "qwt_painter.h" #include "qwt_math.h" #include #if QT_VERSION < 0x040601 #define qAtan2(y, x) ::atan2(y, x) #define qFastSin(x) qSin(x) #define qFastCos(x) qCos(x) #endif class QwtIntervalSymbol::PrivateData { public: PrivateData(): style( QwtIntervalSymbol::NoSymbol ), width( 6 ) { } bool operator==( const PrivateData &other ) const { return ( style == other.style ) && ( width == other.width ) && ( brush == other.brush ) && ( pen == other.pen ); } QwtIntervalSymbol::Style style; int width; QPen pen; QBrush brush; }; /*! Constructor \param style Style of the symbol \sa setStyle(), style(), Style */ QwtIntervalSymbol::QwtIntervalSymbol( Style style ) { d_data = new PrivateData(); d_data->style = style; } //! Copy constructor QwtIntervalSymbol::QwtIntervalSymbol( const QwtIntervalSymbol &other ) { d_data = new PrivateData(); *d_data = *other.d_data; } //! Destructor QwtIntervalSymbol::~QwtIntervalSymbol() { delete d_data; } //! \brief Assignment operator QwtIntervalSymbol &QwtIntervalSymbol::operator=( const QwtIntervalSymbol &other ) { *d_data = *other.d_data; return *this; } //! \brief Compare two symbols bool QwtIntervalSymbol::operator==( const QwtIntervalSymbol &other ) const { return *d_data == *other.d_data; } //! \brief Compare two symbols bool QwtIntervalSymbol::operator!=( const QwtIntervalSymbol &other ) const { return !( *d_data == *other.d_data ); } /*! Specify the symbol style \param style Style \sa style(), Style */ void QwtIntervalSymbol::setStyle( Style style ) { d_data->style = style; } /*! \return Current symbol style \sa setStyle() */ QwtIntervalSymbol::Style QwtIntervalSymbol::style() const { return d_data->style; } /*! Specify the width of the symbol It is used depending on the style. \param width Width \sa width(), setStyle() */ void QwtIntervalSymbol::setWidth( int width ) { d_data->width = width; } /*! \return Width of the symbol. \sa setWidth(), setStyle() */ int QwtIntervalSymbol::width() const { return d_data->width; } /*! \brief Assign a brush The brush is used for the Box style. \param brush Brush \sa brush() */ void QwtIntervalSymbol::setBrush( const QBrush &brush ) { d_data->brush = brush; } /*! \return Brush \sa setBrush() */ const QBrush& QwtIntervalSymbol::brush() const { return d_data->brush; } /*! Assign a pen \param pen Pen \sa pen(), setBrush() */ void QwtIntervalSymbol::setPen( const QPen &pen ) { d_data->pen = pen; } /*! \return Pen \sa setPen(), brush() */ const QPen& QwtIntervalSymbol::pen() const { return d_data->pen; } /*! Draw a symbol depending on its style \param painter Painter \param orientation Orientation \param from Start point of the interval in target device coordinates \param to End point of the interval in target device coordinates \sa setStyle() */ void QwtIntervalSymbol::draw( QPainter *painter, Qt::Orientation orientation, const QPointF &from, const QPointF &to ) const { const qreal pw = qMax( painter->pen().widthF(), qreal( 1.0 ) ); QPointF p1 = from; QPointF p2 = to; if ( QwtPainter::roundingAlignment( painter ) ) { p1 = p1.toPoint(); p2 = p2.toPoint(); } switch ( d_data->style ) { case QwtIntervalSymbol::Bar: { QwtPainter::drawLine( painter, p1, p2 ); if ( d_data->width > pw ) { if ( ( orientation == Qt::Horizontal ) && ( p1.y() == p2.y() ) ) { const double sw = d_data->width; const double y = p1.y() - sw / 2; QwtPainter::drawLine( painter, p1.x(), y, p1.x(), y + sw ); QwtPainter::drawLine( painter, p2.x(), y, p2.x(), y + sw ); } else if ( ( orientation == Qt::Vertical ) && ( p1.x() == p2.x() ) ) { const double sw = d_data->width; const double x = p1.x() - sw / 2; QwtPainter::drawLine( painter, x, p1.y(), x + sw, p1.y() ); QwtPainter::drawLine( painter, x, p2.y(), x + sw, p2.y() ); } else { const double sw = d_data->width; const double dx = p2.x() - p1.x(); const double dy = p2.y() - p1.y(); const double angle = qAtan2( dy, dx ) + M_PI_2; double dw2 = sw / 2.0; const double cx = qFastCos( angle ) * dw2; const double sy = qFastSin( angle ) * dw2; QwtPainter::drawLine( painter, p1.x() - cx, p1.y() - sy, p1.x() + cx, p1.y() + sy ); QwtPainter::drawLine( painter, p2.x() - cx, p2.y() - sy, p2.x() + cx, p2.y() + sy ); } } break; } case QwtIntervalSymbol::Box: { if ( d_data->width <= pw ) { QwtPainter::drawLine( painter, p1, p2 ); } else { if ( ( orientation == Qt::Horizontal ) && ( p1.y() == p2.y() ) ) { const double sw = d_data->width; const double y = p1.y() - d_data->width / 2; QwtPainter::drawRect( painter, p1.x(), y, p2.x() - p1.x(), sw ); } else if ( ( orientation == Qt::Vertical ) && ( p1.x() == p2.x() ) ) { const double sw = d_data->width; const double x = p1.x() - d_data->width / 2; QwtPainter::drawRect( painter, x, p1.y(), sw, p2.y() - p1.y() ); } else { const double sw = d_data->width; const double dx = p2.x() - p1.x(); const double dy = p2.y() - p1.y(); const double angle = qAtan2( dy, dx ) + M_PI_2; double dw2 = sw / 2.0; const double cx = qFastCos( angle ) * dw2; const double sy = qFastSin( angle ) * dw2; QPolygonF polygon; polygon += QPointF( p1.x() - cx, p1.y() - sy ); polygon += QPointF( p1.x() + cx, p1.y() + sy ); polygon += QPointF( p2.x() + cx, p2.y() + sy ); polygon += QPointF( p2.x() - cx, p2.y() - sy ); QwtPainter::drawPolygon( painter, polygon ); } } break; } default:; } } pcp-gui-1.5.11/src/libqwt/qwt_knob.cpp0000644000000000000000000003771012176111212014454 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_knob.h" #include "qwt_round_scale_draw.h" #include "qwt_math.h" #include "qwt_painter.h" #include #include #include #include #include #include #include #if QT_VERSION < 0x040601 #define qAtan2(y, x) ::atan2(y, x) #define qFabs(x) ::fabs(x) #define qFastCos(x) qCos(x) #define qFastSin(x) qSin(x) #endif class QwtKnob::PrivateData { public: PrivateData() { angle = 0.0; nTurns = 0.0; borderWidth = 2; borderDist = 4; totalAngle = 270.0; scaleDist = 4; markerStyle = QwtKnob::Notch; maxScaleTicks = 11; knobStyle = QwtKnob::Raised; knobWidth = 50; markerSize = 8; } QwtKnob::KnobStyle knobStyle; QwtKnob::MarkerStyle markerStyle; int borderWidth; int borderDist; int scaleDist; int maxScaleTicks; int knobWidth; int markerSize; double angle; double totalAngle; double nTurns; mutable QRectF knobRect; // bounding rect of the knob without scale }; /*! Constructor \param parent Parent widget */ QwtKnob::QwtKnob( QWidget* parent ): QwtAbstractSlider( Qt::Horizontal, parent ) { initKnob(); } void QwtKnob::initKnob() { d_data = new PrivateData; setScaleDraw( new QwtRoundScaleDraw() ); setUpdateTime( 50 ); setTotalAngle( 270.0 ); recalcAngle(); setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) ); setRange( 0.0, 10.0, 1.0 ); setValue( 0.0 ); } //! Destructor QwtKnob::~QwtKnob() { delete d_data; } /*! \brief Set the knob type \param knobStyle Knob type \sa knobStyle(), setBorderWidth() */ void QwtKnob::setKnobStyle( KnobStyle knobStyle ) { if ( d_data->knobStyle != knobStyle ) { d_data->knobStyle = knobStyle; update(); } } /*! \return Marker type of the knob \sa setKnobStyle(), setBorderWidth() */ QwtKnob::KnobStyle QwtKnob::knobStyle() const { return d_data->knobStyle; } /*! \brief Set the marker type of the knob \param markerStyle Marker type \sa markerStyle(), setMarkerSize() */ void QwtKnob::setMarkerStyle( MarkerStyle markerStyle ) { if ( d_data->markerStyle != markerStyle ) { d_data->markerStyle = markerStyle; update(); } } /*! \return Marker type of the knob \sa setMarkerStyle(), setMarkerSize() */ QwtKnob::MarkerStyle QwtKnob::markerStyle() const { return d_data->markerStyle; } /*! \brief Set the total angle by which the knob can be turned \param angle Angle in degrees. The default angle is 270 degrees. It is possible to specify an angle of more than 360 degrees so that the knob can be turned several times around its axis. */ void QwtKnob::setTotalAngle ( double angle ) { if ( angle < 10.0 ) d_data->totalAngle = 10.0; else d_data->totalAngle = angle; scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle, 0.5 * d_data->totalAngle ); layoutKnob( true ); } //! Return the total angle double QwtKnob::totalAngle() const { return d_data->totalAngle; } /*! Change the scale draw of the knob For changing the labels of the scales, it is necessary to derive from QwtRoundScaleDraw and overload QwtRoundScaleDraw::label(). \sa scaleDraw() */ void QwtKnob::setScaleDraw( QwtRoundScaleDraw *scaleDraw ) { setAbstractScaleDraw( scaleDraw ); setTotalAngle( d_data->totalAngle ); } /*! \return the scale draw of the knob \sa setScaleDraw() */ const QwtRoundScaleDraw *QwtKnob::scaleDraw() const { return static_cast( abstractScaleDraw() ); } /*! \return the scale draw of the knob \sa setScaleDraw() */ QwtRoundScaleDraw *QwtKnob::scaleDraw() { return static_cast( abstractScaleDraw() ); } /*! \brief Notify change of value Sets the knob's value to the nearest multiple of the step size. */ void QwtKnob::valueChange() { recalcAngle(); update(); QwtAbstractSlider::valueChange(); } /*! \brief Determine the value corresponding to a specified position Called by QwtAbstractSlider \param pos point */ double QwtKnob::getValue( const QPoint &pos ) { const double dx = rect().center().x() - pos.x(); const double dy = rect().center().y() - pos.y(); const double arc = qAtan2( -dx, dy ) * 180.0 / M_PI; double newValue = 0.5 * ( minValue() + maxValue() ) + ( arc + d_data->nTurns * 360.0 ) * ( maxValue() - minValue() ) / d_data->totalAngle; const double oneTurn = qFabs( maxValue() - minValue() ) * 360.0 / d_data->totalAngle; const double eqValue = value() + mouseOffset(); if ( qFabs( newValue - eqValue ) > 0.5 * oneTurn ) { if ( newValue < eqValue ) newValue += oneTurn; else newValue -= oneTurn; } return newValue; } /*! \brief Set the scrolling mode and direction Called by QwtAbstractSlider \param pos Point in question \param scrollMode Scrolling mode \param direction Direction */ void QwtKnob::getScrollMode( const QPoint &pos, QwtAbstractSlider::ScrollMode &scrollMode, int &direction ) const { const double r = 0.5 * d_data->knobRect.width(); const double dx = d_data->knobRect.x() + r - pos.x(); const double dy = d_data->knobRect.y() + r - pos.y(); if ( qwtSqr( dx ) + qwtSqr( dy ) <= qwtSqr( r ) ) { // point is inside the knob scrollMode = QwtAbstractSlider::ScrMouse; direction = 0; } else // point lies outside { scrollMode = QwtAbstractSlider::ScrTimer; double arc = qAtan2( double( -dx ), double( dy ) ) * 180.0 / M_PI; if ( arc < d_data->angle ) direction = -1; else if ( arc > d_data->angle ) direction = 1; else direction = 0; } } /*! \brief Notify a change of the range Called by QwtAbstractSlider */ void QwtKnob::rangeChange() { if ( autoScale() ) rescale( minValue(), maxValue() ); layoutKnob( true ); recalcAngle(); } /*! Qt Resize Event \param event Resize event */ void QwtKnob::resizeEvent( QResizeEvent *event ) { Q_UNUSED( event ); layoutKnob( false ); } /*! Handle QEvent::StyleChange and QEvent::FontChange; \param event Change event */ void QwtKnob::changeEvent( QEvent *event ) { switch( event->type() ) { case QEvent::StyleChange: case QEvent::FontChange: layoutKnob( true ); break; default: break; } } /*! Recalculate the knob's geometry and layout based on the current rect and fonts. \param update_geometry notify the layout system and call update to redraw the scale */ void QwtKnob::layoutKnob( bool update_geometry ) { const double d = d_data->knobWidth; d_data->knobRect.setWidth( d ); d_data->knobRect.setHeight( d ); d_data->knobRect.moveCenter( rect().center() ); scaleDraw()->setRadius( 0.5 * d + d_data->scaleDist ); scaleDraw()->moveCenter( rect().center() ); if ( update_geometry ) { updateGeometry(); update(); } } /*! Repaint the knob \param event Paint event */ void QwtKnob::paintEvent( QPaintEvent *event ) { QPainter painter( this ); painter.setClipRegion( event->region() ); QStyleOption opt; opt.init(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); painter.setRenderHint( QPainter::Antialiasing, true ); if ( !d_data->knobRect.contains( event->region().boundingRect() ) ) scaleDraw()->draw( &painter, palette() ); drawKnob( &painter, d_data->knobRect ); drawMarker( &painter, d_data->knobRect, d_data->angle ); painter.setRenderHint( QPainter::Antialiasing, false ); if ( hasFocus() ) QwtPainter::drawFocusRect( &painter, this ); } /*! \brief Draw the knob \param painter painter \param knobRect Bounding rectangle of the knob (without scale) */ void QwtKnob::drawKnob( QPainter *painter, const QRectF &knobRect ) const { double dim = qMin( knobRect.width(), knobRect.height() ); dim -= d_data->borderWidth * 0.5; QRectF aRect( 0, 0, dim, dim ); aRect.moveCenter( knobRect.center() ); QPen pen( Qt::NoPen ); if ( d_data->borderWidth > 0 ) { QColor c1 = palette().color( QPalette::Light ); QColor c2 = palette().color( QPalette::Dark ); QLinearGradient gradient( aRect.topLeft(), aRect.bottomRight() ); gradient.setColorAt( 0.0, c1 ); gradient.setColorAt( 0.3, c1 ); gradient.setColorAt( 0.7, c2 ); gradient.setColorAt( 1.0, c2 ); pen = QPen( gradient, d_data->borderWidth ); } QBrush brush; switch( d_data->knobStyle ) { case QwtKnob::Raised: { double off = 0.3 * knobRect.width(); QRadialGradient gradient( knobRect.center(), knobRect.width(), knobRect.topLeft() + QPointF( off, off ) ); gradient.setColorAt( 0.0, palette().color( QPalette::Midlight ) ); gradient.setColorAt( 1.0, palette().color( QPalette::Button ) ); brush = QBrush( gradient ); break; } case QwtKnob::Sunken: { QLinearGradient gradient( knobRect.topLeft(), knobRect.bottomRight() ); gradient.setColorAt( 0.0, palette().color( QPalette::Mid ) ); gradient.setColorAt( 0.5, palette().color( QPalette::Button ) ); gradient.setColorAt( 1.0, palette().color( QPalette::Midlight ) ); brush = QBrush( gradient ); break; } default: brush = palette().brush( QPalette::Button ); } painter->setPen( pen ); painter->setBrush( brush ); painter->drawEllipse( aRect ); } /*! \brief Draw the marker at the knob's front \param painter Painter \param rect Bounding rectangle of the knob without scale \param angle Angle of the marker in degrees */ void QwtKnob::drawMarker( QPainter *painter, const QRectF &rect, double angle ) const { if ( d_data->markerStyle == NoMarker || !isValid() ) return; const double radians = angle * M_PI / 180.0; const double sinA = -qFastSin( radians ); const double cosA = qFastCos( radians ); const double xm = rect.center().x(); const double ym = rect.center().y(); const double margin = 4.0; double radius = 0.5 * ( rect.width() - d_data->borderWidth ) - margin; if ( radius < 1.0 ) radius = 1.0; switch ( d_data->markerStyle ) { case Notch: case Nub: { const double dotWidth = qMin( double( d_data->markerSize ), radius); const double dotCenterDist = radius - 0.5 * dotWidth; if ( dotCenterDist > 0.0 ) { const QPointF center( xm - sinA * dotCenterDist, ym - cosA * dotCenterDist ); QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth ); ellipse.moveCenter( center ); QColor c1 = palette().color( QPalette::Light ); QColor c2 = palette().color( QPalette::Mid ); if ( d_data->markerStyle == Notch ) qSwap( c1, c2 ); QLinearGradient gradient( ellipse.topLeft(), ellipse.bottomRight() ); gradient.setColorAt( 0.0, c1 ); gradient.setColorAt( 1.0, c2 ); painter->setPen( Qt::NoPen ); painter->setBrush( gradient ); painter->drawEllipse( ellipse ); } break; } case Dot: { const double dotWidth = qMin( double( d_data->markerSize ), radius); const double dotCenterDist = radius - 0.5 * dotWidth; if ( dotCenterDist > 0.0 ) { const QPointF center( xm - sinA * dotCenterDist, ym - cosA * dotCenterDist ); QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth ); ellipse.moveCenter( center ); painter->setPen( Qt::NoPen ); painter->setBrush( palette().color( QPalette::ButtonText ) ); painter->drawEllipse( ellipse ); } break; } case Tick: { const double rb = qMax( radius - d_data->markerSize, 1.0 ); const double re = radius; const QLineF line( xm - sinA * rb, ym - cosA * rb, xm - sinA * re, ym - cosA * re ); QPen pen( palette().color( QPalette::ButtonText ), 0 ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); painter->drawLine ( line ); break; } #if 0 case Triangle: { const double rb = qMax( radius - d_data->markerSize, 1.0 ); const double re = radius; painter->translate( rect.center() ); painter->rotate( angle - 90.0 ); QPolygonF polygon; polygon += QPointF( re, 0.0 ); polygon += QPointF( rb, 0.5 * ( re - rb ) ); polygon += QPointF( rb, -0.5 * ( re - rb ) ); painter->setPen( Qt::NoPen ); painter->setBrush( palette().color( QPalette::Text ) ); painter->drawPolygon( polygon ); break; } #endif default: break; } } /*! \brief Change the knob's width. The specified width must be >= 5, or it will be clipped. \param width New width */ void QwtKnob::setKnobWidth( int width ) { d_data->knobWidth = qMax( width, 5 ); layoutKnob( true ); } //! Return the width of the knob int QwtKnob::knobWidth() const { return d_data->knobWidth; } /*! \brief Set the knob's border width \param borderWidth new border width */ void QwtKnob::setBorderWidth( int borderWidth ) { d_data->borderWidth = qMax( borderWidth, 0 ); layoutKnob( true ); } //! Return the border width int QwtKnob::borderWidth() const { return d_data->borderWidth; } /*! \brief Set the size of the marker \sa markerSize(), markerStyle() */ void QwtKnob::setMarkerSize( int size ) { if ( d_data->markerSize != size ) { d_data->markerSize = size; update(); } } //! Return the marker size int QwtKnob::markerSize() const { return d_data->markerSize; } /*! \brief Recalculate the marker angle corresponding to the current value */ void QwtKnob::recalcAngle() { // calculate the angle corresponding to the value if ( maxValue() == minValue() ) { d_data->angle = 0; d_data->nTurns = 0; } else { d_data->angle = ( value() - 0.5 * ( minValue() + maxValue() ) ) / ( maxValue() - minValue() ) * d_data->totalAngle; d_data->nTurns = qFloor( ( d_data->angle + 180.0 ) / 360.0 ); d_data->angle = d_data->angle - d_data->nTurns * 360.0; } } /*! Recalculates the layout \sa layoutKnob() */ void QwtKnob::scaleChange() { layoutKnob( true ); } /*! \return minimumSizeHint() */ QSize QwtKnob::sizeHint() const { const QSize hint = minimumSizeHint(); return hint.expandedTo( QApplication::globalStrut() ); } /*! \brief Return a minimum size hint \warning The return value of QwtKnob::minimumSizeHint() depends on the font and the scale. */ QSize QwtKnob::minimumSizeHint() const { // Add the scale radial thickness to the knobWidth const int sh = qCeil( scaleDraw()->extent( font() ) ); const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth; return QSize( d, d ); } pcp-gui-1.5.11/src/libqwt/qwt_legend.cpp0000644000000000000000000003114312176111212014753 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_legend.h" #include "qwt_legend_itemmanager.h" #include "qwt_legend_item.h" #include "qwt_dyngrid_layout.h" #include "qwt_math.h" #include #include #include #include class QwtLegend::PrivateData { public: class LegendMap { public: void insert( const QwtLegendItemManager *, QWidget * ); void remove( const QwtLegendItemManager * ); void remove( QWidget * ); void clear(); uint count() const; inline const QWidget *find( const QwtLegendItemManager * ) const; inline QWidget *find( const QwtLegendItemManager * ); inline const QwtLegendItemManager *find( const QWidget * ) const; inline QwtLegendItemManager *find( const QWidget * ); const QMap &widgetMap() const; QMap &widgetMap(); private: QMap d_widgetMap; QMap d_itemMap; }; QwtLegend::LegendItemMode itemMode; LegendMap map; class LegendView; LegendView *view; }; class QwtLegend::PrivateData::LegendView: public QScrollArea { public: LegendView( QWidget *parent ): QScrollArea( parent ) { setFocusPolicy( Qt::NoFocus ); contentsWidget = new QWidget( this ); contentsWidget->setObjectName( "QwtLegendViewContents" ); setWidget( contentsWidget ); setWidgetResizable( false ); viewport()->setObjectName( "QwtLegendViewport" ); // QScrollArea::setWidget internally sets autoFillBackground to true // But we don't want a background. contentsWidget->setAutoFillBackground( false ); viewport()->setAutoFillBackground( false ); } virtual bool viewportEvent( QEvent *e ) { bool ok = QScrollArea::viewportEvent( e ); if ( e->type() == QEvent::Resize ) { QEvent event( QEvent::LayoutRequest ); QApplication::sendEvent( contentsWidget, &event ); } return ok; } QSize viewportSize( int w, int h ) const { const int sbHeight = horizontalScrollBar()->sizeHint().height(); const int sbWidth = verticalScrollBar()->sizeHint().width(); const int cw = contentsRect().width(); const int ch = contentsRect().height(); int vw = cw; int vh = ch; if ( w > vw ) vh -= sbHeight; if ( h > vh ) { vw -= sbWidth; if ( w > vw && vh == ch ) vh -= sbHeight; } return QSize( vw, vh ); } QWidget *contentsWidget; }; void QwtLegend::PrivateData::LegendMap::insert( const QwtLegendItemManager *item, QWidget *widget ) { d_itemMap.insert( item, widget ); d_widgetMap.insert( widget, item ); } void QwtLegend::PrivateData::LegendMap::remove( const QwtLegendItemManager *item ) { QWidget *widget = d_itemMap[item]; d_itemMap.remove( item ); d_widgetMap.remove( widget ); } void QwtLegend::PrivateData::LegendMap::remove( QWidget *widget ) { const QwtLegendItemManager *item = d_widgetMap[widget]; d_itemMap.remove( item ); d_widgetMap.remove( widget ); } void QwtLegend::PrivateData::LegendMap::clear() { /* We can't delete the widgets in the following loop, because we would get ChildRemoved events, changing d_itemMap, while we are iterating. */ QList widgets; QMap::const_iterator it; for ( it = d_itemMap.begin(); it != d_itemMap.end(); ++it ) widgets.append( it.value() ); d_itemMap.clear(); d_widgetMap.clear(); for ( int i = 0; i < widgets.size(); i++ ) delete widgets[i]; } uint QwtLegend::PrivateData::LegendMap::count() const { return d_itemMap.count(); } inline const QWidget *QwtLegend::PrivateData::LegendMap::find( const QwtLegendItemManager *item ) const { if ( !d_itemMap.contains( item ) ) return NULL; return d_itemMap[item]; } inline QWidget *QwtLegend::PrivateData::LegendMap::find( const QwtLegendItemManager *item ) { if ( !d_itemMap.contains( item ) ) return NULL; return d_itemMap[item]; } inline const QwtLegendItemManager *QwtLegend::PrivateData::LegendMap::find( const QWidget *widget ) const { QWidget *w = const_cast( widget ); if ( !d_widgetMap.contains( w ) ) return NULL; return d_widgetMap[w]; } inline QwtLegendItemManager *QwtLegend::PrivateData::LegendMap::find( const QWidget *widget ) { QWidget *w = const_cast( widget ); if ( !d_widgetMap.contains( w ) ) return NULL; return const_cast( d_widgetMap[w] ); } inline const QMap & QwtLegend::PrivateData::LegendMap::widgetMap() const { return d_widgetMap; } inline QMap & QwtLegend::PrivateData::LegendMap::widgetMap() { return d_widgetMap; } /*! Constructor \param parent Parent widget */ QwtLegend::QwtLegend( QWidget *parent ): QFrame( parent ) { setFrameStyle( NoFrame ); d_data = new QwtLegend::PrivateData; d_data->itemMode = QwtLegend::ReadOnlyItem; d_data->view = new QwtLegend::PrivateData::LegendView( this ); d_data->view->setObjectName( "QwtLegendView" ); d_data->view->setFrameStyle( NoFrame ); QwtDynGridLayout *gridLayout = new QwtDynGridLayout( d_data->view->contentsWidget ); gridLayout->setAlignment( Qt::AlignHCenter | Qt::AlignTop ); d_data->view->contentsWidget->installEventFilter( this ); QVBoxLayout *layout = new QVBoxLayout( this ); layout->setContentsMargins( 0, 0, 0, 0 ); layout->addWidget( d_data->view ); } //! Destructor QwtLegend::~QwtLegend() { delete d_data; } //! \sa LegendItemMode void QwtLegend::setItemMode( LegendItemMode mode ) { d_data->itemMode = mode; } //! \sa LegendItemMode QwtLegend::LegendItemMode QwtLegend::itemMode() const { return d_data->itemMode; } /*! The contents widget is the only child of the viewport of the internal QScrollArea and the parent widget of all legend items. \return Container widget of the legend items */ QWidget *QwtLegend::contentsWidget() { return d_data->view->contentsWidget; } /*! \return Horizontal scrollbar \sa verticalScrollBar() */ QScrollBar *QwtLegend::horizontalScrollBar() const { return d_data->view->horizontalScrollBar(); } /*! \return Vertical scrollbar \sa horizontalScrollBar() */ QScrollBar *QwtLegend::verticalScrollBar() const { return d_data->view->verticalScrollBar(); } /*! The contents widget is the only child of the viewport of the internal QScrollArea and the parent widget of all legend items. \return Container widget of the legend items */ const QWidget *QwtLegend::contentsWidget() const { return d_data->view->contentsWidget; } /*! Insert a new item for a plot item \param plotItem Plot item \param legendItem New legend item \note The parent of item will be changed to contentsWidget() */ void QwtLegend::insert( const QwtLegendItemManager *plotItem, QWidget *legendItem ) { if ( legendItem == NULL || plotItem == NULL ) return; QWidget *contentsWidget = d_data->view->contentsWidget; if ( legendItem->parent() != contentsWidget ) legendItem->setParent( contentsWidget ); legendItem->show(); d_data->map.insert( plotItem, legendItem ); layoutContents(); if ( contentsWidget->layout() ) { contentsWidget->layout()->addWidget( legendItem ); // set tab focus chain QWidget *w = NULL; for ( int i = 0; i < contentsWidget->layout()->count(); i++ ) { QLayoutItem *item = contentsWidget->layout()->itemAt( i ); if ( w && item->widget() ) QWidget::setTabOrder( w, item->widget() ); w = item->widget(); } } if ( parentWidget() && parentWidget()->layout() == NULL ) { /* updateGeometry() doesn't post LayoutRequest in certain situations, like when we are hidden. But we want the parent widget notified, so it can show/hide the legend depending on its items. */ QApplication::postEvent( parentWidget(), new QEvent( QEvent::LayoutRequest ) ); } } /*! Find the widget that represents a plot item \param plotItem Plot item \return Widget on the legend, or NULL */ QWidget *QwtLegend::find( const QwtLegendItemManager *plotItem ) const { return d_data->map.find( plotItem ); } /*! Find the widget that represents a plot item \param legendItem Legend item \return Widget on the legend, or NULL */ QwtLegendItemManager *QwtLegend::find( const QWidget *legendItem ) const { return d_data->map.find( legendItem ); } /*! Find the corresponding item for a plotItem and remove it from the item list. \param plotItem Plot item */ void QwtLegend::remove( const QwtLegendItemManager *plotItem ) { QWidget *legendItem = d_data->map.find( plotItem ); d_data->map.remove( legendItem ); delete legendItem; } //! Remove all items. void QwtLegend::clear() { bool doUpdate = updatesEnabled(); if ( doUpdate ) setUpdatesEnabled( false ); d_data->map.clear(); if ( doUpdate ) setUpdatesEnabled( true ); update(); } //! Return a size hint. QSize QwtLegend::sizeHint() const { QSize hint = d_data->view->contentsWidget->sizeHint(); hint += QSize( 2 * frameWidth(), 2 * frameWidth() ); return hint; } /*! \return The preferred height, for the width w. \param width Width */ int QwtLegend::heightForWidth( int width ) const { width -= 2 * frameWidth(); int h = d_data->view->contentsWidget->heightForWidth( width ); if ( h >= 0 ) h += 2 * frameWidth(); return h; } /*! Adjust contents widget and item layout to the size of the viewport(). */ void QwtLegend::layoutContents() { const QSize visibleSize = d_data->view->viewport()->contentsRect().size(); const QwtDynGridLayout *tl = qobject_cast( d_data->view->contentsWidget->layout() ); if ( tl ) { const int minW = int( tl->maxItemWidth() ) + 2 * tl->margin(); int w = qMax( visibleSize.width(), minW ); int h = qMax( tl->heightForWidth( w ), visibleSize.height() ); const int vpWidth = d_data->view->viewportSize( w, h ).width(); if ( w > vpWidth ) { w = qMax( vpWidth, minW ); h = qMax( tl->heightForWidth( w ), visibleSize.height() ); } d_data->view->contentsWidget->resize( w, h ); } } /*! Handle QEvent::ChildRemoved andQEvent::LayoutRequest events for the contentsWidget(). \param object Object to be filtered \param event Event */ bool QwtLegend::eventFilter( QObject *object, QEvent *event ) { if ( object == d_data->view->contentsWidget ) { switch ( event->type() ) { case QEvent::ChildRemoved: { const QChildEvent *ce = static_cast(event); if ( ce->child()->isWidgetType() ) { QWidget *w = static_cast< QWidget * >( ce->child() ); d_data->map.remove( w ); } break; } case QEvent::LayoutRequest: { layoutContents(); break; } default: break; } } return QFrame::eventFilter( object, event ); } //! Return true, if there are no legend items. bool QwtLegend::isEmpty() const { return d_data->map.count() == 0; } //! Return the number of legend items. uint QwtLegend::itemCount() const { return d_data->map.count(); } //! Return a list of all legend items QList QwtLegend::legendItems() const { const QMap &map = d_data->map.widgetMap(); QList list; QMap::const_iterator it; for ( it = map.begin(); it != map.end(); ++it ) list += it.key(); return list; }pcp-gui-1.5.11/src/libqwt/qwt_legend_item.cpp0000644000000000000000000002152612176111212015775 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_legend_item.h" #include "qwt_math.h" #include "qwt_painter.h" #include "qwt_symbol.h" #include #include #include #include #include #include #include static const int PixmapHeight = 10; static const int PixmapWidth = 15; static const int ButtonFrame = 2; static const int Margin = 2; static QSize buttonShift( const QwtLegendItem *w ) { QStyleOption option; option.init( w ); const int ph = w->style()->pixelMetric( QStyle::PM_ButtonShiftHorizontal, &option, w ); const int pv = w->style()->pixelMetric( QStyle::PM_ButtonShiftVertical, &option, w ); return QSize( ph, pv ); } class QwtLegendItem::PrivateData { public: PrivateData(): itemMode( QwtLegend::ReadOnlyItem ), isDown( false ), identifierSize( PixmapWidth, PixmapHeight ), spacing( Margin ) { } QwtLegend::LegendItemMode itemMode; bool isDown; QSize identifierSize; QPixmap identifier; int spacing; }; /*! \param parent Parent widget */ QwtLegendItem::QwtLegendItem( QWidget *parent ): QwtTextLabel( parent ) { d_data = new PrivateData; setMargin( Margin ); setIndent( Margin + d_data->identifierSize.width() + 2 * d_data->spacing ); } //! Destructor QwtLegendItem::~QwtLegendItem() { delete d_data; d_data = NULL; } /*! Set the text to the legend item \param text Text label \sa QwtTextLabel::text() */ void QwtLegendItem::setText( const QwtText &text ) { const int flags = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextExpandTabs | Qt::TextWordWrap; QwtText txt = text; txt.setRenderFlags( flags ); QwtTextLabel::setText( txt ); } /*! Set the item mode The default is QwtLegend::ReadOnlyItem \param mode Item mode \sa itemMode() */ void QwtLegendItem::setItemMode( QwtLegend::LegendItemMode mode ) { if ( mode != d_data->itemMode ) { d_data->itemMode = mode; d_data->isDown = false; setFocusPolicy( mode != QwtLegend::ReadOnlyItem ? Qt::TabFocus : Qt::NoFocus ); setMargin( ButtonFrame + Margin ); updateGeometry(); } } /*! Return the item mode \sa setItemMode() */ QwtLegend::LegendItemMode QwtLegendItem::itemMode() const { return d_data->itemMode; } /*! Assign the identifier The identifier needs to be created according to the identifierWidth() \param identifier Pixmap representing a plot item \sa identifier(), identifierWidth() */ void QwtLegendItem::setIdentifier( const QPixmap &identifier ) { d_data->identifier = identifier; update(); } /*! \return pixmap representing a plot item \sa setIdentifier() */ QPixmap QwtLegendItem::identifier() const { return d_data->identifier; } /*! Set the size for the identifier Default is PixmapWidth x PixmapHeight pixels \param size New size \sa identifierSize() */ void QwtLegendItem::setIdentifierSize( const QSize &size ) { QSize sz = size.expandedTo( QSize( 0, 0 ) ); if ( sz != d_data->identifierSize ) { d_data->identifierSize = sz; setIndent( margin() + d_data->identifierSize.width() + 2 * d_data->spacing ); updateGeometry(); } } /*! Return the width of the identifier \sa setIdentifierSize() */ QSize QwtLegendItem::identifierSize() const { return d_data->identifierSize; } /*! Change the spacing \param spacing Spacing \sa spacing(), identifierWidth(), QwtTextLabel::margin() */ void QwtLegendItem::setSpacing( int spacing ) { spacing = qMax( spacing, 0 ); if ( spacing != d_data->spacing ) { d_data->spacing = spacing; setIndent( margin() + d_data->identifierSize.width() + 2 * d_data->spacing ); } } /*! Return the spacing \sa setSpacing(), identifierWidth(), QwtTextLabel::margin() */ int QwtLegendItem::spacing() const { return d_data->spacing; } /*! Check/Uncheck a the item \param on check/uncheck \sa setItemMode() */ void QwtLegendItem::setChecked( bool on ) { if ( d_data->itemMode == QwtLegend::CheckableItem ) { const bool isBlocked = signalsBlocked(); blockSignals( true ); setDown( on ); blockSignals( isBlocked ); } } //! Return true, if the item is checked bool QwtLegendItem::isChecked() const { return d_data->itemMode == QwtLegend::CheckableItem && isDown(); } //! Set the item being down void QwtLegendItem::setDown( bool down ) { if ( down == d_data->isDown ) return; d_data->isDown = down; update(); if ( d_data->itemMode == QwtLegend::ClickableItem ) { if ( d_data->isDown ) Q_EMIT pressed(); else { Q_EMIT released(); Q_EMIT clicked(); } } if ( d_data->itemMode == QwtLegend::CheckableItem ) Q_EMIT checked( d_data->isDown ); } //! Return true, if the item is down bool QwtLegendItem::isDown() const { return d_data->isDown; } //! Return a size hint QSize QwtLegendItem::sizeHint() const { QSize sz = QwtTextLabel::sizeHint(); sz.setHeight( qMax( sz.height(), d_data->identifier.height() + 4 ) ); if ( d_data->itemMode != QwtLegend::ReadOnlyItem ) { sz += buttonShift( this ); sz = sz.expandedTo( QApplication::globalStrut() ); } return sz; } //! Paint event void QwtLegendItem::paintEvent( QPaintEvent *e ) { const QRect cr = contentsRect(); QPainter painter( this ); painter.setClipRegion( e->region() ); if ( d_data->isDown ) { qDrawWinButton( &painter, 0, 0, width(), height(), palette(), true ); } painter.save(); if ( d_data->isDown ) { const QSize shiftSize = buttonShift( this ); painter.translate( shiftSize.width(), shiftSize.height() ); } painter.setClipRect( cr ); drawContents( &painter ); if ( !d_data->identifier.isNull() ) { QRect identRect = cr; identRect.setX( identRect.x() + margin() ); if ( d_data->itemMode != QwtLegend::ReadOnlyItem ) identRect.setX( identRect.x() + ButtonFrame ); identRect.setSize( d_data->identifier.size() ); identRect.moveCenter( QPoint( identRect.center().x(), cr.center().y() ) ); painter.drawPixmap( identRect, d_data->identifier ); } painter.restore(); } //! Handle mouse press events void QwtLegendItem::mousePressEvent( QMouseEvent *e ) { if ( e->button() == Qt::LeftButton ) { switch ( d_data->itemMode ) { case QwtLegend::ClickableItem: { setDown( true ); return; } case QwtLegend::CheckableItem: { setDown( !isDown() ); return; } default:; } } QwtTextLabel::mousePressEvent( e ); } //! Handle mouse release events void QwtLegendItem::mouseReleaseEvent( QMouseEvent *e ) { if ( e->button() == Qt::LeftButton ) { switch ( d_data->itemMode ) { case QwtLegend::ClickableItem: { setDown( false ); return; } case QwtLegend::CheckableItem: { return; // do nothing, but accept } default:; } } QwtTextLabel::mouseReleaseEvent( e ); } //! Handle key press events void QwtLegendItem::keyPressEvent( QKeyEvent *e ) { if ( e->key() == Qt::Key_Space ) { switch ( d_data->itemMode ) { case QwtLegend::ClickableItem: { if ( !e->isAutoRepeat() ) setDown( true ); return; } case QwtLegend::CheckableItem: { if ( !e->isAutoRepeat() ) setDown( !isDown() ); return; } default:; } } QwtTextLabel::keyPressEvent( e ); } //! Handle key release events void QwtLegendItem::keyReleaseEvent( QKeyEvent *e ) { if ( e->key() == Qt::Key_Space ) { switch ( d_data->itemMode ) { case QwtLegend::ClickableItem: { if ( !e->isAutoRepeat() ) setDown( false ); return; } case QwtLegend::CheckableItem: { return; // do nothing, but accept } default:; } } QwtTextLabel::keyReleaseEvent( e ); } pcp-gui-1.5.11/src/libqwt/qwt_magnifier.cpp0000644000000000000000000002561212176111212015462 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_magnifier.h" #include "qwt_math.h" #include #include class QwtMagnifier::PrivateData { public: PrivateData(): isEnabled( false ), wheelFactor( 0.9 ), wheelButtonState( Qt::NoButton ), mouseFactor( 0.95 ), mouseButton( Qt::RightButton ), mouseButtonState( Qt::NoButton ), keyFactor( 0.9 ), zoomInKey( Qt::Key_Plus ), zoomOutKey( Qt::Key_Minus ), zoomInKeyModifiers( Qt::NoModifier ), zoomOutKeyModifiers( Qt::NoModifier ), mousePressed( false ) { } bool isEnabled; double wheelFactor; int wheelButtonState; double mouseFactor; int mouseButton; int mouseButtonState; double keyFactor; int zoomInKey; int zoomOutKey; int zoomInKeyModifiers; int zoomOutKeyModifiers; bool mousePressed; bool hasMouseTracking; QPoint mousePos; }; /*! Constructor \param parent Widget to be magnified */ QwtMagnifier::QwtMagnifier( QWidget *parent ): QObject( parent ) { d_data = new PrivateData(); setEnabled( true ); } //! Destructor QwtMagnifier::~QwtMagnifier() { delete d_data; } /*! \brief En/disable the magnifier When enabled is true an event filter is installed for the observed widget, otherwise the event filter is removed. \param on true or false \sa isEnabled(), eventFilter() */ void QwtMagnifier::setEnabled( bool on ) { if ( d_data->isEnabled != on ) { d_data->isEnabled = on; QObject *o = parent(); if ( o ) { if ( d_data->isEnabled ) o->installEventFilter( this ); else o->removeEventFilter( this ); } } } /*! \return true when enabled, false otherwise \sa setEnabled(), eventFilter() */ bool QwtMagnifier::isEnabled() const { return d_data->isEnabled; } /*! \brief Change the wheel factor The wheel factor defines the ratio between the current range on the parent widget and the zoomed range for each step of the wheel. The default value is 0.9. \param factor Wheel factor \sa wheelFactor(), setWheelButtonState(), setMouseFactor(), setKeyFactor() */ void QwtMagnifier::setWheelFactor( double factor ) { d_data->wheelFactor = factor; } /*! \return Wheel factor \sa setWheelFactor() */ double QwtMagnifier::wheelFactor() const { return d_data->wheelFactor; } /*! Assign a mandatory button state for zooming in/out using the wheel. The default button state is Qt::NoButton. \param buttonState Button state \sa wheelButtonState() */ void QwtMagnifier::setWheelButtonState( int buttonState ) { d_data->wheelButtonState = buttonState; } /*! \return Wheel button state \sa setWheelButtonState() */ int QwtMagnifier::wheelButtonState() const { return d_data->wheelButtonState; } /*! \brief Change the mouse factor The mouse factor defines the ratio between the current range on the parent widget and the zoomed range for each vertical mouse movement. The default value is 0.95. \param factor Wheel factor \sa mouseFactor(), setMouseButton(), setWheelFactor(), setKeyFactor() */ void QwtMagnifier::setMouseFactor( double factor ) { d_data->mouseFactor = factor; } /*! \return Mouse factor \sa setMouseFactor() */ double QwtMagnifier::mouseFactor() const { return d_data->mouseFactor; } /*! Assign the mouse button, that is used for zooming in/out. The default value is Qt::RightButton. \param button Button \param buttonState Button state \sa getMouseButton() */ void QwtMagnifier::setMouseButton( int button, int buttonState ) { d_data->mouseButton = button; d_data->mouseButtonState = buttonState; } //! \sa setMouseButton() void QwtMagnifier::getMouseButton( int &button, int &buttonState ) const { button = d_data->mouseButton; buttonState = d_data->mouseButtonState; } /*! \brief Change the key factor The key factor defines the ratio between the current range on the parent widget and the zoomed range for each key press of the zoom in/out keys. The default value is 0.9. \param factor Key factor \sa keyFactor(), setZoomInKey(), setZoomOutKey(), setWheelFactor, setMouseFactor() */ void QwtMagnifier::setKeyFactor( double factor ) { d_data->keyFactor = factor; } /*! \return Key factor \sa setKeyFactor() */ double QwtMagnifier::keyFactor() const { return d_data->keyFactor; } /*! Assign the key, that is used for zooming in. The default combination is Qt::Key_Plus + Qt::NoModifier. \param key \param modifiers \sa getZoomInKey(), setZoomOutKey() */ void QwtMagnifier::setZoomInKey( int key, int modifiers ) { d_data->zoomInKey = key; d_data->zoomInKeyModifiers = modifiers; } //! \sa setZoomInKey() void QwtMagnifier::getZoomInKey( int &key, int &modifiers ) const { key = d_data->zoomInKey; modifiers = d_data->zoomInKeyModifiers; } /*! Assign the key, that is used for zooming out. The default combination is Qt::Key_Minus + Qt::NoModifier. \param key \param modifiers \sa getZoomOutKey(), setZoomOutKey() */ void QwtMagnifier::setZoomOutKey( int key, int modifiers ) { d_data->zoomOutKey = key; d_data->zoomOutKeyModifiers = modifiers; } //! \sa setZoomOutKey() void QwtMagnifier::getZoomOutKey( int &key, int &modifiers ) const { key = d_data->zoomOutKey; modifiers = d_data->zoomOutKeyModifiers; } /*! \brief Event filter When isEnabled() the mouse events of the observed widget are filtered. \param object Object to be filtered \param event Event \sa widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent() widgetKeyReleaseEvent() */ bool QwtMagnifier::eventFilter( QObject *object, QEvent *event ) { if ( object && object == parent() ) { switch ( event->type() ) { case QEvent::MouseButtonPress: { widgetMousePressEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseMove: { widgetMouseMoveEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent( ( QMouseEvent * )event ); break; } case QEvent::Wheel: { widgetWheelEvent( ( QWheelEvent * )event ); break; } case QEvent::KeyPress: { widgetKeyPressEvent( ( QKeyEvent * )event ); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent( ( QKeyEvent * )event ); break; } default:; } } return QObject::eventFilter( object, event ); } /*! Handle a mouse press event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseMoveEvent() */ void QwtMagnifier::widgetMousePressEvent( QMouseEvent *mouseEvent ) { if ( ( mouseEvent->button() != d_data->mouseButton) || parentWidget() == NULL ) { return; } if ( ( mouseEvent->modifiers() & Qt::KeyboardModifierMask ) != ( int )( d_data->mouseButtonState & Qt::KeyboardModifierMask ) ) { return; } d_data->hasMouseTracking = parentWidget()->hasMouseTracking(); parentWidget()->setMouseTracking( true ); d_data->mousePos = mouseEvent->pos(); d_data->mousePressed = true; } /*! Handle a mouse release event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseMoveEvent(), */ void QwtMagnifier::widgetMouseReleaseEvent( QMouseEvent *mouseEvent ) { Q_UNUSED( mouseEvent ); if ( d_data->mousePressed && parentWidget() ) { d_data->mousePressed = false; parentWidget()->setMouseTracking( d_data->hasMouseTracking ); } } /*! Handle a mouse move event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), */ void QwtMagnifier::widgetMouseMoveEvent( QMouseEvent *mouseEvent ) { if ( !d_data->mousePressed ) return; const int dy = mouseEvent->pos().y() - d_data->mousePos.y(); if ( dy != 0 ) { double f = d_data->mouseFactor; if ( dy < 0 ) f = 1 / f; rescale( f ); } d_data->mousePos = mouseEvent->pos(); } /*! Handle a wheel event for the observed widget. \param wheelEvent Wheel event \sa eventFilter() */ void QwtMagnifier::widgetWheelEvent( QWheelEvent *wheelEvent ) { if ( ( wheelEvent->modifiers() & Qt::KeyboardModifierMask ) != ( int )( d_data->wheelButtonState & Qt::KeyboardModifierMask ) ) { return; } if ( d_data->wheelFactor != 0.0 ) { /* A positive delta indicates that the wheel was rotated forwards away from the user; a negative value indicates that the wheel was rotated backwards toward the user. Most mouse types work in steps of 15 degrees, in which case the delta value is a multiple of 120 (== 15 * 8). */ double f = qPow( d_data->wheelFactor, qAbs( wheelEvent->delta() / 120.0 ) ); if ( wheelEvent->delta() > 0 ) f = 1 / f; rescale( f ); } } /*! Handle a key press event for the observed widget. \param keyEvent Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtMagnifier::widgetKeyPressEvent( QKeyEvent *keyEvent ) { const int key = keyEvent->key(); const int state = keyEvent->modifiers(); if ( key == d_data->zoomInKey && state == d_data->zoomInKeyModifiers ) { rescale( d_data->keyFactor ); } else if ( key == d_data->zoomOutKey && state == d_data->zoomOutKeyModifiers ) { rescale( 1.0 / d_data->keyFactor ); } } /*! Handle a key release event for the observed widget. \param keyEvent Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtMagnifier::widgetKeyReleaseEvent( QKeyEvent *keyEvent ) { Q_UNUSED( keyEvent ); } //! \return Parent widget, where the rescaling happens QWidget *QwtMagnifier::parentWidget() { return qobject_cast( parent() ); } //! \return Parent widget, where the rescaling happens const QWidget *QwtMagnifier::parentWidget() const { return qobject_cast( parent() ); } pcp-gui-1.5.11/src/libqwt/qwt_math.cpp0000644000000000000000000000203612176111212014445 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_math.h" /*! \brief Find the smallest value in an array \param array Pointer to an array \param size Array size */ double qwtGetMin( const double *array, int size ) { if ( size <= 0 ) return 0.0; double rv = array[0]; for ( int i = 1; i < size; i++ ) rv = qMin( rv, array[i] ); return rv; } /*! \brief Find the largest value in an array \param array Pointer to an array \param size Array size */ double qwtGetMax( const double *array, int size ) { if ( size <= 0 ) return 0.0; double rv = array[0]; for ( int i = 1; i < size; i++ ) rv = qMax( rv, array[i] ); return rv; } pcp-gui-1.5.11/src/libqwt/qwt_matrix_raster_data.cpp0000644000000000000000000001614012176111212017372 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_matrix_raster_data.h" #include #include class QwtMatrixRasterData::PrivateData { public: PrivateData(): resampleMode(QwtMatrixRasterData::NearestNeighbour), numColumns(0) { } inline double value(size_t row, size_t col) const { return values.data()[ row * numColumns + col ]; } QwtMatrixRasterData::ResampleMode resampleMode; QVector values; size_t numColumns; size_t numRows; double dx; double dy; }; //! Constructor QwtMatrixRasterData::QwtMatrixRasterData() { d_data = new PrivateData(); update(); } //! Destructor QwtMatrixRasterData::~QwtMatrixRasterData() { delete d_data; } /*! \brief Set the resampling algorithm \param mode Resampling mode \sa resampleMode(), value() */ void QwtMatrixRasterData::setResampleMode(ResampleMode mode) { d_data->resampleMode = mode; } /*! \return resampling algorithm \sa setResampleMode(), value() */ QwtMatrixRasterData::ResampleMode QwtMatrixRasterData::resampleMode() const { return d_data->resampleMode; } /*! \brief Assign the bounding interval for an axis Setting the bounding intervals for the X/Y axis is mandatory to define the positions for the values of the value matrix. The interval in Z direction defines the possible range for the values in the matrix, what is f.e used by QwtPlotSpectrogram to map values to colors. The Z-interval might be the bounding interval of the values in the matrix, but usually it isn't. ( f.e a interval of 0.0-100.0 for values in percentage ) \param axis X, Y or Z axis \param interval Interval \sa QwtRasterData::interval(), setValueMatrix() */ void QwtMatrixRasterData::setInterval( Qt::Axis axis, const QwtInterval &interval ) { QwtRasterData::setInterval( axis, interval ); update(); } /*! \brief Assign a value matrix The positions of the values are calculated by dividing the bounding rectangle of the X/Y intervals into equidistant rectangles ( pixels ). Each value corresponds to the center of a pixel. \param values Vector of values \param numColumns Number of columns \sa valueMatrix(), numColumns(), numRows(), setInterval()() */ void QwtMatrixRasterData::setValueMatrix( const QVector &values, size_t numColumns ) { d_data->values = values; d_data->numColumns = numColumns; update(); } /*! \return Value matrix \sa setValueMatrix(), numColumns(), numRows(), setInterval() */ const QVector QwtMatrixRasterData::valueMatrix() const { return d_data->values; } /*! \return Number of columns of the value matrix \sa valueMatrix(), numRows(), setValueMatrix() */ size_t QwtMatrixRasterData::numColumns() const { return d_data->numColumns; } /*! \return Number of rows of the value matrix \sa valueMatrix(), numColumns(), setValueMatrix() */ size_t QwtMatrixRasterData::numRows() const { return d_data->numRows; } /*! \brief Pixel hint - NearestNeighbour\n pixelHint() returns the surrounding pixel of the top left value in the matrix. - BilinearInterpolation\n Returns an empty rectangle recommending to render in target device ( f.e. screen ) resolution. \sa ResampleMode, setMatrix(), setInterval() */ QRectF QwtMatrixRasterData::pixelHint( const QRectF & ) const { QRectF rect; if ( d_data->resampleMode == NearestNeighbour ) { const QwtInterval intervalX = interval( Qt::XAxis ); const QwtInterval intervalY = interval( Qt::YAxis ); if ( intervalX.isValid() && intervalY.isValid() ) { rect = QRectF( intervalX.minValue(), intervalY.minValue(), d_data->dx, d_data->dy ); } } return rect; } /*! \return the value at a raster position \param x X value in plot coordinates \param y Y value in plot coordinates \sa ResampleMode */ double QwtMatrixRasterData::value( double x, double y ) const { const QwtInterval xInterval = interval( Qt::XAxis ); const QwtInterval yInterval = interval( Qt::YAxis ); if ( !( xInterval.contains(x) && yInterval.contains(y) ) ) return qQNaN(); double value; switch( d_data->resampleMode ) { case BilinearInterpolation: { int col1 = qRound( (x - xInterval.minValue() ) / d_data->dx ) - 1; int row1 = qRound( (y - yInterval.minValue() ) / d_data->dy ) - 1; int col2 = col1 + 1; int row2 = row1 + 1; if ( col1 < 0 ) col1 = col2; else if ( col2 >= (int)d_data->numColumns ) col2 = col1; if ( row1 < 0 ) row1 = row2; else if ( row2 >= (int)d_data->numRows ) row2 = row1; const double v11 = d_data->value( row1, col1 ); const double v21 = d_data->value( row1, col2 ); const double v12 = d_data->value( row2, col1 ); const double v22 = d_data->value( row2, col2 ); const double x2 = xInterval.minValue() + ( col2 + 0.5 ) * d_data->dx; const double y2 = yInterval.minValue() + ( row2 + 0.5 ) * d_data->dy; const double rx = ( x2 - x ) / d_data->dx; const double ry = ( y2 - y ) / d_data->dy; const double vr1 = rx * v11 + ( 1.0 - rx ) * v21; const double vr2 = rx * v12 + ( 1.0 - rx ) * v22; value = ry * vr1 + ( 1.0 - ry ) * vr2; break; } case NearestNeighbour: default: { uint row = uint( (y - yInterval.minValue() ) / d_data->dy ); uint col = uint( (x - xInterval.minValue() ) / d_data->dx ); // In case of intervals, where the maximum is included // we get out of bound for row/col, when the value for the // maximum is requested. Instead we return the value // from the last row/col if ( row >= d_data->numRows ) row = d_data->numRows - 1; if ( col >= d_data->numColumns ) col = d_data->numColumns - 1; value = d_data->value( row, col ); } } return value; } void QwtMatrixRasterData::update() { d_data->numRows = 0; d_data->dx = 0.0; d_data->dy = 0.0; if ( d_data->numColumns > 0 ) { d_data->numRows = d_data->values.size() / d_data->numColumns; const QwtInterval xInterval = interval( Qt::XAxis ); const QwtInterval yInterval = interval( Qt::YAxis ); if ( xInterval.isValid() ) d_data->dx = xInterval.width() / d_data->numColumns; if ( yInterval.isValid() ) d_data->dy = yInterval.width() / d_data->numRows; } } pcp-gui-1.5.11/src/libqwt/qwt_null_paintdevice.cpp0000644000000000000000000002273612176111212017052 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_null_paintdevice.h" #include #include class QwtNullPaintDevice::PrivateData { public: PrivateData(): size( 0, 0 ) { } QSize size; }; class QwtNullPaintDevice::PaintEngine: public QPaintEngine { public: PaintEngine( QPaintEngine::PaintEngineFeatures ); virtual bool begin( QPaintDevice * ); virtual bool end(); virtual Type type () const; virtual void updateState(const QPaintEngineState &); virtual void drawRects(const QRect *, int ); virtual void drawRects(const QRectF *, int ); virtual void drawLines(const QLine *, int ); virtual void drawLines(const QLineF *, int ); virtual void drawEllipse(const QRectF &); virtual void drawEllipse(const QRect &); virtual void drawPath(const QPainterPath &); virtual void drawPoints(const QPointF *, int ); virtual void drawPoints(const QPoint *, int ); virtual void drawPolygon(const QPointF *, int , PolygonDrawMode ); virtual void drawPolygon(const QPoint *, int , PolygonDrawMode ); virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &); virtual void drawTextItem(const QPointF &, const QTextItem &); virtual void drawTiledPixmap(const QRectF &, const QPixmap &, const QPointF &s); virtual void drawImage(const QRectF &, const QImage &, const QRectF &, Qt::ImageConversionFlags ); private: QwtNullPaintDevice *d_device; }; QwtNullPaintDevice::PaintEngine::PaintEngine( QPaintEngine::PaintEngineFeatures features ): QPaintEngine( features ), d_device(NULL) { } bool QwtNullPaintDevice::PaintEngine::begin( QPaintDevice *device ) { d_device = static_cast( device ); return true; } bool QwtNullPaintDevice::PaintEngine::end() { d_device = NULL; return true; } QPaintEngine::Type QwtNullPaintDevice::PaintEngine::type () const { return QPaintEngine::User; } void QwtNullPaintDevice::PaintEngine::drawRects( const QRect *rects, int rectCount) { if ( d_device ) d_device->drawRects( rects, rectCount ); } void QwtNullPaintDevice::PaintEngine::drawRects( const QRectF *rects, int rectCount) { if ( d_device ) d_device->drawRects( rects, rectCount ); } void QwtNullPaintDevice::PaintEngine::drawLines( const QLine *lines, int lineCount) { if ( d_device ) d_device->drawLines( lines, lineCount ); } void QwtNullPaintDevice::PaintEngine::drawLines( const QLineF *lines, int lineCount) { if ( d_device ) d_device->drawLines( lines, lineCount ); } void QwtNullPaintDevice::PaintEngine::drawEllipse( const QRectF &rect) { if ( d_device ) d_device->drawEllipse( rect ); } void QwtNullPaintDevice::PaintEngine::drawEllipse( const QRect &rect) { if ( d_device ) d_device->drawEllipse( rect ); } void QwtNullPaintDevice::PaintEngine::drawPath( const QPainterPath &path) { if ( d_device ) d_device->drawPath( path ); } void QwtNullPaintDevice::PaintEngine::drawPoints( const QPointF *points, int pointCount) { if ( d_device ) d_device->drawPoints( points, pointCount ); } void QwtNullPaintDevice::PaintEngine::drawPoints( const QPoint *points, int pointCount) { if ( d_device ) d_device->drawPoints( points, pointCount ); } void QwtNullPaintDevice::PaintEngine::drawPolygon( const QPointF *points, int pointCount, PolygonDrawMode mode) { if ( d_device ) d_device->drawPolygon( points, pointCount, mode ); } void QwtNullPaintDevice::PaintEngine::drawPolygon( const QPoint *points, int pointCount, PolygonDrawMode mode) { if ( d_device ) d_device->drawPolygon( points, pointCount, mode ); } void QwtNullPaintDevice::PaintEngine::drawPixmap( const QRectF &rect, const QPixmap &pm, const QRectF &subRect ) { if ( d_device ) d_device->drawPixmap( rect, pm, subRect ); } void QwtNullPaintDevice::PaintEngine::drawTextItem( const QPointF &pos, const QTextItem &textItem) { if ( d_device ) d_device->drawTextItem( pos, textItem ); } void QwtNullPaintDevice::PaintEngine::drawTiledPixmap( const QRectF &rect, const QPixmap &pixmap, const QPointF &subRect) { if ( d_device ) d_device->drawTiledPixmap( rect, pixmap, subRect ); } void QwtNullPaintDevice::PaintEngine::drawImage( const QRectF &rect, const QImage &image, const QRectF &subRect, Qt::ImageConversionFlags flags) { if ( d_device ) d_device->drawImage( rect, image, subRect, flags ); } void QwtNullPaintDevice::PaintEngine::updateState( const QPaintEngineState &state) { if ( d_device ) d_device->updateState( state ); } //! Constructor QwtNullPaintDevice::QwtNullPaintDevice( QPaintEngine::PaintEngineFeatures features ) { init( features ); } //! Constructor QwtNullPaintDevice::QwtNullPaintDevice( const QSize &size, QPaintEngine::PaintEngineFeatures features ) { init( features ); d_data->size = size; } void QwtNullPaintDevice::init( QPaintEngine::PaintEngineFeatures features ) { d_engine = new PaintEngine( features ); d_data = new PrivateData; } //! Destructor QwtNullPaintDevice::~QwtNullPaintDevice() { delete d_engine; delete d_data; } /*! Set the size of the paint device \param size Size \sa size() */ void QwtNullPaintDevice::setSize( const QSize & size ) { d_data->size = size; } /*! \return Size of the paint device \sa setSize() */ QSize QwtNullPaintDevice::size() const { return d_data->size; } //! See QPaintDevice::paintEngine() QPaintEngine *QwtNullPaintDevice::paintEngine() const { return d_engine; } /*! See QPaintDevice::metric() \sa setSize() */ int QwtNullPaintDevice::metric( PaintDeviceMetric metric ) const { static QPixmap pm; int value; switch ( metric ) { case PdmWidth: value = qMax( d_data->size.width(), 0 ); break; case PdmHeight: value = qMax( d_data->size.height(), 0 ); break; case PdmNumColors: value = 16777216; break; case PdmDepth: value = 24; break; case PdmPhysicalDpiX: case PdmDpiY: case PdmPhysicalDpiY: case PdmWidthMM: case PdmHeightMM: case PdmDpiX: default: value = 0; } return value; } //! See QPaintEngine::drawRects() void QwtNullPaintDevice::drawRects( const QRect *rects, int rectCount) { Q_UNUSED(rects); Q_UNUSED(rectCount); } //! See QPaintEngine::drawRects() void QwtNullPaintDevice::drawRects( const QRectF *rects, int rectCount) { Q_UNUSED(rects); Q_UNUSED(rectCount); } //! See QPaintEngine::drawLines() void QwtNullPaintDevice::drawLines( const QLine *lines, int lineCount) { Q_UNUSED(lines); Q_UNUSED(lineCount); } //! See QPaintEngine::drawLines() void QwtNullPaintDevice::drawLines( const QLineF *lines, int lineCount) { Q_UNUSED(lines); Q_UNUSED(lineCount); } //! See QPaintEngine::drawEllipse() void QwtNullPaintDevice::drawEllipse( const QRectF &rect ) { Q_UNUSED(rect); } //! See QPaintEngine::drawEllipse() void QwtNullPaintDevice::drawEllipse( const QRect &rect ) { Q_UNUSED(rect); } //! See QPaintEngine::drawPath() void QwtNullPaintDevice::drawPath( const QPainterPath &path ) { Q_UNUSED(path); } //! See QPaintEngine::drawPoints() void QwtNullPaintDevice::drawPoints( const QPointF *points, int pointCount) { Q_UNUSED(points); Q_UNUSED(pointCount); } //! See QPaintEngine::drawPoints() void QwtNullPaintDevice::drawPoints( const QPoint *points, int pointCount) { Q_UNUSED(points); Q_UNUSED(pointCount); } //! See QPaintEngine::drawPolygon() void QwtNullPaintDevice::drawPolygon( const QPointF *points, int pointCount, QPaintEngine::PolygonDrawMode mode) { Q_UNUSED(points); Q_UNUSED(pointCount); Q_UNUSED(mode); } //! See QPaintEngine::drawPolygon() void QwtNullPaintDevice::drawPolygon( const QPoint *points, int pointCount, QPaintEngine::PolygonDrawMode mode) { Q_UNUSED(points); Q_UNUSED(pointCount); Q_UNUSED(mode); } //! See QPaintEngine::drawPixmap() void QwtNullPaintDevice::drawPixmap( const QRectF &rect, const QPixmap &pm, const QRectF &subRect ) { Q_UNUSED(rect); Q_UNUSED(pm); Q_UNUSED(subRect); } //! See QPaintEngine::drawTextItem() void QwtNullPaintDevice::drawTextItem( const QPointF &pos, const QTextItem &textItem) { Q_UNUSED(pos); Q_UNUSED(textItem); } //! See QPaintEngine::drawTiledPixmap() void QwtNullPaintDevice::drawTiledPixmap( const QRectF &rect, const QPixmap &pixmap, const QPointF &subRect) { Q_UNUSED(rect); Q_UNUSED(pixmap); Q_UNUSED(subRect); } //! See QPaintEngine::drawImage() void QwtNullPaintDevice::drawImage( const QRectF &rect, const QImage &image, const QRectF &subRect, Qt::ImageConversionFlags flags) { Q_UNUSED(rect); Q_UNUSED(image); Q_UNUSED(subRect); Q_UNUSED(flags); } //! See QPaintEngine::updateState() void QwtNullPaintDevice::updateState( const QPaintEngineState &state ) { Q_UNUSED(state); } pcp-gui-1.5.11/src/libqwt/qwt_painter.cpp0000644000000000000000000005144112176111212015162 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_painter.h" #include "qwt_math.h" #include "qwt_clipper.h" #include "qwt_color_map.h" #include "qwt_scale_map.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool QwtPainter::d_polylineSplitting = true; bool QwtPainter::d_roundingAlignment = true; static inline bool isClippingNeeded( const QPainter *painter, QRectF &clipRect ) { bool doClipping = false; const QPaintEngine *pe = painter->paintEngine(); if ( pe && pe->type() == QPaintEngine::SVG ) { // The SVG paint engine ignores any clipping, if ( painter->hasClipping() ) { doClipping = true; clipRect = painter->clipRegion().boundingRect(); } } return doClipping; } static inline void drawPolyline( QPainter *painter, const QPointF *points, int pointCount, bool polylineSplitting ) { bool doSplit = false; if ( polylineSplitting ) { const QPaintEngine *pe = painter->paintEngine(); if ( pe && pe->type() == QPaintEngine::Raster ) { /* The raster paint engine seems to use some algo with O(n*n). ( Qt 4.3 is better than Qt 4.2, but remains unacceptable) To work around this problem, we have to split the polygon into smaller pieces. */ doSplit = true; } } if ( doSplit ) { const int splitSize = 20; for ( int i = 0; i < pointCount; i += splitSize ) { const int n = qMin( splitSize + 1, pointCount - i ); painter->drawPolyline( points + i, n ); } } else painter->drawPolyline( points, pointCount ); } static inline void unscaleFont( QPainter *painter ) { if ( painter->font().pixelSize() >= 0 ) return; static QSize screenResolution; if ( !screenResolution.isValid() ) { QDesktopWidget *desktop = QApplication::desktop(); if ( desktop ) { screenResolution.setWidth( desktop->logicalDpiX() ); screenResolution.setHeight( desktop->logicalDpiY() ); } } const QPaintDevice *pd = painter->device(); if ( pd->logicalDpiX() != screenResolution.width() || pd->logicalDpiY() != screenResolution.height() ) { QFont pixelFont( painter->font(), QApplication::desktop() ); pixelFont.setPixelSize( QFontInfo( pixelFont ).pixelSize() ); painter->setFont( pixelFont ); } } /*! Check if the painter is using a paint engine, that aligns coordinates to integers. Today these are all paint engines beside QPaintEngine::Pdf and QPaintEngine::SVG. \param painter Painter \return true, when the paint engine is aligning \sa setRoundingAlignment() */ bool QwtPainter::isAligning( QPainter *painter ) { if ( painter && painter->isActive() ) { switch ( painter->paintEngine()->type() ) { case QPaintEngine::Pdf: case QPaintEngine::SVG: return false; default:; } } return true; } /*! Enable whether coordinates should be rounded, before they are painted to a paint engine that floors to integer values. For other paint engines this ( Pdf, SVG ), this flag has no effect. QwtPainter stores this flag only, the rounding itsself is done in the painting code ( f.e the plot items ). The default setting is true. \sa roundingAlignment(), isAligning() */ void QwtPainter::setRoundingAlignment( bool enable ) { d_roundingAlignment = enable; } /*! \brief En/Disable line splitting for the raster paint engine The raster paint engine paints polylines of many points much faster when they are splitted in smaller chunks. \sa polylineSplitting() */ void QwtPainter::setPolylineSplitting( bool enable ) { d_polylineSplitting = enable; } //! Wrapper for QPainter::drawPath() void QwtPainter::drawPath( QPainter *painter, const QPainterPath &path ) { painter->drawPath( path ); } //! Wrapper for QPainter::drawRect() void QwtPainter::drawRect( QPainter *painter, double x, double y, double w, double h ) { drawRect( painter, QRectF( x, y, w, h ) ); } //! Wrapper for QPainter::drawRect() void QwtPainter::drawRect( QPainter *painter, const QRectF &rect ) { const QRectF r = rect; QRectF clipRect; const bool deviceClipping = isClippingNeeded( painter, clipRect ); if ( deviceClipping ) { if ( !clipRect.intersects( r ) ) return; if ( !clipRect.contains( r ) ) { fillRect( painter, r & clipRect, painter->brush() ); painter->save(); painter->setBrush( Qt::NoBrush ); drawPolyline( painter, QPolygonF( r ) ); painter->restore(); return; } } painter->drawRect( r ); } //! Wrapper for QPainter::fillRect() void QwtPainter::fillRect( QPainter *painter, const QRectF &rect, const QBrush &brush ) { if ( !rect.isValid() ) return; QRectF clipRect; const bool deviceClipping = isClippingNeeded( painter, clipRect ); /* Performance of Qt4 is horrible for non trivial brushs. Without clipping expect minutes or hours for repainting large rects (might result from zooming) */ if ( deviceClipping ) clipRect &= painter->window(); else clipRect = painter->window(); if ( painter->hasClipping() ) clipRect &= painter->clipRegion().boundingRect(); QRectF r = rect; if ( deviceClipping ) r = r.intersect( clipRect ); if ( r.isValid() ) painter->fillRect( r, brush ); } //! Wrapper for QPainter::drawPie() void QwtPainter::drawPie( QPainter *painter, const QRectF &rect, int a, int alen ) { QRectF clipRect; const bool deviceClipping = isClippingNeeded( painter, clipRect ); if ( deviceClipping && !clipRect.contains( rect ) ) return; painter->drawPie( rect, a, alen ); } //! Wrapper for QPainter::drawEllipse() void QwtPainter::drawEllipse( QPainter *painter, const QRectF &rect ) { QRectF clipRect; const bool deviceClipping = isClippingNeeded( painter, clipRect ); if ( deviceClipping && !clipRect.contains( rect ) ) return; painter->drawEllipse( rect ); } //! Wrapper for QPainter::drawText() void QwtPainter::drawText( QPainter *painter, double x, double y, const QString &text ) { drawText( painter, QPointF( x, y ), text ); } //! Wrapper for QPainter::drawText() void QwtPainter::drawText( QPainter *painter, const QPointF &pos, const QString &text ) { QRectF clipRect; const bool deviceClipping = isClippingNeeded( painter, clipRect ); if ( deviceClipping && !clipRect.contains( pos ) ) return; painter->save(); unscaleFont( painter ); painter->drawText( pos, text ); painter->restore(); } //! Wrapper for QPainter::drawText() void QwtPainter::drawText( QPainter *painter, double x, double y, double w, double h, int flags, const QString &text ) { drawText( painter, QRectF( x, y, w, h ), flags, text ); } //! Wrapper for QPainter::drawText() void QwtPainter::drawText( QPainter *painter, const QRectF &rect, int flags, const QString &text ) { painter->save(); unscaleFont( painter ); painter->drawText( rect, flags, text ); painter->restore(); } #ifndef QT_NO_RICHTEXT /*! Draw a text document into a rectangle \param painter Painter \param rect Traget rectangle \param flags Alignments/Text flags, see QPainter::drawText() \param text Text document */ void QwtPainter::drawSimpleRichText( QPainter *painter, const QRectF &rect, int flags, const QTextDocument &text ) { QTextDocument *txt = text.clone(); painter->save(); painter->setFont( txt->defaultFont() ); unscaleFont( painter ); txt->setDefaultFont( painter->font() ); txt->setPageSize( QSizeF( rect.width(), QWIDGETSIZE_MAX ) ); QAbstractTextDocumentLayout* layout = txt->documentLayout(); const double height = layout->documentSize().height(); double y = rect.y(); if ( flags & Qt::AlignBottom ) y += ( rect.height() - height ); else if ( flags & Qt::AlignVCenter ) y += ( rect.height() - height ) / 2; QAbstractTextDocumentLayout::PaintContext context; context.palette.setColor( QPalette::Text, painter->pen().color() ); painter->translate( rect.x(), y ); layout->draw( painter, context ); painter->restore(); delete txt; } #endif // !QT_NO_RICHTEXT //! Wrapper for QPainter::drawLine() void QwtPainter::drawLine( QPainter *painter, const QPointF &p1, const QPointF &p2 ) { QRectF clipRect; const bool deviceClipping = isClippingNeeded( painter, clipRect ); if ( deviceClipping && !( clipRect.contains( p1 ) && clipRect.contains( p2 ) ) ) { QPolygonF polygon; polygon += p1; polygon += p2; drawPolyline( painter, polygon ); return; } painter->drawLine( p1, p2 ); } //! Wrapper for QPainter::drawPolygon() void QwtPainter::drawPolygon( QPainter *painter, const QPolygonF &polygon ) { QRectF clipRect; const bool deviceClipping = isClippingNeeded( painter, clipRect ); QPolygonF cpa = polygon; if ( deviceClipping ) cpa = QwtClipper::clipPolygonF( clipRect, polygon ); painter->drawPolygon( cpa ); } //! Wrapper for QPainter::drawPolyline() void QwtPainter::drawPolyline( QPainter *painter, const QPolygonF &polygon ) { QRectF clipRect; const bool deviceClipping = isClippingNeeded( painter, clipRect ); QPolygonF cpa = polygon; if ( deviceClipping ) cpa = QwtClipper::clipPolygonF( clipRect, cpa ); ::drawPolyline( painter, cpa.constData(), cpa.size(), d_polylineSplitting ); } //! Wrapper for QPainter::drawPolyline() void QwtPainter::drawPolyline( QPainter *painter, const QPointF *points, int pointCount ) { QRectF clipRect; const bool deviceClipping = isClippingNeeded( painter, clipRect ); if ( deviceClipping ) { QPolygonF polygon( pointCount ); qMemCopy( polygon.data(), points, pointCount * sizeof( QPointF ) ); polygon = QwtClipper::clipPolygonF( clipRect, polygon ); ::drawPolyline( painter, polygon.constData(), polygon.size(), d_polylineSplitting ); } else ::drawPolyline( painter, points, pointCount, d_polylineSplitting ); } //! Wrapper for QPainter::drawPoint() void QwtPainter::drawPoint( QPainter *painter, const QPointF &pos ) { QRectF clipRect; const bool deviceClipping = isClippingNeeded( painter, clipRect ); if ( deviceClipping && !clipRect.contains( pos ) ) return; painter->drawPoint( pos ); } //! Wrapper for QPainter::drawImage() void QwtPainter::drawImage( QPainter *painter, const QRectF &rect, const QImage &image ) { const QRect alignedRect = rect.toAlignedRect(); if ( alignedRect != rect ) { const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 ); painter->save(); painter->setClipRect( clipRect, Qt::IntersectClip ); painter->drawImage( alignedRect, image ); painter->restore(); } else { painter->drawImage( alignedRect, image ); } } //! Wrapper for QPainter::drawPixmap() void QwtPainter::drawPixmap( QPainter *painter, const QRectF &rect, const QPixmap &pixmap ) { const QRect alignedRect = rect.toAlignedRect(); if ( alignedRect != rect ) { const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 ); painter->save(); painter->setClipRect( clipRect, Qt::IntersectClip ); painter->drawPixmap( alignedRect, pixmap ); painter->restore(); } else { painter->drawPixmap( alignedRect, pixmap ); } } //! Draw a focus rectangle on a widget using its style. void QwtPainter::drawFocusRect( QPainter *painter, QWidget *widget ) { drawFocusRect( painter, widget, widget->rect() ); } //! Draw a focus rectangle on a widget using its style. void QwtPainter::drawFocusRect( QPainter *painter, QWidget *widget, const QRect &rect ) { QStyleOptionFocusRect opt; opt.init( widget ); opt.rect = rect; opt.state |= QStyle::State_HasFocus; widget->style()->drawPrimitive( QStyle::PE_FrameFocusRect, &opt, painter, widget ); } /*! Draw a frame with rounded borders \param painter Painter \param rect Frame rectangle \param xRadius x-radius of the ellipses defining the corners \param yRadius y-radius of the ellipses defining the corners \param palette QPalette::WindowText is used for plain borders QPalette::Dark and QPalette::Light for raised or sunken borders \param lineWidth Line width \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow */ void QwtPainter::drawRoundedFrame( QPainter *painter, const QRectF &rect, double xRadius, double yRadius, const QPalette &palette, int lineWidth, int frameStyle ) { painter->save(); painter->setRenderHint( QPainter::Antialiasing, true ); painter->setBrush( Qt::NoBrush ); double lw2 = lineWidth * 0.5; QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 ); QPainterPath path; path.addRoundedRect( r, xRadius, yRadius ); enum Style { Plain, Sunken, Raised }; Style style = Plain; if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken ) style = Sunken; else if ( (frameStyle & QFrame::Raised) == QFrame::Raised ) style = Raised; if ( style != Plain && path.elementCount() == 17 ) { // move + 4 * ( cubicTo + lineTo ) QPainterPath pathList[8]; for ( int i = 0; i < 4; i++ ) { const int j = i * 4 + 1; pathList[ 2 * i ].moveTo( path.elementAt(j - 1).x, path.elementAt( j - 1 ).y ); pathList[ 2 * i ].cubicTo( path.elementAt(j + 0).x, path.elementAt(j + 0).y, path.elementAt(j + 1).x, path.elementAt(j + 1).y, path.elementAt(j + 2).x, path.elementAt(j + 2).y ); pathList[ 2 * i + 1 ].moveTo( path.elementAt(j + 2).x, path.elementAt(j + 2).y ); pathList[ 2 * i + 1 ].lineTo( path.elementAt(j + 3).x, path.elementAt(j + 3).y ); } QColor c1( palette.color( QPalette::Dark ) ); QColor c2( palette.color( QPalette::Light ) ); if ( style == Raised ) qSwap( c1, c2 ); for ( int i = 0; i < 4; i++ ) { QRectF r = pathList[2 * i].controlPointRect(); QPen arcPen; arcPen.setWidth( lineWidth ); QPen linePen; linePen.setWidth( lineWidth ); switch( i ) { case 0: { arcPen.setColor( c1 ); linePen.setColor( c1 ); break; } case 1: { QLinearGradient gradient; gradient.setStart( r.topLeft() ); gradient.setFinalStop( r.bottomRight() ); gradient.setColorAt( 0.0, c1 ); gradient.setColorAt( 1.0, c2 ); arcPen.setBrush( gradient ); linePen.setColor( c2 ); break; } case 2: { arcPen.setColor( c2 ); linePen.setColor( c2 ); break; } case 3: { QLinearGradient gradient; gradient.setStart( r.bottomRight() ); gradient.setFinalStop( r.topLeft() ); gradient.setColorAt( 0.0, c2 ); gradient.setColorAt( 1.0, c1 ); arcPen.setBrush( gradient ); linePen.setColor( c1 ); break; } } painter->setPen( arcPen ); painter->drawPath( pathList[ 2 * i] ); painter->setPen( linePen ); painter->drawPath( pathList[ 2 * i + 1] ); } } else { QPen pen( palette.color( QPalette::WindowText ), lineWidth ); painter->setPen( pen ); painter->drawPath( path ); } painter->restore(); } /*! Draw a color bar into a rectangle \param painter Painter \param colorMap Color map \param interval Value range \param scaleMap Scale map \param orientation Orientation \param rect Traget rectangle */ void QwtPainter::drawColorBar( QPainter *painter, const QwtColorMap &colorMap, const QwtInterval &interval, const QwtScaleMap &scaleMap, Qt::Orientation orientation, const QRectF &rect ) { QVector colorTable; if ( colorMap.format() == QwtColorMap::Indexed ) colorTable = colorMap.colorTable( interval ); QColor c; const QRect devRect = rect.toAlignedRect(); /* We paint to a pixmap first to have something scalable for printing ( f.e. in a Pdf document ) */ QPixmap pixmap( devRect.size() ); QPainter pmPainter( &pixmap ); pmPainter.translate( -devRect.x(), -devRect.y() ); if ( orientation == Qt::Horizontal ) { QwtScaleMap sMap = scaleMap; sMap.setPaintInterval( rect.left(), rect.right() ); for ( int x = devRect.left(); x <= devRect.right(); x++ ) { const double value = sMap.invTransform( x ); if ( colorMap.format() == QwtColorMap::RGB ) c.setRgb( colorMap.rgb( interval, value ) ); else c = colorTable[colorMap.colorIndex( interval, value )]; pmPainter.setPen( c ); pmPainter.drawLine( x, devRect.top(), x, devRect.bottom() ); } } else // Vertical { QwtScaleMap sMap = scaleMap; sMap.setPaintInterval( rect.bottom(), rect.top() ); for ( int y = devRect.top(); y <= devRect.bottom(); y++ ) { const double value = sMap.invTransform( y ); if ( colorMap.format() == QwtColorMap::RGB ) c.setRgb( colorMap.rgb( interval, value ) ); else c = colorTable[colorMap.colorIndex( interval, value )]; pmPainter.setPen( c ); pmPainter.drawLine( devRect.left(), y, devRect.right(), y ); } } pmPainter.end(); drawPixmap( painter, rect, pixmap ); } #if QT_VERSION >= 0x050000 static inline void qwtFillRect(QPainter *painter, const QRect &rect, const QBrush &brush) { if ( brush.style() == Qt::TexturePattern ) { painter->setClipRect( rect ); painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); } else if (brush.gradient() && brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode) { painter->save(); painter->setClipRect( rect ); painter->fillRect(0, 0, painter->device()->width(), painter->device()->height(), brush); painter->restore(); } else { painter->fillRect(rect, brush); } } void QwtPainter::fillPixmap( const QWidget *widget, QPixmap &pixmap, const QPoint &offset ) { // Qwt 5.0.0 Alpha offers an empty dummy implementation // of QPixmap::fill, that does nothing helpful beside converting // a compiler into a runtime error const QRect rect( offset, pixmap.size() ); QPainter painter( &pixmap ); painter.translate( -offset ); const QBrush autoFillBrush = widget->palette().brush( widget->backgroundRole() ); if ( !( widget->autoFillBackground() && autoFillBrush.isOpaque() ) ) { const QBrush bg = widget->palette().brush( QPalette::Window ); qwtFillRect( &painter, rect, bg); } if ( widget->autoFillBackground() ) qwtFillRect( &painter, rect, autoFillBrush); if ( widget->testAttribute(Qt::WA_StyledBackground) ) { painter.setClipRegion( rect ); QStyleOption opt; opt.initFrom( widget ); widget->style()->drawPrimitive( QStyle::PE_Widget, &opt, &painter, widget ); } } #endif // QT_VERSION >= 0x050000 pcp-gui-1.5.11/src/libqwt/qwt_panner.cpp0000644000000000000000000002766012176111212015011 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_panner.h" #include "qwt_picker.h" #if QT_VERSION >= 0x050000 #include "qwt_painter.h" #endif #include #include #include #include #include static QVector qwtActivePickers( QWidget *w ) { QVector pickers; QObjectList children = w->children(); for ( int i = 0; i < children.size(); i++ ) { QwtPicker *picker = qobject_cast( children[i] ); if ( picker && picker->isEnabled() ) pickers += picker; } return pickers; } class QwtPanner::PrivateData { public: PrivateData(): button( Qt::LeftButton ), buttonState( Qt::NoButton ), abortKey( Qt::Key_Escape ), abortKeyState( Qt::NoButton ), #ifndef QT_NO_CURSOR cursor( NULL ), restoreCursor( NULL ), hasCursor( false ), #endif isEnabled( false ) { orientations = Qt::Vertical | Qt::Horizontal; } ~PrivateData() { #ifndef QT_NO_CURSOR delete cursor; delete restoreCursor; #endif } int button; int buttonState; int abortKey; int abortKeyState; QPoint initialPos; QPoint pos; QPixmap pixmap; QBitmap contentsMask; #ifndef QT_NO_CURSOR QCursor *cursor; QCursor *restoreCursor; bool hasCursor; #endif bool isEnabled; Qt::Orientations orientations; }; /*! Creates an panner that is enabled for the left mouse button. \param parent Parent widget to be panned */ QwtPanner::QwtPanner( QWidget *parent ): QWidget( parent ) { d_data = new PrivateData(); setAttribute( Qt::WA_TransparentForMouseEvents ); setAttribute( Qt::WA_NoSystemBackground ); setFocusPolicy( Qt::NoFocus ); hide(); setEnabled( true ); } //! Destructor QwtPanner::~QwtPanner() { delete d_data; } /*! Change the mouse button The defaults are Qt::LeftButton and Qt::NoButton */ void QwtPanner::setMouseButton( int button, int buttonState ) { d_data->button = button; d_data->buttonState = buttonState; } //! Get the mouse button void QwtPanner::getMouseButton( int &button, int &buttonState ) const { button = d_data->button; buttonState = d_data->buttonState; } /*! Change the abort key The defaults are Qt::Key_Escape and Qt::NoButton \param key Key ( See Qt::Keycode ) \param state State */ void QwtPanner::setAbortKey( int key, int state ) { d_data->abortKey = key; d_data->abortKeyState = state; } //! Get the abort key void QwtPanner::getAbortKey( int &key, int &state ) const { key = d_data->abortKey; state = d_data->abortKeyState; } /*! Change the cursor, that is active while panning The default is the cursor of the parent widget. \param cursor New cursor \sa setCursor() */ #ifndef QT_NO_CURSOR void QwtPanner::setCursor( const QCursor &cursor ) { d_data->cursor = new QCursor( cursor ); } #endif /*! \return Cursor that is active while panning \sa setCursor() */ #ifndef QT_NO_CURSOR const QCursor QwtPanner::cursor() const { if ( d_data->cursor ) return *d_data->cursor; if ( parentWidget() ) return parentWidget()->cursor(); return QCursor(); } #endif /*! \brief En/disable the panner When enabled is true an event filter is installed for the observed widget, otherwise the event filter is removed. \param on true or false \sa isEnabled(), eventFilter() */ void QwtPanner::setEnabled( bool on ) { if ( d_data->isEnabled != on ) { d_data->isEnabled = on; QWidget *w = parentWidget(); if ( w ) { if ( d_data->isEnabled ) { w->installEventFilter( this ); } else { w->removeEventFilter( this ); hide(); } } } } /*! Set the orientations, where panning is enabled The default value is in both directions: Qt::Horizontal | Qt::Vertical /param o Orientation */ void QwtPanner::setOrientations( Qt::Orientations o ) { d_data->orientations = o; } //! Return the orientation, where paning is enabled Qt::Orientations QwtPanner::orientations() const { return d_data->orientations; } /*! Return true if a orientatio is enabled \sa orientations(), setOrientations() */ bool QwtPanner::isOrientationEnabled( Qt::Orientation o ) const { return d_data->orientations & o; } /*! \return true when enabled, false otherwise \sa setEnabled, eventFilter() */ bool QwtPanner::isEnabled() const { return d_data->isEnabled; } /*! \brief Paint event Repaint the grabbed pixmap on its current position and fill the empty spaces by the background of the parent widget. \param pe Paint event */ void QwtPanner::paintEvent( QPaintEvent *pe ) { int dx = d_data->pos.x() - d_data->initialPos.x(); int dy = d_data->pos.y() - d_data->initialPos.y(); QRect r( 0, 0, d_data->pixmap.width(), d_data->pixmap.height() ); r.moveCenter( QPoint( r.center().x() + dx, r.center().y() + dy ) ); QPixmap pm( size() ); #if QT_VERSION >= 0x050000 QwtPainter::fillPixmap( parentWidget(), pm ); #else pm.fill( parentWidget(), 0, 0 ); #endif QPainter painter( &pm ); if ( !d_data->contentsMask.isNull() ) { QPixmap masked = d_data->pixmap; masked.setMask( d_data->contentsMask ); painter.drawPixmap( r, masked ); } else { painter.drawPixmap( r, d_data->pixmap ); } painter.end(); if ( !d_data->contentsMask.isNull() ) pm.setMask( d_data->contentsMask ); painter.begin( this ); painter.setClipRegion( pe->region() ); painter.drawPixmap( 0, 0, pm ); } /*! \brief Calculate a mask for the contents of the panned widget Sometimes only parts of the contents of a widget should be panned. F.e. for a widget with a styled background with rounded borders only the area inside of the border should be panned. \return An empty bitmap, indicating no mask */ QBitmap QwtPanner::contentsMask() const { return QBitmap(); } /*! Grab the widget into a pixmap. */ QPixmap QwtPanner::grab() const { return QPixmap::grabWidget( parentWidget() ); } /*! \brief Event filter When isEnabled() the mouse events of the observed widget are filtered. \param object Object to be filtered \param event Event \sa widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseMoveEvent() */ bool QwtPanner::eventFilter( QObject *object, QEvent *event ) { if ( object == NULL || object != parentWidget() ) return false; switch ( event->type() ) { case QEvent::MouseButtonPress: { widgetMousePressEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseMove: { widgetMouseMoveEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent( ( QMouseEvent * )event ); break; } case QEvent::KeyPress: { widgetKeyPressEvent( ( QKeyEvent * )event ); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent( ( QKeyEvent * )event ); break; } case QEvent::Paint: { if ( isVisible() ) return true; break; } default:; } return false; } /*! Handle a mouse press event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseMoveEvent(), */ void QwtPanner::widgetMousePressEvent( QMouseEvent *mouseEvent ) { if ( mouseEvent->button() != d_data->button ) return; QWidget *w = parentWidget(); if ( w == NULL ) return; if ( ( mouseEvent->modifiers() & Qt::KeyboardModifierMask ) != ( int )( d_data->buttonState & Qt::KeyboardModifierMask ) ) { return; } #ifndef QT_NO_CURSOR showCursor( true ); #endif d_data->initialPos = d_data->pos = mouseEvent->pos(); setGeometry( parentWidget()->rect() ); // We don't want to grab the picker ! QVector pickers = qwtActivePickers( parentWidget() ); for ( int i = 0; i < pickers.size(); i++ ) pickers[i]->setEnabled( false ); d_data->pixmap = grab(); d_data->contentsMask = contentsMask(); for ( int i = 0; i < pickers.size(); i++ ) pickers[i]->setEnabled( true ); show(); } /*! Handle a mouse move event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent() */ void QwtPanner::widgetMouseMoveEvent( QMouseEvent *mouseEvent ) { if ( !isVisible() ) return; QPoint pos = mouseEvent->pos(); if ( !isOrientationEnabled( Qt::Horizontal ) ) pos.setX( d_data->initialPos.x() ); if ( !isOrientationEnabled( Qt::Vertical ) ) pos.setY( d_data->initialPos.y() ); if ( pos != d_data->pos && rect().contains( pos ) ) { d_data->pos = pos; update(); Q_EMIT moved( d_data->pos.x() - d_data->initialPos.x(), d_data->pos.y() - d_data->initialPos.y() ); } } /*! Handle a mouse release event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseMoveEvent(), */ void QwtPanner::widgetMouseReleaseEvent( QMouseEvent *mouseEvent ) { if ( isVisible() ) { hide(); #ifndef QT_NO_CURSOR showCursor( false ); #endif QPoint pos = mouseEvent->pos(); if ( !isOrientationEnabled( Qt::Horizontal ) ) pos.setX( d_data->initialPos.x() ); if ( !isOrientationEnabled( Qt::Vertical ) ) pos.setY( d_data->initialPos.y() ); d_data->pixmap = QPixmap(); d_data->contentsMask = QBitmap(); d_data->pos = pos; if ( d_data->pos != d_data->initialPos ) { Q_EMIT panned( d_data->pos.x() - d_data->initialPos.x(), d_data->pos.y() - d_data->initialPos.y() ); } } } /*! Handle a key press event for the observed widget. \param keyEvent Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtPanner::widgetKeyPressEvent( QKeyEvent *keyEvent ) { if ( keyEvent->key() == d_data->abortKey ) { const bool matched = ( keyEvent->modifiers() & Qt::KeyboardModifierMask ) == ( int )( d_data->abortKeyState & Qt::KeyboardModifierMask ); if ( matched ) { hide(); #ifndef QT_NO_CURSOR showCursor( false ); #endif d_data->pixmap = QPixmap(); } } } /*! Handle a key release event for the observed widget. \param keyEvent Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtPanner::widgetKeyReleaseEvent( QKeyEvent *keyEvent ) { Q_UNUSED( keyEvent ); } #ifndef QT_NO_CURSOR void QwtPanner::showCursor( bool on ) { if ( on == d_data->hasCursor ) return; QWidget *w = parentWidget(); if ( w == NULL || d_data->cursor == NULL ) return; d_data->hasCursor = on; if ( on ) { if ( w->testAttribute( Qt::WA_SetCursor ) ) { delete d_data->restoreCursor; d_data->restoreCursor = new QCursor( w->cursor() ); } w->setCursor( *d_data->cursor ); } else { if ( d_data->restoreCursor ) { w->setCursor( *d_data->restoreCursor ); delete d_data->restoreCursor; d_data->restoreCursor = NULL; } else w->unsetCursor(); } } #endif pcp-gui-1.5.11/src/libqwt/qwt_picker.cpp0000644000000000000000000010735012176111212014776 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_picker.h" #include "qwt_picker_machine.h" #include "qwt_painter.h" #include "qwt_math.h" #include #include #include #include #include #include #include #include #include class QwtPicker::PickerWidget: public QWidget { public: enum Type { RubberBand, Text }; PickerWidget( QwtPicker *, QWidget *, Type ); void updateMask(); /* For a tracker text with a background we can use the background rect as mask. Also for "regular" Qt widgets >= 4.3.0 we don't need to mask the text anymore. */ bool d_hasTextMask; protected: virtual void paintEvent( QPaintEvent * ); virtual void resizeEvent( QResizeEvent * ); QwtPicker *d_picker; Type d_type; }; class QwtPicker::PrivateData { public: bool enabled; QwtPickerMachine *stateMachine; QwtPicker::ResizeMode resizeMode; QwtPicker::RubberBand rubberBand; QPen rubberBandPen; QwtPicker::DisplayMode trackerMode; QPen trackerPen; QFont trackerFont; QPolygon pickedPoints; bool isActive; QPoint trackerPosition; bool mouseTracking; // used to save previous value /* On X11 the widget below the picker widgets gets paint events with a region that is the bounding rect of the mask, if it is complex. In case of (f.e) a CrossRubberBand and a text this creates complete repaints of the widget. So we better use two different widgets. */ QPointer rubberBandWidget; QPointer trackerWidget; }; QwtPicker::PickerWidget::PickerWidget( QwtPicker *picker, QWidget *parent, Type type ): QWidget( parent ), d_hasTextMask( false ), d_picker( picker ), d_type( type ) { setAttribute( Qt::WA_TransparentForMouseEvents ); setAttribute( Qt::WA_NoSystemBackground ); setFocusPolicy( Qt::NoFocus ); } void QwtPicker::PickerWidget::updateMask() { QRegion mask; if ( d_type == RubberBand ) { QBitmap bm( width(), height() ); bm.fill( Qt::color0 ); QPainter painter( &bm ); QPen pen = d_picker->rubberBandPen(); pen.setColor( Qt::color1 ); painter.setPen( pen ); d_picker->drawRubberBand( &painter ); mask = QRegion( bm ); } if ( d_type == Text ) { d_hasTextMask = parentWidget()->testAttribute( Qt::WA_PaintOnScreen ); if ( d_hasTextMask ) { const QwtText label = d_picker->trackerText( d_picker->trackerPosition() ); if ( label.testPaintAttribute( QwtText::PaintBackground ) && label.backgroundBrush().style() != Qt::NoBrush ) { if ( label.backgroundBrush().color().alpha() > 0 ) { // We don't need a text mask, when we have a background d_hasTextMask = false; } } } if ( d_hasTextMask ) { QBitmap bm( width(), height() ); bm.fill( Qt::color0 ); QPainter painter( &bm ); painter.setFont( font() ); QPen pen = d_picker->trackerPen(); pen.setColor( Qt::color1 ); painter.setPen( pen ); d_picker->drawTracker( &painter ); mask = QRegion( bm ); } else { mask = d_picker->trackerRect( font() ); } } QWidget *w = parentWidget(); if ( w && !w->testAttribute( Qt::WA_PaintOnScreen ) ) { // The parent widget gets an update for its complete rectangle // when the mask is changed in visible state. // With this hide/show we only get an update for the // previous mask. hide(); } setMask( mask ); setVisible( !mask.isEmpty() ); } void QwtPicker::PickerWidget::paintEvent( QPaintEvent *e ) { QPainter painter( this ); painter.setClipRegion( e->region() ); if ( d_type == RubberBand ) { painter.setPen( d_picker->rubberBandPen() ); d_picker->drawRubberBand( &painter ); } if ( d_type == Text ) { /* If we have a text mask we simply fill the region of the mask. This gives better results for antialiased fonts. */ if ( d_hasTextMask ) { painter.fillRect( e->rect(), QBrush( d_picker->trackerPen().color() ) ); } else { painter.setPen( d_picker->trackerPen() ); d_picker->drawTracker( &painter ); } } } void QwtPicker::PickerWidget::resizeEvent( QResizeEvent *event ) { QWidget::resizeEvent( event ); if ( isVisible() ) updateMask(); } /*! Constructor Creates an picker that is enabled, but without a state machine. rubberband and tracker are disabled. \param parent Parent widget, that will be observed */ QwtPicker::QwtPicker( QWidget *parent ): QObject( parent ) { init( parent, NoRubberBand, AlwaysOff ); } /*! Constructor \param rubberBand Rubberband style \param trackerMode Tracker mode \param parent Parent widget, that will be observed */ QwtPicker::QwtPicker( RubberBand rubberBand, DisplayMode trackerMode, QWidget *parent ): QObject( parent ) { init( parent, rubberBand, trackerMode ); } //! Destructor QwtPicker::~QwtPicker() { setMouseTracking( false ); delete d_data->stateMachine; delete d_data->rubberBandWidget; delete d_data->trackerWidget; delete d_data; } //! Init the picker, used by the constructors void QwtPicker::init( QWidget *parent, RubberBand rubberBand, DisplayMode trackerMode ) { d_data = new PrivateData; d_data->rubberBandWidget = NULL; d_data->trackerWidget = NULL; d_data->rubberBand = rubberBand; d_data->enabled = false; d_data->resizeMode = Stretch; d_data->trackerMode = AlwaysOff; d_data->isActive = false; d_data->trackerPosition = QPoint( -1, -1 ); d_data->mouseTracking = false; d_data->stateMachine = NULL; if ( parent ) { if ( parent->focusPolicy() == Qt::NoFocus ) parent->setFocusPolicy( Qt::WheelFocus ); d_data->trackerFont = parent->font(); d_data->mouseTracking = parent->hasMouseTracking(); setEnabled( true ); } setTrackerMode( trackerMode ); } /*! Set a state machine and delete the previous one \param stateMachine State machine \sa stateMachine() */ void QwtPicker::setStateMachine( QwtPickerMachine *stateMachine ) { if ( d_data->stateMachine != stateMachine ) { reset(); delete d_data->stateMachine; d_data->stateMachine = stateMachine; if ( d_data->stateMachine ) d_data->stateMachine->reset(); } } /*! \return Assigned state machine \sa setStateMachine() */ QwtPickerMachine *QwtPicker::stateMachine() { return d_data->stateMachine; } /*! \return Assigned state machine \sa setStateMachine() */ const QwtPickerMachine *QwtPicker::stateMachine() const { return d_data->stateMachine; } //! Return the parent widget, where the selection happens QWidget *QwtPicker::parentWidget() { QObject *obj = parent(); if ( obj && obj->isWidgetType() ) return static_cast( obj ); return NULL; } //! Return the parent widget, where the selection happens const QWidget *QwtPicker::parentWidget() const { QObject *obj = parent(); if ( obj && obj->isWidgetType() ) return static_cast< const QWidget *>( obj ); return NULL; } /*! Set the rubberband style \param rubberBand Rubberband style The default value is NoRubberBand. \sa rubberBand(), RubberBand, setRubberBandPen() */ void QwtPicker::setRubberBand( RubberBand rubberBand ) { d_data->rubberBand = rubberBand; } /*! \return Rubberband style \sa setRubberBand(), RubberBand, rubberBandPen() */ QwtPicker::RubberBand QwtPicker::rubberBand() const { return d_data->rubberBand; } /*! \brief Set the display mode of the tracker. A tracker displays information about current position of the cursor as a string. The display mode controls if the tracker has to be displayed whenever the observed widget has focus and cursor (AlwaysOn), never (AlwaysOff), or only when the selection is active (ActiveOnly). \param mode Tracker display mode \warning In case of AlwaysOn, mouseTracking will be enabled for the observed widget. \sa trackerMode(), DisplayMode */ void QwtPicker::setTrackerMode( DisplayMode mode ) { if ( d_data->trackerMode != mode ) { d_data->trackerMode = mode; setMouseTracking( d_data->trackerMode == AlwaysOn ); } } /*! \return Tracker display mode \sa setTrackerMode(), DisplayMode */ QwtPicker::DisplayMode QwtPicker::trackerMode() const { return d_data->trackerMode; } /*! \brief Set the resize mode. The resize mode controls what to do with the selected points of an active selection when the observed widget is resized. Stretch means the points are scaled according to the new size, KeepSize means the points remain unchanged. The default mode is Stretch. \param mode Resize mode \sa resizeMode(), ResizeMode */ void QwtPicker::setResizeMode( ResizeMode mode ) { d_data->resizeMode = mode; } /*! \return Resize mode \sa setResizeMode(), ResizeMode */ QwtPicker::ResizeMode QwtPicker::resizeMode() const { return d_data->resizeMode; } /*! \brief En/disable the picker When enabled is true an event filter is installed for the observed widget, otherwise the event filter is removed. \param enabled true or false \sa isEnabled(), eventFilter() */ void QwtPicker::setEnabled( bool enabled ) { if ( d_data->enabled != enabled ) { d_data->enabled = enabled; QWidget *w = parentWidget(); if ( w ) { if ( enabled ) w->installEventFilter( this ); else w->removeEventFilter( this ); } updateDisplay(); } } /*! \return true when enabled, false otherwise \sa setEnabled(), eventFilter() */ bool QwtPicker::isEnabled() const { return d_data->enabled; } /*! Set the font for the tracker \param font Tracker font \sa trackerFont(), setTrackerMode(), setTrackerPen() */ void QwtPicker::setTrackerFont( const QFont &font ) { if ( font != d_data->trackerFont ) { d_data->trackerFont = font; updateDisplay(); } } /*! \return Tracker font \sa setTrackerFont(), trackerMode(), trackerPen() */ QFont QwtPicker::trackerFont() const { return d_data->trackerFont; } /*! Set the pen for the tracker \param pen Tracker pen \sa trackerPen(), setTrackerMode(), setTrackerFont() */ void QwtPicker::setTrackerPen( const QPen &pen ) { if ( pen != d_data->trackerPen ) { d_data->trackerPen = pen; updateDisplay(); } } /*! \return Tracker pen \sa setTrackerPen(), trackerMode(), trackerFont() */ QPen QwtPicker::trackerPen() const { return d_data->trackerPen; } /*! Set the pen for the rubberband \param pen Rubberband pen \sa rubberBandPen(), setRubberBand() */ void QwtPicker::setRubberBandPen( const QPen &pen ) { if ( pen != d_data->rubberBandPen ) { d_data->rubberBandPen = pen; updateDisplay(); } } /*! \return Rubberband pen \sa setRubberBandPen(), rubberBand() */ QPen QwtPicker::rubberBandPen() const { return d_data->rubberBandPen; } /*! \brief Return the label for a position In case of HLineRubberBand the label is the value of the y position, in case of VLineRubberBand the value of the x position. Otherwise the label contains x and y position separated by a ',' . The format for the string conversion is "%d". \param pos Position \return Converted position as string */ QwtText QwtPicker::trackerText( const QPoint &pos ) const { QString label; switch ( rubberBand() ) { case HLineRubberBand: label.sprintf( "%d", pos.y() ); break; case VLineRubberBand: label.sprintf( "%d", pos.x() ); break; default: label.sprintf( "%d, %d", pos.x(), pos.y() ); } return label; } /*! Draw a rubberband, depending on rubberBand() \param painter Painter, initialized with clip rect \sa rubberBand(), RubberBand */ void QwtPicker::drawRubberBand( QPainter *painter ) const { if ( !isActive() || rubberBand() == NoRubberBand || rubberBandPen().style() == Qt::NoPen ) { return; } const QRect &pRect = pickRect(); const QPolygon pa = adjustedPoints( d_data->pickedPoints ); QwtPickerMachine::SelectionType selectionType = QwtPickerMachine::NoSelection; if ( d_data->stateMachine ) selectionType = d_data->stateMachine->selectionType(); switch ( selectionType ) { case QwtPickerMachine::NoSelection: case QwtPickerMachine::PointSelection: { if ( pa.count() < 1 ) return; const QPoint pos = pa[0]; switch ( rubberBand() ) { case VLineRubberBand: QwtPainter::drawLine( painter, pos.x(), pRect.top(), pos.x(), pRect.bottom() ); break; case HLineRubberBand: QwtPainter::drawLine( painter, pRect.left(), pos.y(), pRect.right(), pos.y() ); break; case CrossRubberBand: QwtPainter::drawLine( painter, pos.x(), pRect.top(), pos.x(), pRect.bottom() ); QwtPainter::drawLine( painter, pRect.left(), pos.y(), pRect.right(), pos.y() ); break; default: break; } break; } case QwtPickerMachine::RectSelection: { if ( pa.count() < 2 ) return; const QPoint p1 = pa[0]; const QPoint p2 = pa[int( pa.count() - 1 )]; const QRect rect = QRect( p1, p2 ).normalized(); switch ( rubberBand() ) { case EllipseRubberBand: QwtPainter::drawEllipse( painter, rect ); break; case RectRubberBand: QwtPainter::drawRect( painter, rect ); break; default: break; } break; } case QwtPickerMachine::PolygonSelection: { if ( rubberBand() == PolygonRubberBand ) painter->drawPolyline( pa ); break; } default: break; } } /*! Draw the tracker \param painter Painter \sa trackerRect(), trackerText() */ void QwtPicker::drawTracker( QPainter *painter ) const { const QRect textRect = trackerRect( painter->font() ); if ( !textRect.isEmpty() ) { const QwtText label = trackerText( d_data->trackerPosition ); if ( !label.isEmpty() ) label.draw( painter, textRect ); } } /*! \brief Map the pickedPoints() into a selection() adjustedPoints() maps the points, that have been collected on the parentWidget() into a selection(). The default implementation simply returns the points unmodified. The reason, why a selection() differs from the picked points depends on the application requirements. F.e. : - A rectangular selection might need to have a specific aspect ratio only.\n - A selection could accept non intersecting polygons only.\n - ...\n The example below is for a rectangular selection, where the first point is the center of the selected rectangle. \par Example \verbatim QPolygon MyPicker::adjustedPoints(const QPolygon &points) const { QPolygon adjusted; if ( points.size() == 2 ) { const int width = qAbs(points[1].x() - points[0].x()); const int height = qAbs(points[1].y() - points[0].y()); QRect rect(0, 0, 2 * width, 2 * height); rect.moveCenter(points[0]); adjusted += rect.topLeft(); adjusted += rect.bottomRight(); } return adjusted; }\endverbatim\n */ QPolygon QwtPicker::adjustedPoints( const QPolygon &points ) const { return points; } /*! \return Selected points \sa pickedPoints(), adjustedPoints() */ QPolygon QwtPicker::selection() const { return adjustedPoints( d_data->pickedPoints ); } //! \return Current position of the tracker QPoint QwtPicker::trackerPosition() const { return d_data->trackerPosition; } /*! Calculate the bounding rectangle for the tracker text from the current position of the tracker \param font Font of the tracker text \return Bounding rectangle of the tracker text \sa trackerPosition() */ QRect QwtPicker::trackerRect( const QFont &font ) const { if ( trackerMode() == AlwaysOff || ( trackerMode() == ActiveOnly && !isActive() ) ) { return QRect(); } if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 ) return QRect(); QwtText text = trackerText( d_data->trackerPosition ); if ( text.isEmpty() ) return QRect(); const QSizeF textSize = text.textSize( font ); QRect textRect( 0, 0, qCeil( textSize.width() ), qCeil( textSize.height() ) ); const QPoint &pos = d_data->trackerPosition; int alignment = 0; if ( isActive() && d_data->pickedPoints.count() > 1 && rubberBand() != NoRubberBand ) { const QPoint last = d_data->pickedPoints[int( d_data->pickedPoints.count() ) - 2]; alignment |= ( pos.x() >= last.x() ) ? Qt::AlignRight : Qt::AlignLeft; alignment |= ( pos.y() > last.y() ) ? Qt::AlignBottom : Qt::AlignTop; } else alignment = Qt::AlignTop | Qt::AlignRight; const int margin = 5; int x = pos.x(); if ( alignment & Qt::AlignLeft ) x -= textRect.width() + margin; else if ( alignment & Qt::AlignRight ) x += margin; int y = pos.y(); if ( alignment & Qt::AlignBottom ) y += margin; else if ( alignment & Qt::AlignTop ) y -= textRect.height() + margin; textRect.moveTopLeft( QPoint( x, y ) ); int right = qMin( textRect.right(), pickRect().right() - margin ); int bottom = qMin( textRect.bottom(), pickRect().bottom() - margin ); textRect.moveBottomRight( QPoint( right, bottom ) ); int left = qMax( textRect.left(), pickRect().left() + margin ); int top = qMax( textRect.top(), pickRect().top() + margin ); textRect.moveTopLeft( QPoint( left, top ) ); return textRect; } /*! \brief Event filter When isEnabled() == true all events of the observed widget are filtered. Mouse and keyboard events are translated into widgetMouse- and widgetKey- and widgetWheel-events. Paint and Resize events are handled to keep rubberband and tracker up to date. \param object Object to be filtered \param event Event \sa widgetEnterEvent(), widgetLeaveEvent(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent(), QObject::installEventFilter(), QObject::event() */ bool QwtPicker::eventFilter( QObject *object, QEvent *event ) { if ( object && object == parentWidget() ) { switch ( event->type() ) { case QEvent::Resize: { const QResizeEvent *re = ( QResizeEvent * )event; if ( d_data->resizeMode == Stretch ) stretchSelection( re->oldSize(), re->size() ); if ( d_data->rubberBandWidget ) d_data->rubberBandWidget->resize( re->size() ); if ( d_data->trackerWidget ) d_data->trackerWidget->resize( re->size() ); break; } case QEvent::Enter: { widgetEnterEvent( event ); break; } case QEvent::Leave: { widgetLeaveEvent( event ); break; } case QEvent::MouseButtonPress: { widgetMousePressEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseButtonDblClick: { widgetMouseDoubleClickEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseMove: { widgetMouseMoveEvent( ( QMouseEvent * )event ); break; } case QEvent::KeyPress: { widgetKeyPressEvent( ( QKeyEvent * )event ); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent( ( QKeyEvent * )event ); break; } case QEvent::Wheel: { widgetWheelEvent( ( QWheelEvent * )event ); break; } default: break; } } return false; } /*! Handle a mouse press event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMousePressEvent( QMouseEvent *mouseEvent ) { transition( mouseEvent ); } /*! Handle a mouse move event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMouseMoveEvent( QMouseEvent *mouseEvent ) { if ( pickRect().contains( mouseEvent->pos() ) ) d_data->trackerPosition = mouseEvent->pos(); else d_data->trackerPosition = QPoint( -1, -1 ); if ( !isActive() ) updateDisplay(); transition( mouseEvent ); } /*! Handle a enter event for the observed widget. \param event Qt event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetEnterEvent( QEvent *event ) { transition( event ); } /*! Handle a leave event for the observed widget. \param event Qt event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetLeaveEvent( QEvent *event ) { transition( event ); d_data->trackerPosition = QPoint( -1, -1 ); if ( !isActive() ) updateDisplay(); } /*! Handle a mouse relase event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMouseReleaseEvent( QMouseEvent *mouseEvent ) { transition( mouseEvent ); } /*! Handle mouse double click event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMouseDoubleClickEvent( QMouseEvent *mouseEvent ) { transition( mouseEvent ); } /*! Handle a wheel event for the observed widget. Move the last point of the selection in case of isActive() == true \param wheelEvent Wheel event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetWheelEvent( QWheelEvent *wheelEvent ) { if ( pickRect().contains( wheelEvent->pos() ) ) d_data->trackerPosition = wheelEvent->pos(); else d_data->trackerPosition = QPoint( -1, -1 ); updateDisplay(); transition( wheelEvent ); } /*! Handle a key press event for the observed widget. Selections can be completely done by the keyboard. The arrow keys move the cursor, the abort key aborts a selection. All other keys are handled by the current state machine. \param keyEvent Key event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyReleaseEvent(), stateMachine(), QwtEventPattern::KeyPatternCode */ void QwtPicker::widgetKeyPressEvent( QKeyEvent *keyEvent ) { int dx = 0; int dy = 0; int offset = 1; if ( keyEvent->isAutoRepeat() ) offset = 5; if ( keyMatch( KeyLeft, keyEvent ) ) dx = -offset; else if ( keyMatch( KeyRight, keyEvent ) ) dx = offset; else if ( keyMatch( KeyUp, keyEvent ) ) dy = -offset; else if ( keyMatch( KeyDown, keyEvent ) ) dy = offset; else if ( keyMatch( KeyAbort, keyEvent ) ) { reset(); } else transition( keyEvent ); if ( dx != 0 || dy != 0 ) { const QRect rect = pickRect(); const QPoint pos = parentWidget()->mapFromGlobal( QCursor::pos() ); int x = pos.x() + dx; x = qMax( rect.left(), x ); x = qMin( rect.right(), x ); int y = pos.y() + dy; y = qMax( rect.top(), y ); y = qMin( rect.bottom(), y ); QCursor::setPos( parentWidget()->mapToGlobal( QPoint( x, y ) ) ); } } /*! Handle a key release event for the observed widget. Passes the event to the state machine. \param keyEvent Key event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), stateMachine() */ void QwtPicker::widgetKeyReleaseEvent( QKeyEvent *keyEvent ) { transition( keyEvent ); } /*! Passes an event to the state machine and executes the resulting commands. Append and Move commands use the current position of the cursor (QCursor::pos()). \param event Event */ void QwtPicker::transition( const QEvent *event ) { if ( !d_data->stateMachine ) return; const QList commandList = d_data->stateMachine->transition( *this, event ); QPoint pos; switch ( event->type() ) { case QEvent::MouseButtonDblClick: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: { const QMouseEvent *me = static_cast< const QMouseEvent * >( event ); pos = me->pos(); break; } default: pos = parentWidget()->mapFromGlobal( QCursor::pos() ); } for ( int i = 0; i < commandList.count(); i++ ) { switch ( commandList[i] ) { case QwtPickerMachine::Begin: { begin(); break; } case QwtPickerMachine::Append: { append( pos ); break; } case QwtPickerMachine::Move: { move( pos ); break; } case QwtPickerMachine::Remove: { remove(); break; } case QwtPickerMachine::End: { end(); break; } } } } /*! Open a selection setting the state to active \sa isActive(), end(), append(), move() */ void QwtPicker::begin() { if ( d_data->isActive ) return; d_data->pickedPoints.resize( 0 ); d_data->isActive = true; Q_EMIT activated( true ); if ( trackerMode() != AlwaysOff ) { if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 ) { QWidget *w = parentWidget(); if ( w ) d_data->trackerPosition = w->mapFromGlobal( QCursor::pos() ); } } updateDisplay(); setMouseTracking( true ); } /*! \brief Close a selection setting the state to inactive. The selection is validated and maybe fixed by accept(). \param ok If true, complete the selection and emit a selected signal otherwise discard the selection. \return true if the selection is accepted, false otherwise \sa isActive(), begin(), append(), move(), selected(), accept() */ bool QwtPicker::end( bool ok ) { if ( d_data->isActive ) { setMouseTracking( false ); d_data->isActive = false; Q_EMIT activated( false ); if ( trackerMode() == ActiveOnly ) d_data->trackerPosition = QPoint( -1, -1 ); if ( ok ) ok = accept( d_data->pickedPoints ); if ( ok ) Q_EMIT selected( d_data->pickedPoints ); else d_data->pickedPoints.resize( 0 ); updateDisplay(); } else ok = false; return ok; } /*! Reset the state machine and terminate (end(false)) the selection */ void QwtPicker::reset() { if ( d_data->stateMachine ) d_data->stateMachine->reset(); if ( isActive() ) end( false ); } /*! Append a point to the selection and update rubberband and tracker. The appended() signal is emitted. \param pos Additional point \sa isActive(), begin(), end(), move(), appended() */ void QwtPicker::append( const QPoint &pos ) { if ( d_data->isActive ) { const int idx = d_data->pickedPoints.count(); d_data->pickedPoints.resize( idx + 1 ); d_data->pickedPoints[idx] = pos; updateDisplay(); Q_EMIT appended( pos ); } } /*! Move the last point of the selection The moved() signal is emitted. \param pos New position \sa isActive(), begin(), end(), append() */ void QwtPicker::move( const QPoint &pos ) { if ( d_data->isActive ) { const int idx = d_data->pickedPoints.count() - 1; if ( idx >= 0 ) { if ( d_data->pickedPoints[idx] != pos ) { d_data->pickedPoints[idx] = pos; updateDisplay(); Q_EMIT moved( pos ); } } } } /*! Remove the last point of the selection The removed() signal is emitted. \sa isActive(), begin(), end(), append(), move() */ void QwtPicker::remove() { if ( d_data->isActive ) { const int idx = d_data->pickedPoints.count() - 1; if ( idx > 0 ) { const int idx = d_data->pickedPoints.count(); const QPoint pos = d_data->pickedPoints[idx - 1]; d_data->pickedPoints.resize( idx - 1 ); updateDisplay(); Q_EMIT removed( pos ); } } } /*! \brief Validate and fixup the selection Accepts all selections unmodified \param selection Selection to validate and fixup \return true, when accepted, false otherwise */ bool QwtPicker::accept( QPolygon &selection ) const { Q_UNUSED( selection ); return true; } /*! A picker is active between begin() and end(). \return true if the selection is active. */ bool QwtPicker::isActive() const { return d_data->isActive; } /*! Return the points, that have been collected so far. The selection() is calculated from the pickedPoints() in adjustedPoints(). \return Picked points */ const QPolygon &QwtPicker::pickedPoints() const { return d_data->pickedPoints; } /*! Scale the selection by the ratios of oldSize and newSize The changed() signal is emitted. \param oldSize Previous size \param newSize Current size \sa ResizeMode, setResizeMode(), resizeMode() */ void QwtPicker::stretchSelection( const QSize &oldSize, const QSize &newSize ) { if ( oldSize.isEmpty() ) { // avoid division by zero. But scaling for small sizes also // doesn't make much sense, because of rounding losses. TODO ... return; } const double xRatio = double( newSize.width() ) / double( oldSize.width() ); const double yRatio = double( newSize.height() ) / double( oldSize.height() ); for ( int i = 0; i < int( d_data->pickedPoints.count() ); i++ ) { QPoint &p = d_data->pickedPoints[i]; p.setX( qRound( p.x() * xRatio ) ); p.setY( qRound( p.y() * yRatio ) ); Q_EMIT changed( d_data->pickedPoints ); } } /*! Set mouse tracking for the observed widget. In case of enable is true, the previous value is saved, that is restored when enable is false. \warning Even when enable is false, mouse tracking might be restored to true. When mouseTracking for the observed widget has been changed directly by QWidget::setMouseTracking while mouse tracking has been set to true, this value can't be restored. */ void QwtPicker::setMouseTracking( bool enable ) { QWidget *widget = parentWidget(); if ( !widget ) return; if ( enable ) { d_data->mouseTracking = widget->hasMouseTracking(); widget->setMouseTracking( true ); } else { widget->setMouseTracking( d_data->mouseTracking ); } } /*! Find the area of the observed widget, where selection might happen. \return parentWidget()->contentsRect() */ QRect QwtPicker::pickRect() const { const QWidget *widget = parentWidget(); if ( widget ) return widget->contentsRect(); return QRect(); } //! Update the state of rubberband and tracker label void QwtPicker::updateDisplay() { QWidget *w = parentWidget(); bool showRubberband = false; bool showTracker = false; if ( w && w->isVisible() && d_data->enabled ) { if ( rubberBand() != NoRubberBand && isActive() && rubberBandPen().style() != Qt::NoPen ) { showRubberband = true; } if ( trackerMode() == AlwaysOn || ( trackerMode() == ActiveOnly && isActive() ) ) { if ( trackerPen() != Qt::NoPen ) showTracker = true; } } QPointer &rw = d_data->rubberBandWidget; if ( showRubberband ) { if ( rw.isNull() ) { rw = new PickerWidget( this, w, PickerWidget::RubberBand ); rw->setObjectName( "PickerRubberBand" ); rw->resize( w->size() ); } rw->updateMask(); rw->update(); // Needed, when the mask doesn't change } else delete rw; QPointer &tw = d_data->trackerWidget; if ( showTracker ) { if ( tw.isNull() ) { tw = new PickerWidget( this, w, PickerWidget::Text ); tw->setObjectName( "PickerTracker" ); tw->resize( w->size() ); } tw->setFont( d_data->trackerFont ); tw->updateMask(); tw->update(); // Needed, when the mask doesn't change } else delete tw; } //! \return Widget displaying the rubberband const QWidget *QwtPicker::rubberBandWidget() const { return d_data->rubberBandWidget; } //! \return Widget displaying the tracker text const QWidget *QwtPicker::trackerWidget() const { return d_data->trackerWidget; } pcp-gui-1.5.11/src/libqwt/qwt_picker_machine.cpp0000644000000000000000000002607012176111212016461 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_picker_machine.h" #include "qwt_event_pattern.h" #include //! Constructor QwtPickerMachine::QwtPickerMachine( SelectionType type ): d_selectionType( type ), d_state( 0 ) { } //! Destructor QwtPickerMachine::~QwtPickerMachine() { } //! Return the selection type QwtPickerMachine::SelectionType QwtPickerMachine::selectionType() const { return d_selectionType; } //! Return the current state int QwtPickerMachine::state() const { return d_state; } //! Change the current state void QwtPickerMachine::setState( int state ) { d_state = state; } //! Set the current state to 0. void QwtPickerMachine::reset() { setState( 0 ); } //! Constructor QwtPickerTrackerMachine::QwtPickerTrackerMachine(): QwtPickerMachine( NoSelection ) { } //! Transition QList QwtPickerTrackerMachine::transition( const QwtEventPattern &, const QEvent *e ) { QList cmdList; switch ( e->type() ) { case QEvent::Enter: case QEvent::MouseMove: { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } else { cmdList += Move; } break; } case QEvent::Leave: { cmdList += Remove; cmdList += End; setState( 0 ); } default: break; } return cmdList; } //! Constructor QwtPickerClickPointMachine::QwtPickerClickPointMachine(): QwtPickerMachine( PointSelection ) { } //! Transition QList QwtPickerClickPointMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) ) { cmdList += Begin; cmdList += Append; cmdList += End; } break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, ( const QKeyEvent * )event ) ) { cmdList += Begin; cmdList += Append; cmdList += End; } break; } default: break; } return cmdList; } //! Constructor QwtPickerDragPointMachine::QwtPickerDragPointMachine(): QwtPickerMachine( PointSelection ) { } //! Transition QList QwtPickerDragPointMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::MouseButtonRelease: { if ( state() != 0 ) { cmdList += End; setState( 0 ); } break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, ( const QKeyEvent * )event ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } else { cmdList += End; setState( 0 ); } } break; } default: break; } return cmdList; } //! Constructor QwtPickerClickRectMachine::QwtPickerClickRectMachine(): QwtPickerMachine( RectSelection ) { } //! Transition QList QwtPickerClickRectMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) ) { switch ( state() ) { case 0: { cmdList += Begin; cmdList += Append; setState( 1 ); break; } case 1: { // Uh, strange we missed the MouseButtonRelease break; } default: { cmdList += End; setState( 0 ); } } } } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::MouseButtonRelease: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) ) { if ( state() == 1 ) { cmdList += Append; setState( 2 ); } } break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, ( const QKeyEvent * )event ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } else { if ( state() == 1 ) { cmdList += Append; setState( 2 ); } else if ( state() == 2 ) { cmdList += End; setState( 0 ); } } } break; } default: break; } return cmdList; } //! Constructor QwtPickerDragRectMachine::QwtPickerDragRectMachine(): QwtPickerMachine( RectSelection ) { } //! Transition QList QwtPickerDragRectMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 2 ); } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::MouseButtonRelease: { if ( state() == 2 ) { cmdList += End; setState( 0 ); } break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, ( const QKeyEvent * )event ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 2 ); } else { cmdList += End; setState( 0 ); } } break; } default: break; } return cmdList; } //! Constructor QwtPickerPolygonMachine::QwtPickerPolygonMachine(): QwtPickerMachine( PolygonSelection ) { } //! Transition QList QwtPickerPolygonMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 1 ); } else { cmdList += Append; } } if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect2, ( const QMouseEvent * )event ) ) { if ( state() == 1 ) { cmdList += End; setState( 0 ); } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, ( const QKeyEvent * )event ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 1 ); } else { cmdList += Append; } } else if ( eventPattern.keyMatch( QwtEventPattern::KeySelect2, ( const QKeyEvent * )event ) ) { if ( state() == 1 ) { cmdList += End; setState( 0 ); } } break; } default: break; } return cmdList; } pcp-gui-1.5.11/src/libqwt/qwt_plot.cpp0000644000000000000000000004532012176111212014475 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot.h" #include "qwt_plot_dict.h" #include "qwt_plot_layout.h" #include "qwt_scale_widget.h" #include "qwt_scale_engine.h" #include "qwt_text_label.h" #include "qwt_legend.h" #include "qwt_dyngrid_layout.h" #include "qwt_plot_canvas.h" #include #include #include #include #include class QwtPlot::PrivateData { public: QPointer titleLabel; QPointer canvas; QPointer legend; QwtPlotLayout *layout; bool autoReplot; }; /*! \brief Constructor \param parent Parent widget */ QwtPlot::QwtPlot( QWidget *parent ): QFrame( parent ) { initPlot( QwtText() ); } /*! \brief Constructor \param title Title text \param parent Parent widget */ QwtPlot::QwtPlot( const QwtText &title, QWidget *parent ): QFrame( parent ) { initPlot( title ); } //! Destructor QwtPlot::~QwtPlot() { detachItems( QwtPlotItem::Rtti_PlotItem, autoDelete() ); delete d_data->layout; deleteAxesData(); delete d_data; } /*! \brief Initializes a QwtPlot instance \param title Title text */ void QwtPlot::initPlot( const QwtText &title ) { d_data = new PrivateData; d_data->layout = new QwtPlotLayout; d_data->autoReplot = false; // title d_data->titleLabel = new QwtTextLabel( this ); d_data->titleLabel->setObjectName( "QwtPlotTitle" ); d_data->titleLabel->setFont( QFont( fontInfo().family(), 14, QFont::Bold ) ); QwtText text( title ); text.setRenderFlags( Qt::AlignCenter | Qt::TextWordWrap ); d_data->titleLabel->setText( text ); // legend d_data->legend = NULL; // axis initAxesData(); // canvas d_data->canvas = new QwtPlotCanvas( this ); d_data->canvas->setObjectName( "QwtPlotCanvas" ); d_data->canvas->setFrameStyle( QFrame::Panel | QFrame::Sunken ); d_data->canvas->setLineWidth( 2 ); updateTabOrder(); setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ); resize( 200, 200 ); } /*! \brief Adds handling of layout requests \param event Event */ bool QwtPlot::event( QEvent *event ) { bool ok = QFrame::event( event ); switch ( event->type() ) { case QEvent::LayoutRequest: updateLayout(); break; case QEvent::PolishRequest: replot(); break; default:; } return ok; } //! Replots the plot if autoReplot() is \c true. void QwtPlot::autoRefresh() { if ( d_data->autoReplot ) replot(); } /*! \brief Set or reset the autoReplot option If the autoReplot option is set, the plot will be updated implicitly by manipulating member functions. Since this may be time-consuming, it is recommended to leave this option switched off and call replot() explicitly if necessary. The autoReplot option is set to false by default, which means that the user has to call replot() in order to make changes visible. \param tf \c true or \c false. Defaults to \c true. \sa replot() */ void QwtPlot::setAutoReplot( bool tf ) { d_data->autoReplot = tf; } /*! \return true if the autoReplot option is set. \sa setAutoReplot() */ bool QwtPlot::autoReplot() const { return d_data->autoReplot; } /*! Change the plot's title \param title New title */ void QwtPlot::setTitle( const QString &title ) { if ( title != d_data->titleLabel->text().text() ) { d_data->titleLabel->setText( title ); updateLayout(); } } /*! Change the plot's title \param title New title */ void QwtPlot::setTitle( const QwtText &title ) { if ( title != d_data->titleLabel->text() ) { d_data->titleLabel->setText( title ); updateLayout(); } } //! \return Title of the plot QwtText QwtPlot::title() const { return d_data->titleLabel->text(); } //! \return the plot's title QwtPlotLayout *QwtPlot::plotLayout() { return d_data->layout; } //! \return the plot's layout const QwtPlotLayout *QwtPlot::plotLayout() const { return d_data->layout; } //! \return the plot's titel label. QwtTextLabel *QwtPlot::titleLabel() { return d_data->titleLabel; } /*! \return the plot's titel label. */ const QwtTextLabel *QwtPlot::titleLabel() const { return d_data->titleLabel; } /*! \return the plot's legend \sa insertLegend() */ QwtLegend *QwtPlot::legend() { return d_data->legend; } /*! \return the plot's legend \sa insertLegend() */ const QwtLegend *QwtPlot::legend() const { return d_data->legend; } /*! \return the plot's canvas */ QwtPlotCanvas *QwtPlot::canvas() { return d_data->canvas; } /*! \return the plot's canvas */ const QwtPlotCanvas *QwtPlot::canvas() const { return d_data->canvas; } /*! Return sizeHint \sa minimumSizeHint() */ QSize QwtPlot::sizeHint() const { int dw = 0; int dh = 0; for ( int axisId = 0; axisId < axisCnt; axisId++ ) { if ( axisEnabled( axisId ) ) { const int niceDist = 40; const QwtScaleWidget *scaleWidget = axisWidget( axisId ); const QwtScaleDiv &scaleDiv = scaleWidget->scaleDraw()->scaleDiv(); const int majCnt = scaleDiv.ticks( QwtScaleDiv::MajorTick ).count(); if ( axisId == yLeft || axisId == yRight ) { int hDiff = ( majCnt - 1 ) * niceDist - scaleWidget->minimumSizeHint().height(); if ( hDiff > dh ) dh = hDiff; } else { int wDiff = ( majCnt - 1 ) * niceDist - scaleWidget->minimumSizeHint().width(); if ( wDiff > dw ) dw = wDiff; } } } return minimumSizeHint() + QSize( dw, dh ); } /*! \brief Return a minimum size hint */ QSize QwtPlot::minimumSizeHint() const { QSize hint = d_data->layout->minimumSizeHint( this ); hint += QSize( 2 * frameWidth(), 2 * frameWidth() ); return hint; } /*! Resize and update internal layout \param e Resize event */ void QwtPlot::resizeEvent( QResizeEvent *e ) { QFrame::resizeEvent( e ); updateLayout(); } /*! \brief Redraw the plot If the autoReplot option is not set (which is the default) or if any curves are attached to raw data, the plot has to be refreshed explicitly in order to make changes visible. \sa setAutoReplot() \warning Calls canvas()->repaint, take care of infinite recursions */ void QwtPlot::replot() { bool doAutoReplot = autoReplot(); setAutoReplot( false ); updateAxes(); /* Maybe the layout needs to be updated, because of changed axes labels. We need to process them here before painting to avoid that scales and canvas get out of sync. */ QApplication::sendPostedEvents( this, QEvent::LayoutRequest ); d_data->canvas->replot(); setAutoReplot( doAutoReplot ); } /*! \brief Adjust plot content to its current size. \sa resizeEvent() */ void QwtPlot::updateLayout() { d_data->layout->activate( this, contentsRect() ); QRect titleRect = d_data->layout->titleRect().toRect(); QRect scaleRect[QwtPlot::axisCnt]; for ( int axisId = 0; axisId < axisCnt; axisId++ ) scaleRect[axisId] = d_data->layout->scaleRect( axisId ).toRect(); QRect legendRect = d_data->layout->legendRect().toRect(); QRect canvasRect = d_data->layout->canvasRect().toRect(); // resize and show the visible widgets if ( !d_data->titleLabel->text().isEmpty() ) { d_data->titleLabel->setGeometry( titleRect ); if ( !d_data->titleLabel->isVisibleTo( this ) ) d_data->titleLabel->show(); } else d_data->titleLabel->hide(); for ( int axisId = 0; axisId < axisCnt; axisId++ ) { if ( axisEnabled( axisId ) ) { axisWidget( axisId )->setGeometry( scaleRect[axisId] ); #if 1 if ( axisId == xBottom || axisId == xTop ) { // do we need this code any longer ??? QRegion r( scaleRect[axisId] ); if ( axisEnabled( yLeft ) ) r = r.subtract( QRegion( scaleRect[yLeft] ) ); if ( axisEnabled( yRight ) ) r = r.subtract( QRegion( scaleRect[yRight] ) ); r.translate( -scaleRect[ axisId ].x(), -scaleRect[axisId].y() ); axisWidget( axisId )->setMask( r ); } #endif if ( !axisWidget( axisId )->isVisibleTo( this ) ) axisWidget( axisId )->show(); } else axisWidget( axisId )->hide(); } if ( d_data->legend && d_data->layout->legendPosition() != ExternalLegend ) { if ( d_data->legend->itemCount() > 0 ) { d_data->legend->setGeometry( legendRect ); d_data->legend->show(); } else d_data->legend->hide(); } d_data->canvas->setGeometry( canvasRect ); } /*! Update the focus tab order The order is changed so that the canvas will be in front of the first legend item, or behind the last legend item - depending on the position of the legend. */ void QwtPlot::updateTabOrder() { if ( d_data->canvas->focusPolicy() == Qt::NoFocus ) return; if ( d_data->legend.isNull() || d_data->layout->legendPosition() == ExternalLegend || d_data->legend->legendItems().count() == 0 ) { return; } // Depending on the position of the legend the // tab order will be changed that the canvas is // next to the last legend item, or before // the first one. const bool canvasFirst = d_data->layout->legendPosition() == QwtPlot::BottomLegend || d_data->layout->legendPosition() == QwtPlot::RightLegend; QWidget *previous = NULL; QWidget *w = d_data->canvas; while ( ( w = w->nextInFocusChain() ) != d_data->canvas ) { bool isLegendItem = false; if ( w->focusPolicy() != Qt::NoFocus && w->parent() && w->parent() == d_data->legend->contentsWidget() ) { isLegendItem = true; } if ( canvasFirst ) { if ( isLegendItem ) break; previous = w; } else { if ( isLegendItem ) previous = w; else { if ( previous ) break; } } } if ( previous && previous != d_data->canvas ) setTabOrder( previous, d_data->canvas ); } /*! Redraw the canvas. \param painter Painter used for drawing \warning drawCanvas calls drawItems what is also used for printing. Applications that like to add individual plot items better overload drawItems() \sa drawItems() */ void QwtPlot::drawCanvas( QPainter *painter ) { QwtScaleMap maps[axisCnt]; for ( int axisId = 0; axisId < axisCnt; axisId++ ) maps[axisId] = canvasMap( axisId ); drawItems( painter, d_data->canvas->contentsRect(), maps ); } /*! Redraw the canvas items. \param painter Painter used for drawing \param canvasRect Bounding rectangle where to paint \param map QwtPlot::axisCnt maps, mapping between plot and paint device coordinates */ void QwtPlot::drawItems( QPainter *painter, const QRectF &canvasRect, const QwtScaleMap map[axisCnt] ) const { const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { QwtPlotItem *item = *it; if ( item && item->isVisible() ) { painter->save(); painter->setRenderHint( QPainter::Antialiasing, item->testRenderHint( QwtPlotItem::RenderAntialiased ) ); item->draw( painter, map[item->xAxis()], map[item->yAxis()], canvasRect ); painter->restore(); } } } /*! \param axisId Axis \return Map for the axis on the canvas. With this map pixel coordinates can translated to plot coordinates and vice versa. \sa QwtScaleMap, transform(), invTransform() */ QwtScaleMap QwtPlot::canvasMap( int axisId ) const { QwtScaleMap map; if ( !d_data->canvas ) return map; map.setTransformation( axisScaleEngine( axisId )->transformation() ); const QwtScaleDiv *sd = axisScaleDiv( axisId ); map.setScaleInterval( sd->lowerBound(), sd->upperBound() ); if ( axisEnabled( axisId ) ) { const QwtScaleWidget *s = axisWidget( axisId ); if ( axisId == yLeft || axisId == yRight ) { double y = s->y() + s->startBorderDist() - d_data->canvas->y(); double h = s->height() - s->startBorderDist() - s->endBorderDist(); map.setPaintInterval( y + h, y ); } else { double x = s->x() + s->startBorderDist() - d_data->canvas->x(); double w = s->width() - s->startBorderDist() - s->endBorderDist(); map.setPaintInterval( x, x + w ); } } else { int margin = 0; if ( !plotLayout()->alignCanvasToScales() ) margin = plotLayout()->canvasMargin( axisId ); const QRect &canvasRect = d_data->canvas->contentsRect(); if ( axisId == yLeft || axisId == yRight ) { map.setPaintInterval( canvasRect.bottom() - margin, canvasRect.top() + margin ); } else { map.setPaintInterval( canvasRect.left() + margin, canvasRect.right() - margin ); } } return map; } /*! \brief Change the background of the plotting area Sets brush to QPalette::Window of all colorgroups of the palette of the canvas. Using canvas()->setPalette() is a more powerful way to set these colors. \param brush New background brush \sa canvasBackground() */ void QwtPlot::setCanvasBackground( const QBrush &brush ) { QPalette pal = d_data->canvas->palette(); pal.setBrush( QPalette::Window, brush ); canvas()->setPalette( pal ); } /*! Nothing else than: canvas()->palette().brush( QPalette::Normal, QPalette::Window); \return Background brush of the plotting area. \sa setCanvasBackground() */ QBrush QwtPlot::canvasBackground() const { return canvas()->palette().brush( QPalette::Normal, QPalette::Window ); } /*! \brief Change the border width of the plotting area Nothing else than canvas()->setLineWidth(w), left for compatibility only. \param width New border width */ void QwtPlot::setCanvasLineWidth( int width ) { canvas()->setLineWidth( width ); updateLayout(); } /*! Nothing else than: canvas()->lineWidth(), left for compatibility only. \return the border width of the plotting area */ int QwtPlot::canvasLineWidth() const { return canvas()->lineWidth(); } /*! \return \c true if the specified axis exists, otherwise \c false \param axisId axis index */ bool QwtPlot::axisValid( int axisId ) { return ( ( axisId >= QwtPlot::yLeft ) && ( axisId < QwtPlot::axisCnt ) ); } /*! Called internally when the legend has been clicked on. Emits a legendClicked() signal. */ void QwtPlot::legendItemClicked() { if ( d_data->legend && sender()->isWidgetType() ) { QwtPlotItem *plotItem = ( QwtPlotItem* )d_data->legend->find( ( QWidget * )sender() ); if ( plotItem ) Q_EMIT legendClicked( plotItem ); } } /*! Called internally when the legend has been checked Emits a legendClicked() signal. */ void QwtPlot::legendItemChecked( bool on ) { if ( d_data->legend && sender()->isWidgetType() ) { QwtPlotItem *plotItem = ( QwtPlotItem* )d_data->legend->find( ( QWidget * )sender() ); if ( plotItem ) Q_EMIT legendChecked( plotItem, on ); } } /*! \brief Insert a legend If the position legend is \c QwtPlot::LeftLegend or \c QwtPlot::RightLegend the legend will be organized in one column from top to down. Otherwise the legend items will be placed in a table with a best fit number of columns from left to right. If pos != QwtPlot::ExternalLegend the plot widget will become parent of the legend. It will be deleted when the plot is deleted, or another legend is set with insertLegend(). \param legend Legend \param pos The legend's position. For top/left position the number of colums will be limited to 1, otherwise it will be set to unlimited. \param ratio Ratio between legend and the bounding rect of title, canvas and axes. The legend will be shrinked if it would need more space than the given ratio. The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0 it will be reset to the default ratio. The default vertical/horizontal ratio is 0.33/0.5. \sa legend(), QwtPlotLayout::legendPosition(), QwtPlotLayout::setLegendPosition() */ void QwtPlot::insertLegend( QwtLegend *legend, QwtPlot::LegendPosition pos, double ratio ) { d_data->layout->setLegendPosition( pos, ratio ); if ( legend != d_data->legend ) { if ( d_data->legend && d_data->legend->parent() == this ) delete d_data->legend; d_data->legend = legend; if ( d_data->legend ) { if ( pos != ExternalLegend ) { if ( d_data->legend->parent() != this ) d_data->legend->setParent( this ); } const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { ( *it )->updateLegend( d_data->legend ); } QwtDynGridLayout *tl = qobject_cast( d_data->legend->contentsWidget()->layout() ); if ( tl ) { switch ( d_data->layout->legendPosition() ) { case LeftLegend: case RightLegend: tl->setMaxCols( 1 ); // 1 column: align vertical break; case TopLegend: case BottomLegend: tl->setMaxCols( 0 ); // unlimited break; case ExternalLegend: break; } } } updateTabOrder(); } updateLayout(); } pcp-gui-1.5.11/src/libqwt/qwt_plot_axis.cpp0000644000000000000000000004036412176111212015524 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot.h" #include "qwt_math.h" #include "qwt_scale_widget.h" #include "qwt_scale_div.h" #include "qwt_scale_engine.h" class QwtPlot::AxisData { public: bool isEnabled; bool doAutoScale; double minValue; double maxValue; double stepSize; int maxMajor; int maxMinor; QwtScaleDiv scaleDiv; QwtScaleEngine *scaleEngine; QwtScaleWidget *scaleWidget; }; //! Initialize axes void QwtPlot::initAxesData() { int axisId; for ( axisId = 0; axisId < axisCnt; axisId++ ) d_axisData[axisId] = new AxisData; d_axisData[yLeft]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::LeftScale, this ); d_axisData[yRight]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::RightScale, this ); d_axisData[xTop]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::TopScale, this ); d_axisData[xBottom]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::BottomScale, this ); d_axisData[yLeft]->scaleWidget->setObjectName( "QwtPlotAxisYLeft" ); d_axisData[yRight]->scaleWidget->setObjectName( "QwtPlotAxisYRight" ); d_axisData[xTop]->scaleWidget->setObjectName( "QwtPlotAxisXTop" ); d_axisData[xBottom]->scaleWidget->setObjectName( "QwtPlotAxisXBottom" ); QFont fscl( fontInfo().family(), 10 ); QFont fttl( fontInfo().family(), 12, QFont::Bold ); for ( axisId = 0; axisId < axisCnt; axisId++ ) { AxisData &d = *d_axisData[axisId]; d.scaleWidget->setFont( fscl ); d.scaleWidget->setMargin( 2 ); QwtText text = d.scaleWidget->title(); text.setFont( fttl ); d.scaleWidget->setTitle( text ); d.doAutoScale = true; d.minValue = 0.0; d.maxValue = 1000.0; d.stepSize = 0.0; d.maxMinor = 5; d.maxMajor = 8; d.scaleEngine = new QwtLinearScaleEngine; d.scaleDiv.invalidate(); } d_axisData[yLeft]->isEnabled = true; d_axisData[yRight]->isEnabled = false; d_axisData[xBottom]->isEnabled = true; d_axisData[xTop]->isEnabled = false; } void QwtPlot::deleteAxesData() { for ( int axisId = 0; axisId < axisCnt; axisId++ ) { delete d_axisData[axisId]->scaleEngine; delete d_axisData[axisId]; d_axisData[axisId] = NULL; } } /*! \return specified axis, or NULL if axisId is invalid. \param axisId axis index */ const QwtScaleWidget *QwtPlot::axisWidget( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleWidget; return NULL; } /*! \return specified axis, or NULL if axisId is invalid. \param axisId axis index */ QwtScaleWidget *QwtPlot::axisWidget( int axisId ) { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleWidget; return NULL; } /*! Change the scale engine for an axis \param axisId axis index \param scaleEngine Scale engine \sa axisScaleEngine() */ void QwtPlot::setAxisScaleEngine( int axisId, QwtScaleEngine *scaleEngine ) { if ( axisValid( axisId ) && scaleEngine != NULL ) { AxisData &d = *d_axisData[axisId]; delete d.scaleEngine; d.scaleEngine = scaleEngine; d.scaleDiv.invalidate(); autoRefresh(); } } /*! \param axisId axis index \return Scale engine for a specific axis */ QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId ) { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleEngine; else return NULL; } /*! \param axisId axis index \return Scale engine for a specific axis */ const QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleEngine; else return NULL; } /*! \return \c true if autoscaling is enabled \param axisId axis index */ bool QwtPlot::axisAutoScale( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->doAutoScale; else return false; } /*! \return \c true if a specified axis is enabled \param axisId axis index */ bool QwtPlot::axisEnabled( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->isEnabled; else return false; } /*! \return the font of the scale labels for a specified axis \param axisId axis index */ QFont QwtPlot::axisFont( int axisId ) const { if ( axisValid( axisId ) ) return axisWidget( axisId )->font(); else return QFont(); } /*! \return the maximum number of major ticks for a specified axis \param axisId axis index \sa setAxisMaxMajor() */ int QwtPlot::axisMaxMajor( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->maxMajor; else return 0; } /*! \return the maximum number of minor ticks for a specified axis \param axisId axis index \sa setAxisMaxMinor() */ int QwtPlot::axisMaxMinor( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->maxMinor; else return 0; } /*! \brief Return the scale division of a specified axis axisScaleDiv(axisId)->lowerBound(), axisScaleDiv(axisId)->upperBound() are the current limits of the axis scale. \param axisId axis index \return Scale division \sa QwtScaleDiv, setAxisScaleDiv() */ const QwtScaleDiv *QwtPlot::axisScaleDiv( int axisId ) const { if ( !axisValid( axisId ) ) return NULL; return &d_axisData[axisId]->scaleDiv; } /*! \brief Return the scale division of a specified axis axisScaleDiv(axisId)->lowerBound(), axisScaleDiv(axisId)->upperBound() are the current limits of the axis scale. \param axisId axis index \return Scale division \sa QwtScaleDiv, setAxisScaleDiv() */ QwtScaleDiv *QwtPlot::axisScaleDiv( int axisId ) { if ( !axisValid( axisId ) ) return NULL; return &d_axisData[axisId]->scaleDiv; } /*! \returns the scale draw of a specified axis \param axisId axis index \return specified scaleDraw for axis, or NULL if axis is invalid. \sa QwtScaleDraw */ const QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId ) const { if ( !axisValid( axisId ) ) return NULL; return axisWidget( axisId )->scaleDraw(); } /*! \returns the scale draw of a specified axis \param axisId axis index \return specified scaleDraw for axis, or NULL if axis is invalid. \sa QwtScaleDraw */ QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId ) { if ( !axisValid( axisId ) ) return NULL; return axisWidget( axisId )->scaleDraw(); } /*! Return the step size parameter, that has been set in setAxisScale. This doesn't need to be the step size of the current scale. \param axisId axis index \return step size parameter value \sa setAxisScale() */ double QwtPlot::axisStepSize( int axisId ) const { if ( !axisValid( axisId ) ) return 0; return d_axisData[axisId]->stepSize; } /*! \brief Return the current interval of the specified axis This is only a convenience function for axisScaleDiv( axisId )->interval(); \param axisId axis index \return Scale interval \sa QwtScaleDiv, axisScaleDiv() */ QwtInterval QwtPlot::axisInterval( int axisId ) const { if ( !axisValid( axisId ) ) return QwtInterval(); return d_axisData[axisId]->scaleDiv.interval(); } /*! \return the title of a specified axis \param axisId axis index */ QwtText QwtPlot::axisTitle( int axisId ) const { if ( axisValid( axisId ) ) return axisWidget( axisId )->title(); else return QwtText(); } /*! \brief Enable or disable a specified axis When an axis is disabled, this only means that it is not visible on the screen. Curves, markers and can be attached to disabled axes, and transformation of screen coordinates into values works as normal. Only xBottom and yLeft are enabled by default. \param axisId axis index \param tf \c true (enabled) or \c false (disabled) */ void QwtPlot::enableAxis( int axisId, bool tf ) { if ( axisValid( axisId ) && tf != d_axisData[axisId]->isEnabled ) { d_axisData[axisId]->isEnabled = tf; updateLayout(); } } /*! Transform the x or y coordinate of a position in the drawing region into a value. \param axisId axis index \param pos position \warning The position can be an x or a y coordinate, depending on the specified axis. */ double QwtPlot::invTransform( int axisId, int pos ) const { if ( axisValid( axisId ) ) return( canvasMap( axisId ).invTransform( pos ) ); else return 0.0; } /*! \brief Transform a value into a coordinate in the plotting region \param axisId axis index \param value value \return X or y coordinate in the plotting region corresponding to the value. */ double QwtPlot::transform( int axisId, double value ) const { if ( axisValid( axisId ) ) return( canvasMap( axisId ).transform( value ) ); else return 0.0; } /*! \brief Change the font of an axis \param axisId axis index \param f font \warning This function changes the font of the tick labels, not of the axis title. */ void QwtPlot::setAxisFont( int axisId, const QFont &f ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setFont( f ); } /*! \brief Enable autoscaling for a specified axis This member function is used to switch back to autoscaling mode after a fixed scale has been set. Autoscaling is enabled by default. \param axisId axis index \param on On/Off \sa setAxisScale(), setAxisScaleDiv(), updateAxes() \note The autoscaling flag has no effect until updateAxes() is executed ( called by replot() ). */ void QwtPlot::setAxisAutoScale( int axisId, bool on ) { if ( axisValid( axisId ) && ( d_axisData[axisId]->doAutoScale != on ) ) { d_axisData[axisId]->doAutoScale = on; autoRefresh(); } } /*! \brief Disable autoscaling and specify a fixed scale for a selected axis. \param axisId axis index \param min \param max minimum and maximum of the scale \param stepSize Major step size. If step == 0, the step size is calculated automatically using the maxMajor setting. \sa setAxisMaxMajor(), setAxisAutoScale(), axisStepSize() */ void QwtPlot::setAxisScale( int axisId, double min, double max, double stepSize ) { if ( axisValid( axisId ) ) { AxisData &d = *d_axisData[axisId]; d.doAutoScale = false; d.scaleDiv.invalidate(); d.minValue = min; d.maxValue = max; d.stepSize = stepSize; autoRefresh(); } } /*! \brief Disable autoscaling and specify a fixed scale for a selected axis. \param axisId axis index \param scaleDiv Scale division \sa setAxisScale(), setAxisAutoScale() */ void QwtPlot::setAxisScaleDiv( int axisId, const QwtScaleDiv &scaleDiv ) { if ( axisValid( axisId ) ) { AxisData &d = *d_axisData[axisId]; d.doAutoScale = false; d.scaleDiv = scaleDiv; autoRefresh(); } } /*! \brief Set a scale draw \param axisId axis index \param scaleDraw object responsible for drawing scales. By passing scaleDraw it is possible to extend QwtScaleDraw functionality and let it take place in QwtPlot. Please note that scaleDraw has to be created with new and will be deleted by the corresponding QwtScale member ( like a child object ). \sa QwtScaleDraw, QwtScaleWidget \warning The attributes of scaleDraw will be overwritten by those of the previous QwtScaleDraw. */ void QwtPlot::setAxisScaleDraw( int axisId, QwtScaleDraw *scaleDraw ) { if ( axisValid( axisId ) ) { axisWidget( axisId )->setScaleDraw( scaleDraw ); autoRefresh(); } } /*! Change the alignment of the tick labels \param axisId axis index \param alignment Or'd Qt::AlignmentFlags see \sa QwtScaleDraw::setLabelAlignment() */ void QwtPlot::setAxisLabelAlignment( int axisId, Qt::Alignment alignment ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setLabelAlignment( alignment ); } /*! Rotate all tick labels \param axisId axis index \param rotation Angle in degrees. When changing the label rotation, the label alignment might be adjusted too. \sa QwtScaleDraw::setLabelRotation(), setAxisLabelAlignment() */ void QwtPlot::setAxisLabelRotation( int axisId, double rotation ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setLabelRotation( rotation ); } /*! Set the maximum number of minor scale intervals for a specified axis \param axisId axis index \param maxMinor maximum number of minor steps \sa axisMaxMinor() */ void QwtPlot::setAxisMaxMinor( int axisId, int maxMinor ) { if ( axisValid( axisId ) ) { maxMinor = qBound( 0, maxMinor, 100 ); AxisData &d = *d_axisData[axisId]; if ( maxMinor != d.maxMinor ) { d.maxMinor = maxMinor; d.scaleDiv.invalidate(); autoRefresh(); } } } /*! Set the maximum number of major scale intervals for a specified axis \param axisId axis index \param maxMajor maximum number of major steps \sa axisMaxMajor() */ void QwtPlot::setAxisMaxMajor( int axisId, int maxMajor ) { if ( axisValid( axisId ) ) { maxMajor = qBound( 1, maxMajor, 10000 ); AxisData &d = *d_axisData[axisId]; if ( maxMajor != d.maxMajor ) { d.maxMajor = maxMajor; d.scaleDiv.invalidate(); autoRefresh(); } } } /*! \brief Change the title of a specified axis \param axisId axis index \param title axis title */ void QwtPlot::setAxisTitle( int axisId, const QString &title ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setTitle( title ); } /*! \brief Change the title of a specified axis \param axisId axis index \param title axis title */ void QwtPlot::setAxisTitle( int axisId, const QwtText &title ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setTitle( title ); } //! Rebuild the scales void QwtPlot::updateAxes() { // Find bounding interval of the item data // for all axes, where autoscaling is enabled QwtInterval intv[axisCnt]; const QwtPlotItemList& itmList = itemList(); QwtPlotItemIterator it; for ( it = itmList.begin(); it != itmList.end(); ++it ) { const QwtPlotItem *item = *it; if ( !item->testItemAttribute( QwtPlotItem::AutoScale ) ) continue; if ( !item->isVisible() ) continue; if ( axisAutoScale( item->xAxis() ) || axisAutoScale( item->yAxis() ) ) { const QRectF rect = item->boundingRect(); intv[item->xAxis()] |= QwtInterval( rect.left(), rect.right() ); intv[item->yAxis()] |= QwtInterval( rect.top(), rect.bottom() ); } } // Adjust scales for ( int axisId = 0; axisId < axisCnt; axisId++ ) { AxisData &d = *d_axisData[axisId]; double minValue = d.minValue; double maxValue = d.maxValue; double stepSize = d.stepSize; if ( d.doAutoScale && intv[axisId].isValid() ) { d.scaleDiv.invalidate(); minValue = intv[axisId].minValue(); maxValue = intv[axisId].maxValue(); d.scaleEngine->autoScale( d.maxMajor, minValue, maxValue, stepSize ); } if ( !d.scaleDiv.isValid() ) { d.scaleDiv = d.scaleEngine->divideScale( minValue, maxValue, d.maxMajor, d.maxMinor, stepSize ); } QwtScaleWidget *scaleWidget = axisWidget( axisId ); scaleWidget->setScaleDiv( d.scaleEngine->transformation(), d.scaleDiv ); int startDist, endDist; scaleWidget->getBorderDistHint( startDist, endDist ); scaleWidget->setBorderDist( startDist, endDist ); } for ( it = itmList.begin(); it != itmList.end(); ++it ) { QwtPlotItem *item = *it; item->updateScaleDiv( *axisScaleDiv( item->xAxis() ), *axisScaleDiv( item->yAxis() ) ); } } pcp-gui-1.5.11/src/libqwt/qwt_plot_canvas.cpp0000644000000000000000000006705612176111212016042 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_canvas.h" #include "qwt_painter.h" #include "qwt_null_paintdevice.h" #include "qwt_math.h" #include "qwt_plot.h" #include #include #include #include #include #include #ifdef Q_WS_X11 #include #endif class QwtStyleSheetRecorder: public QwtNullPaintDevice { public: QwtStyleSheetRecorder( const QSize &size ): QwtNullPaintDevice( QPaintEngine::AllFeatures ) { setSize( size ); } virtual void updateState( const QPaintEngineState &state ) { if ( state.state() & QPaintEngine::DirtyPen ) { d_pen = state.pen(); } if ( state.state() & QPaintEngine::DirtyBrush ) { d_brush = state.brush(); } if ( state.state() & QPaintEngine::DirtyBrushOrigin ) { d_origin = state.brushOrigin(); } } virtual void drawRects(const QRectF *rects, int count ) { for ( int i = 0; i < count; i++ ) border.rectList += rects[i]; } virtual void drawPath( const QPainterPath &path ) { const QRectF rect( QPointF( 0.0, 0.0 ) , size() ); if ( path.controlPointRect().contains( rect.center() ) ) { setCornerRects( path ); alignCornerRects( rect ); background.path = path; background.brush = d_brush; background.origin = d_origin; } else { border.pathList += path; } } void setCornerRects( const QPainterPath &path ) { QPointF pos( 0.0, 0.0 ); for ( int i = 0; i < path.elementCount(); i++ ) { QPainterPath::Element el = path.elementAt(i); switch( el.type ) { case QPainterPath::MoveToElement: case QPainterPath::LineToElement: { pos.setX( el.x ); pos.setY( el.y ); break; } case QPainterPath::CurveToElement: { QRectF r( pos, QPointF( el.x, el.y ) ); clipRects += r.normalized(); pos.setX( el.x ); pos.setY( el.y ); break; } case QPainterPath::CurveToDataElement: { if ( clipRects.size() > 0 ) { QRectF r = clipRects.last(); r.setCoords( qMin( r.left(), el.x ), qMin( r.top(), el.y ), qMax( r.right(), el.x ), qMax( r.bottom(), el.y ) ); clipRects.last() = r.normalized(); } break; } } } } private: void alignCornerRects( const QRectF &rect ) { for ( int i = 0; i < clipRects.size(); i++ ) { QRectF &r = clipRects[i]; if ( r.center().x() < rect.center().x() ) r.setLeft( rect.left() ); else r.setRight( rect.right() ); if ( r.center().y() < rect.center().y() ) r.setTop( rect.top() ); else r.setBottom( rect.bottom() ); } } public: QVector clipRects; struct Border { QList pathList; QList rectList; QRegion clipRegion; } border; struct Background { QPainterPath path; QBrush brush; QPointF origin; } background; private: QPen d_pen; QBrush d_brush; QPointF d_origin; }; static void qwtDrawBackground( QPainter *painter, QWidget *widget ) { const QBrush &brush = widget->palette().brush( widget->backgroundRole() ); if ( brush.style() == Qt::TexturePattern ) { QPixmap pm( widget->size() ); #if QT_VERSION >= 0x050000 QwtPainter::fillPixmap( widget, pm ); #else pm.fill( widget, 0, 0 ); #endif painter->drawPixmap( 0, 0, pm ); } else if ( brush.gradient() ) { QVector rects; if ( brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode ) { rects += widget->rect(); } else { rects = painter->clipRegion().rects(); } #if 1 bool useRaster = false; if ( painter->paintEngine()->type() == QPaintEngine::X11 ) { // Qt 4.7.1: gradients on X11 are broken ( subrects + // QGradient::StretchToDeviceMode ) and horrible slow. // As workaround we have to use the raster paintengine. // Even if the QImage -> QPixmap translation is slow // it is three times faster, than using X11 directly useRaster = true; } #endif if ( useRaster ) { QImage::Format format = QImage::Format_RGB32; const QGradientStops stops = brush.gradient()->stops(); for ( int i = 0; i < stops.size(); i++ ) { if ( stops[i].second.alpha() != 255 ) { // don't use Format_ARGB32_Premultiplied. It's // recommended by the Qt docs, but QPainter::drawImage() // is horrible slow on X11. format = QImage::Format_ARGB32; break; } } QImage image( widget->size(), format ); QPainter p( &image ); p.setPen( Qt::NoPen ); p.setBrush( brush ); p.drawRects( rects ); p.end(); painter->drawImage( 0, 0, image ); } else { painter->save(); painter->setPen( Qt::NoPen ); painter->setBrush( brush ); painter->drawRects( rects ); painter->restore(); } } else { painter->save(); painter->setPen( Qt::NoPen ); painter->setBrush( brush ); painter->drawRects( painter->clipRegion().rects() ); painter->restore(); } } static inline void qwtRevertPath( QPainterPath &path ) { if ( path.elementCount() == 4 ) { QPainterPath::Element el0 = path.elementAt(0); QPainterPath::Element el3 = path.elementAt(3); path.setElementPositionAt( 0, el3.x, el3.y ); path.setElementPositionAt( 3, el0.x, el0.y ); } } static QPainterPath qwtCombinePathList( const QRectF &rect, const QList &pathList ) { if ( pathList.isEmpty() ) return QPainterPath(); QPainterPath ordered[8]; // starting top left for ( int i = 0; i < pathList.size(); i++ ) { int index = -1; QPainterPath subPath = pathList[i]; const QRectF br = pathList[i].controlPointRect(); if ( br.center().x() < rect.center().x() ) { if ( br.center().y() < rect.center().y() ) { if ( qAbs( br.top() - rect.top() ) < qAbs( br.left() - rect.left() ) ) { index = 1; } else { index = 0; } } else { if ( qAbs( br.bottom() - rect.bottom() ) < qAbs( br.left() - rect.left() ) ) { index = 6; } else { index = 7; } } if ( subPath.currentPosition().y() > br.center().y() ) qwtRevertPath( subPath ); } else { if ( br.center().y() < rect.center().y() ) { if ( qAbs( br.top() - rect.top() ) < qAbs( br.right() - rect.right() ) ) { index = 2; } else { index = 3; } } else { if ( qAbs( br.bottom() - rect.bottom() ) < qAbs( br.right() - rect.right() ) ) { index = 5; } else { index = 4; } } if ( subPath.currentPosition().y() < br.center().y() ) qwtRevertPath( subPath ); } ordered[index] = subPath; } for ( int i = 0; i < 4; i++ ) { if ( ordered[ 2 * i].isEmpty() != ordered[2 * i + 1].isEmpty() ) { // we don't accept incomplete rounded borders return QPainterPath(); } } const QPolygonF corners( rect ); QPainterPath path; //path.moveTo( rect.topLeft() ); for ( int i = 0; i < 4; i++ ) { if ( ordered[2 * i].isEmpty() ) { path.lineTo( corners[i] ); } else { path.connectPath( ordered[2 * i] ); path.connectPath( ordered[2 * i + 1] ); } } path.closeSubpath(); #if 0 return path.simplified(); #else return path; #endif } static inline void qwtDrawStyledBackground( QWidget *w, QPainter *painter ) { QStyleOption opt; opt.initFrom(w); w->style()->drawPrimitive( QStyle::PE_Widget, &opt, painter, w); } static QWidget *qwtBackgroundWidget( QWidget *w ) { if ( w->parentWidget() == NULL ) return w; if ( w->autoFillBackground() ) { const QBrush brush = w->palette().brush( w->backgroundRole() ); if ( brush.color().alpha() > 0 ) return w; } if ( w->testAttribute( Qt::WA_StyledBackground ) ) { QImage image( 1, 1, QImage::Format_ARGB32 ); image.fill( Qt::transparent ); QPainter painter( &image ); painter.translate( -w->rect().center() ); qwtDrawStyledBackground( w, &painter ); painter.end(); if ( qAlpha( image.pixel( 0, 0 ) ) != 0 ) return w; } return qwtBackgroundWidget( w->parentWidget() ); } static void qwtFillBackground( QPainter *painter, QWidget *widget, const QVector &fillRects ) { if ( fillRects.isEmpty() ) return; QRegion clipRegion; if ( painter->hasClipping() ) clipRegion = painter->transform().map( painter->clipRegion() ); else clipRegion = widget->contentsRect(); // Try to find out which widget fills // the unfilled areas of the styled background QWidget *bgWidget = qwtBackgroundWidget( widget->parentWidget() ); for ( int i = 0; i < fillRects.size(); i++ ) { const QRect rect = fillRects[i].toAlignedRect(); if ( clipRegion.intersects( rect ) ) { const QPoint topLeft = widget->mapTo( bgWidget, rect.topLeft() ); QPixmap pm( rect.size() ); #if QT_VERSION >= 0x050000 QwtPainter::fillPixmap( bgWidget, pm, topLeft ); #else pm.fill( bgWidget, topLeft ); #endif painter->drawPixmap( rect, pm ); } } } static void qwtFillBackground( QPainter *painter, QwtPlotCanvas *canvas ) { QVector rects; if ( canvas->testAttribute( Qt::WA_StyledBackground ) ) { QwtStyleSheetRecorder recorder( canvas->size() ); QPainter p( &recorder ); qwtDrawStyledBackground( canvas, &p ); p.end(); if ( recorder.background.brush.isOpaque() ) rects = recorder.clipRects; else rects += canvas->rect(); } else { const QRectF r = canvas->rect(); const double radius = canvas->borderRadius(); if ( radius > 0.0 ) { QSizeF sz( radius, radius ); rects += QRectF( r.topLeft(), sz ); rects += QRectF( r.topRight() - QPointF( radius, 0 ), sz ); rects += QRectF( r.bottomRight() - QPointF( radius, radius ), sz ); rects += QRectF( r.bottomLeft() - QPointF( 0, radius ), sz ); } } qwtFillBackground( painter, canvas, rects); } class QwtPlotCanvas::PrivateData { public: PrivateData(): focusIndicator( NoFocusIndicator ), borderRadius( 0 ), paintAttributes( 0 ), backingStore( NULL ) { styleSheet.hasBorder = false; } ~PrivateData() { delete backingStore; } FocusIndicator focusIndicator; double borderRadius; QwtPlotCanvas::PaintAttributes paintAttributes; QPixmap *backingStore; struct StyleSheet { bool hasBorder; QPainterPath borderPath; QVector cornerRects; struct StyleSheetBackground { QBrush brush; QPointF origin; } background; } styleSheet; }; //! Sets a cross cursor, enables QwtPlotCanvas::BackingStore QwtPlotCanvas::QwtPlotCanvas( QwtPlot *plot ): QFrame( plot ) { d_data = new PrivateData; #ifndef QT_NO_CURSOR setCursor( Qt::CrossCursor ); #endif setAutoFillBackground( true ); setPaintAttribute( QwtPlotCanvas::BackingStore, true ); setPaintAttribute( QwtPlotCanvas::Opaque, true ); setPaintAttribute( QwtPlotCanvas::HackStyledBackground, true ); } //! Destructor QwtPlotCanvas::~QwtPlotCanvas() { delete d_data; } //! Return parent plot widget QwtPlot *QwtPlotCanvas::plot() { return qobject_cast( parent() ); } //! Return parent plot widget const QwtPlot *QwtPlotCanvas::plot() const { return qobject_cast( parent() ); } /*! \brief Changing the paint attributes \param attribute Paint attribute \param on On/Off \sa testPaintAttribute(), backingStore() */ void QwtPlotCanvas::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( bool( d_data->paintAttributes & attribute ) == on ) return; if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; switch ( attribute ) { case BackingStore: { if ( on ) { if ( d_data->backingStore == NULL ) d_data->backingStore = new QPixmap(); if ( isVisible() ) { #if QT_VERSION >= 0x050000 *d_data->backingStore = grab( rect() ); #else *d_data->backingStore = QPixmap::grabWidget( this, rect() ); #endif } } else { delete d_data->backingStore; d_data->backingStore = NULL; } break; } case Opaque: { if ( on ) setAttribute( Qt::WA_OpaquePaintEvent, true ); break; } case HackStyledBackground: case ImmediatePaint: { break; } } } /*! Test wether a paint attribute is enabled \param attribute Paint attribute \return true if the attribute is enabled \sa setPaintAttribute() */ bool QwtPlotCanvas::testPaintAttribute( PaintAttribute attribute ) const { return d_data->paintAttributes & attribute; } //! \return Backing store, might be null const QPixmap *QwtPlotCanvas::backingStore() const { return d_data->backingStore; } //! Invalidate the internal backing store void QwtPlotCanvas::invalidateBackingStore() { if ( d_data->backingStore ) *d_data->backingStore = QPixmap(); } /*! Set the focus indicator \sa FocusIndicator, focusIndicator() */ void QwtPlotCanvas::setFocusIndicator( FocusIndicator focusIndicator ) { d_data->focusIndicator = focusIndicator; } /*! \return Focus indicator \sa FocusIndicator, setFocusIndicator() */ QwtPlotCanvas::FocusIndicator QwtPlotCanvas::focusIndicator() const { return d_data->focusIndicator; } /*! Set the radius for the corners of the border frame \param radius Radius of a rounded corner \sa borderRadius() */ void QwtPlotCanvas::setBorderRadius( double radius ) { d_data->borderRadius = qMax( 0.0, radius ); } /*! \return Radius for the corners of the border frame \sa setBorderRadius() */ double QwtPlotCanvas::borderRadius() const { return d_data->borderRadius; } /*! Qt event handler for QEvent::PolishRequest and QEvent::StyleChange \param event Qt Event */ bool QwtPlotCanvas::event( QEvent *event ) { if ( event->type() == QEvent::PolishRequest ) { if ( testPaintAttribute( QwtPlotCanvas::Opaque ) ) { // Setting a style sheet changes the // Qt::WA_OpaquePaintEvent attribute, but we insist // on painting the background. setAttribute( Qt::WA_OpaquePaintEvent, true ); } } if ( event->type() == QEvent::PolishRequest || event->type() == QEvent::StyleChange ) { updateStyleSheetInfo(); } return QFrame::event( event ); } /*! Paint event \param event Paint event */ void QwtPlotCanvas::paintEvent( QPaintEvent *event ) { QPainter painter( this ); painter.setClipRegion( event->region() ); if ( testPaintAttribute( QwtPlotCanvas::BackingStore ) && d_data->backingStore != NULL ) { QPixmap &bs = *d_data->backingStore; if ( bs.size() != size() ) { bs = QPixmap( size() ); #ifdef Q_WS_X11 if ( bs.x11Info().screen() != x11Info().screen() ) bs.x11SetScreen( x11Info().screen() ); #endif if ( testAttribute(Qt::WA_StyledBackground) ) { QPainter p( &bs ); qwtFillBackground( &p, this ); drawCanvas( &p, true ); } else { QPainter p; if ( d_data->borderRadius <= 0.0 ) { #if QT_VERSION >= 0x050000 QwtPainter::fillPixmap( this, bs ); #else bs.fill( this, 0, 0 ); #endif p.begin( &bs ); drawCanvas( &p, false ); } else { p.begin( &bs ); qwtFillBackground( &p, this ); drawCanvas( &p, true ); } if ( frameWidth() > 0 ) drawBorder( &p ); } } painter.drawPixmap( 0, 0, *d_data->backingStore ); } else { if ( testAttribute(Qt::WA_StyledBackground ) ) { if ( testAttribute( Qt::WA_OpaquePaintEvent ) ) { qwtFillBackground( &painter, this ); drawCanvas( &painter, true ); } else { drawCanvas( &painter, false ); } } else { if ( testAttribute( Qt::WA_OpaquePaintEvent ) ) { if ( autoFillBackground() ) qwtDrawBackground( &painter, this ); } drawCanvas( &painter, false ); if ( frameWidth() > 0 ) drawBorder( &painter ); } } if ( hasFocus() && focusIndicator() == CanvasFocusIndicator ) drawFocusIndicator( &painter ); } void QwtPlotCanvas::drawCanvas( QPainter *painter, bool withBackground ) { bool hackStyledBackground = false; if ( withBackground && testAttribute( Qt::WA_StyledBackground ) && testPaintAttribute( HackStyledBackground ) ) { // Antialiasing rounded borders is done by // inserting pixels with colors between the // border color and the color on the canvas, // When the border is painted before the plot items // these colors are interpolated for the canvas // and the plot items need to be clipped excluding // the anialiased pixels. In situations, where // the plot items fill the area at the rounded // borders this is noticeable. // The only way to avoid these annoying "artefacts" // is to paint the border on top of the plot items. if ( d_data->styleSheet.hasBorder && !d_data->styleSheet.borderPath.isEmpty() ) { // We have a border with at least one rounded corner hackStyledBackground = true; } } if ( withBackground ) { painter->save(); if ( testAttribute( Qt::WA_StyledBackground ) ) { if ( hackStyledBackground ) { // paint background without border painter->setPen( Qt::NoPen ); painter->setBrush( d_data->styleSheet.background.brush ); painter->setBrushOrigin( d_data->styleSheet.background.origin ); painter->setClipPath( d_data->styleSheet.borderPath ); painter->drawRect( contentsRect() ); } else { qwtDrawStyledBackground( this, painter ); } } else if ( autoFillBackground() ) { painter->setPen( Qt::NoPen ); painter->setBrush( palette().brush( backgroundRole() ) ); if ( d_data->borderRadius > 0.0 ) { if ( frameWidth() > 0 ) { painter->setClipPath( borderPath( rect() ) ); painter->drawRect( rect() ); } else { painter->setRenderHint( QPainter::Antialiasing, true ); painter->drawPath( borderPath( rect() ) ); } } else { painter->drawRect( contentsRect() ); } } painter->restore(); } painter->save(); if ( !d_data->styleSheet.borderPath.isEmpty() ) { painter->setClipPath( d_data->styleSheet.borderPath, Qt::IntersectClip ); } else { if ( d_data->borderRadius > 0.0 ) painter->setClipPath( borderPath( rect() ), Qt::IntersectClip ); else painter->setClipRect( contentsRect(), Qt::IntersectClip ); } plot()->drawCanvas( painter ); painter->restore(); if ( withBackground && hackStyledBackground ) { // Now paint the border on top QStyleOptionFrame opt; opt.initFrom(this); style()->drawPrimitive( QStyle::PE_Frame, &opt, painter, this); } } /*! Draw the border of the plot canvas \param painter Painter \sa setBorderRadius(), QFrame::drawFrame() */ void QwtPlotCanvas::drawBorder( QPainter *painter ) { if ( d_data->borderRadius > 0 ) { if ( frameWidth() > 0 ) { QwtPainter::drawRoundedFrame( painter, QRectF( rect() ), d_data->borderRadius, d_data->borderRadius, palette(), frameWidth(), frameStyle() ); } } else { drawFrame( painter ); } } /*! Resize event \param event Resize event */ void QwtPlotCanvas::resizeEvent( QResizeEvent *event ) { QFrame::resizeEvent( event ); updateStyleSheetInfo(); } /*! Draw the focus indication \param painter Painter */ void QwtPlotCanvas::drawFocusIndicator( QPainter *painter ) { const int margin = 1; QRect focusRect = contentsRect(); focusRect.setRect( focusRect.x() + margin, focusRect.y() + margin, focusRect.width() - 2 * margin, focusRect.height() - 2 * margin ); QwtPainter::drawFocusRect( painter, this, focusRect ); } /*! Invalidate the paint cache and repaint the canvas \sa invalidatePaintCache() */ void QwtPlotCanvas::replot() { invalidateBackingStore(); if ( testPaintAttribute( QwtPlotCanvas::ImmediatePaint ) ) repaint( contentsRect() ); else update( contentsRect() ); } //! Update the cached informations about the current style sheet void QwtPlotCanvas::updateStyleSheetInfo() { if ( !testAttribute(Qt::WA_StyledBackground ) ) return; QwtStyleSheetRecorder recorder( size() ); QPainter painter( &recorder ); QStyleOption opt; opt.initFrom(this); style()->drawPrimitive( QStyle::PE_Widget, &opt, &painter, this); painter.end(); d_data->styleSheet.hasBorder = !recorder.border.rectList.isEmpty(); d_data->styleSheet.cornerRects = recorder.clipRects; if ( recorder.background.path.isEmpty() ) { if ( !recorder.border.rectList.isEmpty() ) { d_data->styleSheet.borderPath = qwtCombinePathList( rect(), recorder.border.pathList ); } } else { d_data->styleSheet.borderPath = recorder.background.path; d_data->styleSheet.background.brush = recorder.background.brush; d_data->styleSheet.background.origin = recorder.background.origin; } } /*! Calculate the painter path for a styled or rounded border When the canvas has no styled background or rounded borders the painter path is empty. \param rect Bounding rectangle of the canvas \return Painter path, that can be used for clipping */ QPainterPath QwtPlotCanvas::borderPath( const QRect &rect ) const { if ( testAttribute(Qt::WA_StyledBackground ) ) { QwtStyleSheetRecorder recorder( rect.size() ); QPainter painter( &recorder ); QStyleOption opt; opt.initFrom(this); opt.rect = rect; style()->drawPrimitive( QStyle::PE_Widget, &opt, &painter, this); painter.end(); if ( !recorder.background.path.isEmpty() ) return recorder.background.path; if ( !recorder.border.rectList.isEmpty() ) return qwtCombinePathList( rect, recorder.border.pathList ); } else if ( d_data->borderRadius > 0.0 ) { double fw2 = frameWidth() * 0.5; QRectF r = QRectF(rect).adjusted( fw2, fw2, -fw2, -fw2 ); QPainterPath path; path.addRoundedRect( r, d_data->borderRadius, d_data->borderRadius ); return path; } return QPainterPath(); } /*! Calculate a mask, that can be used to clip away the border frame \param size Size including the frame */ QBitmap QwtPlotCanvas::borderMask( const QSize &size ) const { const QRect r( 0, 0, size.width(), size.height() ); const QPainterPath path = borderPath( r ); if ( path.isEmpty() ) return QBitmap(); QImage image( size, QImage::Format_ARGB32_Premultiplied ); image.fill( Qt::color0 ); QPainter painter( &image ); painter.setClipPath( path ); painter.fillRect( r, Qt::color1 ); // now erase the frame painter.setCompositionMode( QPainter::CompositionMode_DestinationOut ); if ( testAttribute(Qt::WA_StyledBackground ) ) { QStyleOptionFrame opt; opt.initFrom(this); opt.rect = r; style()->drawPrimitive( QStyle::PE_Frame, &opt, &painter, this ); } else { if ( d_data->borderRadius > 0 && frameWidth() > 0 ) { painter.setPen( QPen( Qt::color1, frameWidth() ) ); painter.setBrush( Qt::NoBrush ); painter.setRenderHint( QPainter::Antialiasing, true ); painter.drawPath( path ); } } painter.end(); const QImage mask = image.createMaskFromColor( QColor( Qt::color1 ).rgb(), Qt::MaskOutColor ); return QBitmap::fromImage( mask ); } pcp-gui-1.5.11/src/libqwt/qwt_plot_curve.cpp0000644000000000000000000007070212176111212015703 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_curve.h" #include "qwt_math.h" #include "qwt_clipper.h" #include "qwt_painter.h" #include "qwt_legend.h" #include "qwt_legend_item.h" #include "qwt_scale_map.h" #include "qwt_plot.h" #include "qwt_plot_canvas.h" #include "qwt_curve_fitter.h" #include "qwt_symbol.h" #include #include #include #include static int verifyRange( int size, int &i1, int &i2 ) { if ( size < 1 ) return 0; i1 = qBound( 0, i1, size - 1 ); i2 = qBound( 0, i2, size - 1 ); if ( i1 > i2 ) qSwap( i1, i2 ); return ( i2 - i1 + 1 ); } class QwtPlotCurve::PrivateData { public: PrivateData(): style( QwtPlotCurve::Lines ), baseline( 0.0 ), symbol( NULL ), attributes( 0 ), paintAttributes( QwtPlotCurve::ClipPolygons ), legendAttributes( 0 ) { pen = QPen( Qt::black ); legendPen = Qt::NoPen; curveFitter = new QwtSplineCurveFitter; } ~PrivateData() { delete symbol; delete curveFitter; } QwtPlotCurve::CurveStyle style; double baseline; const QwtSymbol *symbol; QwtCurveFitter *curveFitter; QPen pen; QPen legendPen; QBrush brush; QwtPlotCurve::CurveAttributes attributes; QwtPlotCurve::PaintAttributes paintAttributes; QwtPlotCurve::LegendAttributes legendAttributes; }; /*! Constructor \param title Title of the curve */ QwtPlotCurve::QwtPlotCurve( const QwtText &title ): QwtPlotSeriesItem( title ) { init(); } /*! Constructor \param title Title of the curve */ QwtPlotCurve::QwtPlotCurve( const QString &title ): QwtPlotSeriesItem( QwtText( title ) ) { init(); } //! Destructor QwtPlotCurve::~QwtPlotCurve() { delete d_data; } //! Initialize internal members void QwtPlotCurve::init() { setItemAttribute( QwtPlotItem::Legend ); setItemAttribute( QwtPlotItem::AutoScale ); d_data = new PrivateData; d_series = new QwtPointSeriesData(); setZ( 20.0 ); } //! \return QwtPlotItem::Rtti_PlotCurve int QwtPlotCurve::rtti() const { return QwtPlotItem::Rtti_PlotCurve; } /*! Specify an attribute how to draw the curve \param attribute Paint attribute \param on On/Off \sa testPaintAttribute() */ void QwtPlotCurve::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; } /*! \brief Return the current paint attributes \sa setPaintAttribute() */ bool QwtPlotCurve::testPaintAttribute( PaintAttribute attribute ) const { return ( d_data->paintAttributes & attribute ); } /*! Specify an attribute how to draw the legend identifier \param attribute Attribute \param on On/Off /sa testLegendAttribute() */ void QwtPlotCurve::setLegendAttribute( LegendAttribute attribute, bool on ) { if ( on ) d_data->legendAttributes |= attribute; else d_data->legendAttributes &= ~attribute; } /*! \brief Return the current paint attributes \sa setLegendAttribute() */ bool QwtPlotCurve::testLegendAttribute( LegendAttribute attribute ) const { return ( d_data->legendAttributes & attribute ); } /*! Set the curve's drawing style \param style Curve style \sa style() */ void QwtPlotCurve::setStyle( CurveStyle style ) { if ( style != d_data->style ) { d_data->style = style; itemChanged(); } } /*! Return the current style \sa setStyle() */ QwtPlotCurve::CurveStyle QwtPlotCurve::style() const { return d_data->style; } /*! Assign a symbol The curve will take the ownership of the symbol, hence the previously set symbol will be delete by setting a new one. If \p symbol is \c NULL no symbol will be drawn. \param symbol Symbol \sa symbol() */ void QwtPlotCurve::setSymbol( const QwtSymbol *symbol ) { if ( symbol != d_data->symbol ) { delete d_data->symbol; d_data->symbol = symbol; itemChanged(); } } /*! \return Current symbol or NULL, when no symbol has been assigned \sa setSymbol() */ const QwtSymbol *QwtPlotCurve::symbol() const { return d_data->symbol; } /*! Assign a pen \param pen New pen \sa pen(), brush() */ void QwtPlotCurve::setPen( const QPen &pen ) { if ( pen != d_data->pen ) { d_data->pen = pen; itemChanged(); } } /*! \return Pen used to draw the lines \sa setPen(), brush() */ const QPen& QwtPlotCurve::pen() const { return d_data->pen; } /*! \brief Assign a brush. In case of brush.style() != QBrush::NoBrush and style() != QwtPlotCurve::Sticks the area between the curve and the baseline will be filled. In case !brush.color().isValid() the area will be filled by pen.color(). The fill algorithm simply connects the first and the last curve point to the baseline. So the curve data has to be sorted (ascending or descending). \param brush New brush \sa brush(), setBaseline(), baseline() */ void QwtPlotCurve::setBrush( const QBrush &brush ) { if ( brush != d_data->brush ) { d_data->brush = brush; itemChanged(); } } /*! \return Brush used to fill the area between lines and the baseline \sa setBrush(), setBaseline(), baseline() */ const QBrush& QwtPlotCurve::brush() const { return d_data->brush; } /*! Draw an interval of the curve \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas \param from Index of the first point to be painted \param to Index of the last point to be painted. If to < 0 the curve will be painted to its last point. \sa drawCurve(), drawSymbols(), */ void QwtPlotCurve::drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { if ( !painter || dataSize() <= 0 ) return; if ( to < 0 ) to = dataSize() - 1; if ( verifyRange( dataSize(), from, to ) > 0 ) { painter->save(); painter->setPen( d_data->pen ); /* Qt 4.0.0 is slow when drawing lines, but it's even slower when the painter has a brush. So we don't set the brush before we really need it. */ drawCurve( painter, d_data->style, xMap, yMap, canvasRect, from, to ); painter->restore(); if ( d_data->symbol && ( d_data->symbol->style() != QwtSymbol::NoSymbol ) ) { painter->save(); drawSymbols( painter, *d_data->symbol, xMap, yMap, canvasRect, from, to ); painter->restore(); } } } /*! \brief Draw the line part (without symbols) of a curve interval. \param painter Painter \param style curve style, see QwtPlotCurve::CurveStyle \param xMap x map \param yMap y map \param canvasRect Contents rect of the canvas \param from index of the first point to be painted \param to index of the last point to be painted \sa draw(), drawDots(), drawLines(), drawSteps(), drawSticks() */ void QwtPlotCurve::drawCurve( QPainter *painter, int style, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { switch ( style ) { case Lines: if ( testCurveAttribute( Fitted ) ) { // we always need the complete // curve for fitting from = 0; to = dataSize() - 1; } drawLines( painter, xMap, yMap, canvasRect, from, to ); break; case Sticks: drawSticks( painter, xMap, yMap, canvasRect, from, to ); break; case Steps: drawSteps( painter, xMap, yMap, canvasRect, from, to ); break; case Dots: drawDots( painter, xMap, yMap, canvasRect, from, to ); break; case NoCurve: default: break; } } /*! \brief Draw lines If the CurveAttribute Fitted is enabled a QwtCurveFitter tries to interpolate/smooth the curve, before it is painted. \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rect of the canvas \param from index of the first point to be painted \param to index of the last point to be painted \sa setCurveAttribute(), setCurveFitter(), draw(), drawLines(), drawDots(), drawSteps(), drawSticks() */ void QwtPlotCurve::drawLines( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { int size = to - from + 1; if ( size <= 0 ) return; const bool doAlign = QwtPainter::roundingAlignment( painter ); QPolygonF polyline( size ); QPointF *points = polyline.data(); for ( int i = from; i <= to; i++ ) { const QPointF sample = d_series->sample( i ); double x = xMap.transform( sample.x() ); double y = yMap.transform( sample.y() ); if ( doAlign ) { x = qRound( x ); y = qRound( y ); } points[i - from].rx() = x; points[i - from].ry() = y; } if ( ( d_data->attributes & Fitted ) && d_data->curveFitter ) polyline = d_data->curveFitter->fitCurve( polyline ); if ( d_data->paintAttributes & ClipPolygons ) { qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF()); const QPolygonF clipped = QwtClipper::clipPolygonF( canvasRect.adjusted(-pw, -pw, pw, pw), polyline, false ); QwtPainter::drawPolyline( painter, clipped ); } else { QwtPainter::drawPolyline( painter, polyline ); } if ( d_data->brush.style() != Qt::NoBrush ) fillCurve( painter, xMap, yMap, canvasRect, polyline ); } /*! Draw sticks \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rect of the canvas \param from index of the first point to be painted \param to index of the last point to be painted \sa draw(), drawCurve(), drawDots(), drawLines(), drawSteps() */ void QwtPlotCurve::drawSticks( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &, int from, int to ) const { painter->save(); painter->setRenderHint( QPainter::Antialiasing, false ); const bool doAlign = QwtPainter::roundingAlignment( painter ); double x0 = xMap.transform( d_data->baseline ); double y0 = yMap.transform( d_data->baseline ); if ( doAlign ) { x0 = qRound( x0 ); y0 = qRound( y0 ); } const Qt::Orientation o = orientation(); for ( int i = from; i <= to; i++ ) { const QPointF sample = d_series->sample( i ); double xi = xMap.transform( sample.x() ); double yi = yMap.transform( sample.y() ); if ( doAlign ) { xi = qRound( xi ); yi = qRound( yi ); } if ( o == Qt::Horizontal ) QwtPainter::drawLine( painter, x0, yi, xi, yi ); else QwtPainter::drawLine( painter, xi, y0, xi, yi ); } painter->restore(); } /*! Draw dots \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rect of the canvas \param from index of the first point to be painted \param to index of the last point to be painted \sa draw(), drawCurve(), drawSticks(), drawLines(), drawSteps() */ void QwtPlotCurve::drawDots( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { const bool doFill = d_data->brush.style() != Qt::NoBrush; const bool doAlign = QwtPainter::roundingAlignment( painter ); QPolygonF polyline; if ( doFill ) polyline.resize( to - from + 1 ); QPointF *points = polyline.data(); for ( int i = from; i <= to; i++ ) { const QPointF sample = d_series->sample( i ); double xi = xMap.transform( sample.x() ); double yi = yMap.transform( sample.y() ); if ( doAlign ) { xi = qRound( xi ); yi = qRound( yi ); } QwtPainter::drawPoint( painter, QPointF( xi, yi ) ); if ( doFill ) { points[i - from].rx() = xi; points[i - from].ry() = yi; } } if ( doFill ) fillCurve( painter, xMap, yMap, canvasRect, polyline ); } /*! Draw step function The direction of the steps depends on Inverted attribute. \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rect of the canvas \param from index of the first point to be painted \param to index of the last point to be painted \sa CurveAttribute, setCurveAttribute(), draw(), drawCurve(), drawDots(), drawLines(), drawSticks() */ void QwtPlotCurve::drawSteps( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { const bool doAlign = QwtPainter::roundingAlignment( painter ); QPolygonF polygon( 2 * ( to - from ) + 1 ); QPointF *points = polygon.data(); bool inverted = orientation() == Qt::Vertical; if ( d_data->attributes & Inverted ) inverted = !inverted; int i, ip; for ( i = from, ip = 0; i <= to; i++, ip += 2 ) { const QPointF sample = d_series->sample( i ); double xi = xMap.transform( sample.x() ); double yi = yMap.transform( sample.y() ); if ( doAlign ) { xi = qRound( xi ); yi = qRound( yi ); } if ( ip > 0 ) { const QPointF &p0 = points[ip - 2]; QPointF &p = points[ip - 1]; if ( inverted ) { p.rx() = p0.x(); p.ry() = yi; } else { p.rx() = xi; p.ry() = p0.y(); } } points[ip].rx() = xi; points[ip].ry() = yi; } if ( d_data->paintAttributes & ClipPolygons ) { const QPolygonF clipped = QwtClipper::clipPolygonF( canvasRect, polygon, false ); QwtPainter::drawPolyline( painter, clipped ); } else { QwtPainter::drawPolyline( painter, polygon ); } if ( d_data->brush.style() != Qt::NoBrush ) fillCurve( painter, xMap, yMap, canvasRect, polygon ); } /*! Specify an attribute for drawing the curve \param attribute Curve attribute \param on On/Off /sa testCurveAttribute(), setCurveFitter() */ void QwtPlotCurve::setCurveAttribute( CurveAttribute attribute, bool on ) { if ( bool( d_data->attributes & attribute ) == on ) return; if ( on ) d_data->attributes |= attribute; else d_data->attributes &= ~attribute; itemChanged(); } /*! \return true, if attribute is enabled \sa setCurveAttribute() */ bool QwtPlotCurve::testCurveAttribute( CurveAttribute attribute ) const { return d_data->attributes & attribute; } /*! Assign a curve fitter The curve fitter "smooths" the curve points, when the Fitted CurveAttribute is set. setCurveFitter(NULL) also disables curve fitting. The curve fitter operates on the translated points ( = widget coordinates) to be functional for logarithmic scales. Obviously this is less performant for fitting algorithms, that reduce the number of points. For situations, where curve fitting is used to improve the performance of painting huge series of points it might be better to execute the fitter on the curve points once and to cache the result in the QwtSeriesData object. \param curveFitter() Curve fitter \sa Fitted */ void QwtPlotCurve::setCurveFitter( QwtCurveFitter *curveFitter ) { delete d_data->curveFitter; d_data->curveFitter = curveFitter; itemChanged(); } /*! Get the curve fitter. If curve fitting is disabled NULL is returned. \return Curve fitter \sa setCurveFitter(), Fitted */ QwtCurveFitter *QwtPlotCurve::curveFitter() const { return d_data->curveFitter; } /*! Fill the area between the curve and the baseline with the curve brush \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rect of the canvas \param polygon Polygon - will be modified ! \sa setBrush(), setBaseline(), setStyle() */ void QwtPlotCurve::fillCurve( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, QPolygonF &polygon ) const { if ( d_data->brush.style() == Qt::NoBrush ) return; closePolyline( painter, xMap, yMap, polygon ); if ( polygon.count() <= 2 ) // a line can't be filled return; QBrush brush = d_data->brush; if ( !brush.color().isValid() ) brush.setColor( d_data->pen.color() ); if ( d_data->paintAttributes & ClipPolygons ) polygon = QwtClipper::clipPolygonF( canvasRect, polygon, true ); painter->save(); painter->setPen( Qt::NoPen ); painter->setBrush( brush ); QwtPainter::drawPolygon( painter, polygon ); painter->restore(); } /*! \brief Complete a polygon to be a closed polygon including the area between the original polygon and the baseline. \param painter Painter \param xMap X map \param yMap Y map \param polygon Polygon to be completed */ void QwtPlotCurve::closePolyline( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, QPolygonF &polygon ) const { if ( polygon.size() < 2 ) return; const bool doAlign = QwtPainter::roundingAlignment( painter ); double baseline = d_data->baseline; if ( orientation() == Qt::Vertical ) { if ( yMap.transformation()->type() == QwtScaleTransformation::Log10 ) { if ( baseline < QwtScaleMap::LogMin ) baseline = QwtScaleMap::LogMin; } double refY = yMap.transform( baseline ); if ( doAlign ) refY = qRound( refY ); polygon += QPointF( polygon.last().x(), refY ); polygon += QPointF( polygon.first().x(), refY ); } else { if ( xMap.transformation()->type() == QwtScaleTransformation::Log10 ) { if ( baseline < QwtScaleMap::LogMin ) baseline = QwtScaleMap::LogMin; } double refX = xMap.transform( baseline ); if ( doAlign ) refX = qRound( refX ); polygon += QPointF( refX, polygon.last().y() ); polygon += QPointF( refX, polygon.first().y() ); } } /*! Draw symbols \param painter Painter \param symbol Curve symbol \param xMap x map \param yMap y map \param canvasRect Contents rect of the canvas \param from Index of the first point to be painted \param to Index of the last point to be painted \sa setSymbol(), drawSeries(), drawCurve() */ void QwtPlotCurve::drawSymbols( QPainter *painter, const QwtSymbol &symbol, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { const bool doAlign = QwtPainter::roundingAlignment( painter ); bool usePixmap = testPaintAttribute( CacheSymbols ); if ( usePixmap && !doAlign ) { // Don't use the pixmap, when the paint device // could generate scalable vectors usePixmap = false; } if ( usePixmap ) { const QSize sz = ( 2 * symbol.boundingSize() + QSize( 1, 1 ) ) / 2; const int w2 = sz.width() / 2; const int h2 = sz.height() / 2; QPixmap pm( sz ); pm.fill( Qt::transparent ); QPainter p( &pm ); p.setRenderHints( painter->renderHints() ); symbol.drawSymbol( &p, QPointF( w2, h2 ) ); p.end(); for ( int i = from; i <= to; i++ ) { const QPointF sample = d_series->sample( i ); const double xi = xMap.transform( sample.x() ); const double yi = yMap.transform( sample.y() ); if ( canvasRect.contains( xi, yi ) ) { const int left = qRound( xi ) - w2; const int top = qRound( yi ) - h2; painter->drawPixmap( left, top, pm ); } } } else { const int chunkSize = 500; for ( int i = from; i <= to; i += chunkSize ) { const int n = qMin( chunkSize, to - i + 1 ); QPolygonF points; for ( int j = 0; j < n; j++ ) { const QPointF sample = d_series->sample( i + j ); const double xi = xMap.transform( sample.x() ); const double yi = yMap.transform( sample.y() ); if ( canvasRect.contains( xi, yi ) ) points += QPointF( xi, yi ); } if ( points.size() > 0 ) symbol.drawSymbols( painter, points ); } } } /*! \brief Set the value of the baseline The baseline is needed for filling the curve with a brush or the Sticks drawing style. The interpretation of the baseline depends on the orientation(). With Qt::Horizontal, the baseline is interpreted as a horizontal line at y = baseline(), with Qt::Vertical, it is interpreted as a vertical line at x = baseline(). The default value is 0.0. \param value Value of the baseline \sa baseline(), setBrush(), setStyle(), QwtPlotAbstractSeriesItem::orientation() */ void QwtPlotCurve::setBaseline( double value ) { if ( d_data->baseline != value ) { d_data->baseline = value; itemChanged(); } } /*! \return Value of the baseline \sa setBaseline() */ double QwtPlotCurve::baseline() const { return d_data->baseline; } /*! Find the closest curve point for a specific position \param pos Position, where to look for the closest curve point \param dist If dist != NULL, closestPoint() returns the distance between the position and the clostest curve point \return Index of the closest curve point, or -1 if none can be found ( f.e when the curve has no points ) \note closestPoint() implements a dumb algorithm, that iterates over all points */ int QwtPlotCurve::closestPoint( const QPoint &pos, double *dist ) const { if ( plot() == NULL || dataSize() <= 0 ) return -1; const QwtScaleMap xMap = plot()->canvasMap( xAxis() ); const QwtScaleMap yMap = plot()->canvasMap( yAxis() ); int index = -1; double dmin = 1.0e10; for ( uint i = 0; i < dataSize(); i++ ) { const QPointF sample = d_series->sample( i ); const double cx = xMap.transform( sample.x() ) - pos.x(); const double cy = yMap.transform( sample.y() ) - pos.y(); const double f = qwtSqr( cx ) + qwtSqr( cy ); if ( f < dmin ) { index = i; dmin = f; } } if ( dist ) *dist = qSqrt( dmin ); return index; } /*! \brief Update the widget that represents the item on the legend \param legend Legend \sa drawLegendIdentifier(), legendItem(), QwtPlotItem::Legend */ void QwtPlotCurve::updateLegend( QwtLegend *legend ) const { if ( legend && testItemAttribute( QwtPlotItem::Legend ) && ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol ) && d_data->symbol && d_data->symbol->style() != QwtSymbol::NoSymbol ) { QWidget *lgdItem = legend->find( this ); if ( lgdItem == NULL ) { lgdItem = legendItem(); if ( lgdItem ) legend->insert( this, lgdItem ); } QwtLegendItem *l = qobject_cast( lgdItem ); if ( l ) { QSize sz = d_data->symbol->boundingSize(); sz += QSize( 2, 2 ); // margin if ( d_data->legendAttributes & QwtPlotCurve::LegendShowLine ) { // Avoid, that the line is completely covered by the symbol int w = qCeil( 1.5 * sz.width() ); if ( w % 2 ) w++; sz.setWidth( qMax( 8, w ) ); } l->setIdentifierSize( sz ); } } QwtPlotItem::updateLegend( legend ); } /*! \brief Draw the identifier representing the curve on the legend \param painter Painter \param rect Bounding rectangle for the identifier \sa setLegendAttribute(), QwtPlotItem::Legend */ void QwtPlotCurve::drawLegendIdentifier( QPainter *painter, const QRectF &rect ) const { if ( rect.isEmpty() ) return; const double dim = qMin( rect.width(), rect.height() ); QSizeF size( dim, dim ); QRectF r( 0, 0, size.width(), size.height() ); r.moveCenter( rect.center() ); if ( d_data->legendAttributes == 0 ) { QBrush brush = d_data->brush; if ( brush.style() == Qt::NoBrush ) { if ( style() != QwtPlotCurve::NoCurve ) brush = QBrush( pen().color() ); else if ( d_data->symbol && ( d_data->symbol->style() != QwtSymbol::NoSymbol ) ) { brush = QBrush( d_data->symbol->pen().color() ); } } if ( brush.style() != Qt::NoBrush ) painter->fillRect( r, brush ); } if ( d_data->legendAttributes & QwtPlotCurve::LegendShowBrush ) { if ( d_data->brush.style() != Qt::NoBrush ) painter->fillRect( r, d_data->brush ); } if ( d_data->legendAttributes & QwtPlotCurve::LegendShowLine ) { if ( pen() != Qt::NoPen ) { painter->setPen( pen() ); QwtPainter::drawLine( painter, rect.left(), rect.center().y(), rect.right() - 1.0, rect.center().y() ); } } if ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol ) { if ( d_data->symbol && ( d_data->symbol->style() != QwtSymbol::NoSymbol ) ) { QSize symbolSize = d_data->symbol->boundingSize(); symbolSize -= QSize( 2, 2 ); // scale the symbol size down if it doesn't fit into rect. double xRatio = 1.0; if ( rect.width() < symbolSize.width() ) xRatio = rect.width() / symbolSize.width(); double yRatio = 1.0; if ( rect.height() < symbolSize.height() ) yRatio = rect.height() / symbolSize.height(); const double ratio = qMin( xRatio, yRatio ); painter->save(); painter->scale( ratio, ratio ); d_data->symbol->drawSymbol( painter, rect.center() / ratio ); painter->restore(); } } } /*! Initialize data with an array of points (explicitly shared). \param samples Vector of points */ void QwtPlotCurve::setSamples( const QVector &samples ) { delete d_series; d_series = new QwtPointSeriesData( samples ); itemChanged(); } #ifndef QWT_NO_COMPAT /*! \brief Initialize the data by pointing to memory blocks which are not managed by QwtPlotCurve. setRawSamples is provided for efficiency. It is important to keep the pointers during the lifetime of the underlying QwtCPointerData class. \param xData pointer to x data \param yData pointer to y data \param size size of x and y \sa QwtCPointerData */ void QwtPlotCurve::setRawSamples( const double *xData, const double *yData, int size ) { delete d_series; d_series = new QwtCPointerData( xData, yData, size ); itemChanged(); } /*! Set data by copying x- and y-values from specified memory blocks. Contrary to setRawSamples(), this function makes a 'deep copy' of the data. \param xData pointer to x values \param yData pointer to y values \param size size of xData and yData \sa QwtPointArrayData */ void QwtPlotCurve::setSamples( const double *xData, const double *yData, int size ) { delete d_series; d_series = new QwtPointArrayData( xData, yData, size ); itemChanged(); } /*! \brief Initialize data with x- and y-arrays (explicitly shared) \param xData x data \param yData y data \sa QwtPointArrayData */ void QwtPlotCurve::setSamples( const QVector &xData, const QVector &yData ) { delete d_series; d_series = new QwtPointArrayData( xData, yData ); itemChanged(); } #endif // !QWT_NO_COMPAT pcp-gui-1.5.11/src/libqwt/qwt_plot_dict.cpp0000644000000000000000000001071712176111212015502 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_dict.h" class QwtPlotDict::PrivateData { public: class ItemList: public QList { public: void insertItem( QwtPlotItem *item ) { if ( item == NULL ) return; QList::iterator it = qUpperBound( begin(), end(), item, LessZThan() ); insert( it, item ); } void removeItem( QwtPlotItem *item ) { if ( item == NULL ) return; QList::iterator it = qLowerBound( begin(), end(), item, LessZThan() ); for ( ; it != end(); ++it ) { if ( item == *it ) { erase( it ); break; } } } private: class LessZThan { public: inline bool operator()( const QwtPlotItem *item1, const QwtPlotItem *item2 ) const { return item1->z() < item2->z(); } }; }; ItemList itemList; bool autoDelete; }; /*! Constructor Auto deletion is enabled. \sa setAutoDelete(), attachItem() */ QwtPlotDict::QwtPlotDict() { d_data = new QwtPlotDict::PrivateData; d_data->autoDelete = true; } /*! Destructor If autoDelete is on, all attached items will be deleted \sa setAutoDelete(), autoDelete(), attachItem() */ QwtPlotDict::~QwtPlotDict() { detachItems( QwtPlotItem::Rtti_PlotItem, d_data->autoDelete ); delete d_data; } /*! En/Disable Auto deletion If Auto deletion is on all attached plot items will be deleted in the destructor of QwtPlotDict. The default value is on. \sa autoDelete(), attachItem() */ void QwtPlotDict::setAutoDelete( bool autoDelete ) { d_data->autoDelete = autoDelete; } /*! \return true if auto deletion is enabled \sa setAutoDelete(), attachItem() */ bool QwtPlotDict::autoDelete() const { return d_data->autoDelete; } /*! Attach/Detach a plot item Attached items will be deleted in the destructor, if auto deletion is enabled (default). Manually detached items are not deleted. \param item Plot item to attach/detach \ on If true attach, else detach the item \sa setAutoDelete(), ~QwtPlotDict() */ void QwtPlotDict::attachItem( QwtPlotItem *item, bool on ) { if ( on ) d_data->itemList.insertItem( item ); else d_data->itemList.removeItem( item ); } /*! Detach items from the dictionary \param rtti In case of QwtPlotItem::Rtti_PlotItem detach all items otherwise only those items of the type rtti. \param autoDelete If true, delete all detached items */ void QwtPlotDict::detachItems( int rtti, bool autoDelete ) { PrivateData::ItemList list = d_data->itemList; QwtPlotItemIterator it = list.begin(); while ( it != list.end() ) { QwtPlotItem *item = *it; ++it; // increment before removing item from the list if ( rtti == QwtPlotItem::Rtti_PlotItem || item->rtti() == rtti ) { item->attach( NULL ); if ( autoDelete ) delete item; } } } /*! \brief A QwtPlotItemList of all attached plot items. Use caution when iterating these lists, as removing/detaching an item will invalidate the iterator. Instead you can place pointers to objects to be removed in a removal list, and traverse that list later. \return List of all attached plot items. */ const QwtPlotItemList &QwtPlotDict::itemList() const { return d_data->itemList; } /*! \return List of all attached plot items of a specific type. \sa QwtPlotItem::rtti() */ QwtPlotItemList QwtPlotDict::itemList( int rtti ) const { if ( rtti == QwtPlotItem::Rtti_PlotItem ) return d_data->itemList; QwtPlotItemList items; PrivateData::ItemList list = d_data->itemList; for ( QwtPlotItemIterator it = list.begin(); it != list.end(); ++it ) { QwtPlotItem *item = *it; if ( item->rtti() == rtti ) items += item; } return items; } pcp-gui-1.5.11/src/libqwt/qwt_plot_directpainter.cpp0000644000000000000000000002001412176111212017403 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_directpainter.h" #include "qwt_scale_map.h" #include "qwt_plot.h" #include "qwt_plot_canvas.h" #include "qwt_plot_seriesitem.h" #include #include #include #include static inline void renderItem( QPainter *painter, const QRect &canvasRect, QwtPlotAbstractSeriesItem *seriesItem, int from, int to ) { // A minor performance improvement is possible // with caching the maps. TODO ... QwtPlot *plot = seriesItem->plot(); const QwtScaleMap xMap = plot->canvasMap( seriesItem->xAxis() ); const QwtScaleMap yMap = plot->canvasMap( seriesItem->yAxis() ); painter->setRenderHint( QPainter::Antialiasing, seriesItem->testRenderHint( QwtPlotItem::RenderAntialiased ) ); seriesItem->drawSeries( painter, xMap, yMap, canvasRect, from, to ); } class QwtPlotDirectPainter::PrivateData { public: PrivateData(): attributes( 0 ), hasClipping(false), seriesItem( NULL ) { } QwtPlotDirectPainter::Attributes attributes; bool hasClipping; QRegion clipRegion; QPainter painter; QwtPlotAbstractSeriesItem *seriesItem; int from; int to; }; //! Constructor QwtPlotDirectPainter::QwtPlotDirectPainter( QObject *parent ): QObject( parent ) { d_data = new PrivateData; } //! Destructor QwtPlotDirectPainter::~QwtPlotDirectPainter() { delete d_data; } /*! Change an attribute \param attribute Attribute to change \param on On/Off \sa Attribute, testAttribute() */ void QwtPlotDirectPainter::setAttribute( Attribute attribute, bool on ) { if ( bool( d_data->attributes & attribute ) != on ) { if ( on ) d_data->attributes |= attribute; else d_data->attributes &= ~attribute; if ( ( attribute == AtomicPainter ) && on ) reset(); } } /*! Check if a attribute is set. \param attribute Attribute to be tested \sa Attribute, setAttribute() */ bool QwtPlotDirectPainter::testAttribute( Attribute attribute ) const { return d_data->attributes & attribute; } /*! En/Disables clipping \param enable Enables clipping is true, disable it otherwise \sa hasClipping(), clipRegion(), setClipRegion() */ void QwtPlotDirectPainter::setClipping( bool enable ) { d_data->hasClipping = enable; } /*! \return true, when clipping is enabled \sa setClipping(), clipRegion(), setClipRegion() */ bool QwtPlotDirectPainter::hasClipping() const { return d_data->hasClipping; } /*! \brief Assign a clip region and enable clipping Depending on the environment setting a proper clip region might improve the performance heavily. F.e. on Qt embedded only the clipped part of the backing store will be copied to a ( maybe unaccelerated ) frame buffer device. \param region Clip region \sa clipRegion(), hasClipping(), setClipping() */ void QwtPlotDirectPainter::setClipRegion( const QRegion ®ion ) { d_data->clipRegion = region; d_data->hasClipping = true; } /*! \return Currently set clip region. \sa setClipRegion(), setClipping(), hasClipping() */ QRegion QwtPlotDirectPainter::clipRegion() const { return d_data->clipRegion; } /*! \brief Draw a set of points of a seriesItem. When observing an measurement while it is running, new points have to be added to an existing seriesItem. drawSeries can be used to display them avoiding a complete redraw of the canvas. Setting plot()->canvas()->setAttribute(Qt::WA_PaintOutsidePaintEvent, true); will result in faster painting, if the paint engine of the canvas widget supports this feature. \param seriesItem Item to be painted \param from Index of the first point to be painted \param to Index of the last point to be painted. If to < 0 the series will be painted to its last point. */ void QwtPlotDirectPainter::drawSeries( QwtPlotAbstractSeriesItem *seriesItem, int from, int to ) { if ( seriesItem == NULL || seriesItem->plot() == NULL ) return; QwtPlotCanvas *canvas = seriesItem->plot()->canvas(); const QRect canvasRect = canvas->contentsRect(); const bool hasBackingStore = canvas->testPaintAttribute( QwtPlotCanvas::BackingStore ) && canvas->backingStore() && !canvas->backingStore()->isNull(); if ( hasBackingStore ) { QPainter painter( const_cast( canvas->backingStore() ) ); if ( d_data->hasClipping ) painter.setClipRegion( d_data->clipRegion ); renderItem( &painter, canvasRect, seriesItem, from, to ); if ( testAttribute( QwtPlotDirectPainter::FullRepaint ) ) { canvas->repaint(); return; } } bool immediatePaint = true; if ( !canvas->testAttribute( Qt::WA_WState_InPaintEvent ) ) { #if QT_VERSION < 0x050000 if ( !canvas->testAttribute( Qt::WA_PaintOutsidePaintEvent ) ) #endif immediatePaint = false; } if ( immediatePaint ) { if ( !d_data->painter.isActive() ) { reset(); d_data->painter.begin( canvas ); canvas->installEventFilter( this ); } if ( d_data->hasClipping ) { d_data->painter.setClipRegion( QRegion( canvasRect ) & d_data->clipRegion ); } else { if ( !d_data->painter.hasClipping() ) d_data->painter.setClipRect( canvasRect ); } renderItem( &d_data->painter, canvasRect, seriesItem, from, to ); if ( d_data->attributes & QwtPlotDirectPainter::AtomicPainter ) { reset(); } else { if ( d_data->hasClipping ) d_data->painter.setClipping( false ); } } else { reset(); d_data->seriesItem = seriesItem; d_data->from = from; d_data->to = to; QRegion clipRegion = canvasRect; if ( d_data->hasClipping ) clipRegion &= d_data->clipRegion; canvas->installEventFilter( this ); canvas->repaint(clipRegion); canvas->removeEventFilter( this ); d_data->seriesItem = NULL; } } //! Close the internal QPainter void QwtPlotDirectPainter::reset() { if ( d_data->painter.isActive() ) { QWidget *w = ( QWidget * )d_data->painter.device(); if ( w ) w->removeEventFilter( this ); d_data->painter.end(); } } //! Event filter bool QwtPlotDirectPainter::eventFilter( QObject *, QEvent *event ) { if ( event->type() == QEvent::Paint ) { reset(); if ( d_data->seriesItem ) { const QPaintEvent *pe = static_cast< QPaintEvent *>( event ); QwtPlotCanvas *canvas = d_data->seriesItem->plot()->canvas(); QPainter painter( canvas ); painter.setClipRegion( pe->region() ); bool copyCache = testAttribute( CopyBackingStore ) && canvas->testPaintAttribute( QwtPlotCanvas::BackingStore ); if ( copyCache ) { // is something valid in the cache ? copyCache = ( canvas->backingStore() != NULL ) && !canvas->backingStore()->isNull(); } if ( copyCache ) { painter.drawPixmap( canvas->contentsRect().topLeft(), *canvas->backingStore() ); } else { renderItem( &painter, canvas->contentsRect(), d_data->seriesItem, d_data->from, d_data->to ); } return true; // don't call QwtPlotCanvas::paintEvent() } } return false; } pcp-gui-1.5.11/src/libqwt/qwt_plot_grid.cpp0000644000000000000000000001765312176111212015512 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_grid.h" #include "qwt_painter.h" #include "qwt_text.h" #include "qwt_scale_map.h" #include "qwt_scale_div.h" #include "qwt_math.h" #include #include class QwtPlotGrid::PrivateData { public: PrivateData(): xEnabled( true ), yEnabled( true ), xMinEnabled( false ), yMinEnabled( false ) { } bool xEnabled; bool yEnabled; bool xMinEnabled; bool yMinEnabled; QwtScaleDiv xScaleDiv; QwtScaleDiv yScaleDiv; QPen majPen; QPen minPen; }; //! Enables major grid, disables minor grid QwtPlotGrid::QwtPlotGrid(): QwtPlotItem( QwtText( "Grid" ) ) { d_data = new PrivateData; setZ( 10.0 ); } //! Destructor QwtPlotGrid::~QwtPlotGrid() { delete d_data; } //! \return QwtPlotItem::Rtti_PlotGrid int QwtPlotGrid::rtti() const { return QwtPlotItem::Rtti_PlotGrid; } /*! \brief Enable or disable vertical gridlines \param tf Enable (true) or disable \sa Minor gridlines can be enabled or disabled with enableXMin() */ void QwtPlotGrid::enableX( bool tf ) { if ( d_data->xEnabled != tf ) { d_data->xEnabled = tf; itemChanged(); } } /*! \brief Enable or disable horizontal gridlines \param tf Enable (true) or disable \sa Minor gridlines can be enabled or disabled with enableYMin() */ void QwtPlotGrid::enableY( bool tf ) { if ( d_data->yEnabled != tf ) { d_data->yEnabled = tf; itemChanged(); } } /*! \brief Enable or disable minor vertical gridlines. \param tf Enable (true) or disable \sa enableX() */ void QwtPlotGrid::enableXMin( bool tf ) { if ( d_data->xMinEnabled != tf ) { d_data->xMinEnabled = tf; itemChanged(); } } /*! \brief Enable or disable minor horizontal gridlines \param tf Enable (true) or disable \sa enableY() */ void QwtPlotGrid::enableYMin( bool tf ) { if ( d_data->yMinEnabled != tf ) { d_data->yMinEnabled = tf; itemChanged(); } } /*! Assign an x axis scale division \param scaleDiv Scale division */ void QwtPlotGrid::setXDiv( const QwtScaleDiv &scaleDiv ) { if ( d_data->xScaleDiv != scaleDiv ) { d_data->xScaleDiv = scaleDiv; itemChanged(); } } /*! Assign a y axis division \param scaleDiv Scale division */ void QwtPlotGrid::setYDiv( const QwtScaleDiv &scaleDiv ) { if ( d_data->yScaleDiv != scaleDiv ) { d_data->yScaleDiv = scaleDiv; itemChanged(); } } /*! Assign a pen for both major and minor gridlines \param pen Pen \sa setMajPen(), setMinPen() */ void QwtPlotGrid::setPen( const QPen &pen ) { if ( d_data->majPen != pen || d_data->minPen != pen ) { d_data->majPen = pen; d_data->minPen = pen; itemChanged(); } } /*! Assign a pen for the major gridlines \param pen Pen \sa majPen(), setMinPen(), setPen() */ void QwtPlotGrid::setMajPen( const QPen &pen ) { if ( d_data->majPen != pen ) { d_data->majPen = pen; itemChanged(); } } /*! Assign a pen for the minor gridlines \param pen Pen \sa minPen(), setMajPen(), setPen() */ void QwtPlotGrid::setMinPen( const QPen &pen ) { if ( d_data->minPen != pen ) { d_data->minPen = pen; itemChanged(); } } /*! \brief Draw the grid The grid is drawn into the bounding rectangle such that gridlines begin and end at the rectangle's borders. The X and Y maps are used to map the scale divisions into the drawing region screen. \param painter Painter \param xMap X axis map \param yMap Y axis \param canvasRect Contents rect of the plot canvas */ void QwtPlotGrid::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { // draw minor gridlines QPen minPen = d_data->minPen; minPen.setCapStyle( Qt::FlatCap ); painter->setPen( minPen ); if ( d_data->xEnabled && d_data->xMinEnabled ) { drawLines( painter, canvasRect, Qt::Vertical, xMap, d_data->xScaleDiv.ticks( QwtScaleDiv::MinorTick ) ); drawLines( painter, canvasRect, Qt::Vertical, xMap, d_data->xScaleDiv.ticks( QwtScaleDiv::MediumTick ) ); } if ( d_data->yEnabled && d_data->yMinEnabled ) { drawLines( painter, canvasRect, Qt::Horizontal, yMap, d_data->yScaleDiv.ticks( QwtScaleDiv::MinorTick ) ); drawLines( painter, canvasRect, Qt::Horizontal, yMap, d_data->yScaleDiv.ticks( QwtScaleDiv::MediumTick ) ); } // draw major gridlines QPen majPen = d_data->majPen; majPen.setCapStyle( Qt::FlatCap ); painter->setPen( majPen ); if ( d_data->xEnabled ) { drawLines( painter, canvasRect, Qt::Vertical, xMap, d_data->xScaleDiv.ticks( QwtScaleDiv::MajorTick ) ); } if ( d_data->yEnabled ) { drawLines( painter, canvasRect, Qt::Horizontal, yMap, d_data->yScaleDiv.ticks( QwtScaleDiv::MajorTick ) ); } } void QwtPlotGrid::drawLines( QPainter *painter, const QRectF &canvasRect, Qt::Orientation orientation, const QwtScaleMap &scaleMap, const QList &values ) const { const double x1 = canvasRect.left(); const double x2 = canvasRect.right() - 1.0; const double y1 = canvasRect.top(); const double y2 = canvasRect.bottom() - 1.0; const bool doAlign = QwtPainter::roundingAlignment( painter ); for ( int i = 0; i < values.count(); i++ ) { double value = scaleMap.transform( values[i] ); if ( doAlign ) value = qRound( value ); if ( orientation == Qt::Horizontal ) { if ( qwtFuzzyGreaterOrEqual( value, y1 ) && qwtFuzzyLessOrEqual( value, y2 ) ) { QwtPainter::drawLine( painter, x1, value, x2, value ); } } else { if ( qwtFuzzyGreaterOrEqual( value, x1 ) && qwtFuzzyLessOrEqual( value, x2 ) ) { QwtPainter::drawLine( painter, value, y1, value, y2 ); } } } } /*! \return the pen for the major gridlines \sa setMajPen(), setMinPen(), setPen() */ const QPen &QwtPlotGrid::majPen() const { return d_data->majPen; } /*! \return the pen for the minor gridlines \sa setMinPen(), setMajPen(), setPen() */ const QPen &QwtPlotGrid::minPen() const { return d_data->minPen; } /*! \return true if vertical gridlines are enabled \sa enableX() */ bool QwtPlotGrid::xEnabled() const { return d_data->xEnabled; } /*! \return true if minor vertical gridlines are enabled \sa enableXMin() */ bool QwtPlotGrid::xMinEnabled() const { return d_data->xMinEnabled; } /*! \return true if horizontal gridlines are enabled \sa enableY() */ bool QwtPlotGrid::yEnabled() const { return d_data->yEnabled; } /*! \return true if minor horizontal gridlines are enabled \sa enableYMin() */ bool QwtPlotGrid::yMinEnabled() const { return d_data->yMinEnabled; } /*! \return the scale division of the x axis */ const QwtScaleDiv &QwtPlotGrid::xScaleDiv() const { return d_data->xScaleDiv; } /*! \return the scale division of the y axis */ const QwtScaleDiv &QwtPlotGrid::yScaleDiv() const { return d_data->yScaleDiv; } /*! Update the grid to changes of the axes scale division \param xScaleDiv Scale division of the x-axis \param yScaleDiv Scale division of the y-axis \sa QwtPlot::updateAxes() */ void QwtPlotGrid::updateScaleDiv( const QwtScaleDiv& xScaleDiv, const QwtScaleDiv& yScaleDiv ) { setXDiv( xScaleDiv ); setYDiv( yScaleDiv ); } pcp-gui-1.5.11/src/libqwt/qwt_plot_histogram.cpp0000644000000000000000000004152712176111212016557 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_histogram.h" #include "qwt_plot.h" #include "qwt_legend.h" #include "qwt_legend_item.h" #include "qwt_painter.h" #include "qwt_column_symbol.h" #include "qwt_scale_map.h" #include #include static inline bool isCombinable( const QwtInterval &d1, const QwtInterval &d2 ) { if ( d1.isValid() && d2.isValid() ) { if ( d1.maxValue() == d2.minValue() ) { if ( !( d1.borderFlags() & QwtInterval::ExcludeMaximum && d2.borderFlags() & QwtInterval::ExcludeMinimum ) ) { return true; } } } return false; } class QwtPlotHistogram::PrivateData { public: PrivateData(): baseline( 0.0 ), style( Columns ), symbol( NULL ) { } ~PrivateData() { delete symbol; } double baseline; QPen pen; QBrush brush; QwtPlotHistogram::HistogramStyle style; const QwtColumnSymbol *symbol; }; /*! Constructor \param title Title of the histogram. */ QwtPlotHistogram::QwtPlotHistogram( const QwtText &title ): QwtPlotSeriesItem( title ) { init(); } /*! Constructor \param title Title of the histogram. */ QwtPlotHistogram::QwtPlotHistogram( const QString &title ): QwtPlotSeriesItem( title ) { init(); } //! Destructor QwtPlotHistogram::~QwtPlotHistogram() { delete d_data; } //! Initialize data members void QwtPlotHistogram::init() { d_data = new PrivateData(); d_series = new QwtIntervalSeriesData(); setItemAttribute( QwtPlotItem::AutoScale, true ); setItemAttribute( QwtPlotItem::Legend, true ); setZ( 20.0 ); } /*! Set the histogram's drawing style \param style Histogram style \sa HistogramStyle, style() */ void QwtPlotHistogram::setStyle( HistogramStyle style ) { if ( style != d_data->style ) { d_data->style = style; itemChanged(); } } /*! Return the current style \sa HistogramStyle, setStyle() */ QwtPlotHistogram::HistogramStyle QwtPlotHistogram::style() const { return d_data->style; } /*! Assign a pen, that is used in a style() depending way. \param pen New pen \sa pen(), brush() */ void QwtPlotHistogram::setPen( const QPen &pen ) { if ( pen != d_data->pen ) { d_data->pen = pen; itemChanged(); } } /*! \return Pen used in a style() depending way. \sa setPen(), brush() */ const QPen &QwtPlotHistogram::pen() const { return d_data->pen; } /*! Assign a brush, that is used in a style() depending way. \param brush New brush \sa pen(), brush() */ void QwtPlotHistogram::setBrush( const QBrush &brush ) { if ( brush != d_data->brush ) { d_data->brush = brush; itemChanged(); } } /*! \return Brush used in a style() depending way. \sa setPen(), brush() */ const QBrush &QwtPlotHistogram::brush() const { return d_data->brush; } /*! \brief Assign a symbol In Column style an optional symbol can be assigned, that is responsible for displaying the rectangle that is defined by the interval and the distance between baseline() and value. When no symbol has been defined the area is displayed as plain rectangle using pen() and brush(). \sa style(), symbol(), drawColumn(), pen(), brush() \note In applications, where different intervals need to be displayed in a different way ( f.e different colors or even using differnt symbols) it is recommended to overload drawColumn(). */ void QwtPlotHistogram::setSymbol( const QwtColumnSymbol *symbol ) { if ( symbol != d_data->symbol ) { delete d_data->symbol; d_data->symbol = symbol; itemChanged(); } } /*! \return Current symbol or NULL, when no symbol has been assigned \sa setSymbol() */ const QwtColumnSymbol *QwtPlotHistogram::symbol() const { return d_data->symbol; } /*! \brief Set the value of the baseline Each column representing an QwtIntervalSample is defined by its interval and the interval between baseline and the value of the sample. The default value of the baseline is 0.0. \param value Value of the baseline \sa baseline() */ void QwtPlotHistogram::setBaseline( double value ) { if ( d_data->baseline != value ) { d_data->baseline = value; itemChanged(); } } /*! \return Value of the baseline \sa setBaseline() */ double QwtPlotHistogram::baseline() const { return d_data->baseline; } /*! \return Bounding rectangle of all samples. For an empty series the rectangle is invalid. */ QRectF QwtPlotHistogram::boundingRect() const { QRectF rect = d_series->boundingRect(); if ( !rect.isValid() ) return rect; if ( orientation() == Qt::Horizontal ) { rect = QRectF( rect.y(), rect.x(), rect.height(), rect.width() ); if ( rect.left() > d_data->baseline ) rect.setLeft( d_data->baseline ); else if ( rect.right() < d_data->baseline ) rect.setRight( d_data->baseline ); } else { if ( rect.bottom() < d_data->baseline ) rect.setBottom( d_data->baseline ); else if ( rect.top() > d_data->baseline ) rect.setTop( d_data->baseline ); } return rect; } //! \return QwtPlotItem::Rtti_PlotHistogram int QwtPlotHistogram::rtti() const { return QwtPlotItem::Rtti_PlotHistogram; } /*! Initialize data with an array of samples. \param samples Vector of points */ void QwtPlotHistogram::setSamples( const QVector &samples ) { delete d_series; d_series = new QwtIntervalSeriesData( samples ); itemChanged(); } /*! Draw a subset of the histogram samples \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the series will be painted to its last sample. \sa drawOutline(), drawLines(), drawColumns */ void QwtPlotHistogram::drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &, int from, int to ) const { if ( !painter || dataSize() <= 0 ) return; if ( to < 0 ) to = dataSize() - 1; switch ( d_data->style ) { case Outline: drawOutline( painter, xMap, yMap, from, to ); break; case Lines: drawLines( painter, xMap, yMap, from, to ); break; case Columns: drawColumns( painter, xMap, yMap, from, to ); break; default: break; } } /*! Draw a histogram in Outline style() \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the histogram will be painted to its last point. \sa setStyle(), style() \warning The outline style requires, that the intervals are in increasing order and not overlapping. */ void QwtPlotHistogram::drawOutline( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const { const bool doAlign = QwtPainter::roundingAlignment( painter ); double v0 = ( orientation() == Qt::Horizontal ) ? xMap.transform( baseline() ) : yMap.transform( baseline() ); if ( doAlign ) v0 = qRound( v0 ); QwtIntervalSample previous; QPolygonF polygon; for ( int i = from; i <= to; i++ ) { const QwtIntervalSample sample = d_series->sample( i ); if ( !sample.interval.isValid() ) { flushPolygon( painter, v0, polygon ); previous = sample; continue; } if ( previous.interval.isValid() ) { if ( !isCombinable( previous.interval, sample.interval ) ) flushPolygon( painter, v0, polygon ); } if ( orientation() == Qt::Vertical ) { double x1 = xMap.transform( sample.interval.minValue() ); double x2 = xMap.transform( sample.interval.maxValue() ); double y = yMap.transform( sample.value ); if ( doAlign ) { x1 = qRound( x1 ); x2 = qRound( x2 ); y = qRound( y ); } if ( polygon.size() == 0 ) polygon += QPointF( x1, v0 ); polygon += QPointF( x1, y ); polygon += QPointF( x2, y ); } else { double y1 = yMap.transform( sample.interval.minValue() ); double y2 = yMap.transform( sample.interval.maxValue() ); double x = xMap.transform( sample.value ); if ( doAlign ) { y1 = qRound( y1 ); y2 = qRound( y2 ); x = qRound( x ); } if ( polygon.size() == 0 ) polygon += QPointF( v0, y1 ); polygon += QPointF( x, y1 ); polygon += QPointF( x, y2 ); } previous = sample; } flushPolygon( painter, v0, polygon ); } /*! Draw a histogram in Columns style() \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the histogram will be painted to its last point. \sa setStyle(), style(), setSymbol(), drawColumn() */ void QwtPlotHistogram::drawColumns( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const { painter->setPen( d_data->pen ); painter->setBrush( d_data->brush ); for ( int i = from; i <= to; i++ ) { const QwtIntervalSample sample = d_series->sample( i ); if ( !sample.interval.isNull() ) { const QwtColumnRect rect = columnRect( sample, xMap, yMap ); drawColumn( painter, rect, sample ); } } } /*! Draw a histogram in Lines style() \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the histogram will be painted to its last point. \sa setStyle(), style(), setPen() */ void QwtPlotHistogram::drawLines( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const { const bool doAlign = QwtPainter::roundingAlignment( painter ); painter->setPen( d_data->pen ); painter->setBrush( Qt::NoBrush ); for ( int i = from; i <= to; i++ ) { const QwtIntervalSample sample = d_series->sample( i ); if ( !sample.interval.isNull() ) { const QwtColumnRect rect = columnRect( sample, xMap, yMap ); QRectF r = rect.toRect(); if ( doAlign ) { r.setLeft( qRound( r.left() ) ); r.setRight( qRound( r.right() ) ); r.setTop( qRound( r.top() ) ); r.setBottom( qRound( r.bottom() ) ); } switch ( rect.direction ) { case QwtColumnRect::LeftToRight: { QwtPainter::drawLine( painter, r.topRight(), r.bottomRight() ); break; } case QwtColumnRect::RightToLeft: { QwtPainter::drawLine( painter, r.topLeft(), r.bottomLeft() ); break; } case QwtColumnRect::TopToBottom: { QwtPainter::drawLine( painter, r.bottomRight(), r.bottomLeft() ); break; } case QwtColumnRect::BottomToTop: { QwtPainter::drawLine( painter, r.topRight(), r.topLeft() ); break; } } } } } //! Internal, used by the Outline style. void QwtPlotHistogram::flushPolygon( QPainter *painter, double baseLine, QPolygonF &polygon ) const { if ( polygon.size() == 0 ) return; if ( orientation() == Qt::Horizontal ) polygon += QPointF( baseLine, polygon.last().y() ); else polygon += QPointF( polygon.last().x(), baseLine ); if ( d_data->brush.style() != Qt::NoBrush ) { painter->setPen( Qt::NoPen ); painter->setBrush( d_data->brush ); if ( orientation() == Qt::Horizontal ) { polygon += QPointF( polygon.last().x(), baseLine ); polygon += QPointF( polygon.first().x(), baseLine ); } else { polygon += QPointF( baseLine, polygon.last().y() ); polygon += QPointF( baseLine, polygon.first().y() ); } QwtPainter::drawPolygon( painter, polygon ); polygon.resize( polygon.size() - 2 ); } if ( d_data->pen.style() != Qt::NoPen ) { painter->setBrush( Qt::NoBrush ); painter->setPen( d_data->pen ); QwtPainter::drawPolyline( painter, polygon ); } polygon.clear(); } /*! Calculate the area that is covered by a sample \param sample Sample \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \return Rectangle, that is covered by a sample */ QwtColumnRect QwtPlotHistogram::columnRect( const QwtIntervalSample &sample, const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const { QwtColumnRect rect; const QwtInterval &iv = sample.interval; if ( !iv.isValid() ) return rect; if ( orientation() == Qt::Horizontal ) { const double x0 = xMap.transform( baseline() ); const double x = xMap.transform( sample.value ); const double y1 = yMap.transform( iv.minValue() ); const double y2 = yMap.transform( iv.maxValue() ); rect.hInterval.setInterval( x0, x ); rect.vInterval.setInterval( y1, y2, iv.borderFlags() ); rect.direction = ( x < x0 ) ? QwtColumnRect::RightToLeft : QwtColumnRect::LeftToRight; } else { const double x1 = xMap.transform( iv.minValue() ); const double x2 = xMap.transform( iv.maxValue() ); const double y0 = yMap.transform( baseline() ); const double y = yMap.transform( sample.value ); rect.hInterval.setInterval( x1, x2, iv.borderFlags() ); rect.vInterval.setInterval( y0, y ); rect.direction = ( y < y0 ) ? QwtColumnRect::BottomToTop : QwtColumnRect::TopToBottom; } return rect; } /*! Draw a column for a sample in Columns style(). When a symbol() has been set the symbol is used otherwise the column is displayed as plain rectangle using pen() and brush(). \param painter Painter \param rect Rectangle where to paint the column in paint device coordinates \param sample Sample to be displayed \note In applications, where different intervals need to be displayed in a different way ( f.e different colors or even using differnt symbols) it is recommended to overload drawColumn(). */ void QwtPlotHistogram::drawColumn( QPainter *painter, const QwtColumnRect &rect, const QwtIntervalSample &sample ) const { Q_UNUSED( sample ); if ( d_data->symbol && ( d_data->symbol->style() != QwtColumnSymbol::NoStyle ) ) { d_data->symbol->draw( painter, rect ); } else { QRectF r = rect.toRect(); if ( QwtPainter::roundingAlignment( painter ) ) { r.setLeft( qRound( r.left() ) ); r.setRight( qRound( r.right() ) ); r.setTop( qRound( r.top() ) ); r.setBottom( qRound( r.bottom() ) ); } QwtPainter::drawRect( painter, r ); } } /*! Draw a plain rectangle without pen using the brush() as identifier \param painter Painter \param rect Bounding rectangle for the identifier */ void QwtPlotHistogram::drawLegendIdentifier( QPainter *painter, const QRectF &rect ) const { const double dim = qMin( rect.width(), rect.height() ); QSizeF size( dim, dim ); QRectF r( 0, 0, size.width(), size.height() ); r.moveCenter( rect.center() ); painter->fillRect( r, d_data->brush ); } pcp-gui-1.5.11/src/libqwt/qwt_plot_intervalcurve.cpp0000644000000000000000000003367312176111212017456 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_intervalcurve.h" #include "qwt_interval_symbol.h" #include "qwt_scale_map.h" #include "qwt_clipper.h" #include "qwt_painter.h" #include static inline bool qwtIsHSampleInside( const QwtIntervalSample &sample, double xMin, double xMax, double yMin, double yMax ) { const double y = sample.value; const double x1 = sample.interval.minValue(); const double x2 = sample.interval.maxValue(); const bool isOffScreen = ( y < yMin ) || ( y > yMax ) || ( x1 < xMin && x2 < xMin ) || ( x1 > xMax && x2 > xMax ); return !isOffScreen; } static inline bool qwtIsVSampleInside( const QwtIntervalSample &sample, double xMin, double xMax, double yMin, double yMax ) { const double x = sample.value; const double y1 = sample.interval.minValue(); const double y2 = sample.interval.maxValue(); const bool isOffScreen = ( x < xMin ) || ( x > xMax ) || ( y1 < yMin && y2 < yMin ) || ( y1 > yMax && y2 > yMax ); return !isOffScreen; } class QwtPlotIntervalCurve::PrivateData { public: PrivateData(): style( QwtPlotIntervalCurve::Tube ), symbol( NULL ), pen( Qt::black ), brush( Qt::white ) { paintAttributes = QwtPlotIntervalCurve::ClipPolygons; paintAttributes |= QwtPlotIntervalCurve::ClipSymbol; pen.setCapStyle( Qt::FlatCap ); } ~PrivateData() { delete symbol; } QwtPlotIntervalCurve::CurveStyle style; const QwtIntervalSymbol *symbol; QPen pen; QBrush brush; QwtPlotIntervalCurve::PaintAttributes paintAttributes; }; /*! Constructor \param title Title of the curve */ QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QwtText &title ): QwtPlotSeriesItem( title ) { init(); } /*! Constructor \param title Title of the curve */ QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QString &title ): QwtPlotSeriesItem( QwtText( title ) ) { init(); } //! Destructor QwtPlotIntervalCurve::~QwtPlotIntervalCurve() { delete d_data; } //! Initialize internal members void QwtPlotIntervalCurve::init() { setItemAttribute( QwtPlotItem::Legend, true ); setItemAttribute( QwtPlotItem::AutoScale, true ); d_data = new PrivateData; d_series = new QwtIntervalSeriesData(); setZ( 19.0 ); } //! \return QwtPlotItem::Rtti_PlotIntervalCurve int QwtPlotIntervalCurve::rtti() const { return QwtPlotIntervalCurve::Rtti_PlotIntervalCurve; } /*! Specify an attribute how to draw the curve \param attribute Paint attribute \param on On/Off \sa testPaintAttribute() */ void QwtPlotIntervalCurve::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; } /*! \brief Return the current paint attributes \sa PaintAttribute, setPaintAttribute() */ bool QwtPlotIntervalCurve::testPaintAttribute( PaintAttribute attribute ) const { return ( d_data->paintAttributes & attribute ); } /*! Initialize data with an array of samples. \param samples Vector of samples */ void QwtPlotIntervalCurve::setSamples( const QVector &samples ) { delete d_series; d_series = new QwtIntervalSeriesData( samples ); itemChanged(); } /*! Set the curve's drawing style \param style Curve style \sa CurveStyle, style() */ void QwtPlotIntervalCurve::setStyle( CurveStyle style ) { if ( style != d_data->style ) { d_data->style = style; itemChanged(); } } /*! \brief Return the current style \sa setStyle() */ QwtPlotIntervalCurve::CurveStyle QwtPlotIntervalCurve::style() const { return d_data->style; } /*! Assign a symbol. \param symbol Symbol \sa symbol() */ void QwtPlotIntervalCurve::setSymbol( const QwtIntervalSymbol *symbol ) { if ( symbol != d_data->symbol ) { delete d_data->symbol; d_data->symbol = symbol; itemChanged(); } } /*! \return Current symbol or NULL, when no symbol has been assigned \sa setSymbol() */ const QwtIntervalSymbol *QwtPlotIntervalCurve::symbol() const { return d_data->symbol; } /*! \brief Assign a pen \param pen New pen \sa pen(), brush() */ void QwtPlotIntervalCurve::setPen( const QPen &pen ) { if ( pen != d_data->pen ) { d_data->pen = pen; itemChanged(); } } /*! \brief Return the pen used to draw the lines \sa setPen(), brush() */ const QPen& QwtPlotIntervalCurve::pen() const { return d_data->pen; } /*! Assign a brush. The brush is used to fill the area in Tube style(). \param brush Brush \sa brush(), pen(), setStyle(), CurveStyle */ void QwtPlotIntervalCurve::setBrush( const QBrush &brush ) { if ( brush != d_data->brush ) { d_data->brush = brush; itemChanged(); } } /*! \return Brush used to fill the area in Tube style() \sa setBrush(), setStyle(), CurveStyle */ const QBrush& QwtPlotIntervalCurve::brush() const { return d_data->brush; } /*! \return Bounding rectangle of all samples. For an empty series the rectangle is invalid. */ QRectF QwtPlotIntervalCurve::boundingRect() const { QRectF rect = QwtPlotSeriesItem::boundingRect(); if ( rect.isValid() && orientation() == Qt::Vertical ) rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() ); return rect; } /*! Draw a subset of the samples \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the series will be painted to its last sample. \sa drawTube(), drawSymbols() */ void QwtPlotIntervalCurve::drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { if ( to < 0 ) to = dataSize() - 1; if ( from < 0 ) from = 0; if ( from > to ) return; switch ( d_data->style ) { case Tube: drawTube( painter, xMap, yMap, canvasRect, from, to ); break; case NoCurve: default: break; } if ( d_data->symbol && ( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) ) { drawSymbols( painter, *d_data->symbol, xMap, yMap, canvasRect, from, to ); } } /*! Draw a tube Builds 2 curves from the upper and lower limits of the intervals and draws them with the pen(). The area between the curves is filled with the brush(). \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the series will be painted to its last sample. \sa drawSeries(), drawSymbols() */ void QwtPlotIntervalCurve::drawTube( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { const bool doAlign = QwtPainter::roundingAlignment( painter ); painter->save(); const size_t size = to - from + 1; QPolygonF polygon( 2 * size ); QPointF *points = polygon.data(); for ( uint i = 0; i < size; i++ ) { QPointF &minValue = points[i]; QPointF &maxValue = points[2 * size - 1 - i]; const QwtIntervalSample intervalSample = sample( from + i ); if ( orientation() == Qt::Vertical ) { double x = xMap.transform( intervalSample.value ); double y1 = yMap.transform( intervalSample.interval.minValue() ); double y2 = yMap.transform( intervalSample.interval.maxValue() ); if ( doAlign ) { x = qRound( x ); y1 = qRound( y1 ); y2 = qRound( y2 ); } minValue.rx() = x; minValue.ry() = y1; maxValue.rx() = x; maxValue.ry() = y2; } else { double y = yMap.transform( intervalSample.value ); double x1 = xMap.transform( intervalSample.interval.minValue() ); double x2 = xMap.transform( intervalSample.interval.maxValue() ); if ( doAlign ) { y = qRound( y ); x1 = qRound( x1 ); x2 = qRound( x2 ); } minValue.rx() = x1; minValue.ry() = y; maxValue.rx() = x2; maxValue.ry() = y; } } if ( d_data->brush.style() != Qt::NoBrush ) { painter->setPen( QPen( Qt::NoPen ) ); painter->setBrush( d_data->brush ); if ( d_data->paintAttributes & ClipPolygons ) { const qreal m = 1.0; const QPolygonF p = QwtClipper::clipPolygonF( canvasRect.adjusted( -m, -m, m, m ), polygon, true ); QwtPainter::drawPolygon( painter, p ); } else { QwtPainter::drawPolygon( painter, polygon ); } } if ( d_data->pen.style() != Qt::NoPen ) { painter->setPen( d_data->pen ); painter->setBrush( Qt::NoBrush ); if ( d_data->paintAttributes & ClipPolygons ) { qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF() ); const QRectF clipRect = canvasRect.adjusted( -pw, -pw, pw, pw ); QPolygonF p; p.resize( size ); qMemCopy( p.data(), points, size * sizeof( QPointF ) ); p = QwtClipper::clipPolygonF( clipRect, p ); QwtPainter::drawPolyline( painter, p ); p.resize( size ); qMemCopy( p.data(), points + size, size * sizeof( QPointF ) ); p = QwtClipper::clipPolygonF( clipRect, p ); QwtPainter::drawPolyline( painter, p ); } else { QwtPainter::drawPolyline( painter, points, size ); QwtPainter::drawPolyline( painter, points + size, size ); } } painter->restore(); } /*! Draw symbols for a subset of the samples \param painter Painter \param symbol Interval symbol \param xMap x map \param yMap y map \param canvasRect Contents rect of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted \sa setSymbol(), drawSeries(), drawTube() */ void QwtPlotIntervalCurve::drawSymbols( QPainter *painter, const QwtIntervalSymbol &symbol, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { painter->save(); QPen pen = symbol.pen(); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); painter->setBrush( symbol.brush() ); const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect ); const double xMin = tr.left(); const double xMax = tr.right(); const double yMin = tr.top(); const double yMax = tr.bottom(); const bool doClip = d_data->paintAttributes & ClipSymbol; for ( int i = from; i <= to; i++ ) { const QwtIntervalSample s = sample( i ); if ( orientation() == Qt::Vertical ) { if ( !doClip || qwtIsVSampleInside( s, xMin, xMax, yMin, yMax ) ) { const double x = xMap.transform( s.value ); const double y1 = yMap.transform( s.interval.minValue() ); const double y2 = yMap.transform( s.interval.maxValue() ); symbol.draw( painter, orientation(), QPointF( x, y1 ), QPointF( x, y2 ) ); } } else { if ( !doClip || qwtIsHSampleInside( s, xMin, xMax, yMin, yMax ) ) { const double y = yMap.transform( s.value ); const double x1 = xMap.transform( s.interval.minValue() ); const double x2 = xMap.transform( s.interval.maxValue() ); symbol.draw( painter, orientation(), QPointF( x1, y ), QPointF( x2, y ) ); } } } painter->restore(); } /*! \brief Draw the identifier for the legend In case of Tube style() a plain rectangle filled with the brush() is painted. If a symbol is assigned it is painted centered into rect. \param painter Painter \param rect Bounding rectangle for the identifier */ void QwtPlotIntervalCurve::drawLegendIdentifier( QPainter *painter, const QRectF &rect ) const { const double dim = qMin( rect.width(), rect.height() ); QSizeF size( dim, dim ); QRectF r( 0, 0, size.width(), size.height() ); r.moveCenter( rect.center() ); if ( d_data->style == Tube ) { painter->fillRect( r, d_data->brush ); } if ( d_data->symbol && ( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) ) { QPen pen = d_data->symbol->pen(); pen.setWidthF( pen.widthF() ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); painter->setBrush( d_data->symbol->brush() ); if ( orientation() == Qt::Vertical ) { d_data->symbol->draw( painter, orientation(), QPointF( r.center().x(), r.top() ), QPointF( r.center().x(), r.bottom() - 1 ) ); } else { d_data->symbol->draw( painter, orientation(), QPointF( r.left(), r.center().y() ), QPointF( r.right() - 1, r.center().y() ) ); } } } pcp-gui-1.5.11/src/libqwt/qwt_plot_item.cpp0000644000000000000000000002651712176111212015522 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_item.h" #include "qwt_text.h" #include "qwt_plot.h" #include "qwt_legend.h" #include "qwt_legend_item.h" #include "qwt_scale_div.h" #include class QwtPlotItem::PrivateData { public: PrivateData(): plot( NULL ), isVisible( true ), attributes( 0 ), renderHints( 0 ), z( 0.0 ), xAxis( QwtPlot::xBottom ), yAxis( QwtPlot::yLeft ) { } mutable QwtPlot *plot; bool isVisible; QwtPlotItem::ItemAttributes attributes; QwtPlotItem::RenderHints renderHints; double z; int xAxis; int yAxis; QwtText title; }; /*! Constructor \param title Title of the item */ QwtPlotItem::QwtPlotItem( const QwtText &title ) { d_data = new PrivateData; d_data->title = title; } //! Destroy the QwtPlotItem QwtPlotItem::~QwtPlotItem() { attach( NULL ); delete d_data; } /*! \brief Attach the item to a plot. This method will attach a QwtPlotItem to the QwtPlot argument. It will first detach the QwtPlotItem from any plot from a previous call to attach (if necessary). If a NULL argument is passed, it will detach from any QwtPlot it was attached to. \param plot Plot widget \sa detach() */ void QwtPlotItem::attach( QwtPlot *plot ) { if ( plot == d_data->plot ) return; // remove the item from the previous plot if ( d_data->plot ) { if ( d_data->plot->legend() ) d_data->plot->legend()->remove( this ); d_data->plot->attachItem( this, false ); if ( d_data->plot->autoReplot() ) d_data->plot->update(); } d_data->plot = plot; if ( d_data->plot ) { // insert the item into the current plot d_data->plot->attachItem( this, true ); itemChanged(); } } /*! \brief This method detaches a QwtPlotItem from any QwtPlot it has been associated with. detach() is equivalent to calling attach( NULL ) \sa attach() */ void QwtPlotItem::detach() { attach( NULL ); } /*! Return rtti for the specific class represented. QwtPlotItem is simply a virtual interface class, and base classes will implement this method with specific rtti values so a user can differentiate them. The rtti value is useful for environments, where the runtime type information is disabled and it is not possible to do a dynamic_cast<...>. \return rtti value \sa RttiValues */ int QwtPlotItem::rtti() const { return Rtti_PlotItem; } //! Return attached plot QwtPlot *QwtPlotItem::plot() const { return d_data->plot; } /*! Plot items are painted in increasing z-order. \return setZ(), QwtPlotDict::itemList() */ double QwtPlotItem::z() const { return d_data->z; } /*! \brief Set the z value Plot items are painted in increasing z-order. \param z Z-value \sa z(), QwtPlotDict::itemList() */ void QwtPlotItem::setZ( double z ) { if ( d_data->z != z ) { if ( d_data->plot ) // update the z order d_data->plot->attachItem( this, false ); d_data->z = z; if ( d_data->plot ) d_data->plot->attachItem( this, true ); itemChanged(); } } /*! Set a new title \param title Title \sa title() */ void QwtPlotItem::setTitle( const QString &title ) { setTitle( QwtText( title ) ); } /*! Set a new title \param title Title \sa title() */ void QwtPlotItem::setTitle( const QwtText &title ) { if ( d_data->title != title ) { d_data->title = title; itemChanged(); } } /*! \return Title of the item \sa setTitle() */ const QwtText &QwtPlotItem::title() const { return d_data->title; } /*! Toggle an item attribute \param attribute Attribute type \param on true/false \sa testItemAttribute(), ItemAttribute */ void QwtPlotItem::setItemAttribute( ItemAttribute attribute, bool on ) { if ( bool( d_data->attributes & attribute ) != on ) { if ( on ) d_data->attributes |= attribute; else d_data->attributes &= ~attribute; itemChanged(); } } /*! Test an item attribute \param attribute Attribute type \return true/false \sa setItemAttribute(), ItemAttribute */ bool QwtPlotItem::testItemAttribute( ItemAttribute attribute ) const { return ( d_data->attributes & attribute ); } /*! Toggle an render hint \param hint Render hint \param on true/false \sa testRenderHint(), RenderHint */ void QwtPlotItem::setRenderHint( RenderHint hint, bool on ) { if ( ( ( d_data->renderHints & hint ) != 0 ) != on ) { if ( on ) d_data->renderHints |= hint; else d_data->renderHints &= ~hint; itemChanged(); } } /*! Test a render hint \param hint Render hint \return true/false \sa setRenderHint(), RenderHint */ bool QwtPlotItem::testRenderHint( RenderHint hint ) const { return ( d_data->renderHints & hint ); } //! Show the item void QwtPlotItem::show() { setVisible( true ); } //! Hide the item void QwtPlotItem::hide() { setVisible( false ); } /*! Show/Hide the item \param on Show if true, otherwise hide \sa isVisible(), show(), hide() */ void QwtPlotItem::setVisible( bool on ) { if ( on != d_data->isVisible ) { d_data->isVisible = on; itemChanged(); } } /*! \return true if visible \sa setVisible(), show(), hide() */ bool QwtPlotItem::isVisible() const { return d_data->isVisible; } /*! Update the legend and call QwtPlot::autoRefresh for the parent plot. \sa updateLegend() */ void QwtPlotItem::itemChanged() { if ( d_data->plot ) { if ( d_data->plot->legend() ) updateLegend( d_data->plot->legend() ); d_data->plot->autoRefresh(); } } /*! Set X and Y axis The item will painted according to the coordinates its Axes. \param xAxis X Axis \param yAxis Y Axis \sa setXAxis(), setYAxis(), xAxis(), yAxis() */ void QwtPlotItem::setAxes( int xAxis, int yAxis ) { if ( xAxis == QwtPlot::xBottom || xAxis == QwtPlot::xTop ) d_data->xAxis = xAxis; if ( yAxis == QwtPlot::yLeft || yAxis == QwtPlot::yRight ) d_data->yAxis = yAxis; itemChanged(); } /*! Set the X axis The item will painted according to the coordinates its Axes. \param axis X Axis \sa setAxes(), setYAxis(), xAxis() */ void QwtPlotItem::setXAxis( int axis ) { if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) { d_data->xAxis = axis; itemChanged(); } } /*! Set the Y axis The item will painted according to the coordinates its Axes. \param axis Y Axis \sa setAxes(), setXAxis(), yAxis() */ void QwtPlotItem::setYAxis( int axis ) { if ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) { d_data->yAxis = axis; itemChanged(); } } //! Return xAxis int QwtPlotItem::xAxis() const { return d_data->xAxis; } //! Return yAxis int QwtPlotItem::yAxis() const { return d_data->yAxis; } /*! \return An invalid bounding rect: QRectF(1.0, 1.0, -2.0, -2.0) */ QRectF QwtPlotItem::boundingRect() const { return QRectF( 1.0, 1.0, -2.0, -2.0 ); // invalid } /*! \brief Allocate the widget that represents the item on the legend The default implementation returns a QwtLegendItem(), but an item could be represented by any type of widget, by overloading legendItem() and updateLegend(). \return QwtLegendItem() \sa updateLegend() QwtLegend() */ QWidget *QwtPlotItem::legendItem() const { QwtLegendItem *item = new QwtLegendItem; if ( d_data->plot ) { QObject::connect( item, SIGNAL( clicked() ), d_data->plot, SLOT( legendItemClicked() ) ); QObject::connect( item, SIGNAL( checked( bool ) ), d_data->plot, SLOT( legendItemChecked( bool ) ) ); } return item; } /*! \brief Update the widget that represents the item on the legend updateLegend() is called from itemChanged() to adopt the widget representing the item on the legend to its new configuration. The default implementation updates a QwtLegendItem(), but an item could be represented by any type of widget, by overloading legendItem() and updateLegend(). \param legend Legend \sa legendItem(), itemChanged(), QwtLegend() */ void QwtPlotItem::updateLegend( QwtLegend *legend ) const { if ( legend == NULL ) return; QWidget *lgdItem = legend->find( this ); if ( testItemAttribute( QwtPlotItem::Legend ) ) { if ( lgdItem == NULL ) { lgdItem = legendItem(); if ( lgdItem ) legend->insert( this, lgdItem ); } QwtLegendItem *label = qobject_cast( lgdItem ); if ( label ) { // paint the identifier const QSize sz = label->identifierSize(); QPixmap identifier( sz.width(), sz.height() ); identifier.fill( Qt::transparent ); QPainter painter( &identifier ); painter.setRenderHint( QPainter::Antialiasing, testRenderHint( QwtPlotItem::RenderAntialiased ) ); drawLegendIdentifier( &painter, QRect( 0, 0, sz.width(), sz.height() ) ); painter.end(); const bool doUpdate = label->updatesEnabled(); if ( doUpdate ) label->setUpdatesEnabled( false ); label->setText( title() ); label->setIdentifier( identifier ); label->setItemMode( legend->itemMode() ); if ( doUpdate ) label->setUpdatesEnabled( true ); label->update(); } } else { if ( lgdItem ) { lgdItem->hide(); lgdItem->deleteLater(); } } } /*! \brief Update the item to changes of the axes scale division Update the item, when the axes of plot have changed. The default implementation does nothing, but items that depend on the scale division (like QwtPlotGrid()) have to reimplement updateScaleDiv() \param xScaleDiv Scale division of the x-axis \param yScaleDiv Scale division of the y-axis \sa QwtPlot::updateAxes() */ void QwtPlotItem::updateScaleDiv( const QwtScaleDiv &xScaleDiv, const QwtScaleDiv &yScaleDiv ) { Q_UNUSED( xScaleDiv ); Q_UNUSED( yScaleDiv ); } /*! \brief Calculate the bounding scale rect of 2 maps \param xMap X map \param yMap Y map \return Bounding scale rect of the scale maps, not normalized */ QRectF QwtPlotItem::scaleRect( const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const { return QRectF( xMap.s1(), yMap.s1(), xMap.sDist(), yMap.sDist() ); } /*! \brief Calculate the bounding paint rect of 2 maps \param xMap X map \param yMap Y map \return Bounding paint rect of the scale maps, not normalized */ QRectF QwtPlotItem::paintRect( const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const { const QRectF rect( xMap.p1(), yMap.p1(), xMap.pDist(), yMap.pDist() ); return rect; } pcp-gui-1.5.11/src/libqwt/qwt_plot_layout.cpp0000644000000000000000000011523612176111212016076 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_layout.h" #include "qwt_text.h" #include "qwt_text_label.h" #include "qwt_plot_canvas.h" #include "qwt_scale_widget.h" #include "qwt_legend.h" #include #include class QwtPlotLayout::LayoutData { public: void init( const QwtPlot *, const QRectF &rect ); struct t_legendData { int frameWidth; int vScrollBarWidth; int hScrollBarHeight; QSize hint; } legend; struct t_titleData { QwtText text; int frameWidth; } title; struct t_scaleData { bool isEnabled; const QwtScaleWidget *scaleWidget; QFont scaleFont; int start; int end; int baseLineOffset; double tickOffset; int dimWithoutTitle; } scale[QwtPlot::axisCnt]; struct t_canvasData { int frameWidth; } canvas; }; /* Extract all layout relevant data from the plot components */ void QwtPlotLayout::LayoutData::init( const QwtPlot *plot, const QRectF &rect ) { // legend if ( plot->plotLayout()->legendPosition() != QwtPlot::ExternalLegend && plot->legend() ) { legend.frameWidth = plot->legend()->frameWidth(); legend.vScrollBarWidth = plot->legend()->verticalScrollBar()->sizeHint().width(); legend.hScrollBarHeight = plot->legend()->horizontalScrollBar()->sizeHint().height(); const QSize hint = plot->legend()->sizeHint(); int w = qMin( hint.width(), qFloor( rect.width() ) ); int h = plot->legend()->heightForWidth( w ); if ( h == 0 ) h = hint.height(); if ( h > rect.height() ) w += legend.vScrollBarWidth; legend.hint = QSize( w, h ); } // title title.frameWidth = 0; title.text = QwtText(); if ( plot->titleLabel() ) { const QwtTextLabel *label = plot->titleLabel(); title.text = label->text(); if ( !( title.text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) ) title.text.setFont( label->font() ); title.frameWidth = plot->titleLabel()->frameWidth(); } // scales for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( plot->axisEnabled( axis ) ) { const QwtScaleWidget *scaleWidget = plot->axisWidget( axis ); scale[axis].isEnabled = true; scale[axis].scaleWidget = scaleWidget; scale[axis].scaleFont = scaleWidget->font(); scale[axis].start = scaleWidget->startBorderDist(); scale[axis].end = scaleWidget->endBorderDist(); scale[axis].baseLineOffset = scaleWidget->margin(); scale[axis].tickOffset = scaleWidget->margin(); if ( scaleWidget->scaleDraw()->hasComponent( QwtAbstractScaleDraw::Ticks ) ) { scale[axis].tickOffset += scaleWidget->scaleDraw()->maxTickLength(); } scale[axis].dimWithoutTitle = scaleWidget->dimForLength( QWIDGETSIZE_MAX, scale[axis].scaleFont ); if ( !scaleWidget->title().isEmpty() ) { scale[axis].dimWithoutTitle -= scaleWidget->titleHeightForWidth( QWIDGETSIZE_MAX ); } } else { scale[axis].isEnabled = false; scale[axis].start = 0; scale[axis].end = 0; scale[axis].baseLineOffset = 0; scale[axis].tickOffset = 0.0; scale[axis].dimWithoutTitle = 0; } } // canvas canvas.frameWidth = plot->canvas()->frameWidth(); } class QwtPlotLayout::PrivateData { public: PrivateData(): spacing( 5 ), alignCanvasToScales( false ) { } QRectF titleRect; QRectF legendRect; QRectF scaleRect[QwtPlot::axisCnt]; QRectF canvasRect; QwtPlotLayout::LayoutData layoutData; QwtPlot::LegendPosition legendPos; double legendRatio; unsigned int spacing; unsigned int fixedOffset[QwtPlot::axisCnt]; unsigned int canvasMargin[QwtPlot::axisCnt]; bool alignCanvasToScales; }; /*! \brief Constructor */ QwtPlotLayout::QwtPlotLayout() { d_data = new PrivateData; setLegendPosition( QwtPlot::BottomLegend ); setFixedAxisOffset(0); setCanvasMargin( 4 ); invalidate(); } //! Destructor QwtPlotLayout::~QwtPlotLayout() { delete d_data; } /*! Change a margin of the canvas. The margin is the space above/below the scale ticks. A negative margin will be set to -1, excluding the borders of the scales. \param margin New margin \param axis One of QwtPlot::Axis. Specifies where the position of the margin. -1 means margin at all borders. \sa canvasMargin() \warning The margin will have no effect when alignCanvasToScales is true */ void QwtPlotLayout::setCanvasMargin( int margin, int axis ) { if ( margin < -1 ) margin = -1; if ( axis == -1 ) { for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) d_data->canvasMargin[axis] = margin; } else if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->canvasMargin[axis] = margin; } /*! \return Margin around the scale tick borders \sa setCanvasMargin() */ int QwtPlotLayout::canvasMargin( int axis ) const { if ( axis < 0 || axis >= QwtPlot::axisCnt ) return 0; return d_data->canvasMargin[axis]; } /*! * Set a fixed offset for the given axis scale. The offset is the space * between an outer edge of the plot widget and the scale backbone. * * \param offset New offset * \param axis One of QwtPlot::Axis. Specifies which axis to make fixed offset. * -1 means margin at all borders. * \sa fixedAxisOffset() * */ void QwtPlotLayout::setFixedAxisOffset(int offset, int axis) { if ( offset < 0 ) offset = 0; if ( axis == -1 ) { for (axis = 0; axis < QwtPlot::axisCnt; axis++) d_data->fixedOffset[axis] = offset; } else if ( axis >= 0 || axis < QwtPlot::axisCnt ) d_data->fixedOffset[axis] = offset; } /*! * \return Fixed offset, if any, for a given axis scale * \sa setFixedAxisOffset() * */ int QwtPlotLayout::fixedAxisOffset(int axis) const { if ( axis < 0 || axis >= QwtPlot::axisCnt ) return 0; return d_data->fixedOffset[axis]; } /*! Change the align-canvas-to-axis-scales setting. The canvas may: - extend beyond the axis scale ends to maximize its size, - align with the axis scale ends to control its size. \param alignCanvasToScales New align-canvas-to-axis-scales setting \sa setCanvasMargin() \note In this context the term 'scale' means the backbone of a scale. \warning In case of alignCanvasToScales == true canvasMargin will have no effect */ void QwtPlotLayout::setAlignCanvasToScales( bool alignCanvasToScales ) { d_data->alignCanvasToScales = alignCanvasToScales; } /*! Return the align-canvas-to-axis-scales setting. The canvas may: - extend beyond the axis scale ends to maximize its size - align with the axis scale ends to control its size. \return align-canvas-to-axis-scales setting \sa setAlignCanvasToScales, setCanvasMargin() \note In this context the term 'scale' means the backbone of a scale. */ bool QwtPlotLayout::alignCanvasToScales() const { return d_data->alignCanvasToScales; } /*! Change the spacing of the plot. The spacing is the distance between the plot components. \param spacing new spacing \sa setMargin(), spacing() */ void QwtPlotLayout::setSpacing( int spacing ) { d_data->spacing = qMax( 0, spacing ); } /*! \return spacing \sa margin(), setSpacing() */ int QwtPlotLayout::spacing() const { return d_data->spacing; } /*! \brief Specify the position of the legend \param pos The legend's position. \param ratio Ratio between legend and the bounding rect of title, canvas and axes. The legend will be shrinked if it would need more space than the given ratio. The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0 it will be reset to the default ratio. The default vertical/horizontal ratio is 0.33/0.5. \sa QwtPlot::setLegendPosition() */ void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos, double ratio ) { if ( ratio > 1.0 ) ratio = 1.0; switch ( pos ) { case QwtPlot::TopLegend: case QwtPlot::BottomLegend: if ( ratio <= 0.0 ) ratio = 0.33; d_data->legendRatio = ratio; d_data->legendPos = pos; break; case QwtPlot::LeftLegend: case QwtPlot::RightLegend: if ( ratio <= 0.0 ) ratio = 0.5; d_data->legendRatio = ratio; d_data->legendPos = pos; break; case QwtPlot::ExternalLegend: d_data->legendRatio = ratio; // meaningless d_data->legendPos = pos; default: break; } } /*! \brief Specify the position of the legend \param pos The legend's position. Valid values are \c QwtPlot::LeftLegend, \c QwtPlot::RightLegend, \c QwtPlot::TopLegend, \c QwtPlot::BottomLegend. \sa QwtPlot::setLegendPosition() */ void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos ) { setLegendPosition( pos, 0.0 ); } /*! \return Position of the legend \sa setLegendPosition(), QwtPlot::setLegendPosition(), QwtPlot::legendPosition() */ QwtPlot::LegendPosition QwtPlotLayout::legendPosition() const { return d_data->legendPos; } /*! Specify the relative size of the legend in the plot \param ratio Ratio between legend and the bounding rect of title, canvas and axes. The legend will be shrinked if it would need more space than the given ratio. The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0 it will be reset to the default ratio. The default vertical/horizontal ratio is 0.33/0.5. */ void QwtPlotLayout::setLegendRatio( double ratio ) { setLegendPosition( legendPosition(), ratio ); } /*! \return The relative size of the legend in the plot. \sa setLegendPosition() */ double QwtPlotLayout::legendRatio() const { return d_data->legendRatio; } /*! \return Geometry for the title \sa activate(), invalidate() */ const QRectF &QwtPlotLayout::titleRect() const { return d_data->titleRect; } /*! \return Geometry for the legend \sa activate(), invalidate() */ const QRectF &QwtPlotLayout::legendRect() const { return d_data->legendRect; } /*! \param axis Axis index \return Geometry for the scale \sa activate(), invalidate() */ const QRectF &QwtPlotLayout::scaleRect( int axis ) const { if ( axis < 0 || axis >= QwtPlot::axisCnt ) { static QRectF dummyRect; return dummyRect; } return d_data->scaleRect[axis]; } /*! \return Geometry for the canvas \sa activate(), invalidate() */ const QRectF &QwtPlotLayout::canvasRect() const { return d_data->canvasRect; } /*! Invalidate the geometry of all components. \sa activate() */ void QwtPlotLayout::invalidate() { d_data->titleRect = d_data->legendRect = d_data->canvasRect = QRect(); for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) d_data->scaleRect[axis] = QRect(); } /*! \brief Return a minimum size hint \sa QwtPlot::minimumSizeHint() */ QSize QwtPlotLayout::minimumSizeHint( const QwtPlot *plot ) const { class ScaleData { public: ScaleData() { w = h = minLeft = minRight = tickOffset = 0; } int w; int h; int minLeft; int minRight; int tickOffset; } scaleData[QwtPlot::axisCnt]; int canvasBorder[QwtPlot::axisCnt]; int axis; for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( plot->axisEnabled( axis ) ) { const QwtScaleWidget *scl = plot->axisWidget( axis ); ScaleData &sd = scaleData[axis]; const QSize hint = scl->minimumSizeHint(); sd.w = hint.width(); sd.h = hint.height(); scl->getBorderDistHint( sd.minLeft, sd.minRight ); sd.tickOffset = scl->margin(); if ( scl->scaleDraw()->hasComponent( QwtAbstractScaleDraw::Ticks ) ) sd.tickOffset += qCeil( scl->scaleDraw()->maxTickLength() ); } canvasBorder[axis] = plot->canvas()->frameWidth() + d_data->canvasMargin[axis] + 1; } for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) { ScaleData &sd = scaleData[axis]; if ( sd.w && ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) ) { if ( ( sd.minLeft > canvasBorder[QwtPlot::yLeft] ) && scaleData[QwtPlot::yLeft].w ) { int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft]; if ( shiftLeft > scaleData[QwtPlot::yLeft].w ) shiftLeft = scaleData[QwtPlot::yLeft].w; sd.w -= shiftLeft; } if ( ( sd.minRight > canvasBorder[QwtPlot::yRight] ) && scaleData[QwtPlot::yRight].w ) { int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight]; if ( shiftRight > scaleData[QwtPlot::yRight].w ) shiftRight = scaleData[QwtPlot::yRight].w; sd.w -= shiftRight; } } if ( sd.h && ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) ) { if ( ( sd.minLeft > canvasBorder[QwtPlot::xBottom] ) && scaleData[QwtPlot::xBottom].h ) { int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom]; if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset ) shiftBottom = scaleData[QwtPlot::xBottom].tickOffset; sd.h -= shiftBottom; } if ( ( sd.minLeft > canvasBorder[QwtPlot::xTop] ) && scaleData[QwtPlot::xTop].h ) { int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop]; if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset ) shiftTop = scaleData[QwtPlot::xTop].tickOffset; sd.h -= shiftTop; } } } const QwtPlotCanvas *canvas = plot->canvas(); const QSize minCanvasSize = canvas->minimumSize(); int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w; int cw = qMax( scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w ) + 2 * ( canvas->frameWidth() + 1 ); w += qMax( cw, minCanvasSize.width() ); int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h; int ch = qMax( scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h ) + 2 * ( canvas->frameWidth() + 1 ); h += qMax( ch, minCanvasSize.height() ); const QwtTextLabel *title = plot->titleLabel(); if ( title && !title->text().isEmpty() ) { // If only QwtPlot::yLeft or QwtPlot::yRight is showing, // we center on the plot canvas. const bool centerOnCanvas = !( plot->axisEnabled( QwtPlot::yLeft ) && plot->axisEnabled( QwtPlot::yRight ) ); int titleW = w; if ( centerOnCanvas ) { titleW -= scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w; } int titleH = title->heightForWidth( titleW ); if ( titleH > titleW ) // Compensate for a long title { w = titleW = titleH; if ( centerOnCanvas ) { w += scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w; } titleH = title->heightForWidth( titleW ); } h += titleH + d_data->spacing; } // Compute the legend contribution const QwtLegend *legend = plot->legend(); if ( d_data->legendPos != QwtPlot::ExternalLegend && legend && !legend->isEmpty() ) { if ( d_data->legendPos == QwtPlot::LeftLegend || d_data->legendPos == QwtPlot::RightLegend ) { int legendW = legend->sizeHint().width(); int legendH = legend->heightForWidth( legendW ); if ( legend->frameWidth() > 0 ) w += d_data->spacing; if ( legendH > h ) legendW += legend->verticalScrollBar()->sizeHint().width(); if ( d_data->legendRatio < 1.0 ) legendW = qMin( legendW, int( w / ( 1.0 - d_data->legendRatio ) ) ); w += legendW + d_data->spacing; } else // QwtPlot::Top, QwtPlot::Bottom { int legendW = qMin( legend->sizeHint().width(), w ); int legendH = legend->heightForWidth( legendW ); if ( legend->frameWidth() > 0 ) h += d_data->spacing; if ( d_data->legendRatio < 1.0 ) legendH = qMin( legendH, int( h / ( 1.0 - d_data->legendRatio ) ) ); h += legendH + d_data->spacing; } } return QSize( w, h ); } /*! Find the geometry for the legend \param options Options how to layout the legend \param rect Rectangle where to place the legend \return Geometry for the legend \sa Options */ QRectF QwtPlotLayout::layoutLegend( Options options, const QRectF &rect ) const { const QSize hint( d_data->layoutData.legend.hint ); int dim; if ( d_data->legendPos == QwtPlot::LeftLegend || d_data->legendPos == QwtPlot::RightLegend ) { // We don't allow vertical legends to take more than // half of the available space. dim = qMin( hint.width(), int( rect.width() * d_data->legendRatio ) ); if ( !( options & IgnoreScrollbars ) ) { if ( hint.height() > rect.height() ) { // The legend will need additional // space for the vertical scrollbar. dim += d_data->layoutData.legend.vScrollBarWidth; } } } else { dim = qMin( hint.height(), int( rect.height() * d_data->legendRatio ) ); dim = qMax( dim, d_data->layoutData.legend.hScrollBarHeight ); } QRectF legendRect = rect; switch ( d_data->legendPos ) { case QwtPlot::LeftLegend: legendRect.setWidth( dim ); break; case QwtPlot::RightLegend: legendRect.setX( rect.right() - dim ); legendRect.setWidth( dim ); break; case QwtPlot::TopLegend: legendRect.setHeight( dim ); break; case QwtPlot::BottomLegend: legendRect.setY( rect.bottom() - dim ); legendRect.setHeight( dim ); break; case QwtPlot::ExternalLegend: break; } return legendRect; } /*! Align the legend to the canvas \param canvasRect Geometry of the canvas \param legendRect Maximum geometry for the legend \return Geometry for the aligned legend */ QRectF QwtPlotLayout::alignLegend( const QRectF &canvasRect, const QRectF &legendRect ) const { QRectF alignedRect = legendRect; if ( d_data->legendPos == QwtPlot::BottomLegend || d_data->legendPos == QwtPlot::TopLegend ) { if ( d_data->layoutData.legend.hint.width() < canvasRect.width() ) { alignedRect.setX( canvasRect.x() ); alignedRect.setWidth( canvasRect.width() ); } } else { if ( d_data->layoutData.legend.hint.height() < canvasRect.height() ) { alignedRect.setY( canvasRect.y() ); alignedRect.setHeight( canvasRect.height() ); } } return alignedRect; } /*! Expand all line breaks in text labels, and calculate the height of their widgets in orientation of the text. \param options Options how to layout the legend \param rect Bounding rect for title, axes and canvas. \param dimTitle Expanded height of the title widget \param dimAxis Expanded heights of the axis in axis orientation. \sa Options */ void QwtPlotLayout::expandLineBreaks( int options, const QRectF &rect, int &dimTitle, int dimAxis[QwtPlot::axisCnt] ) const { dimTitle = 0; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) dimAxis[axis] = 0; int backboneOffset[QwtPlot::axisCnt]; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { backboneOffset[axis] = 0; if ( !d_data->alignCanvasToScales ) backboneOffset[axis] += d_data->canvasMargin[axis]; if ( !( options & IgnoreFrames ) ) backboneOffset[axis] += d_data->layoutData.canvas.frameWidth; } bool done = false; while ( !done ) { done = true; // the size for the 4 axis depend on each other. Expanding // the height of a horizontal axis will shrink the height // for the vertical axis, shrinking the height of a vertical // axis will result in a line break what will expand the // width and results in shrinking the width of a horizontal // axis what might result in a line break of a horizontal // axis ... . So we loop as long until no size changes. if ( !d_data->layoutData.title.text.isEmpty() ) { double w = rect.width(); if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled != d_data->layoutData.scale[QwtPlot::yRight].isEnabled ) { // center to the canvas w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight]; } int d = qCeil( d_data->layoutData.title.text.heightForWidth( w ) ); if ( !( options & IgnoreFrames ) ) d += 2 * d_data->layoutData.title.frameWidth; if ( d > dimTitle ) { dimTitle = d; done = false; } } for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { const struct LayoutData::t_scaleData &scaleData = d_data->layoutData.scale[axis]; if ( scaleData.isEnabled ) { double length; if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom ) { length = rect.width() - dimAxis[QwtPlot::yLeft] - dimAxis[QwtPlot::yRight]; length -= scaleData.start + scaleData.end; if ( dimAxis[QwtPlot::yRight] > 0 ) length -= 1; length += qMin( dimAxis[QwtPlot::yLeft], scaleData.start - backboneOffset[QwtPlot::yLeft] ); length += qMin( dimAxis[QwtPlot::yRight], scaleData.end - backboneOffset[QwtPlot::yRight] ); } else // QwtPlot::yLeft, QwtPlot::yRight { length = rect.height() - dimAxis[QwtPlot::xTop] - dimAxis[QwtPlot::xBottom]; length -= scaleData.start + scaleData.end; length -= 1; if ( dimAxis[QwtPlot::xBottom] <= 0 ) length -= 1; if ( dimAxis[QwtPlot::xTop] <= 0 ) length -= 1; if ( dimAxis[QwtPlot::xBottom] > 0 ) { length += qMin( d_data->layoutData.scale[QwtPlot::xBottom].tickOffset, double( scaleData.start - backboneOffset[QwtPlot::xBottom] ) ); } if ( dimAxis[QwtPlot::xTop] > 0 ) { length += qMin( d_data->layoutData.scale[QwtPlot::xTop].tickOffset, double( scaleData.end - backboneOffset[QwtPlot::xTop] ) ); } if ( dimTitle > 0 ) length -= dimTitle + d_data->spacing; } if (d_data->fixedOffset[axis]) { dimAxis[axis] = d_data->fixedOffset[axis] + backboneOffset[QwtPlot::yLeft]; continue; } int d = scaleData.dimWithoutTitle; if ( !scaleData.scaleWidget->title().isEmpty() ) { d += scaleData.scaleWidget->titleHeightForWidth( qFloor( length ) ); } if ( d > dimAxis[axis] ) { dimAxis[axis] = d; done = false; } } } } } /*! Align the ticks of the axis to the canvas borders using the empty corners. \sa Options */ void QwtPlotLayout::alignScales( int options, QRectF &canvasRect, QRectF scaleRect[QwtPlot::axisCnt] ) const { int backboneOffset[QwtPlot::axisCnt]; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { backboneOffset[axis] = 0; if ( !d_data->alignCanvasToScales ) backboneOffset[axis] += d_data->canvasMargin[axis]; if ( !( options & IgnoreFrames ) ) backboneOffset[axis] += d_data->layoutData.canvas.frameWidth; } for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( !scaleRect[axis].isValid() ) continue; const int startDist = d_data->layoutData.scale[axis].start; const int endDist = d_data->layoutData.scale[axis].end; QRectF &axisRect = scaleRect[axis]; if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom ) { const QRectF &leftScaleRect = scaleRect[QwtPlot::yLeft]; const int leftOffset = backboneOffset[QwtPlot::yLeft] - startDist; if ( leftScaleRect.isValid() ) { const double dx = leftOffset + leftScaleRect.width(); if ( d_data->alignCanvasToScales && dx < 0.0 ) { /* The axis needs more space than the width of the left scale. */ const double cLeft = canvasRect.left(); // qreal -> double canvasRect.setLeft( qMax( cLeft, axisRect.left() - dx ) ); } else { const double minLeft = leftScaleRect.left(); const double left = axisRect.left() + leftOffset; axisRect.setLeft( qMax( left, minLeft ) ); } } else { if ( d_data->alignCanvasToScales && leftOffset < 0 ) { canvasRect.setLeft( qMax( canvasRect.left(), axisRect.left() - leftOffset ) ); } else { if ( leftOffset > 0 ) axisRect.setLeft( axisRect.left() + leftOffset ); } } const QRectF &rightScaleRect = scaleRect[QwtPlot::yRight]; const int rightOffset = backboneOffset[QwtPlot::yRight] - endDist + 1; if ( rightScaleRect.isValid() ) { const double dx = rightOffset + rightScaleRect.width(); if ( d_data->alignCanvasToScales && dx < 0 ) { /* The axis needs more space than the width of the right scale. */ const double cRight = canvasRect.right(); // qreal -> double canvasRect.setRight( qMin( cRight, axisRect.right() + dx ) ); } const double maxRight = rightScaleRect.right(); const double right = axisRect.right() - rightOffset; axisRect.setRight( qMin( right, maxRight ) ); } else { if ( d_data->alignCanvasToScales && rightOffset < 0 ) { canvasRect.setRight( qMin( canvasRect.right(), axisRect.right() + rightOffset ) ); } else { if ( rightOffset > 0 ) axisRect.setRight( axisRect.right() - rightOffset ); } } } else // QwtPlot::yLeft, QwtPlot::yRight { const QRectF &bottomScaleRect = scaleRect[QwtPlot::xBottom]; const int bottomOffset = backboneOffset[QwtPlot::xBottom] - endDist + 1; if ( bottomScaleRect.isValid() ) { const double dy = bottomOffset + bottomScaleRect.height(); if ( d_data->alignCanvasToScales && dy < 0 ) { /* The axis needs more space than the height of the bottom scale. */ const double cBottom = canvasRect.bottom(); // qreal -> double canvasRect.setBottom( qMin( cBottom, axisRect.bottom() + dy ) ); } else { const double maxBottom = bottomScaleRect.top() + d_data->layoutData.scale[QwtPlot::xBottom].tickOffset; const double bottom = axisRect.bottom() - bottomOffset; axisRect.setBottom( qMin( bottom, maxBottom ) ); } } else { if ( d_data->alignCanvasToScales && bottomOffset < 0 ) { canvasRect.setBottom( qMin( canvasRect.bottom(), axisRect.bottom() + bottomOffset ) ); } else { if ( bottomOffset > 0 ) axisRect.setBottom( axisRect.bottom() - bottomOffset ); } } const QRectF &topScaleRect = scaleRect[QwtPlot::xTop]; const int topOffset = backboneOffset[QwtPlot::xTop] - startDist; if ( topScaleRect.isValid() ) { const double dy = topOffset + topScaleRect.height(); if ( d_data->alignCanvasToScales && dy < 0 ) { /* The axis needs more space than the height of the top scale. */ const double cTop = canvasRect.top(); // qreal -> double canvasRect.setTop( qMax( cTop, axisRect.top() - dy ) ); } else { const double minTop = topScaleRect.bottom() - d_data->layoutData.scale[QwtPlot::xTop].tickOffset; const double top = axisRect.top() + topOffset; axisRect.setTop( qMax( top, minTop ) ); } } else { if ( d_data->alignCanvasToScales && topOffset < 0 ) { canvasRect.setTop( qMax( canvasRect.top(), axisRect.top() - topOffset ) ); } else { if ( topOffset > 0 ) axisRect.setTop( axisRect.top() + topOffset ); } } } } if ( d_data->alignCanvasToScales ) { /* The canvas has been aligned to the scale with largest border distances. Now we have to realign the other scale. */ int fw = 0; if ( !( options & IgnoreFrames ) ) fw = d_data->layoutData.canvas.frameWidth; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( !scaleRect[axis].isValid() ) continue; if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) { scaleRect[axis].setLeft( canvasRect.left() + fw - d_data->layoutData.scale[axis].start ); scaleRect[axis].setRight( canvasRect.right() - fw - 1 + d_data->layoutData.scale[axis].end ); } else { scaleRect[axis].setTop( canvasRect.top() + fw - d_data->layoutData.scale[axis].start ); scaleRect[axis].setBottom( canvasRect.bottom() - fw - 1 + d_data->layoutData.scale[axis].end ); } } if ( scaleRect[QwtPlot::xTop].isValid() ) scaleRect[QwtPlot::xTop].setBottom( canvasRect.top() ); if ( scaleRect[QwtPlot::xBottom].isValid() ) scaleRect[QwtPlot::xBottom].setTop( canvasRect.bottom() ); if ( scaleRect[QwtPlot::yLeft].isValid() ) scaleRect[QwtPlot::yLeft].setRight( canvasRect.left() ); if ( scaleRect[QwtPlot::yRight].isValid() ) scaleRect[QwtPlot::yRight].setLeft( canvasRect.right() ); } } /*! \brief Recalculate the geometry of all components. \param plot Plot to be layout \param plotRect Rect where to place the components \param options Layout options \sa invalidate(), titleRect(), legendRect(), scaleRect(), canvasRect() */ void QwtPlotLayout::activate( const QwtPlot *plot, const QRectF &plotRect, Options options ) { invalidate(); QRectF rect( plotRect ); // undistributed rest of the plot rect // We extract all layout relevant data from the widgets, // filter them through pfilter and save them to d_data->layoutData. d_data->layoutData.init( plot, rect ); if ( !( options & IgnoreLegend ) && d_data->legendPos != QwtPlot::ExternalLegend && plot->legend() && !plot->legend()->isEmpty() ) { d_data->legendRect = layoutLegend( options, rect ); // subtract d_data->legendRect from rect const QRegion region( rect.toRect() ); rect = region.subtract( d_data->legendRect.toRect() ).boundingRect(); switch ( d_data->legendPos ) { case QwtPlot::LeftLegend: rect.setLeft( rect.left() + d_data->spacing ); break; case QwtPlot::RightLegend: rect.setRight( rect.right() - d_data->spacing ); break; case QwtPlot::TopLegend: rect.setTop( rect.top() + d_data->spacing ); break; case QwtPlot::BottomLegend: rect.setBottom( rect.bottom() - d_data->spacing ); break; case QwtPlot::ExternalLegend: break; // suppress compiler warning } } /* +---+-----------+---+ | Title | +---+-----------+---+ | | Axis | | +---+-----------+---+ | A | | A | | x | Canvas | x | | i | | i | | s | | s | +---+-----------+---+ | | Axis | | +---+-----------+---+ */ // axes and title include text labels. The height of each // label depends on its line breaks, that depend on the width // for the label. A line break in a horizontal text will reduce // the available width for vertical texts and vice versa. // expandLineBreaks finds the height/width for title and axes // including all line breaks. int dimTitle, dimAxes[QwtPlot::axisCnt]; expandLineBreaks( options, rect, dimTitle, dimAxes ); if ( dimTitle > 0 ) { d_data->titleRect.setRect( rect.left(), rect.top(), rect.width(), dimTitle ); if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled != d_data->layoutData.scale[QwtPlot::yRight].isEnabled ) { // if only one of the y axes is missing we align // the title centered to the canvas d_data->titleRect.setX( rect.left() + dimAxes[QwtPlot::yLeft] ); d_data->titleRect.setWidth( rect.width() - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight] ); } // subtract title rect.setTop( rect.top() + dimTitle + d_data->spacing ); } d_data->canvasRect.setRect( rect.x() + dimAxes[QwtPlot::yLeft], rect.y() + dimAxes[QwtPlot::xTop], rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft], rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop] ); for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { // set the rects for the axes if ( dimAxes[axis] ) { int dim = dimAxes[axis]; QRectF &scaleRect = d_data->scaleRect[axis]; scaleRect = d_data->canvasRect; switch ( axis ) { case QwtPlot::yLeft: scaleRect.setX( d_data->canvasRect.left() - dim ); scaleRect.setWidth( dim ); break; case QwtPlot::yRight: scaleRect.setX( d_data->canvasRect.right() ); scaleRect.setWidth( dim ); break; case QwtPlot::xBottom: scaleRect.setY( d_data->canvasRect.bottom() ); scaleRect.setHeight( dim ); break; case QwtPlot::xTop: scaleRect.setY( d_data->canvasRect.top() - dim ); scaleRect.setHeight( dim ); break; } scaleRect = scaleRect.normalized(); } } // +---+-----------+---+ // | <- Axis -> | // +-^-+-----------+-^-+ // | | | | | | // | | | | // | A | | A | // | x | Canvas | x | // | i | | i | // | s | | s | // | | | | // | | | | | | // +-V-+-----------+-V-+ // | <- Axis -> | // +---+-----------+---+ // The ticks of the axes - not the labels above - should // be aligned to the canvas. So we try to use the empty // corners to extend the axes, so that the label texts // left/right of the min/max ticks are moved into them. alignScales( options, d_data->canvasRect, d_data->scaleRect ); if ( !d_data->legendRect.isEmpty() ) { // We prefer to align the legend to the canvas - not to // the complete plot - if possible. d_data->legendRect = alignLegend( d_data->canvasRect, d_data->legendRect ); } } pcp-gui-1.5.11/src/libqwt/qwt_plot_magnifier.cpp0000644000000000000000000000637512176111212016525 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot.h" #include "qwt_plot_canvas.h" #include "qwt_scale_div.h" #include "qwt_plot_magnifier.h" #include class QwtPlotMagnifier::PrivateData { public: PrivateData() { for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) isAxisEnabled[axis] = true; } bool isAxisEnabled[QwtPlot::axisCnt]; }; /*! Constructor \param canvas Plot canvas to be magnified */ QwtPlotMagnifier::QwtPlotMagnifier( QwtPlotCanvas *canvas ): QwtMagnifier( canvas ) { d_data = new PrivateData(); } //! Destructor QwtPlotMagnifier::~QwtPlotMagnifier() { delete d_data; } /*! \brief En/Disable an axis Only Axes that are enabled will be zoomed. All other axes will remain unchanged. \param axis Axis, see QwtPlot::Axis \param on On/Off \sa isAxisEnabled() */ void QwtPlotMagnifier::setAxisEnabled( int axis, bool on ) { if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->isAxisEnabled[axis] = on; } /*! Test if an axis is enabled \param axis Axis, see QwtPlot::Axis \return True, if the axis is enabled \sa setAxisEnabled() */ bool QwtPlotMagnifier::isAxisEnabled( int axis ) const { if ( axis >= 0 && axis < QwtPlot::axisCnt ) return d_data->isAxisEnabled[axis]; return true; } //! Return observed plot canvas QwtPlotCanvas *QwtPlotMagnifier::canvas() { return qobject_cast( parent() ); } //! Return Observed plot canvas const QwtPlotCanvas *QwtPlotMagnifier::canvas() const { return qobject_cast( parent() ); } //! Return plot widget, containing the observed plot canvas QwtPlot *QwtPlotMagnifier::plot() { QwtPlotCanvas *w = canvas(); if ( w ) return w->plot(); return NULL; } //! Return plot widget, containing the observed plot canvas const QwtPlot *QwtPlotMagnifier::plot() const { const QwtPlotCanvas *w = canvas(); if ( w ) return w->plot(); return NULL; } /*! Zoom in/out the axes scales \param factor A value < 1.0 zooms in, a value > 1.0 zooms out. */ void QwtPlotMagnifier::rescale( double factor ) { factor = qAbs( factor ); if ( factor == 1.0 || factor == 0.0 ) return; bool doReplot = false; QwtPlot* plt = plot(); const bool autoReplot = plt->autoReplot(); plt->setAutoReplot( false ); for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) { const QwtScaleDiv *scaleDiv = plt->axisScaleDiv( axisId ); if ( isAxisEnabled( axisId ) && scaleDiv->isValid() ) { const double center = scaleDiv->lowerBound() + scaleDiv->range() / 2; const double width_2 = scaleDiv->range() / 2 * factor; plt->setAxisScale( axisId, center - width_2, center + width_2 ); doReplot = true; } } plt->setAutoReplot( autoReplot ); if ( doReplot ) plt->replot(); } pcp-gui-1.5.11/src/libqwt/qwt_plot_marker.cpp0000644000000000000000000003446712176111212016050 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_marker.h" #include "qwt_painter.h" #include "qwt_scale_map.h" #include "qwt_symbol.h" #include "qwt_text.h" #include "qwt_math.h" #include "qwt_legend.h" #include "qwt_legend_item.h" #include class QwtPlotMarker::PrivateData { public: PrivateData(): labelAlignment( Qt::AlignCenter ), labelOrientation( Qt::Horizontal ), spacing( 2 ), symbol( NULL ), style( QwtPlotMarker::NoLine ), xValue( 0.0 ), yValue( 0.0 ) { } ~PrivateData() { delete symbol; } QwtText label; Qt::Alignment labelAlignment; Qt::Orientation labelOrientation; int spacing; QPen pen; const QwtSymbol *symbol; LineStyle style; double xValue; double yValue; }; //! Sets alignment to Qt::AlignCenter, and style to QwtPlotMarker::NoLine QwtPlotMarker::QwtPlotMarker(): QwtPlotItem( QwtText( "Marker" ) ) { d_data = new PrivateData; setZ( 30.0 ); } //! Destructor QwtPlotMarker::~QwtPlotMarker() { delete d_data; } //! \return QwtPlotItem::Rtti_PlotMarker int QwtPlotMarker::rtti() const { return QwtPlotItem::Rtti_PlotMarker; } //! Return Value QPointF QwtPlotMarker::value() const { return QPointF( d_data->xValue, d_data->yValue ); } //! Return x Value double QwtPlotMarker::xValue() const { return d_data->xValue; } //! Return y Value double QwtPlotMarker::yValue() const { return d_data->yValue; } //! Set Value void QwtPlotMarker::setValue( const QPointF& pos ) { setValue( pos.x(), pos.y() ); } //! Set Value void QwtPlotMarker::setValue( double x, double y ) { if ( x != d_data->xValue || y != d_data->yValue ) { d_data->xValue = x; d_data->yValue = y; itemChanged(); } } //! Set X Value void QwtPlotMarker::setXValue( double x ) { setValue( x, d_data->yValue ); } //! Set Y Value void QwtPlotMarker::setYValue( double y ) { setValue( d_data->xValue, y ); } /*! Draw the marker \param painter Painter \param xMap x Scale Map \param yMap y Scale Map \param canvasRect Contents rect of the canvas in painter coordinates */ void QwtPlotMarker::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { const QPointF pos( xMap.transform( d_data->xValue ), yMap.transform( d_data->yValue ) ); // draw lines drawLines( painter, canvasRect, pos ); // draw symbol if ( d_data->symbol && ( d_data->symbol->style() != QwtSymbol::NoSymbol ) ) { const QSizeF sz = d_data->symbol->size(); const QRectF clipRect = canvasRect.adjusted( -sz.width(), -sz.height(), sz.width(), sz.height() ); if ( clipRect.contains( pos ) ) d_data->symbol->drawSymbol( painter, pos ); } drawLabel( painter, canvasRect, pos ); } /*! Draw the lines marker \param painter Painter \param canvasRect Contents rect of the canvas in painter coordinates \param pos Position of the marker, translated into widget coordinates \sa drawLabel(), QwtSymbol::drawSymbol() */ void QwtPlotMarker::drawLines( QPainter *painter, const QRectF &canvasRect, const QPointF &pos ) const { if ( d_data->style == NoLine ) return; const bool doAlign = QwtPainter::roundingAlignment( painter ); painter->setPen( d_data->pen ); if ( d_data->style == QwtPlotMarker::HLine || d_data->style == QwtPlotMarker::Cross ) { double y = pos.y(); if ( doAlign ) y = qRound( y ); QwtPainter::drawLine( painter, canvasRect.left(), y, canvasRect.right() - 1.0, y ); } if ( d_data->style == QwtPlotMarker::VLine || d_data->style == QwtPlotMarker::Cross ) { double x = pos.x(); if ( doAlign ) x = qRound( x ); QwtPainter::drawLine( painter, x, canvasRect.top(), x, canvasRect.bottom() - 1.0 ); } } /*! Align and draw the text label of the marker \param painter Painter \param canvasRect Contents rect of the canvas in painter coordinates \param pos Position of the marker, translated into widget coordinates \sa drawLabel(), QwtSymbol::drawSymbol() */ void QwtPlotMarker::drawLabel( QPainter *painter, const QRectF &canvasRect, const QPointF &pos ) const { if ( d_data->label.isEmpty() ) return; Qt::Alignment align = d_data->labelAlignment; QPointF alignPos = pos; QSizeF symbolOff( 0, 0 ); switch ( d_data->style ) { case QwtPlotMarker::VLine: { // In VLine-style the y-position is pointless and // the alignment flags are relative to the canvas if ( d_data->labelAlignment & Qt::AlignTop ) { alignPos.setY( canvasRect.top() ); align &= ~Qt::AlignTop; align |= Qt::AlignBottom; } else if ( d_data->labelAlignment & Qt::AlignBottom ) { // In HLine-style the x-position is pointless and // the alignment flags are relative to the canvas alignPos.setY( canvasRect.bottom() - 1 ); align &= ~Qt::AlignBottom; align |= Qt::AlignTop; } else { alignPos.setY( canvasRect.center().y() ); } break; } case QwtPlotMarker::HLine: { if ( d_data->labelAlignment & Qt::AlignLeft ) { alignPos.setX( canvasRect.left() ); align &= ~Qt::AlignLeft; align |= Qt::AlignRight; } else if ( d_data->labelAlignment & Qt::AlignRight ) { alignPos.setX( canvasRect.right() - 1 ); align &= ~Qt::AlignRight; align |= Qt::AlignLeft; } else { alignPos.setX( canvasRect.center().x() ); } break; } default: { if ( d_data->symbol && ( d_data->symbol->style() != QwtSymbol::NoSymbol ) ) { symbolOff = d_data->symbol->size() + QSizeF( 1, 1 ); symbolOff /= 2; } } } qreal pw2 = d_data->pen.widthF() / 2.0; if ( pw2 == 0.0 ) pw2 = 0.5; const int spacing = d_data->spacing; const qreal xOff = qMax( pw2, symbolOff.width() ); const qreal yOff = qMax( pw2, symbolOff.height() ); const QSizeF textSize = d_data->label.textSize( painter->font() ); if ( align & Qt::AlignLeft ) { alignPos.rx() -= xOff + spacing; if ( d_data->labelOrientation == Qt::Vertical ) alignPos.rx() -= textSize.height(); else alignPos.rx() -= textSize.width(); } else if ( align & Qt::AlignRight ) { alignPos.rx() += xOff + spacing; } else { if ( d_data->labelOrientation == Qt::Vertical ) alignPos.rx() -= textSize.height() / 2; else alignPos.rx() -= textSize.width() / 2; } if ( align & Qt::AlignTop ) { alignPos.ry() -= yOff + spacing; if ( d_data->labelOrientation != Qt::Vertical ) alignPos.ry() -= textSize.height(); } else if ( align & Qt::AlignBottom ) { alignPos.ry() += yOff + spacing; if ( d_data->labelOrientation == Qt::Vertical ) alignPos.ry() += textSize.width(); } else { if ( d_data->labelOrientation == Qt::Vertical ) alignPos.ry() += textSize.width() / 2; else alignPos.ry() -= textSize.height() / 2; } painter->translate( alignPos.x(), alignPos.y() ); if ( d_data->labelOrientation == Qt::Vertical ) painter->rotate( -90.0 ); const QRectF textRect( 0, 0, textSize.width(), textSize.height() ); d_data->label.draw( painter, textRect ); } /*! \brief Set the line style \param style Line style. \sa lineStyle() */ void QwtPlotMarker::setLineStyle( LineStyle style ) { if ( style != d_data->style ) { d_data->style = style; itemChanged(); } } /*! \return the line style \sa setLineStyle() */ QwtPlotMarker::LineStyle QwtPlotMarker::lineStyle() const { return d_data->style; } /*! \brief Assign a symbol \param symbol New symbol \sa symbol() */ void QwtPlotMarker::setSymbol( const QwtSymbol *symbol ) { if ( symbol != d_data->symbol ) { delete d_data->symbol; d_data->symbol = symbol; itemChanged(); } } /*! \return the symbol \sa setSymbol(), QwtSymbol */ const QwtSymbol *QwtPlotMarker::symbol() const { return d_data->symbol; } /*! \brief Set the label \param label label text \sa label() */ void QwtPlotMarker::setLabel( const QwtText& label ) { if ( label != d_data->label ) { d_data->label = label; itemChanged(); } } /*! \return the label \sa setLabel() */ QwtText QwtPlotMarker::label() const { return d_data->label; } /*! \brief Set the alignment of the label In case of QwtPlotMarker::HLine the alignment is relative to the y position of the marker, but the horizontal flags correspond to the canvas rectangle. In case of QwtPlotMarker::VLine the alignment is relative to the x position of the marker, but the vertical flags correspond to the canvas rectangle. In all other styles the alignment is relative to the marker's position. \param align Alignment. \sa labelAlignment(), labelOrientation() */ void QwtPlotMarker::setLabelAlignment( Qt::Alignment align ) { if ( align != d_data->labelAlignment ) { d_data->labelAlignment = align; itemChanged(); } } /*! \return the label alignment \sa setLabelAlignment(), setLabelOrientation() */ Qt::Alignment QwtPlotMarker::labelAlignment() const { return d_data->labelAlignment; } /*! \brief Set the orientation of the label When orientation is Qt::Vertical the label is rotated by 90.0 degrees ( from bottom to top ). \param orientation Orientation of the label \sa labelOrientation(), setLabelAlignment() */ void QwtPlotMarker::setLabelOrientation( Qt::Orientation orientation ) { if ( orientation != d_data->labelOrientation ) { d_data->labelOrientation = orientation; itemChanged(); } } /*! \return the label orientation \sa setLabelOrientation(), labelAlignment() */ Qt::Orientation QwtPlotMarker::labelOrientation() const { return d_data->labelOrientation; } /*! \brief Set the spacing When the label is not centered on the marker position, the spacing is the distance between the position and the label. \param spacing Spacing \sa spacing(), setLabelAlignment() */ void QwtPlotMarker::setSpacing( int spacing ) { if ( spacing < 0 ) spacing = 0; if ( spacing == d_data->spacing ) return; d_data->spacing = spacing; itemChanged(); } /*! \return the spacing \sa setSpacing() */ int QwtPlotMarker::spacing() const { return d_data->spacing; } /*! Specify a pen for the line. \param pen New pen \sa linePen() */ void QwtPlotMarker::setLinePen( const QPen &pen ) { if ( pen != d_data->pen ) { d_data->pen = pen; itemChanged(); } } /*! \return the line pen \sa setLinePen() */ const QPen &QwtPlotMarker::linePen() const { return d_data->pen; } QRectF QwtPlotMarker::boundingRect() const { return QRectF( d_data->xValue, d_data->yValue, 0.0, 0.0 ); } /*! \brief Update the widget that represents the item on the legend \param legend Legend \sa drawLegendIdentifier(), legendItem(), itemChanged(), QwtLegend() \note In the default setting QwtPlotItem::Legend is disabled */ void QwtPlotMarker::updateLegend( QwtLegend *legend ) const { if ( legend && testItemAttribute( QwtPlotItem::Legend ) && d_data->symbol && d_data->symbol->style() != QwtSymbol::NoSymbol ) { QWidget *lgdItem = legend->find( this ); if ( lgdItem == NULL ) { lgdItem = legendItem(); if ( lgdItem ) legend->insert( this, lgdItem ); } QwtLegendItem *l = qobject_cast( lgdItem ); if ( l ) l->setIdentifierSize( d_data->symbol->boundingSize() ); } QwtPlotItem::updateLegend( legend ); } /*! \brief Draw the identifier representing the marker on the legend \param painter Painter \param rect Bounding rectangle for the identifier \sa updateLegend(), QwtPlotItem::Legend */ void QwtPlotMarker::drawLegendIdentifier( QPainter *painter, const QRectF &rect ) const { if ( rect.isEmpty() ) return; painter->save(); painter->setClipRect( rect, Qt::IntersectClip ); if ( d_data->style != QwtPlotMarker::NoLine ) { painter->setPen( d_data->pen ); if ( d_data->style == QwtPlotMarker::HLine || d_data->style == QwtPlotMarker::Cross ) { QwtPainter::drawLine( painter, rect.left(), rect.center().y(), rect.right(), rect.center().y() ); } if ( d_data->style == QwtPlotMarker::VLine || d_data->style == QwtPlotMarker::Cross ) { QwtPainter::drawLine( painter, rect.center().x(), rect.top(), rect.center().x(), rect.bottom() ); } } if ( d_data->symbol && d_data->symbol->style() != QwtSymbol::NoSymbol ) { QSize symbolSize = d_data->symbol->boundingSize(); symbolSize -= QSize( 2, 2 ); // scale the symbol size down if it doesn't fit into rect. double xRatio = 1.0; if ( rect.width() < symbolSize.width() ) xRatio = rect.width() / symbolSize.width(); double yRatio = 1.0; if ( rect.height() < symbolSize.height() ) yRatio = rect.height() / symbolSize.height(); const double ratio = qMin( xRatio, yRatio ); painter->scale( ratio, ratio ); d_data->symbol->drawSymbol( painter, rect.center() / ratio ); } painter->restore(); } pcp-gui-1.5.11/src/libqwt/qwt_plot_panner.cpp0000644000000000000000000000770012176111212016040 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_panner.h" #include "qwt_scale_div.h" #include "qwt_plot.h" #include "qwt_plot_canvas.h" class QwtPlotPanner::PrivateData { public: PrivateData() { for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) isAxisEnabled[axis] = true; } bool isAxisEnabled[QwtPlot::axisCnt]; }; /*! \brief Create a plot panner The panner is enabled for all axes \param canvas Plot canvas to pan, also the parent object \sa setAxisEnabled() */ QwtPlotPanner::QwtPlotPanner( QwtPlotCanvas *canvas ): QwtPanner( canvas ) { d_data = new PrivateData(); connect( this, SIGNAL( panned( int, int ) ), SLOT( moveCanvas( int, int ) ) ); } //! Destructor QwtPlotPanner::~QwtPlotPanner() { delete d_data; } /*! \brief En/Disable an axis Axes that are enabled will be synchronized to the result of panning. All other axes will remain unchanged. \param axis Axis, see QwtPlot::Axis \param on On/Off \sa isAxisEnabled(), moveCanvas() */ void QwtPlotPanner::setAxisEnabled( int axis, bool on ) { if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->isAxisEnabled[axis] = on; } /*! Test if an axis is enabled \param axis Axis, see QwtPlot::Axis \return True, if the axis is enabled \sa setAxisEnabled(), moveCanvas() */ bool QwtPlotPanner::isAxisEnabled( int axis ) const { if ( axis >= 0 && axis < QwtPlot::axisCnt ) return d_data->isAxisEnabled[axis]; return true; } //! Return observed plot canvas QwtPlotCanvas *QwtPlotPanner::canvas() { return qobject_cast( parentWidget() ); } //! Return Observed plot canvas const QwtPlotCanvas *QwtPlotPanner::canvas() const { return qobject_cast( parentWidget() ); } //! Return plot widget, containing the observed plot canvas QwtPlot *QwtPlotPanner::plot() { QwtPlotCanvas *w = canvas(); if ( w ) return w->plot(); return NULL; } //! Return plot widget, containing the observed plot canvas const QwtPlot *QwtPlotPanner::plot() const { const QwtPlotCanvas *w = canvas(); if ( w ) return w->plot(); return NULL; } /*! Adjust the enabled axes according to dx/dy \param dx Pixel offset in x direction \param dy Pixel offset in y direction \sa QwtPanner::panned() */ void QwtPlotPanner::moveCanvas( int dx, int dy ) { if ( dx == 0 && dy == 0 ) return; QwtPlot *plot = this->plot(); if ( plot == NULL ) return; const bool doAutoReplot = plot->autoReplot(); plot->setAutoReplot( false ); for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( !d_data->isAxisEnabled[axis] ) continue; const QwtScaleMap map = plot->canvasMap( axis ); const double p1 = map.transform( plot->axisScaleDiv( axis )->lowerBound() ); const double p2 = map.transform( plot->axisScaleDiv( axis )->upperBound() ); double d1, d2; if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) { d1 = map.invTransform( p1 - dx ); d2 = map.invTransform( p2 - dx ); } else { d1 = map.invTransform( p1 - dy ); d2 = map.invTransform( p2 - dy ); } plot->setAxisScale( axis, d1, d2 ); } plot->setAutoReplot( doAutoReplot ); plot->replot(); } /*! Calculate a mask from the border mask of the canvas \sa QwtPlotCanvas::borderMask() */ QBitmap QwtPlotPanner::contentsMask() const { if ( canvas() ) return canvas()->borderMask( size() ); return QwtPanner::contentsMask(); } pcp-gui-1.5.11/src/libqwt/qwt_plot_picker.cpp0000644000000000000000000002205312176111212016030 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_picker.h" #include "qwt_plot.h" #include "qwt_plot_canvas.h" #include "qwt_scale_div.h" #include "qwt_painter.h" #include "qwt_scale_map.h" #include "qwt_picker_machine.h" /*! \brief Create a plot picker The picker is set to those x- and y-axis of the plot that are enabled. If both or no x-axis are enabled, the picker is set to QwtPlot::xBottom. If both or no y-axis are enabled, it is set to QwtPlot::yLeft. \param canvas Plot canvas to observe, also the parent object \sa QwtPlot::autoReplot(), QwtPlot::replot(), scaleRect() */ QwtPlotPicker::QwtPlotPicker( QwtPlotCanvas *canvas ): QwtPicker( canvas ), d_xAxis( -1 ), d_yAxis( -1 ) { if ( !canvas ) return; // attach axes int xAxis = QwtPlot::xBottom; const QwtPlot *plot = QwtPlotPicker::plot(); if ( !plot->axisEnabled( QwtPlot::xBottom ) && plot->axisEnabled( QwtPlot::xTop ) ) { xAxis = QwtPlot::xTop; } int yAxis = QwtPlot::yLeft; if ( !plot->axisEnabled( QwtPlot::yLeft ) && plot->axisEnabled( QwtPlot::yRight ) ) { yAxis = QwtPlot::yRight; } setAxis( xAxis, yAxis ); } /*! Create a plot picker \param xAxis Set the x axis of the picker \param yAxis Set the y axis of the picker \param canvas Plot canvas to observe, also the parent object \sa QwtPlot::autoReplot(), QwtPlot::replot(), scaleRect() */ QwtPlotPicker::QwtPlotPicker( int xAxis, int yAxis, QwtPlotCanvas *canvas ): QwtPicker( canvas ), d_xAxis( xAxis ), d_yAxis( yAxis ) { } /*! Create a plot picker \param xAxis X axis of the picker \param yAxis Y axis of the picker \param rubberBand Rubberband style \param trackerMode Tracker mode \param canvas Plot canvas to observe, also the parent object \sa QwtPicker, QwtPicker::setSelectionFlags(), QwtPicker::setRubberBand(), QwtPicker::setTrackerMode \sa QwtPlot::autoReplot(), QwtPlot::replot(), scaleRect() */ QwtPlotPicker::QwtPlotPicker( int xAxis, int yAxis, RubberBand rubberBand, DisplayMode trackerMode, QwtPlotCanvas *canvas ): QwtPicker( rubberBand, trackerMode, canvas ), d_xAxis( xAxis ), d_yAxis( yAxis ) { } //! Destructor QwtPlotPicker::~QwtPlotPicker() { } //! Return observed plot canvas QwtPlotCanvas *QwtPlotPicker::canvas() { return qobject_cast( parentWidget() ); } //! Return Observed plot canvas const QwtPlotCanvas *QwtPlotPicker::canvas() const { return qobject_cast( parentWidget() ); } //! Return plot widget, containing the observed plot canvas QwtPlot *QwtPlotPicker::plot() { QwtPlotCanvas *w = canvas(); if ( w ) return w->plot(); return NULL; } //! Return plot widget, containing the observed plot canvas const QwtPlot *QwtPlotPicker::plot() const { const QwtPlotCanvas *w = canvas(); if ( w ) return w->plot(); return NULL; } /*! Return normalized bounding rect of the axes \sa QwtPlot::autoReplot(), QwtPlot::replot(). */ QRectF QwtPlotPicker::scaleRect() const { QRectF rect; if ( plot() ) { const QwtScaleDiv *xs = plot()->axisScaleDiv( xAxis() ); const QwtScaleDiv *ys = plot()->axisScaleDiv( yAxis() ); if ( xs && ys ) { rect = QRectF( xs->lowerBound(), ys->lowerBound(), xs->range(), ys->range() ); rect = rect.normalized(); } } return rect; } /*! Set the x and y axes of the picker \param xAxis X axis \param yAxis Y axis */ void QwtPlotPicker::setAxis( int xAxis, int yAxis ) { const QwtPlot *plt = plot(); if ( !plt ) return; if ( xAxis != d_xAxis || yAxis != d_yAxis ) { d_xAxis = xAxis; d_yAxis = yAxis; } } //! Return x axis int QwtPlotPicker::xAxis() const { return d_xAxis; } //! Return y axis int QwtPlotPicker::yAxis() const { return d_yAxis; } /*! Translate a pixel position into a position string \param pos Position in pixel coordinates \return Position string */ QwtText QwtPlotPicker::trackerText( const QPoint &pos ) const { return trackerTextF( invTransform( pos ) ); } /*! \brief Translate a position into a position string In case of HLineRubberBand the label is the value of the y position, in case of VLineRubberBand the value of the x position. Otherwise the label contains x and y position separated by a ',' . The format for the double to string conversion is "%.4f". \param pos Position \return Position string */ QwtText QwtPlotPicker::trackerTextF( const QPointF &pos ) const { QString text; switch ( rubberBand() ) { case HLineRubberBand: text.sprintf( "%.4f", pos.y() ); break; case VLineRubberBand: text.sprintf( "%.4f", pos.x() ); break; default: text.sprintf( "%.4f, %.4f", pos.x(), pos.y() ); } return QwtText( text ); } /*! Append a point to the selection and update rubberband and tracker. \param pos Additional point \sa isActive, begin(), end(), move(), appended() \note The appended(const QPoint &), appended(const QDoublePoint &) signals are emitted. */ void QwtPlotPicker::append( const QPoint &pos ) { QwtPicker::append( pos ); Q_EMIT appended( invTransform( pos ) ); } /*! Move the last point of the selection \param pos New position \sa isActive, begin(), end(), append() \note The moved(const QPoint &), moved(const QDoublePoint &) signals are emitted. */ void QwtPlotPicker::move( const QPoint &pos ) { QwtPicker::move( pos ); Q_EMIT moved( invTransform( pos ) ); } /*! Close a selection setting the state to inactive. \param ok If true, complete the selection and emit selected signals otherwise discard the selection. \return true if the selection is accepted, false otherwise */ bool QwtPlotPicker::end( bool ok ) { ok = QwtPicker::end( ok ); if ( !ok ) return false; QwtPlot *plot = QwtPlotPicker::plot(); if ( !plot ) return false; const QPolygon points = selection(); if ( points.count() == 0 ) return false; QwtPickerMachine::SelectionType selectionType = QwtPickerMachine::NoSelection; if ( stateMachine() ) selectionType = stateMachine()->selectionType(); switch ( selectionType ) { case QwtPickerMachine::PointSelection: { const QPointF pos = invTransform( points.first() ); Q_EMIT selected( pos ); break; } case QwtPickerMachine::RectSelection: { if ( points.count() >= 2 ) { const QPoint p1 = points.first(); const QPoint p2 = points.last(); const QRect rect = QRect( p1, p2 ).normalized(); Q_EMIT selected( invTransform( rect ) ); } break; } case QwtPickerMachine::PolygonSelection: { QVector dpa( points.count() ); for ( int i = 0; i < points.count(); i++ ) dpa[i] = invTransform( points[i] ); Q_EMIT selected( dpa ); } default: break; } return true; } /*! Translate a rectangle from pixel into plot coordinates \return Rectangle in plot coordinates \sa transform() */ QRectF QwtPlotPicker::invTransform( const QRect &rect ) const { const QwtScaleMap xMap = plot()->canvasMap( d_xAxis ); const QwtScaleMap yMap = plot()->canvasMap( d_yAxis ); return QwtScaleMap::invTransform( xMap, yMap, rect ); } /*! Translate a rectangle from plot into pixel coordinates \return Rectangle in pixel coordinates \sa invTransform() */ QRect QwtPlotPicker::transform( const QRectF &rect ) const { const QwtScaleMap xMap = plot()->canvasMap( d_xAxis ); const QwtScaleMap yMap = plot()->canvasMap( d_yAxis ); return QwtScaleMap::transform( xMap, yMap, rect ).toRect(); } /*! Translate a point from pixel into plot coordinates \return Point in plot coordinates \sa transform() */ QPointF QwtPlotPicker::invTransform( const QPoint &pos ) const { QwtScaleMap xMap = plot()->canvasMap( d_xAxis ); QwtScaleMap yMap = plot()->canvasMap( d_yAxis ); return QPointF( xMap.invTransform( pos.x() ), yMap.invTransform( pos.y() ) ); } /*! Translate a point from plot into pixel coordinates \return Point in pixel coordinates \sa invTransform() */ QPoint QwtPlotPicker::transform( const QPointF &pos ) const { QwtScaleMap xMap = plot()->canvasMap( d_xAxis ); QwtScaleMap yMap = plot()->canvasMap( d_yAxis ); const QPointF p( xMap.transform( pos.x() ), yMap.transform( pos.y() ) ); return p.toPoint(); } pcp-gui-1.5.11/src/libqwt/qwt_plot_rasteritem.cpp0000644000000000000000000005732012176111212016737 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_rasteritem.h" #include "qwt_legend.h" #include "qwt_legend_item.h" #include "qwt_scale_map.h" #include "qwt_painter.h" #include #include #include #include #include class QwtPlotRasterItem::PrivateData { public: PrivateData(): alpha( -1 ), paintAttributes( QwtPlotRasterItem::PaintInDeviceResolution ) { cache.policy = QwtPlotRasterItem::NoCache; } int alpha; QwtPlotRasterItem::PaintAttributes paintAttributes; struct ImageCache { QwtPlotRasterItem::CachePolicy policy; QRectF area; QSizeF size; QImage image; } cache; }; static QRectF qwtAlignRect(const QRectF &rect) { QRectF r; r.setLeft( qRound( rect.left() ) ); r.setRight( qRound( rect.right() ) ); r.setTop( qRound( rect.top() ) ); r.setBottom( qRound( rect.bottom() ) ); return r; } static QRectF qwtStripRect(const QRectF &rect, const QRectF &area, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtInterval &xInterval, const QwtInterval &yInterval) { QRectF r = rect; if ( xInterval.borderFlags() & QwtInterval::ExcludeMinimum ) { if ( area.left() <= xInterval.minValue() ) { if ( xMap.isInverting() ) r.adjust(0, 0, -1, 0); else r.adjust(1, 0, 0, 0); } } if ( xInterval.borderFlags() & QwtInterval::ExcludeMaximum ) { if ( area.right() >= xInterval.maxValue() ) { if ( xMap.isInverting() ) r.adjust(1, 0, 0, 0); else r.adjust(0, 0, -1, 0); } } if ( yInterval.borderFlags() & QwtInterval::ExcludeMinimum ) { if ( area.top() <= yInterval.minValue() ) { if ( yMap.isInverting() ) r.adjust(0, 0, 0, -1); else r.adjust(0, 1, 0, 0); } } if ( yInterval.borderFlags() & QwtInterval::ExcludeMaximum ) { if ( area.bottom() >= yInterval.maxValue() ) { if ( yMap.isInverting() ) r.adjust(0, 1, 0, 0); else r.adjust(0, 0, 0, -1); } } return r; } static QImage qwtExpandImage(const QImage &image, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &area, const QRectF &area2, const QRectF &paintRect, const QwtInterval &xInterval, const QwtInterval &yInterval ) { const QRectF strippedRect = qwtStripRect(paintRect, area2, xMap, yMap, xInterval, yInterval); const QSize sz = strippedRect.toRect().size(); const int w = image.width(); const int h = image.height(); const QRectF r = QwtScaleMap::transform(xMap, yMap, area).normalized(); const double pw = ( r.width() - 1) / w; const double ph = ( r.height() - 1) / h; double px0, py0; if ( !xMap.isInverting() ) { px0 = xMap.transform( area2.left() ); px0 = qRound( px0 ); px0 = px0 - xMap.transform( area.left() ); } else { px0 = xMap.transform( area2.right() ); px0 = qRound( px0 ); px0 -= xMap.transform( area.right() ); px0 -= 1.0; } px0 += strippedRect.left() - paintRect.left(); if ( !yMap.isInverting() ) { py0 = yMap.transform( area2.top() ); py0 = qRound( py0 ); py0 -= yMap.transform( area.top() ); } else { py0 = yMap.transform( area2.bottom() ); py0 = qRound( py0 ); py0 -= yMap.transform( area.bottom() ); py0 -= 1.0; } py0 += strippedRect.top() - paintRect.top(); QImage expanded(sz, image.format()); switch( image.depth() ) { case 32: { for ( int y1 = 0; y1 < h; y1++ ) { int yy1; if ( y1 == 0 ) { yy1 = 0; } else { yy1 = qRound( y1 * ph - py0 ); if ( yy1 < 0 ) yy1 = 0; } int yy2; if ( y1 == h - 1 ) { yy2 = sz.height(); } else { yy2 = qRound( ( y1 + 1 ) * ph - py0 ); if ( yy2 > sz.height() ) yy2 = sz.height(); } const quint32 *line1 = (const quint32 *) image.scanLine( y1 ); for ( int x1 = 0; x1 < w; x1++ ) { int xx1; if ( x1 == 0 ) { xx1 = 0; } else { xx1 = qRound( x1 * pw - px0 ); if ( xx1 < 0 ) xx1 = 0; } int xx2; if ( x1 == w - 1 ) { xx2 = sz.width(); } else { xx2 = qRound( ( x1 + 1 ) * pw - px0 ); if ( xx2 > sz.width() ) xx2 = sz.width(); } const quint32 rgb( line1[x1] ); for ( int y2 = yy1; y2 < yy2; y2++ ) { quint32 *line2 = ( quint32 *) expanded.scanLine( y2 ); for ( int x2 = xx1; x2 < xx2; x2++ ) line2[x2] = rgb; } } } break; } case 8: { for ( int y1 = 0; y1 < h; y1++ ) { int yy1; if ( y1 == 0 ) { yy1 = 0; } else { yy1 = qRound( y1 * ph - py0 ); if ( yy1 < 0 ) yy1 = 0; } int yy2; if ( y1 == h - 1 ) { yy2 = sz.height(); } else { yy2 = qRound( ( y1 + 1 ) * ph - py0 ); if ( yy2 > sz.height() ) yy2 = sz.height(); } const uchar *line1 = image.scanLine( y1 ); for ( int x1 = 0; x1 < w; x1++ ) { int xx1; if ( x1 == 0 ) { xx1 = 0; } else { xx1 = qRound( x1 * pw - px0 ); if ( xx1 < 0 ) xx1 = 0; } int xx2; if ( x1 == w - 1 ) { xx2 = sz.width(); } else { xx2 = qRound( ( x1 + 1 ) * pw - px0 ); if ( xx2 > sz.width() ) xx2 = sz.width(); } for ( int y2 = yy1; y2 < yy2; y2++ ) { uchar *line2 = expanded.scanLine( y2 ); memset( line2 + xx1, line1[x1], xx2 - xx1 ); } } } break; } default: expanded = image; } return expanded; } static QRectF expandToPixels(const QRectF &rect, const QRectF &pixelRect) { const double pw = pixelRect.width(); const double ph = pixelRect.height(); const double dx1 = pixelRect.left() - rect.left(); const double dx2 = pixelRect.right() - rect.right(); const double dy1 = pixelRect.top() - rect.top(); const double dy2 = pixelRect.bottom() - rect.bottom(); QRectF r; r.setLeft( pixelRect.left() - qCeil( dx1 / pw ) * pw ); r.setTop( pixelRect.top() - qCeil( dy1 / ph ) * ph ); r.setRight( pixelRect.right() - qFloor( dx2 / pw ) * pw ); r.setBottom( pixelRect.bottom() - qFloor( dy2 / ph ) * ph ); return r; } static void transformMaps( const QTransform &tr, const QwtScaleMap &xMap, const QwtScaleMap &yMap, QwtScaleMap &xxMap, QwtScaleMap &yyMap ) { const QPointF p1 = tr.map( QPointF( xMap.p1(), yMap.p1() ) ); const QPointF p2 = tr.map( QPointF( xMap.p2(), yMap.p2() ) ); xxMap = xMap; xxMap.setPaintInterval( p1.x(), p2.x() ); yyMap = yMap; yyMap.setPaintInterval( p1.y(), p2.y() ); } static void adjustMaps( QwtScaleMap &xMap, QwtScaleMap &yMap, const QRectF &area, const QRectF &paintRect) { double sx1 = area.left(); double sx2 = area.right(); if ( xMap.isInverting() ) qSwap(sx1, sx2); double sy1 = area.top(); double sy2 = area.bottom(); if ( yMap.isInverting() ) qSwap(sy1, sy2); xMap.setPaintInterval(paintRect.left(), paintRect.right()); xMap.setScaleInterval(sx1, sx2); yMap.setPaintInterval(paintRect.top(), paintRect.bottom()); yMap.setScaleInterval(sy1, sy2); } static bool useCache( QwtPlotRasterItem::CachePolicy policy, const QPainter *painter ) { bool doCache = false; if ( policy == QwtPlotRasterItem::PaintCache ) { // Caching doesn't make sense, when the item is // not painted to screen switch ( painter->paintEngine()->type() ) { case QPaintEngine::SVG: case QPaintEngine::Pdf: case QPaintEngine::PostScript: case QPaintEngine::MacPrinter: case QPaintEngine::Picture: break; default:; doCache = true; } } return doCache; } static QImage toRgba( const QImage& image, int alpha ) { if ( alpha < 0 || alpha >= 255 ) return image; QImage alphaImage( image.size(), QImage::Format_ARGB32 ); const QRgb mask1 = qRgba( 0, 0, 0, alpha ); const QRgb mask2 = qRgba( 255, 255, 255, 0 ); const QRgb mask3 = qRgba( 0, 0, 0, 255 ); const int w = image.size().width(); const int h = image.size().height(); if ( image.depth() == 8 ) { for ( int y = 0; y < h; y++ ) { QRgb* alphaLine = ( QRgb* )alphaImage.scanLine( y ); const unsigned char *line = image.scanLine( y ); for ( int x = 0; x < w; x++ ) *alphaLine++ = ( image.color( *line++ ) & mask2 ) | mask1; } } else if ( image.depth() == 32 ) { for ( int y = 0; y < h; y++ ) { QRgb* alphaLine = ( QRgb* )alphaImage.scanLine( y ); const QRgb* line = ( const QRgb* ) image.scanLine( y ); for ( int x = 0; x < w; x++ ) { const QRgb rgb = *line++; if ( rgb & mask3 ) // alpha != 0 *alphaLine++ = ( rgb & mask2 ) | mask1; else *alphaLine++ = rgb; } } } return alphaImage; } //! Constructor QwtPlotRasterItem::QwtPlotRasterItem( const QString& title ): QwtPlotItem( QwtText( title ) ) { init(); } //! Constructor QwtPlotRasterItem::QwtPlotRasterItem( const QwtText& title ): QwtPlotItem( title ) { init(); } //! Destructor QwtPlotRasterItem::~QwtPlotRasterItem() { delete d_data; } void QwtPlotRasterItem::init() { d_data = new PrivateData(); setItemAttribute( QwtPlotItem::AutoScale, true ); setItemAttribute( QwtPlotItem::Legend, false ); setZ( 8.0 ); } /*! Specify an attribute how to draw the raster item \param attribute Paint attribute \param on On/Off /sa PaintAttribute, testPaintAttribute() */ void QwtPlotRasterItem::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; } /*! \brief Return the current paint attributes \sa PaintAttribute, setPaintAttribute() */ bool QwtPlotRasterItem::testPaintAttribute( PaintAttribute attribute ) const { return ( d_data->paintAttributes & attribute ); } /*! \brief Set an alpha value for the raster data Often a plot has several types of raster data organized in layers. ( f.e a geographical map, with weather statistics ). Using setAlpha() raster items can be stacked easily. The alpha value is a value [0, 255] to control the transparency of the image. 0 represents a fully transparent color, while 255 represents a fully opaque color. \param alpha Alpha value - alpha >= 0\n All alpha values of the pixels returned by renderImage() will be set to alpha, beside those with an alpha value of 0 (invalid pixels). - alpha < 0 The alpha values returned by renderImage() are not changed. The default alpha value is -1. \sa alpha() */ void QwtPlotRasterItem::setAlpha( int alpha ) { if ( alpha < 0 ) alpha = -1; if ( alpha > 255 ) alpha = 255; if ( alpha != d_data->alpha ) { d_data->alpha = alpha; itemChanged(); } } /*! \return Alpha value of the raster item \sa setAlpha() */ int QwtPlotRasterItem::alpha() const { return d_data->alpha; } /*! Change the cache policy The default policy is NoCache \param policy Cache policy \sa CachePolicy, cachePolicy() */ void QwtPlotRasterItem::setCachePolicy( QwtPlotRasterItem::CachePolicy policy ) { if ( d_data->cache.policy != policy ) { d_data->cache.policy = policy; invalidateCache(); itemChanged(); } } /*! \return Cache policy \sa CachePolicy, setCachePolicy() */ QwtPlotRasterItem::CachePolicy QwtPlotRasterItem::cachePolicy() const { return d_data->cache.policy; } /*! Invalidate the paint cache \sa setCachePolicy() */ void QwtPlotRasterItem::invalidateCache() { d_data->cache.image = QImage(); d_data->cache.area = QRect(); d_data->cache.size = QSize(); } /*! \brief Pixel hint The geometry of a pixel is used to calculated the resolution and alignment of the rendered image. Width and height of the hint need to be the horizontal and vertical distances between 2 neighboured points. The center of the hint has to be the position of any point ( it doesn't matter which one ). Limiting the resolution of the image might significantly improve the performance and heavily reduce the amount of memory when rendering a QImage from the raster data. The default implementation returns an empty rectangle (QRectF()), meaning, that the image will be rendered in target device ( f.e screen ) resolution. \param area In most implementations the resolution of the data doesn't depend on the requested area. \return Bounding rectangle of a pixel \sa render(), renderImage() */ QRectF QwtPlotRasterItem::pixelHint( const QRectF &area ) const { Q_UNUSED( area ); return QRectF(); } /*! \brief Draw the raster data \param painter Painter \param xMap X-Scale Map \param yMap Y-Scale Map \param canvasRect Contents rect of the plot canvas */ void QwtPlotRasterItem::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { if ( canvasRect.isEmpty() || d_data->alpha == 0 ) return; const bool doCache = useCache( d_data->cache.policy, painter ); const QwtInterval xInterval = interval( Qt::XAxis ); const QwtInterval yInterval = interval( Qt::YAxis ); /* Scaling a rastered image always results in a loss of precision/quality. So we always render the image in paint device resolution. */ QwtScaleMap xxMap, yyMap; transformMaps( painter->transform(), xMap, yMap, xxMap, yyMap ); QRectF paintRect = painter->transform().mapRect( canvasRect ); QRectF area = QwtScaleMap::invTransform( xxMap, yyMap, paintRect ); const QRectF br = boundingRect(); if ( br.isValid() && !br.contains( area ) ) { area &= br; if ( !area.isValid() ) return; paintRect = QwtScaleMap::transform( xxMap, yyMap, area ); } QRectF imageRect; QImage image; QRectF pixelRect = pixelHint(area); if ( !pixelRect.isEmpty() ) { // pixel in target device resolution const double dx = qAbs( xxMap.invTransform( 1 ) - xxMap.invTransform( 0 ) ); const double dy = qAbs( yyMap.invTransform( 1 ) - yyMap.invTransform( 0 ) ); if ( dx > pixelRect.width() && dy > pixelRect.height() ) { /* When the resolution of the data pixels is higher than the resolution of the target device we render in target device resolution. */ pixelRect = QRectF(); } } if ( pixelRect.isEmpty() ) { if ( QwtPainter::roundingAlignment( painter ) ) { // we want to have maps, where the boundaries of // the aligned paint rectangle exactly match the area paintRect = qwtAlignRect(paintRect); adjustMaps(xxMap, yyMap, area, paintRect); } // When we have no information about position and size of // data pixels we render in resolution of the paint device. image = compose(xxMap, yyMap, area, paintRect, paintRect.size().toSize(), doCache); if ( image.isNull() ) return; // Remove pixels at the boundaries, when explicitly // excluded in the intervals imageRect = qwtStripRect(paintRect, area, xxMap, yyMap, xInterval, yInterval); if ( imageRect != paintRect ) { const QRect r( qRound( imageRect.x() - paintRect.x()), qRound( imageRect.y() - paintRect.y() ), qRound( imageRect.width() ), qRound( imageRect.height() ) ); image = image.copy(r); } } else { if ( QwtPainter::roundingAlignment( painter ) ) paintRect = qwtAlignRect(paintRect); // align the area to the data pixels QRectF imageArea = expandToPixels(area, pixelRect); if ( imageArea.right() == xInterval.maxValue() && !( xInterval.borderFlags() & QwtInterval::ExcludeMaximum ) ) { imageArea.adjust(0, 0, pixelRect.width(), 0); } if ( imageArea.bottom() == yInterval.maxValue() && !( yInterval.borderFlags() & QwtInterval::ExcludeMaximum ) ) { imageArea.adjust(0, 0, 0, pixelRect.height() ); } QSize imageSize; imageSize.setWidth( qRound( imageArea.width() / pixelRect.width() ) ); imageSize.setHeight( qRound( imageArea.height() / pixelRect.height() ) ); image = compose(xxMap, yyMap, imageArea, paintRect, imageSize, doCache ); if ( image.isNull() ) return; imageRect = qwtStripRect(paintRect, area, xxMap, yyMap, xInterval, yInterval); if ( ( image.width() > 1 || image.height() > 1 ) && testPaintAttribute( PaintInDeviceResolution ) ) { // Because of rounding errors the pixels // need to be expanded manually to rectangles of // different sizes image = qwtExpandImage(image, xxMap, yyMap, imageArea, area, paintRect, xInterval, yInterval ); } } painter->save(); painter->setWorldTransform( QTransform() ); QwtPainter::drawImage( painter, imageRect, image ); painter->restore(); } /*! \return Bounding interval for an axis This method is intended to be reimplemented by derived classes. The default implementation returns an invalid interval. \param axis X, Y, or Z axis */ QwtInterval QwtPlotRasterItem::interval(Qt::Axis axis) const { Q_UNUSED( axis ); return QwtInterval(); } /*! \return Bounding rect of the data \sa QwtPlotRasterItem::interval() */ QRectF QwtPlotRasterItem::boundingRect() const { const QwtInterval intervalX = interval( Qt::XAxis ); const QwtInterval intervalY = interval( Qt::YAxis ); if ( !intervalX.isValid() && !intervalY.isValid() ) return QRectF(); // no bounding rect QRectF r; if ( intervalX.isValid() ) { r.setLeft( intervalX.minValue() ); r.setRight( intervalX.maxValue() ); } else { r.setLeft(-0.5 * FLT_MAX); r.setWidth(FLT_MAX); } if ( intervalY.isValid() ) { r.setTop( intervalY.minValue() ); r.setBottom( intervalY.maxValue() ); } else { r.setTop(-0.5 * FLT_MAX); r.setHeight(FLT_MAX); } return r.normalized(); } QImage QwtPlotRasterItem::compose( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &imageArea, const QRectF &paintRect, const QSize &imageSize, bool doCache) const { QImage image; if ( imageArea.isEmpty() || paintRect.isEmpty() || imageSize.isEmpty() ) return image; if ( doCache ) { if ( !d_data->cache.image.isNull() && d_data->cache.area == imageArea && d_data->cache.size == paintRect.size() ) { image = d_data->cache.image; } } if ( image.isNull() ) { double dx = 0.0; if ( paintRect.toRect().width() > imageSize.width() ) dx = imageArea.width() / imageSize.width(); const QwtScaleMap xxMap = imageMap(Qt::Horizontal, xMap, imageArea, imageSize, dx); double dy = 0.0; if ( paintRect.toRect().height() > imageSize.height() ) dy = imageArea.height() / imageSize.height(); const QwtScaleMap yyMap = imageMap(Qt::Vertical, yMap, imageArea, imageSize, dy); image = renderImage( xxMap, yyMap, imageArea, imageSize ); if ( doCache ) { d_data->cache.area = imageArea; d_data->cache.size = paintRect.size(); d_data->cache.image = image; } } if ( d_data->alpha >= 0 && d_data->alpha < 255 ) image = toRgba( image, d_data->alpha ); return image; } /*! \brief Calculate a scale map for painting to an image \param orientation Orientation, Qt::Horizontal means a X axis \param map Scale map for rendering the plot item \param area Area to be painted on the image \param imageSize Image size \param pixelSize Width/Height of a data pixel */ QwtScaleMap QwtPlotRasterItem::imageMap( Qt::Orientation orientation, const QwtScaleMap &map, const QRectF &area, const QSize &imageSize, double pixelSize) const { double p1, p2, s1, s2; if ( orientation == Qt::Horizontal ) { p1 = 0.0; p2 = imageSize.width(); s1 = area.left(); s2 = area.right(); } else { p1 = 0.0; p2 = imageSize.height(); s1 = area.top(); s2 = area.bottom(); } if ( pixelSize > 0.0 ) { double off = 0.5 * pixelSize; if ( map.isInverting() ) off = -off; s1 += off; s2 += off; } else { p2--; } if ( map.isInverting() && ( s1 < s2 ) ) qSwap( s1, s2 ); QwtScaleMap newMap = map; newMap.setPaintInterval( p1, p2 ); newMap.setScaleInterval( s1, s2 ); return newMap; } pcp-gui-1.5.11/src/libqwt/qwt_plot_renderer.cpp0000644000000000000000000006054412176111212016370 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_renderer.h" #include "qwt_plot.h" #include "qwt_painter.h" #include "qwt_plot_canvas.h" #include "qwt_plot_layout.h" #include "qwt_legend.h" #include "qwt_legend_item.h" #include "qwt_dyngrid_layout.h" #include "qwt_scale_widget.h" #include "qwt_scale_engine.h" #include "qwt_text.h" #include "qwt_text_label.h" #include "qwt_math.h" #include #include #include #include #include #include #include #include #ifndef QWT_NO_SVG #ifdef QT_SVG_LIB #include #endif #endif class QwtPlotRenderer::PrivateData { public: PrivateData(): discardFlags( QwtPlotRenderer::DiscardBackground ), layoutFlags( QwtPlotRenderer::DefaultLayout ) { } QwtPlotRenderer::DiscardFlags discardFlags; QwtPlotRenderer::LayoutFlags layoutFlags; }; static void qwtRenderBackground( QPainter *painter, const QRectF &rect, const QWidget *widget ) { if ( widget->testAttribute( Qt::WA_StyledBackground ) ) { QStyleOption opt; opt.initFrom( widget ); opt.rect = rect.toAlignedRect(); widget->style()->drawPrimitive( QStyle::PE_Widget, &opt, painter, widget); } else { const QBrush brush = widget->palette().brush( widget->backgroundRole() ); painter->fillRect( rect, brush ); } } /*! Constructor \param parent Parent object */ QwtPlotRenderer::QwtPlotRenderer( QObject *parent ): QObject( parent ) { d_data = new PrivateData; } //! Destructor QwtPlotRenderer::~QwtPlotRenderer() { delete d_data; } /*! Change a flag, indicating what to discard from rendering \param flag Flag to change \param on On/Off \sa DiscardFlag, testDiscardFlag(), setDiscardFlags(), discardFlags() */ void QwtPlotRenderer::setDiscardFlag( DiscardFlag flag, bool on ) { if ( on ) d_data->discardFlags |= flag; else d_data->discardFlags &= ~flag; } /*! Check if a flag is set. \param flag Flag to be tested \sa DiscardFlag, setDiscardFlag(), setDiscardFlags(), discardFlags() */ bool QwtPlotRenderer::testDiscardFlag( DiscardFlag flag ) const { return d_data->discardFlags & flag; } /*! Set the flags, indicating what to discard from rendering \param flags Flags \sa DiscardFlag, setDiscardFlag(), testDiscardFlag(), discardFlags() */ void QwtPlotRenderer::setDiscardFlags( DiscardFlags flags ) { d_data->discardFlags = flags; } /*! \return Flags, indicating what to discard from rendering \sa DiscardFlag, setDiscardFlags(), setDiscardFlag(), testDiscardFlag() */ QwtPlotRenderer::DiscardFlags QwtPlotRenderer::discardFlags() const { return d_data->discardFlags; } /*! Change a layout flag \param flag Flag to change \param on On/Off \sa LayoutFlag, testLayoutFlag(), setLayoutFlags(), layoutFlags() */ void QwtPlotRenderer::setLayoutFlag( LayoutFlag flag, bool on ) { if ( on ) d_data->layoutFlags |= flag; else d_data->layoutFlags &= ~flag; } /*! Check if a flag is set. \param flag Flag to be tested \sa LayoutFlag, setLayoutFlag(), setLayoutFlags(), layoutFlags() */ bool QwtPlotRenderer::testLayoutFlag( LayoutFlag flag ) const { return d_data->layoutFlags & flag; } /*! Set the layout flags \param flags Flags \sa LayoutFlag, setLayoutFlag(), testLayoutFlag(), layoutFlags() */ void QwtPlotRenderer::setLayoutFlags( LayoutFlags flags ) { d_data->layoutFlags = flags; } /*! \return Layout flags \sa LayoutFlag, setLayoutFlags(), setLayoutFlag(), testLayoutFlag() */ QwtPlotRenderer::LayoutFlags QwtPlotRenderer::layoutFlags() const { return d_data->layoutFlags; } /*! Render a plot to a file The format of the document will be autodetected from the suffix of the filename. \param plot Plot widget \param fileName Path of the file, where the document will be stored \param sizeMM Size for the document in millimeters. \param resolution Resolution in dots per Inch (dpi) */ void QwtPlotRenderer::renderDocument( QwtPlot *plot, const QString &fileName, const QSizeF &sizeMM, int resolution ) { renderDocument( plot, fileName, QFileInfo( fileName ).suffix(), sizeMM, resolution ); } /*! Render a plot to a file Supported formats are: - pdf\n Portable Document Format PDF - ps\n Postcript - svg\n Scalable Vector Graphics SVG - all image formats supported by Qt\n see QImageWriter::supportedImageFormats() Scalable vector graphic formats like PDF or SVG are superior to raster graphics formats. \param plot Plot widget \param fileName Path of the file, where the document will be stored \param format Format for the document \param sizeMM Size for the document in millimeters. \param resolution Resolution in dots per Inch (dpi) \sa renderTo(), render(), QwtPainter::setRoundingAlignment() */ void QwtPlotRenderer::renderDocument( QwtPlot *plot, const QString &fileName, const QString &format, const QSizeF &sizeMM, int resolution ) { if ( plot == NULL || sizeMM.isEmpty() || resolution <= 0 ) return; QString title = plot->title().text(); if ( title.isEmpty() ) title = "Plot Document"; const double mmToInch = 1.0 / 25.4; const QSizeF size = sizeMM * mmToInch * resolution; const QRectF documentRect( 0.0, 0.0, size.width(), size.height() ); const QString fmt = format.toLower(); if ( fmt == "pdf" ) { #ifndef QT_NO_PRINTER QPrinter printer; printer.setFullPage( true ); printer.setPaperSize( sizeMM, QPrinter::Millimeter ); printer.setDocName( title ); printer.setOutputFileName( fileName ); printer.setOutputFormat( QPrinter::PdfFormat ); printer.setResolution( resolution ); QPainter painter( &printer ); render( plot, &painter, documentRect ); #endif } else if ( fmt == "ps" ) { #if QT_VERSION < 0x050000 #ifndef QT_NO_PRINTER QPrinter printer; printer.setFullPage( true ); printer.setPaperSize( sizeMM, QPrinter::Millimeter ); printer.setDocName( title ); printer.setOutputFileName( fileName ); printer.setOutputFormat( QPrinter::PostScriptFormat ); printer.setResolution( resolution ); QPainter painter( &printer ); render( plot, &painter, documentRect ); #endif #endif } else if ( fmt == "svg" ) { #ifndef QWT_NO_SVG #ifdef QT_SVG_LIB #if QT_VERSION >= 0x040500 QSvgGenerator generator; generator.setTitle( title ); generator.setFileName( fileName ); generator.setResolution( resolution ); generator.setViewBox( documentRect ); QPainter painter( &generator ); render( plot, &painter, documentRect ); #endif #endif #endif } else { if ( QImageWriter::supportedImageFormats().indexOf( format.toLatin1() ) >= 0 ) { const QRect imageRect = documentRect.toRect(); const int dotsPerMeter = qRound( resolution * mmToInch * 1000.0 ); QImage image( imageRect.size(), QImage::Format_ARGB32 ); image.setDotsPerMeterX( dotsPerMeter ); image.setDotsPerMeterY( dotsPerMeter ); image.fill( QColor( Qt::white ).rgb() ); QPainter painter( &image ); render( plot, &painter, imageRect ); painter.end(); image.save( fileName, format.toLatin1() ); } } } /*! \brief Render the plot to a \c QPaintDevice This function renders the contents of a QwtPlot instance to \c QPaintDevice object. The target rectangle is derived from its device metrics. \param plot Plot to be rendered \param paintDevice device to paint on, f.e a QImage \sa renderDocument(), render(), QwtPainter::setRoundingAlignment() */ void QwtPlotRenderer::renderTo( QwtPlot *plot, QPaintDevice &paintDevice ) const { int w = paintDevice.width(); int h = paintDevice.height(); QPainter p( &paintDevice ); render( plot, &p, QRectF( 0, 0, w, h ) ); } /*! \brief Render the plot to a QPrinter This function renders the contents of a QwtPlot instance to \c QPaintDevice object. The size is derived from the printer metrics. \param plot Plot to be rendered \param printer Printer to paint on \sa renderDocument(), render(), QwtPainter::setRoundingAlignment() */ #ifndef QT_NO_PRINTER void QwtPlotRenderer::renderTo( QwtPlot *plot, QPrinter &printer ) const { int w = printer.width(); int h = printer.height(); QRectF rect( 0, 0, w, h ); double aspect = rect.width() / rect.height(); if ( ( aspect < 1.0 ) ) rect.setHeight( aspect * rect.width() ); QPainter p( &printer ); render( plot, &p, rect ); } #endif #ifndef QWT_NO_SVG #ifdef QT_SVG_LIB #if QT_VERSION >= 0x040500 /*! \brief Render the plot to a QSvgGenerator If the generator has a view box, the plot will be rendered into it. If it has no viewBox but a valid size the target coordinates will be (0, 0, generator.width(), generator.height()). Otherwise the target rectangle will be QRectF(0, 0, 800, 600); \param plot Plot to be rendered \param generator SVG generator */ void QwtPlotRenderer::renderTo( QwtPlot *plot, QSvgGenerator &generator ) const { QRectF rect = generator.viewBoxF(); if ( rect.isEmpty() ) rect.setRect( 0, 0, generator.width(), generator.height() ); if ( rect.isEmpty() ) rect.setRect( 0, 0, 800, 600 ); // something QPainter p( &generator ); render( plot, &p, rect ); } #endif #endif #endif /*! Paint the contents of a QwtPlot instance into a given rectangle. \param plot Plot to be rendered \param painter Painter \param plotRect Bounding rectangle \sa renderDocument(), renderTo(), QwtPainter::setRoundingAlignment() */ void QwtPlotRenderer::render( QwtPlot *plot, QPainter *painter, const QRectF &plotRect ) const { int axisId; if ( painter == 0 || !painter->isActive() || !plotRect.isValid() || plot->size().isNull() ) return; if ( !( d_data->discardFlags & DiscardBackground ) ) qwtRenderBackground( painter, plotRect, plot ); /* The layout engine uses the same methods as they are used by the Qt layout system. Therefore we need to calculate the layout in screen coordinates and paint with a scaled painter. */ QTransform transform; transform.scale( double( painter->device()->logicalDpiX() ) / plot->logicalDpiX(), double( painter->device()->logicalDpiY() ) / plot->logicalDpiY() ); QRectF layoutRect = transform.inverted().mapRect( plotRect ); if ( !( d_data->discardFlags & DiscardBackground ) ) { // subtract the contents margins int left, top, right, bottom; plot->getContentsMargins( &left, &top, &right, &bottom ); layoutRect.adjust( left, top, -right, -bottom ); } int baseLineDists[QwtPlot::axisCnt]; if ( d_data->layoutFlags & FrameWithScales ) { for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) { QwtScaleWidget *scaleWidget = plot->axisWidget( axisId ); if ( scaleWidget ) { baseLineDists[axisId] = scaleWidget->margin(); scaleWidget->setMargin( 0 ); } if ( !plot->axisEnabled( axisId ) ) { int left = 0; int right = 0; int top = 0; int bottom = 0; // When we have a scale the frame is painted on // the position of the backbone - otherwise we // need to introduce a margin around the canvas switch( axisId ) { case QwtPlot::yLeft: layoutRect.adjust( 1, 0, 0, 0 ); break; case QwtPlot::yRight: layoutRect.adjust( 0, 0, -1, 0 ); break; case QwtPlot::xTop: layoutRect.adjust( 0, 1, 0, 0 ); break; case QwtPlot::xBottom: layoutRect.adjust( 0, 0, 0, -1 ); break; default: break; } layoutRect.adjust( left, top, right, bottom ); } } } // Calculate the layout for the document. QwtPlotLayout::Options layoutOptions = QwtPlotLayout::IgnoreScrollbars | QwtPlotLayout::IgnoreFrames; if ( d_data->discardFlags & DiscardLegend ) layoutOptions |= QwtPlotLayout::IgnoreLegend; plot->plotLayout()->activate( plot, layoutRect, layoutOptions ); // now start painting painter->save(); painter->setWorldTransform( transform, true ); // canvas QwtScaleMap maps[QwtPlot::axisCnt]; buildCanvasMaps( plot, plot->plotLayout()->canvasRect(), maps ); renderCanvas( plot, painter, plot->plotLayout()->canvasRect(), maps ); if ( !( d_data->discardFlags & DiscardTitle ) && ( !plot->titleLabel()->text().isEmpty() ) ) { renderTitle( plot, painter, plot->plotLayout()->titleRect() ); } if ( !( d_data->discardFlags & DiscardLegend ) && plot->legend() && !plot->legend()->isEmpty() ) { renderLegend( plot, painter, plot->plotLayout()->legendRect() ); } for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) { QwtScaleWidget *scaleWidget = plot->axisWidget( axisId ); if ( scaleWidget ) { int baseDist = scaleWidget->margin(); int startDist, endDist; scaleWidget->getBorderDistHint( startDist, endDist ); renderScale( plot, painter, axisId, startDist, endDist, baseDist, plot->plotLayout()->scaleRect( axisId ) ); } } plot->plotLayout()->invalidate(); // reset all widgets with their original attributes. if ( d_data->layoutFlags & FrameWithScales ) { // restore the previous base line dists for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) { QwtScaleWidget *scaleWidget = plot->axisWidget( axisId ); if ( scaleWidget ) scaleWidget->setMargin( baseLineDists[axisId] ); } } painter->restore(); } /*! Render the title into a given rectangle. \param plot Plot widget \param painter Painter \param rect Bounding rectangle */ void QwtPlotRenderer::renderTitle( const QwtPlot *plot, QPainter *painter, const QRectF &rect ) const { painter->setFont( plot->titleLabel()->font() ); const QColor color = plot->titleLabel()->palette().color( QPalette::Active, QPalette::Text ); painter->setPen( color ); plot->titleLabel()->text().draw( painter, rect ); } /*! Render the legend into a given rectangle. \param plot Plot widget \param painter Painter \param rect Bounding rectangle */ void QwtPlotRenderer::renderLegend( const QwtPlot *plot, QPainter *painter, const QRectF &rect ) const { if ( !plot->legend() || plot->legend()->isEmpty() ) return; if ( !( d_data->discardFlags & DiscardBackground ) ) { if ( plot->legend()->autoFillBackground() || plot->legend()->testAttribute( Qt::WA_StyledBackground ) ) { qwtRenderBackground( painter, rect, plot->legend() ); } } const QwtDynGridLayout *legendLayout = qobject_cast( plot->legend()->contentsWidget()->layout() ); if ( legendLayout == NULL ) return; uint numCols = legendLayout->columnsForWidth( qFloor( rect.width() ) ); QList itemRects = legendLayout->layoutItems( rect.toRect(), numCols ); int index = 0; for ( int i = 0; i < legendLayout->count(); i++ ) { QLayoutItem *item = legendLayout->itemAt( i ); QWidget *w = item->widget(); if ( w ) { painter->save(); painter->setClipRect( itemRects[index] ); renderLegendItem( plot, painter, w, itemRects[index] ); index++; painter->restore(); } } } /*! Render the legend item into a given rectangle. \param plot Plot widget \param painter Painter \param widget Widget representing a legend item \param rect Bounding rectangle \note When widget is not derived from QwtLegendItem renderLegendItem does nothing and needs to be overloaded */ void QwtPlotRenderer::renderLegendItem( const QwtPlot *plot, QPainter *painter, const QWidget *widget, const QRectF &rect ) const { if ( !( d_data->discardFlags & DiscardBackground ) ) { if ( widget->autoFillBackground() || widget->testAttribute( Qt::WA_StyledBackground ) ) { qwtRenderBackground( painter, rect, widget ); } } const QwtLegendItem *item = qobject_cast( widget ); if ( item ) { const QSize sz = item->identifierSize(); const QRectF identifierRect( rect.x() + item->margin(), rect.center().y() - 0.5 * sz.height(), sz.width(), sz.height() ); QwtLegendItemManager *itemManger = plot->legend()->find( item ); if ( itemManger ) { painter->save(); painter->setClipRect( identifierRect, Qt::IntersectClip ); itemManger->drawLegendIdentifier( painter, identifierRect ); painter->restore(); } // Label QRectF titleRect = rect; titleRect.setX( identifierRect.right() + 2 * item->spacing() ); painter->setFont( item->font() ); item->text().draw( painter, titleRect ); } } /*! \brief Paint a scale into a given rectangle. Paint the scale into a given rectangle. \param plot Plot widget \param painter Painter \param axisId Axis \param startDist Start border distance \param endDist End border distance \param baseDist Base distance \param rect Bounding rectangle */ void QwtPlotRenderer::renderScale( const QwtPlot *plot, QPainter *painter, int axisId, int startDist, int endDist, int baseDist, const QRectF &rect ) const { if ( !plot->axisEnabled( axisId ) ) return; const QwtScaleWidget *scaleWidget = plot->axisWidget( axisId ); if ( scaleWidget->isColorBarEnabled() && scaleWidget->colorBarWidth() > 0 ) { scaleWidget->drawColorBar( painter, scaleWidget->colorBarRect( rect ) ); const int off = scaleWidget->colorBarWidth() + scaleWidget->spacing(); if ( scaleWidget->scaleDraw()->orientation() == Qt::Horizontal ) baseDist += off; else baseDist += off; } painter->save(); QwtScaleDraw::Alignment align; double x, y, w; switch ( axisId ) { case QwtPlot::yLeft: { x = rect.right() - 1.0 - baseDist; y = rect.y() + startDist; w = rect.height() - startDist - endDist; align = QwtScaleDraw::LeftScale; break; } case QwtPlot::yRight: { x = rect.left() + baseDist; y = rect.y() + startDist; w = rect.height() - startDist - endDist; align = QwtScaleDraw::RightScale; break; } case QwtPlot::xTop: { x = rect.left() + startDist; y = rect.bottom() - 1.0 - baseDist; w = rect.width() - startDist - endDist; align = QwtScaleDraw::TopScale; break; } case QwtPlot::xBottom: { x = rect.left() + startDist; y = rect.top() + baseDist; w = rect.width() - startDist - endDist; align = QwtScaleDraw::BottomScale; break; } default: return; } scaleWidget->drawTitle( painter, align, rect ); painter->setFont( scaleWidget->font() ); QwtScaleDraw *sd = const_cast( scaleWidget->scaleDraw() ); const QPointF sdPos = sd->pos(); const double sdLength = sd->length(); sd->move( x, y ); sd->setLength( w ); QPalette palette = scaleWidget->palette(); palette.setCurrentColorGroup( QPalette::Active ); sd->draw( painter, palette ); // reset previous values sd->move( sdPos ); sd->setLength( sdLength ); painter->restore(); } /*! Render the canvas into a given rectangle. \param plot Plot widget \param painter Painter \param map Maps mapping between plot and paint device coordinates \param canvasRect Canvas rectangle */ void QwtPlotRenderer::renderCanvas( const QwtPlot *plot, QPainter *painter, const QRectF &canvasRect, const QwtScaleMap *map ) const { painter->save(); QPainterPath clipPath; QRectF r = canvasRect.adjusted( 0.0, 0.0, -1.0, -1.0 ); if ( d_data->layoutFlags & FrameWithScales ) { r.adjust( -1.0, -1.0, 1.0, 1.0 ); painter->setPen( QPen( Qt::black ) ); if ( !( d_data->discardFlags & DiscardCanvasBackground ) ) { const QBrush bgBrush = plot->canvas()->palette().brush( plot->backgroundRole() ); painter->setBrush( bgBrush ); } QwtPainter::drawRect( painter, r ); } else { if ( !( d_data->discardFlags & DiscardCanvasBackground ) ) { qwtRenderBackground( painter, r, plot->canvas() ); if ( plot->canvas()->testAttribute( Qt::WA_StyledBackground ) ) { // The clip region is calculated in integers // To avoid too much rounding errors better // calculate it in target device resolution // TODO ... int x1 = qCeil( canvasRect.left() ); int x2 = qFloor( canvasRect.right() ); int y1 = qCeil( canvasRect.top() ); int y2 = qFloor( canvasRect.bottom() ); clipPath = plot->canvas()->borderPath( QRect( x1, y1, x2 - x1 - 1, y2 - y1 - 1 ) ); } } } painter->restore(); painter->save(); if ( clipPath.isEmpty() ) painter->setClipRect( canvasRect ); else painter->setClipPath( clipPath ); plot->drawItems( painter, canvasRect, map ); painter->restore(); } /*! Calculated the scale maps for rendering the canvas \param plot Plot widget \param canvasRect Target rectangle \param maps Scale maps to be calculated */ void QwtPlotRenderer::buildCanvasMaps( const QwtPlot *plot, const QRectF &canvasRect, QwtScaleMap maps[] ) const { for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) { maps[axisId].setTransformation( plot->axisScaleEngine( axisId )->transformation() ); const QwtScaleDiv &scaleDiv = *plot->axisScaleDiv( axisId ); maps[axisId].setScaleInterval( scaleDiv.lowerBound(), scaleDiv.upperBound() ); double from, to; if ( plot->axisEnabled( axisId ) ) { const int sDist = plot->axisWidget( axisId )->startBorderDist(); const int eDist = plot->axisWidget( axisId )->endBorderDist(); const QRectF &scaleRect = plot->plotLayout()->scaleRect( axisId ); if ( axisId == QwtPlot::xTop || axisId == QwtPlot::xBottom ) { from = scaleRect.left() + sDist; to = scaleRect.right() - eDist; } else { from = scaleRect.bottom() - eDist; to = scaleRect.top() + sDist; } } else { int margin = 0; if ( !plot->plotLayout()->alignCanvasToScales() ) margin = plot->plotLayout()->canvasMargin( axisId ); if ( axisId == QwtPlot::yLeft || axisId == QwtPlot::yRight ) { from = canvasRect.bottom() - margin; to = canvasRect.top() + margin; } else { from = canvasRect.left() + margin; to = canvasRect.right() - margin; } } maps[axisId].setPaintInterval( from, to ); } } pcp-gui-1.5.11/src/libqwt/qwt_plot_rescaler.cpp0000644000000000000000000003565412176111212016366 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_rescaler.h" #include "qwt_plot.h" #include "qwt_plot_canvas.h" #include "qwt_scale_div.h" #include "qwt_interval.h" #include #include class QwtPlotRescaler::AxisData { public: AxisData(): aspectRatio( 1.0 ), expandingDirection( QwtPlotRescaler::ExpandUp ) { } double aspectRatio; QwtInterval intervalHint; QwtPlotRescaler::ExpandingDirection expandingDirection; mutable QwtScaleDiv scaleDiv; }; class QwtPlotRescaler::PrivateData { public: PrivateData(): referenceAxis( QwtPlot::xBottom ), rescalePolicy( QwtPlotRescaler::Expanding ), isEnabled( false ), inReplot( 0 ) { } int referenceAxis; RescalePolicy rescalePolicy; QwtPlotRescaler::AxisData axisData[QwtPlot::axisCnt]; bool isEnabled; mutable int inReplot; }; /*! Constructor \param canvas Canvas \param referenceAxis Reference axis, see RescalePolicy \param policy Rescale policy \sa setRescalePolicy(), setReferenceAxis() */ QwtPlotRescaler::QwtPlotRescaler( QwtPlotCanvas *canvas, int referenceAxis, RescalePolicy policy ): QObject( canvas ) { d_data = new PrivateData; d_data->referenceAxis = referenceAxis; d_data->rescalePolicy = policy; setEnabled( true ); } //! Destructor QwtPlotRescaler::~QwtPlotRescaler() { delete d_data; } /*! \brief En/disable the rescaler When enabled is true an event filter is installed for the canvas, otherwise the event filter is removed. \param on true or false \sa isEnabled(), eventFilter() */ void QwtPlotRescaler::setEnabled( bool on ) { if ( d_data->isEnabled != on ) { d_data->isEnabled = on; QWidget *w = canvas(); if ( w ) { if ( d_data->isEnabled ) w->installEventFilter( this ); else w->removeEventFilter( this ); } } } /*! \return true when enabled, false otherwise \sa setEnabled, eventFilter() */ bool QwtPlotRescaler::isEnabled() const { return d_data->isEnabled; } /*! Change the rescale policy \param policy Rescale policy \sa rescalePolicy() */ void QwtPlotRescaler::setRescalePolicy( RescalePolicy policy ) { d_data->rescalePolicy = policy; } /*! \return Rescale policy \sa setRescalePolicy() */ QwtPlotRescaler::RescalePolicy QwtPlotRescaler::rescalePolicy() const { return d_data->rescalePolicy; } /*! Set the reference axis ( see RescalePolicy ) \param axis Axis index ( QwtPlot::Axis ) \sa referenceAxis() */ void QwtPlotRescaler::setReferenceAxis( int axis ) { d_data->referenceAxis = axis; } /*! \return Reference axis ( see RescalePolicy ) \sa setReferenceAxis() */ int QwtPlotRescaler::referenceAxis() const { return d_data->referenceAxis; } /*! Set the direction in which all axis should be expanded \param direction Direction \sa expandingDirection() */ void QwtPlotRescaler::setExpandingDirection( ExpandingDirection direction ) { for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) setExpandingDirection( axis, direction ); } /*! Set the direction in which an axis should be expanded \param axis Axis index ( see QwtPlot::AxisId ) \param direction Direction \sa expandingDirection() */ void QwtPlotRescaler::setExpandingDirection( int axis, ExpandingDirection direction ) { if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->axisData[axis].expandingDirection = direction; } /*! Return direction in which an axis should be expanded \param axis Axis index ( see QwtPlot::AxisId ) \sa setExpandingDirection() */ QwtPlotRescaler::ExpandingDirection QwtPlotRescaler::expandingDirection( int axis ) const { if ( axis >= 0 && axis < QwtPlot::axisCnt ) return d_data->axisData[axis].expandingDirection; return ExpandBoth; } /*! Set the aspect ratio between the scale of the reference axis and the other scales. The default ratio is 1.0 \param ratio Aspect ratio \sa aspectRatio() */ void QwtPlotRescaler::setAspectRatio( double ratio ) { for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) setAspectRatio( axis, ratio ); } /*! Set the aspect ratio between the scale of the reference axis and another scale. The default ratio is 1.0 \param axis Axis index ( see QwtPlot::AxisId ) \param ratio Aspect ratio \sa aspectRatio() */ void QwtPlotRescaler::setAspectRatio( int axis, double ratio ) { if ( ratio < 0.0 ) ratio = 0.0; if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->axisData[axis].aspectRatio = ratio; } /*! Return aspect ratio between an axis and the reference axis. \param axis Axis index ( see QwtPlot::AxisId ) \sa setAspectRatio() */ double QwtPlotRescaler::aspectRatio( int axis ) const { if ( axis >= 0 && axis < QwtPlot::axisCnt ) return d_data->axisData[axis].aspectRatio; return 0.0; } /*! Set an interval hint for an axis In Fitting mode, the hint is used as minimal interval taht always needs to be displayed. \param axis Axis, see QwtPlot::Axis \param interval Axis \sa intervalHint(), RescalePolicy */ void QwtPlotRescaler::setIntervalHint( int axis, const QwtInterval &interval ) { if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->axisData[axis].intervalHint = interval; } /*! \param axis Axis, see QwtPlot::Axis \return Interval hint \sa setIntervalHint(), RescalePolicy */ QwtInterval QwtPlotRescaler::intervalHint( int axis ) const { if ( axis >= 0 && axis < QwtPlot::axisCnt ) return d_data->axisData[axis].intervalHint; return QwtInterval(); } //! \return plot canvas QwtPlotCanvas *QwtPlotRescaler::canvas() { return qobject_cast( parent() ); } //! \return plot canvas const QwtPlotCanvas *QwtPlotRescaler::canvas() const { return qobject_cast( parent() ); } //! \return plot widget QwtPlot *QwtPlotRescaler::plot() { QwtPlotCanvas *w = canvas(); if ( w ) return w->plot(); return NULL; } //! \return plot widget const QwtPlot *QwtPlotRescaler::plot() const { const QwtPlotCanvas *w = canvas(); if ( w ) return w->plot(); return NULL; } //! Event filter for the plot canvas bool QwtPlotRescaler::eventFilter( QObject *object, QEvent *event ) { if ( object && object == canvas() ) { switch ( event->type() ) { case QEvent::Resize: { canvasResizeEvent( ( QResizeEvent * )event ); break; } case QEvent::PolishRequest: { rescale(); break; } default:; } } return false; } /*! Event handler for resize events of the plot canvas \param event Resize event \sa rescale() */ void QwtPlotRescaler::canvasResizeEvent( QResizeEvent* event ) { const int fw = 2 * canvas()->frameWidth(); const QSize newSize = event->size() - QSize( fw, fw ); const QSize oldSize = event->oldSize() - QSize( fw, fw ); rescale( oldSize, newSize ); } //! Adjust the plot axes scales void QwtPlotRescaler::rescale() const { const QSize size = canvas()->contentsRect().size(); rescale( size, size ); } /*! Adjust the plot axes scales \param oldSize Previous size of the canvas \param newSize New size of the canvas */ void QwtPlotRescaler::rescale( const QSize &oldSize, const QSize &newSize ) const { if ( newSize.isEmpty() ) return; QwtInterval intervals[QwtPlot::axisCnt]; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) intervals[axis] = interval( axis ); const int refAxis = referenceAxis(); intervals[refAxis] = expandScale( refAxis, oldSize, newSize ); for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( aspectRatio( axis ) > 0.0 && axis != refAxis ) intervals[axis] = syncScale( axis, intervals[refAxis], newSize ); } updateScales( intervals ); } /*! Calculate the new scale interval of a plot axis \param axis Axis index ( see QwtPlot::AxisId ) \param oldSize Previous size of the canvas \param newSize New size of the canvas \return Calculated new interval for the axis */ QwtInterval QwtPlotRescaler::expandScale( int axis, const QSize &oldSize, const QSize &newSize ) const { const QwtInterval oldInterval = interval( axis ); QwtInterval expanded = oldInterval; switch ( rescalePolicy() ) { case Fixed: { break; // do nothing } case Expanding: { if ( !oldSize.isEmpty() ) { double width = oldInterval.width(); if ( orientation( axis ) == Qt::Horizontal ) width *= double( newSize.width() ) / oldSize.width(); else width *= double( newSize.height() ) / oldSize.height(); expanded = expandInterval( oldInterval, width, expandingDirection( axis ) ); } break; } case Fitting: { double dist = 0.0; for ( int ax = 0; ax < QwtPlot::axisCnt; ax++ ) { const double d = pixelDist( ax, newSize ); if ( d > dist ) dist = d; } if ( dist > 0.0 ) { double width; if ( orientation( axis ) == Qt::Horizontal ) width = newSize.width() * dist; else width = newSize.height() * dist; expanded = expandInterval( intervalHint( axis ), width, expandingDirection( axis ) ); } break; } } return expanded; } /*! Synchronize an axis scale according to the scale of the reference axis \param axis Axis index ( see QwtPlot::AxisId ) \param reference Interval of the reference axis \param size Size of the canvas */ QwtInterval QwtPlotRescaler::syncScale( int axis, const QwtInterval& reference, const QSize &size ) const { double dist; if ( orientation( referenceAxis() ) == Qt::Horizontal ) dist = reference.width() / size.width(); else dist = reference.width() / size.height(); if ( orientation( axis ) == Qt::Horizontal ) dist *= size.width(); else dist *= size.height(); dist /= aspectRatio( axis ); QwtInterval intv; if ( rescalePolicy() == Fitting ) intv = intervalHint( axis ); else intv = interval( axis ); intv = expandInterval( intv, dist, expandingDirection( axis ) ); return intv; } /*! Return orientation of an axis \param axis Axis index ( see QwtPlot::AxisId ) */ Qt::Orientation QwtPlotRescaler::orientation( int axis ) const { if ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) return Qt::Vertical; return Qt::Horizontal; } /*! Return interval of an axis \param axis Axis index ( see QwtPlot::AxisId ) */ QwtInterval QwtPlotRescaler::interval( int axis ) const { if ( axis < 0 || axis >= QwtPlot::axisCnt ) return QwtInterval(); const QwtPlot *plt = plot(); const double v1 = plt->axisScaleDiv( axis )->lowerBound(); const double v2 = plt->axisScaleDiv( axis )->upperBound(); return QwtInterval( v1, v2 ).normalized(); } /*! Expand the interval \param interval Interval to be expanded \param width Distance to be added to the interval \param direction Direction of the expand operation \return Expanded interval */ QwtInterval QwtPlotRescaler::expandInterval( const QwtInterval &interval, double width, ExpandingDirection direction ) const { QwtInterval expanded = interval; switch ( direction ) { case ExpandUp: expanded.setMinValue( interval.minValue() ); expanded.setMaxValue( interval.minValue() + width ); break; case ExpandDown: expanded.setMaxValue( interval.maxValue() ); expanded.setMinValue( interval.maxValue() - width ); break; case ExpandBoth: default: expanded.setMinValue( interval.minValue() + interval.width() / 2.0 - width / 2.0 ); expanded.setMaxValue( expanded.minValue() + width ); } return expanded; } double QwtPlotRescaler::pixelDist( int axis, const QSize &size ) const { const QwtInterval intv = intervalHint( axis ); double dist = 0.0; if ( !intv.isNull() ) { if ( axis == referenceAxis() ) dist = intv.width(); else { const double r = aspectRatio( axis ); if ( r > 0.0 ) dist = intv.width() * r; } } if ( dist > 0.0 ) { if ( orientation( axis ) == Qt::Horizontal ) dist /= size.width(); else dist /= size.height(); } return dist; } /*! Update the axes scales \param intervals Scale intervals */ void QwtPlotRescaler::updateScales( QwtInterval intervals[QwtPlot::axisCnt] ) const { if ( d_data->inReplot >= 5 ) { return; } QwtPlot *plt = const_cast( plot() ); const bool doReplot = plt->autoReplot(); plt->setAutoReplot( false ); for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( axis == referenceAxis() || aspectRatio( axis ) > 0.0 ) { double v1 = intervals[axis].minValue(); double v2 = intervals[axis].maxValue(); if ( plt->axisScaleDiv( axis )->lowerBound() > plt->axisScaleDiv( axis )->upperBound() ) { qSwap( v1, v2 ); } if ( d_data->inReplot >= 1 ) { d_data->axisData[axis].scaleDiv = *plt->axisScaleDiv( axis ); } if ( d_data->inReplot >= 2 ) { QList ticks[QwtScaleDiv::NTickTypes]; for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ ) ticks[i] = d_data->axisData[axis].scaleDiv.ticks( i ); plt->setAxisScaleDiv( axis, QwtScaleDiv( v1, v2, ticks ) ); } else { plt->setAxisScale( axis, v1, v2 ); } } } const bool immediatePaint = plt->canvas()->testPaintAttribute( QwtPlotCanvas::ImmediatePaint ); plt->canvas()->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, false ); plt->setAutoReplot( doReplot ); d_data->inReplot++; plt->replot(); d_data->inReplot--; plt->canvas()->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, immediatePaint ); } pcp-gui-1.5.11/src/libqwt/qwt_plot_scaleitem.cpp0000644000000000000000000002505512176111212016526 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_scaleitem.h" #include "qwt_plot.h" #include "qwt_plot_canvas.h" #include "qwt_scale_map.h" #include "qwt_interval.h" #include #include class QwtPlotScaleItem::PrivateData { public: PrivateData(): position( 0.0 ), borderDistance( -1 ), scaleDivFromAxis( true ), scaleDraw( new QwtScaleDraw() ) { } ~PrivateData() { delete scaleDraw; } void updateBorders( const QRectF &, const QwtScaleMap &, const QwtScaleMap & ); QPalette palette; QFont font; double position; int borderDistance; bool scaleDivFromAxis; QwtScaleDraw *scaleDraw; QRectF canvasRectCache; }; void QwtPlotScaleItem::PrivateData::updateBorders( const QRectF &canvasRect, const QwtScaleMap &xMap, const QwtScaleMap &yMap ) { QwtInterval interval; if ( scaleDraw->orientation() == Qt::Horizontal ) { interval.setMinValue( xMap.invTransform( canvasRect.left() ) ); interval.setMaxValue( xMap.invTransform( canvasRect.right() - 1 ) ); } else { interval.setMinValue( yMap.invTransform( canvasRect.bottom() - 1 ) ); interval.setMaxValue( yMap.invTransform( canvasRect.top() ) ); } QwtScaleDiv scaleDiv = scaleDraw->scaleDiv(); scaleDiv.setInterval( interval ); scaleDraw->setScaleDiv( scaleDiv ); } /*! \brief Constructor for scale item at the position pos. \param alignment In case of QwtScaleDraw::BottomScale or QwtScaleDraw::TopScale the scale item is corresponding to the xAxis(), otherwise it corresponds to the yAxis(). \param pos x or y position, depending on the corresponding axis. \sa setPosition(), setAlignment() */ QwtPlotScaleItem::QwtPlotScaleItem( QwtScaleDraw::Alignment alignment, const double pos ): QwtPlotItem( QwtText( "Scale" ) ) { d_data = new PrivateData; d_data->position = pos; d_data->scaleDraw->setAlignment( alignment ); setZ( 11.0 ); } //! Destructor QwtPlotScaleItem::~QwtPlotScaleItem() { delete d_data; } //! \return QwtPlotItem::Rtti_PlotScale int QwtPlotScaleItem::rtti() const { return QwtPlotItem::Rtti_PlotScale; } /*! \brief Assign a scale division When assigning a scaleDiv the scale division won't be synchronized with the corresponding axis anymore. \param scaleDiv Scale division \sa scaleDiv(), setScaleDivFromAxis(), isScaleDivFromAxis() */ void QwtPlotScaleItem::setScaleDiv( const QwtScaleDiv& scaleDiv ) { d_data->scaleDivFromAxis = false; d_data->scaleDraw->setScaleDiv( scaleDiv ); } //! \return Scale division const QwtScaleDiv& QwtPlotScaleItem::scaleDiv() const { return d_data->scaleDraw->scaleDiv(); } /*! Enable/Disable the synchronization of the scale division with the corresponding axis. \param on true/false \sa isScaleDivFromAxis() */ void QwtPlotScaleItem::setScaleDivFromAxis( bool on ) { if ( on != d_data->scaleDivFromAxis ) { d_data->scaleDivFromAxis = on; if ( on ) { const QwtPlot *plt = plot(); if ( plt ) { updateScaleDiv( *plt->axisScaleDiv( xAxis() ), *plt->axisScaleDiv( yAxis() ) ); itemChanged(); } } } } /*! \return True, if the synchronization of the scale division with the corresponding axis is enabled. \sa setScaleDiv(), setScaleDivFromAxis() */ bool QwtPlotScaleItem::isScaleDivFromAxis() const { return d_data->scaleDivFromAxis; } /*! Set the palette \sa QwtAbstractScaleDraw::draw(), palette() */ void QwtPlotScaleItem::setPalette( const QPalette &palette ) { if ( palette != d_data->palette ) { d_data->palette = palette; itemChanged(); } } /*! \return palette \sa setPalette() */ QPalette QwtPlotScaleItem::palette() const { return d_data->palette; } /*! Change the tick label font \sa font() */ void QwtPlotScaleItem::setFont( const QFont &font ) { if ( font != d_data->font ) { d_data->font = font; itemChanged(); } } /*! \return tick label font \sa setFont() */ QFont QwtPlotScaleItem::font() const { return d_data->font; } /*! \brief Set a scale draw \param scaleDraw object responsible for drawing scales. The main use case for replacing the default QwtScaleDraw is to overload QwtAbstractScaleDraw::label, to replace or swallow tick labels. \sa scaleDraw() */ void QwtPlotScaleItem::setScaleDraw( QwtScaleDraw *scaleDraw ) { if ( scaleDraw == NULL ) return; if ( scaleDraw != d_data->scaleDraw ) delete d_data->scaleDraw; d_data->scaleDraw = scaleDraw; const QwtPlot *plt = plot(); if ( plt ) { updateScaleDiv( *plt->axisScaleDiv( xAxis() ), *plt->axisScaleDiv( yAxis() ) ); } itemChanged(); } /*! \return Scale draw \sa setScaleDraw() */ const QwtScaleDraw *QwtPlotScaleItem::scaleDraw() const { return d_data->scaleDraw; } /*! \return Scale draw \sa setScaleDraw() */ QwtScaleDraw *QwtPlotScaleItem::scaleDraw() { return d_data->scaleDraw; } /*! Change the position of the scale The position is interpreted as y value for horizontal axes and as x value for vertical axes. The border distance is set to -1. \param pos New position \sa position(), setAlignment() */ void QwtPlotScaleItem::setPosition( double pos ) { if ( d_data->position != pos ) { d_data->position = pos; d_data->borderDistance = -1; itemChanged(); } } /*! \return Position of the scale \sa setPosition(), setAlignment() */ double QwtPlotScaleItem::position() const { return d_data->position; } /*! \brief Align the scale to the canvas If distance is >= 0 the scale will be aligned to a border of the contents rect of the canvas. If alignment() is QwtScaleDraw::LeftScale, the scale will be aligned to the right border, if it is QwtScaleDraw::TopScale it will be aligned to the bottom (and vice versa), If distance is < 0 the scale will be at the position(). \param distance Number of pixels between the canvas border and the backbone of the scale. \sa setPosition(), borderDistance() */ void QwtPlotScaleItem::setBorderDistance( int distance ) { if ( distance < 0 ) distance = -1; if ( distance != d_data->borderDistance ) { d_data->borderDistance = distance; itemChanged(); } } /*! \return Distance from a canvas border \sa setBorderDistance(), setPosition() */ int QwtPlotScaleItem::borderDistance() const { return d_data->borderDistance; } /*! Change the alignment of the scale The alignment sets the orientation of the scale and the position of the ticks: - QwtScaleDraw::BottomScale: horizontal, ticks below - QwtScaleDraw::TopScale: horizontal, ticks above - QwtScaleDraw::LeftScale: vertical, ticks left - QwtScaleDraw::RightScale: vertical, ticks right For horizontal scales the position corresponds to QwtPlotItem::yAxis(), otherwise to QwtPlotItem::xAxis(). \sa scaleDraw(), QwtScaleDraw::alignment(), setPosition() */ void QwtPlotScaleItem::setAlignment( QwtScaleDraw::Alignment alignment ) { QwtScaleDraw *sd = d_data->scaleDraw; if ( sd->alignment() != alignment ) { sd->setAlignment( alignment ); itemChanged(); } } /*! \brief Draw the scale */ void QwtPlotScaleItem::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { if ( d_data->scaleDivFromAxis ) { if ( canvasRect != d_data->canvasRectCache ) { d_data->updateBorders( canvasRect, xMap, yMap ); d_data->canvasRectCache = canvasRect; } } QPen pen = painter->pen(); pen.setStyle( Qt::SolidLine ); painter->setPen( pen ); QwtScaleDraw *sd = d_data->scaleDraw; if ( sd->orientation() == Qt::Horizontal ) { double y; if ( d_data->borderDistance >= 0 ) { if ( sd->alignment() == QwtScaleDraw::BottomScale ) y = canvasRect.top() + d_data->borderDistance; else { y = canvasRect.bottom() - d_data->borderDistance; } } else { y = yMap.transform( d_data->position ); } if ( y < canvasRect.top() || y > canvasRect.bottom() ) return; sd->move( canvasRect.left(), y ); sd->setLength( canvasRect.width() - 1 ); sd->setTransformation( xMap.transformation()->copy() ); } else // == Qt::Vertical { double x; if ( d_data->borderDistance >= 0 ) { if ( sd->alignment() == QwtScaleDraw::RightScale ) x = canvasRect.left() + d_data->borderDistance; else { x = canvasRect.right() - d_data->borderDistance; } } else { x = xMap.transform( d_data->position ); } if ( x < canvasRect.left() || x > canvasRect.right() ) return; sd->move( x, canvasRect.top() ); sd->setLength( canvasRect.height() - 1 ); sd->setTransformation( yMap.transformation()->copy() ); } painter->setFont( d_data->font ); sd->draw( painter, d_data->palette ); } /*! \brief Update the item to changes of the axes scale division In case of isScaleDivFromAxis(), the scale draw is synchronized to the correspond axis. \param xScaleDiv Scale division of the x-axis \param yScaleDiv Scale division of the y-axis \sa QwtPlot::updateAxes() */ void QwtPlotScaleItem::updateScaleDiv( const QwtScaleDiv& xScaleDiv, const QwtScaleDiv& yScaleDiv ) { QwtScaleDraw *sd = d_data->scaleDraw; if ( d_data->scaleDivFromAxis && sd ) { sd->setScaleDiv( sd->orientation() == Qt::Horizontal ? xScaleDiv : yScaleDiv ); const QwtPlot *plt = plot(); if ( plt != NULL ) { d_data->updateBorders( plt->canvas()->contentsRect(), plt->canvasMap( xAxis() ), plt->canvasMap( yAxis() ) ); d_data->canvasRectCache = QRect(); } } } pcp-gui-1.5.11/src/libqwt/qwt_plot_seriesitem.cpp0000644000000000000000000000414012176111212016721 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_seriesitem.h" class QwtPlotAbstractSeriesItem::PrivateData { public: PrivateData(): orientation( Qt::Vertical ) { } Qt::Orientation orientation; }; /*! Constructor \param title Title of the curve */ QwtPlotAbstractSeriesItem::QwtPlotAbstractSeriesItem( const QwtText &title ): QwtPlotItem( title ) { d_data = new PrivateData(); } /*! Constructor \param title Title of the curve */ QwtPlotAbstractSeriesItem::QwtPlotAbstractSeriesItem( const QString &title ): QwtPlotItem( QwtText( title ) ) { d_data = new PrivateData(); } //! Destructor QwtPlotAbstractSeriesItem::~QwtPlotAbstractSeriesItem() { delete d_data; } /*! Set the orientation of the item. The orientation() might be used in specific way by a plot item. F.e. a QwtPlotCurve uses it to identify how to display the curve int QwtPlotCurve::Steps or QwtPlotCurve::Sticks style. \sa orientation() */ void QwtPlotAbstractSeriesItem::setOrientation( Qt::Orientation orientation ) { if ( d_data->orientation != orientation ) { d_data->orientation = orientation; itemChanged(); } } /*! \return Orientation of the plot item \sa setOrientation() */ Qt::Orientation QwtPlotAbstractSeriesItem::orientation() const { return d_data->orientation; } /*! \brief Draw the complete series \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas */ void QwtPlotAbstractSeriesItem::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { drawSeries( painter, xMap, yMap, canvasRect, 0, -1 ); } pcp-gui-1.5.11/src/libqwt/qwt_plot_spectrocurve.cpp0000644000000000000000000001625212176111212017303 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_spectrocurve.h" #include "qwt_color_map.h" #include "qwt_scale_map.h" #include "qwt_painter.h" #include class QwtPlotSpectroCurve::PrivateData { public: PrivateData(): colorRange( 0.0, 1000.0 ), penWidth(0.0), paintAttributes( QwtPlotSpectroCurve::ClipPoints ) { colorMap = new QwtLinearColorMap(); } ~PrivateData() { delete colorMap; } QwtColorMap *colorMap; QwtInterval colorRange; QVector colorTable; double penWidth; QwtPlotSpectroCurve::PaintAttributes paintAttributes; }; /*! Constructor \param title Title of the curve */ QwtPlotSpectroCurve::QwtPlotSpectroCurve( const QwtText &title ): QwtPlotSeriesItem( title ) { init(); } /*! Constructor \param title Title of the curve */ QwtPlotSpectroCurve::QwtPlotSpectroCurve( const QString &title ): QwtPlotSeriesItem( QwtText( title ) ) { init(); } //! Destructor QwtPlotSpectroCurve::~QwtPlotSpectroCurve() { delete d_data; } /*! \brief Initialize data members */ void QwtPlotSpectroCurve::init() { setItemAttribute( QwtPlotItem::Legend ); setItemAttribute( QwtPlotItem::AutoScale ); d_data = new PrivateData; d_series = new QwtPoint3DSeriesData(); setZ( 20.0 ); } //! \return QwtPlotItem::Rtti_PlotSpectroCurve int QwtPlotSpectroCurve::rtti() const { return QwtPlotItem::Rtti_PlotSpectroCurve; } /*! Specify an attribute how to draw the curve \param attribute Paint attribute \param on On/Off /sa PaintAttribute, testPaintAttribute() */ void QwtPlotSpectroCurve::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; } /*! \brief Return the current paint attributes \sa PaintAttribute, setPaintAttribute() */ bool QwtPlotSpectroCurve::testPaintAttribute( PaintAttribute attribute ) const { return ( d_data->paintAttributes & attribute ); } /*! Initialize data with an array of samples. \param samples Vector of points */ void QwtPlotSpectroCurve::setSamples( const QVector &samples ) { delete d_series; d_series = new QwtPoint3DSeriesData( samples ); itemChanged(); } /*! Change the color map Often it is useful to display the mapping between intensities and colors as an additional plot axis, showing a color bar. \param colorMap Color Map \sa colorMap(), setColorRange(), QwtColorMap::color(), QwtScaleWidget::setColorBarEnabled(), QwtScaleWidget::setColorMap() */ void QwtPlotSpectroCurve::setColorMap( QwtColorMap *colorMap ) { if ( colorMap != d_data->colorMap ) { delete d_data->colorMap; d_data->colorMap = colorMap; } itemChanged(); } /*! \return Color Map used for mapping the intensity values to colors \sa setColorMap(), setColorRange(), QwtColorMap::color() */ const QwtColorMap *QwtPlotSpectroCurve::colorMap() const { return d_data->colorMap; } /*! Set the value interval, that corresponds to the color map \param interval interval.minValue() corresponds to 0.0, interval.maxValue() to 1.0 on the color map. \sa colorRange(), setColorMap(), QwtColorMap::color() */ void QwtPlotSpectroCurve::setColorRange( const QwtInterval &interval ) { if ( interval != d_data->colorRange ) { d_data->colorRange = interval; itemChanged(); } } /*! \return Value interval, that corresponds to the color map \sa setColorRange(), setColorMap(), QwtColorMap::color() */ QwtInterval &QwtPlotSpectroCurve::colorRange() const { return d_data->colorRange; } /*! Assign a pen width \param penWidth New pen width \sa penWidth() */ void QwtPlotSpectroCurve::setPenWidth(double penWidth) { if ( penWidth < 0.0 ) penWidth = 0.0; if ( d_data->penWidth != penWidth ) { d_data->penWidth = penWidth; itemChanged(); } } /*! \return Pen width used to draw a dot \sa setPenWidth() */ double QwtPlotSpectroCurve::penWidth() const { return d_data->penWidth; } /*! Draw a subset of the points \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the series will be painted to its last sample. \sa drawDots() */ void QwtPlotSpectroCurve::drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { if ( !painter || dataSize() <= 0 ) return; if ( to < 0 ) to = dataSize() - 1; if ( from < 0 ) from = 0; if ( from > to ) return; drawDots( painter, xMap, yMap, canvasRect, from, to ); } /*! Draw a subset of the points \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the series will be painted to its last sample. \sa drawSeries() */ void QwtPlotSpectroCurve::drawDots( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { if ( !d_data->colorRange.isValid() ) return; const bool doAlign = QwtPainter::roundingAlignment( painter ); const QwtColorMap::Format format = d_data->colorMap->format(); if ( format == QwtColorMap::Indexed ) d_data->colorTable = d_data->colorMap->colorTable( d_data->colorRange ); for ( int i = from; i <= to; i++ ) { const QwtPoint3D sample = d_series->sample( i ); double xi = xMap.transform( sample.x() ); double yi = yMap.transform( sample.y() ); if ( doAlign ) { xi = qRound( xi ); yi = qRound( yi ); } if ( d_data->paintAttributes & QwtPlotSpectroCurve::ClipPoints ) { if ( !canvasRect.contains( xi, yi ) ) continue; } if ( format == QwtColorMap::RGB ) { const QRgb rgb = d_data->colorMap->rgb( d_data->colorRange, sample.z() ); painter->setPen( QPen( QColor( rgb ), d_data->penWidth ) ); } else { const unsigned char index = d_data->colorMap->colorIndex( d_data->colorRange, sample.z() ); painter->setPen( QPen( QColor( d_data->colorTable[index] ), d_data->penWidth ) ); } QwtPainter::drawPoint( painter, QPointF( xi, yi ) ); } d_data->colorTable.clear(); } pcp-gui-1.5.11/src/libqwt/qwt_plot_spectrogram.cpp0000644000000000000000000004173712176111212017113 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_spectrogram.h" #include "qwt_painter.h" #include "qwt_interval.h" #include "qwt_scale_map.h" #include "qwt_color_map.h" #include #include #include #include #include #if QT_VERSION >= 0x040400 #include #include #include #endif class QwtPlotSpectrogram::PrivateData { public: PrivateData(): data( NULL ), renderThreadCount( 1 ) { colorMap = new QwtLinearColorMap(); displayMode = ImageMode; conrecFlags = QwtRasterData::IgnoreAllVerticesOnLevel; conrecFlags |= QwtRasterData::IgnoreOutOfRange; } ~PrivateData() { delete data; delete colorMap; } QwtRasterData *data; QwtColorMap *colorMap; DisplayModes displayMode; uint renderThreadCount; QList contourLevels; QPen defaultContourPen; QwtRasterData::ConrecFlags conrecFlags; }; /*! Sets the following item attributes: - QwtPlotItem::AutoScale: true - QwtPlotItem::Legend: false The z value is initialized by 8.0. \param title Title \sa QwtPlotItem::setItemAttribute(), QwtPlotItem::setZ() */ QwtPlotSpectrogram::QwtPlotSpectrogram( const QString &title ): QwtPlotRasterItem( title ) { d_data = new PrivateData(); setItemAttribute( QwtPlotItem::AutoScale, true ); setItemAttribute( QwtPlotItem::Legend, false ); setZ( 8.0 ); } //! Destructor QwtPlotSpectrogram::~QwtPlotSpectrogram() { delete d_data; } //! \return QwtPlotItem::Rtti_PlotSpectrogram int QwtPlotSpectrogram::rtti() const { return QwtPlotItem::Rtti_PlotSpectrogram; } /*! The display mode controls how the raster data will be represented. \param mode Display mode \param on On/Off The default setting enables ImageMode. \sa DisplayMode, displayMode() */ void QwtPlotSpectrogram::setDisplayMode( DisplayMode mode, bool on ) { if ( on != bool( mode & d_data->displayMode ) ) { if ( on ) d_data->displayMode |= mode; else d_data->displayMode &= ~mode; } itemChanged(); } /*! The display mode controls how the raster data will be represented. \param mode Display mode \return true if mode is enabled */ bool QwtPlotSpectrogram::testDisplayMode( DisplayMode mode ) const { return ( d_data->displayMode & mode ); } /*! Rendering an image from the raster data can often be done parallel on a multicore system. \param numThreads Number of threads to be used for rendering. If numThreads is set to 0, the system specific ideal thread count is used. The default thread count is 1 ( = no additional threads ) \warning Rendering in multiple threads is only supported for Qt >= 4.4 \sa renderThreadCount(), renderImage(), renderTile() */ void QwtPlotSpectrogram::setRenderThreadCount( uint numThreads ) { d_data->renderThreadCount = numThreads; } /*! \return Number of threads to be used for rendering. If numThreads is set to 0, the system specific ideal thread count is used. \warning Rendering in multiple threads is only supported for Qt >= 4.4 \sa setRenderThreadCount(), renderImage(), renderTile() */ uint QwtPlotSpectrogram::renderThreadCount() const { return d_data->renderThreadCount; } /*! Change the color map Often it is useful to display the mapping between intensities and colors as an additional plot axis, showing a color bar. \param colorMap Color Map \sa colorMap(), QwtScaleWidget::setColorBarEnabled(), QwtScaleWidget::setColorMap() */ void QwtPlotSpectrogram::setColorMap( QwtColorMap *colorMap ) { if ( d_data->colorMap != colorMap ) { delete d_data->colorMap; d_data->colorMap = colorMap; } invalidateCache(); itemChanged(); } /*! \return Color Map used for mapping the intensity values to colors \sa setColorMap() */ const QwtColorMap *QwtPlotSpectrogram::colorMap() const { return d_data->colorMap; } /*! \brief Set the default pen for the contour lines If the spectrogram has a valid default contour pen a contour line is painted using the default contour pen. Otherwise (pen.style() == Qt::NoPen) the pen is calculated for each contour level using contourPen(). \sa defaultContourPen(), contourPen() */ void QwtPlotSpectrogram::setDefaultContourPen( const QPen &pen ) { if ( pen != d_data->defaultContourPen ) { d_data->defaultContourPen = pen; itemChanged(); } } /*! \return Default contour pen \sa setDefaultContourPen() */ QPen QwtPlotSpectrogram::defaultContourPen() const { return d_data->defaultContourPen; } /*! \brief Calculate the pen for a contour line The color of the pen is the color for level calculated by the color map \param level Contour level \return Pen for the contour line \note contourPen is only used if defaultContourPen().style() == Qt::NoPen \sa setDefaultContourPen(), setColorMap(), setContourLevels() */ QPen QwtPlotSpectrogram::contourPen( double level ) const { if ( d_data->data == NULL || d_data->colorMap == NULL ) return QPen(); const QwtInterval intensityRange = d_data->data->interval(Qt::ZAxis); const QColor c( d_data->colorMap->rgb( intensityRange, level ) ); return QPen( c ); } /*! Modify an attribute of the CONREC algorithm, used to calculate the contour lines. \param flag CONREC flag \param on On/Off \sa testConrecFlag(), renderContourLines(), QwtRasterData::contourLines() */ void QwtPlotSpectrogram::setConrecFlag( QwtRasterData::ConrecFlag flag, bool on ) { if ( bool( d_data->conrecFlags & flag ) == on ) return; if ( on ) d_data->conrecFlags |= flag; else d_data->conrecFlags &= ~flag; itemChanged(); } /*! Test an attribute of the CONREC algorithm, used to calculate the contour lines. \param flag CONREC flag \return true, is enabled \sa setConrecClag(), renderContourLines(), QwtRasterData::contourLines() */ bool QwtPlotSpectrogram::testConrecFlag( QwtRasterData::ConrecFlag flag ) const { return d_data->conrecFlags & flag; } /*! Set the levels of the contour lines \param levels Values of the contour levels \sa contourLevels(), renderContourLines(), QwtRasterData::contourLines() \note contourLevels returns the same levels but sorted. */ void QwtPlotSpectrogram::setContourLevels( const QList &levels ) { d_data->contourLevels = levels; qSort( d_data->contourLevels ); itemChanged(); } /*! \brief Return the levels of the contour lines. The levels are sorted in increasing order. \sa contourLevels(), renderContourLines(), QwtRasterData::contourLines() */ QList QwtPlotSpectrogram::contourLevels() const { return d_data->contourLevels; } /*! Set the data to be displayed \param data Spectrogram Data \sa data() */ void QwtPlotSpectrogram::setData( QwtRasterData *data ) { if ( data != d_data->data ) { delete d_data->data; d_data->data = data; invalidateCache(); itemChanged(); } } /*! \return Spectrogram data \sa setData() */ const QwtRasterData *QwtPlotSpectrogram::data() const { return d_data->data; } /*! \return Spectrogram data \sa setData() */ QwtRasterData *QwtPlotSpectrogram::data() { return d_data->data; } /*! \return Bounding interval for an axis The default implementation returns the interval of the associated raster data object. \param axis X, Y, or Z axis \sa QwtRasterData::interval() */ QwtInterval QwtPlotSpectrogram::interval(Qt::Axis axis) const { if ( d_data->data == NULL ) return QwtInterval(); return d_data->data->interval( axis ); } /*! \brief Pixel hint The geometry of a pixel is used to calculated the resolution and alignment of the rendered image. The default implementation returns data()->pixelHint( rect ); \param area In most implementations the resolution of the data doesn't depend on the requested area. \return Bounding rectangle of a pixel \sa QwtPlotRasterItem::pixelHint(), QwtRasterData::pixelHint(), render(), renderImage() */ QRectF QwtPlotSpectrogram::pixelHint( const QRectF &area ) const { if ( d_data->data == NULL ) return QRectF(); return d_data->data->pixelHint( area ); } /*! \brief Render an image from data and color map. For each pixel of rect the value is mapped into a color. \param xMap X-Scale Map \param yMap Y-Scale Map \param area Requested area for the image in scale coordinates \param imageSize Size of the requested image \return A QImage::Format_Indexed8 or QImage::Format_ARGB32 depending on the color map. \sa QwtRasterData::value(), QwtColorMap::rgb(), QwtColorMap::colorIndex() */ QImage QwtPlotSpectrogram::renderImage( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &area, const QSize &imageSize ) const { if ( imageSize.isEmpty() || d_data->data == NULL || d_data->colorMap == NULL ) { return QImage(); } const QwtInterval intensityRange = d_data->data->interval( Qt::ZAxis ); if ( !intensityRange.isValid() ) return QImage(); QImage::Format format = ( d_data->colorMap->format() == QwtColorMap::RGB ) ? QImage::Format_ARGB32 : QImage::Format_Indexed8; QImage image( imageSize, format ); if ( d_data->colorMap->format() == QwtColorMap::Indexed ) image.setColorTable( d_data->colorMap->colorTable( intensityRange ) ); d_data->data->initRaster( area, image.size() ); #if QT_VERSION >= 0x040400 && !defined(QT_NO_QFUTURE) uint numThreads = d_data->renderThreadCount; if ( numThreads <= 0 ) numThreads = QThread::idealThreadCount(); if ( numThreads <= 0 ) numThreads = 1; const int numRows = imageSize.height() / numThreads; QList< QFuture > futures; for ( uint i = 0; i < numThreads; i++ ) { QRect tile( 0, i * numRows, image.width(), numRows ); if ( i == numThreads - 1 ) { tile.setHeight( image.height() - i * numRows ); renderTile( xMap, yMap, tile, &image ); } else { futures += QtConcurrent::run( this, &QwtPlotSpectrogram::renderTile, xMap, yMap, tile, &image ); } } for ( int i = 0; i < futures.size(); i++ ) futures[i].waitForFinished(); #else // QT_VERSION < 0x040400 const QRect tile( 0, 0, image.width(), image.height() ); renderTile( xMap, yMap, tile, &image ); #endif d_data->data->discardRaster(); return image; } /*! \brief Render a tile of an image. Rendering in tiles can be used to composite an image in parallel threads. \param xMap X-Scale Map \param yMap Y-Scale Map \param tile Geometry of the tile in image coordinates \param image Image to be rendered */ void QwtPlotSpectrogram::renderTile( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRect &tile, QImage *image ) const { const QwtInterval range = d_data->data->interval( Qt::ZAxis ); if ( !range.isValid() ) return; if ( d_data->colorMap->format() == QwtColorMap::RGB ) { for ( int y = tile.top(); y <= tile.bottom(); y++ ) { const double ty = yMap.invTransform( y ); QRgb *line = ( QRgb * )image->scanLine( y ); line += tile.left(); for ( int x = tile.left(); x <= tile.right(); x++ ) { const double tx = xMap.invTransform( x ); *line++ = d_data->colorMap->rgb( range, d_data->data->value( tx, ty ) ); } } } else if ( d_data->colorMap->format() == QwtColorMap::Indexed ) { for ( int y = tile.top(); y <= tile.bottom(); y++ ) { const double ty = yMap.invTransform( y ); unsigned char *line = image->scanLine( y ); line += tile.left(); for ( int x = tile.left(); x <= tile.right(); x++ ) { const double tx = xMap.invTransform( x ); *line++ = d_data->colorMap->colorIndex( range, d_data->data->value( tx, ty ) ); } } } } /*! \brief Return the raster to be used by the CONREC contour algorithm. A larger size will improve the precisision of the CONREC algorithm, but will slow down the time that is needed to calculate the lines. The default implementation returns rect.size() / 2 bounded to the resolution depending on pixelSize(). \param area Rect, where to calculate the contour lines \param rect Rect in pixel coordinates, where to paint the contour lines \return Raster to be used by the CONREC contour algorithm. \note The size will be bounded to rect.size(). \sa drawContourLines(), QwtRasterData::contourLines() */ QSize QwtPlotSpectrogram::contourRasterSize( const QRectF &area, const QRect &rect ) const { QSize raster = rect.size() / 2; const QRectF pixelRect = pixelHint( area ); if ( !pixelRect.isEmpty() ) { const QSize res( qCeil( rect.width() / pixelRect.width() ), qCeil( rect.height() / pixelRect.height() ) ); raster = raster.boundedTo( res ); } return raster; } /*! Calculate contour lines \param rect Rectangle, where to calculate the contour lines \param raster Raster, used by the CONREC algorithm \sa contourLevels(), setConrecFlag(), QwtRasterData::contourLines() */ QwtRasterData::ContourLines QwtPlotSpectrogram::renderContourLines( const QRectF &rect, const QSize &raster ) const { if ( d_data->data == NULL ) return QwtRasterData::ContourLines(); return d_data->data->contourLines( rect, raster, d_data->contourLevels, d_data->conrecFlags ); } /*! Paint the contour lines \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param contourLines Contour lines \sa renderContourLines(), defaultContourPen(), contourPen() */ void QwtPlotSpectrogram::drawContourLines( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtRasterData::ContourLines &contourLines ) const { if ( d_data->data == NULL ) return; const int numLevels = d_data->contourLevels.size(); for ( int l = 0; l < numLevels; l++ ) { const double level = d_data->contourLevels[l]; QPen pen = defaultContourPen(); if ( pen.style() == Qt::NoPen ) pen = contourPen( level ); if ( pen.style() == Qt::NoPen ) continue; painter->setPen( pen ); const QPolygonF &lines = contourLines[level]; for ( int i = 0; i < lines.size(); i += 2 ) { const QPointF p1( xMap.transform( lines[i].x() ), yMap.transform( lines[i].y() ) ); const QPointF p2( xMap.transform( lines[i+1].x() ), yMap.transform( lines[i+1].y() ) ); QwtPainter::drawLine( painter, p1, p2 ); } } } /*! \brief Draw the spectrogram \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas in painter coordinates \sa setDisplayMode(), renderImage(), QwtPlotRasterItem::draw(), drawContourLines() */ void QwtPlotSpectrogram::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { if ( d_data->displayMode & ImageMode ) QwtPlotRasterItem::draw( painter, xMap, yMap, canvasRect ); if ( d_data->displayMode & ContourMode ) { // Add some pixels at the borders const int margin = 2; QRectF rasterRect( canvasRect.x() - margin, canvasRect.y() - margin, canvasRect.width() + 2 * margin, canvasRect.height() + 2 * margin ); QRectF area = QwtScaleMap::invTransform( xMap, yMap, rasterRect ); const QRectF br = boundingRect(); if ( br.isValid() ) { area &= br; if ( area.isEmpty() ) return; rasterRect = QwtScaleMap::transform( xMap, yMap, area ); } QSize raster = contourRasterSize( area, rasterRect.toRect() ); raster = raster.boundedTo( rasterRect.toRect().size() ); if ( raster.isValid() ) { const QwtRasterData::ContourLines lines = renderContourLines( area, raster ); drawContourLines( painter, xMap, yMap, lines ); } } } pcp-gui-1.5.11/src/libqwt/qwt_plot_svgitem.cpp0000644000000000000000000001151512176111212016232 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_svgitem.h" #include "qwt_scale_map.h" #include "qwt_legend.h" #include "qwt_legend_item.h" #include "qwt_painter.h" #include #include class QwtPlotSvgItem::PrivateData { public: PrivateData() { } QRectF boundingRect; QSvgRenderer renderer; }; /*! \brief Constructor Sets the following item attributes: - QwtPlotItem::AutoScale: true - QwtPlotItem::Legend: false \param title Title */ QwtPlotSvgItem::QwtPlotSvgItem( const QString& title ): QwtPlotItem( QwtText( title ) ) { init(); } /*! \brief Constructor Sets the following item attributes: - QwtPlotItem::AutoScale: true - QwtPlotItem::Legend: false \param title Title */ QwtPlotSvgItem::QwtPlotSvgItem( const QwtText& title ): QwtPlotItem( title ) { init(); } //! Destructor QwtPlotSvgItem::~QwtPlotSvgItem() { delete d_data; } void QwtPlotSvgItem::init() { d_data = new PrivateData(); setItemAttribute( QwtPlotItem::AutoScale, true ); setItemAttribute( QwtPlotItem::Legend, false ); setZ( 8.0 ); } //! \return QwtPlotItem::Rtti_PlotSVG int QwtPlotSvgItem::rtti() const { return QwtPlotItem::Rtti_PlotSVG; } /*! Load a SVG file \param rect Bounding rectangle \param fileName SVG file name \return true, if the SVG file could be loaded */ bool QwtPlotSvgItem::loadFile( const QRectF &rect, const QString &fileName ) { d_data->boundingRect = rect; const bool ok = d_data->renderer.load( fileName ); itemChanged(); return ok; } /*! Load SVG data \param rect Bounding rectangle \param data in SVG format \return true, if the SVG data could be loaded */ bool QwtPlotSvgItem::loadData( const QRectF &rect, const QByteArray &data ) { d_data->boundingRect = rect; const bool ok = d_data->renderer.load( data ); itemChanged(); return ok; } //! Bounding rect of the item QRectF QwtPlotSvgItem::boundingRect() const { return d_data->boundingRect; } //! \return Renderer used to render the SVG data const QSvgRenderer &QwtPlotSvgItem::renderer() const { return d_data->renderer; } //! \return Renderer used to render the SVG data QSvgRenderer &QwtPlotSvgItem::renderer() { return d_data->renderer; } /*! Draw the SVG item \param painter Painter \param xMap X-Scale Map \param yMap Y-Scale Map \param canvasRect Contents rect of the plot canvas */ void QwtPlotSvgItem::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { const QRectF cRect = QwtScaleMap::invTransform( xMap, yMap, canvasRect.toRect() ); const QRectF bRect = boundingRect(); if ( bRect.isValid() && cRect.isValid() ) { QRectF rect = bRect; if ( bRect.contains( cRect ) ) rect = cRect; const QRectF r = QwtScaleMap::transform( xMap, yMap, rect ); render( painter, viewBox( rect ), r ); } } /*! Render the SVG data \param painter Painter \param viewBox View Box, see QSvgRenderer::viewBox \param rect Traget rectangle on the paint device */ void QwtPlotSvgItem::render( QPainter *painter, const QRectF &viewBox, const QRectF &rect ) const { if ( !viewBox.isValid() ) return; QRectF r = rect; if ( QwtPainter::roundingAlignment( painter ) ) { r.setLeft ( qRound( r.left() ) ); r.setRight ( qRound( r.right() ) ); r.setTop ( qRound( r.top() ) ); r.setBottom ( qRound( r.bottom() ) ); } d_data->renderer.setViewBox( viewBox ); d_data->renderer.render( painter, r ); } /*! Calculate the viewBox from an rect and boundingRect(). \param rect Rectangle in scale coordinates \return viewBox View Box, see QSvgRenderer::viewBox */ QRectF QwtPlotSvgItem::viewBox( const QRectF &rect ) const { const QSize sz = d_data->renderer.defaultSize(); const QRectF br = boundingRect(); if ( !rect.isValid() || !br.isValid() || sz.isNull() ) return QRectF(); QwtScaleMap xMap; xMap.setScaleInterval( br.left(), br.right() ); xMap.setPaintInterval( 0, sz.width() ); QwtScaleMap yMap; yMap.setScaleInterval( br.top(), br.bottom() ); yMap.setPaintInterval( sz.height(), 0 ); const double x1 = xMap.transform( rect.left() ); const double x2 = xMap.transform( rect.right() ); const double y1 = yMap.transform( rect.bottom() ); const double y2 = yMap.transform( rect.top() ); return QRectF( x1, y1, x2 - x1, y2 - y1 ); } pcp-gui-1.5.11/src/libqwt/qwt_plot_xml.cpp0000644000000000000000000000211312176111212015346 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot.h" /*! This method is intended for manipulating the plot widget from a specific editor in the Qwt designer plugin. \warning The plot editor has never been implemented. */ void QwtPlot::applyProperties( const QString & /* xmlDocument */ ) { #if 0 // Temporary dummy code, for designer tests setTitle( xmlDocument ); replot(); #endif } /*! This method is intended for manipulating the plot widget from a specific editor in the Qwt designer plugin. \warning The plot editor has never been implemented. */ QString QwtPlot::grabProperties() const { #if 0 // Temporary dummy code, for designer tests return title().text(); #else return QString::null; #endif } pcp-gui-1.5.11/src/libqwt/qwt_plot_zoomer.cpp0000644000000000000000000003536712176111212016102 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_zoomer.h" #include "qwt_plot.h" #include "qwt_plot_canvas.h" #include "qwt_scale_div.h" #include "qwt_picker_machine.h" #include class QwtPlotZoomer::PrivateData { public: uint zoomRectIndex; QStack zoomStack; int maxStackDepth; }; /*! \brief Create a zoomer for a plot canvas. The zoomer is set to those x- and y-axis of the parent plot of the canvas that are enabled. If both or no x-axis are enabled, the picker is set to QwtPlot::xBottom. If both or no y-axis are enabled, it is set to QwtPlot::yLeft. The zoomer is initialized with a QwtPickerDragRectMachine, the tracker mode is set to QwtPicker::ActiveOnly and the rubberband is set to QwtPicker::RectRubberBand \param canvas Plot canvas to observe, also the parent object \param doReplot Call replot for the attached plot before initializing the zoomer with its scales. This might be necessary, when the plot is in a state with pending scale changes. \sa QwtPlot::autoReplot(), QwtPlot::replot(), setZoomBase() */ QwtPlotZoomer::QwtPlotZoomer( QwtPlotCanvas *canvas, bool doReplot ): QwtPlotPicker( canvas ) { if ( canvas ) init( doReplot ); } /*! \brief Create a zoomer for a plot canvas. The zoomer is initialized with a QwtPickerDragRectMachine, the tracker mode is set to QwtPicker::ActiveOnly and the rubberband is set to QwtPicker;;RectRubberBand \param xAxis X axis of the zoomer \param yAxis Y axis of the zoomer \param canvas Plot canvas to observe, also the parent object \param doReplot Call replot for the attached plot before initializing the zoomer with its scales. This might be necessary, when the plot is in a state with pending scale changes. \sa QwtPlot::autoReplot(), QwtPlot::replot(), setZoomBase() */ QwtPlotZoomer::QwtPlotZoomer( int xAxis, int yAxis, QwtPlotCanvas *canvas, bool doReplot ): QwtPlotPicker( xAxis, yAxis, canvas ) { if ( canvas ) init( doReplot ); } //! Init the zoomer, used by the constructors void QwtPlotZoomer::init( bool doReplot ) { d_data = new PrivateData; d_data->maxStackDepth = -1; setTrackerMode( ActiveOnly ); setRubberBand( RectRubberBand ); setStateMachine( new QwtPickerDragRectMachine() ); if ( doReplot && plot() ) plot()->replot(); setZoomBase( scaleRect() ); } QwtPlotZoomer::~QwtPlotZoomer() { delete d_data; } /*! \brief Limit the number of recursive zoom operations to depth. A value of -1 set the depth to unlimited, 0 disables zooming. If the current zoom rectangle is below depth, the plot is unzoomed. \param depth Maximum for the stack depth \sa maxStackDepth() \note depth doesn't include the zoom base, so zoomStack().count() might be maxStackDepth() + 1. */ void QwtPlotZoomer::setMaxStackDepth( int depth ) { d_data->maxStackDepth = depth; if ( depth >= 0 ) { // unzoom if the current depth is below d_data->maxStackDepth const int zoomOut = int( d_data->zoomStack.count() ) - 1 - depth; // -1 for the zoom base if ( zoomOut > 0 ) { zoom( -zoomOut ); for ( int i = int( d_data->zoomStack.count() ) - 1; i > int( d_data->zoomRectIndex ); i-- ) { ( void )d_data->zoomStack.pop(); // remove trailing rects } } } } /*! \return Maximal depth of the zoom stack. \sa setMaxStackDepth() */ int QwtPlotZoomer::maxStackDepth() const { return d_data->maxStackDepth; } /*! Return the zoom stack. zoomStack()[0] is the zoom base, zoomStack()[1] the first zoomed rectangle. \sa setZoomStack(), zoomRectIndex() */ const QStack &QwtPlotZoomer::zoomStack() const { return d_data->zoomStack; } /*! \return Initial rectangle of the zoomer \sa setZoomBase(), zoomRect() */ QRectF QwtPlotZoomer::zoomBase() const { return d_data->zoomStack[0]; } /*! Reinitialized the zoom stack with scaleRect() as base. \param doReplot Call replot for the attached plot before initializing the zoomer with its scales. This might be necessary, when the plot is in a state with pending scale changes. \sa zoomBase(), scaleRect() QwtPlot::autoReplot(), QwtPlot::replot(). */ void QwtPlotZoomer::setZoomBase( bool doReplot ) { QwtPlot *plt = plot(); if ( plt == NULL ) return; if ( doReplot ) plt->replot(); d_data->zoomStack.clear(); d_data->zoomStack.push( scaleRect() ); d_data->zoomRectIndex = 0; rescale(); } /*! \brief Set the initial size of the zoomer. base is united with the current scaleRect() and the zoom stack is reinitalized with it as zoom base. plot is zoomed to scaleRect(). \param base Zoom base \sa zoomBase(), scaleRect() */ void QwtPlotZoomer::setZoomBase( const QRectF &base ) { const QwtPlot *plt = plot(); if ( !plt ) return; const QRectF sRect = scaleRect(); const QRectF bRect = base | sRect; d_data->zoomStack.clear(); d_data->zoomStack.push( bRect ); d_data->zoomRectIndex = 0; if ( base != sRect ) { d_data->zoomStack.push( sRect ); d_data->zoomRectIndex++; } rescale(); } /*! Rectangle at the current position on the zoom stack. \sa zoomRectIndex(), scaleRect(). */ QRectF QwtPlotZoomer::zoomRect() const { return d_data->zoomStack[d_data->zoomRectIndex]; } /*! \return Index of current position of zoom stack. */ uint QwtPlotZoomer::zoomRectIndex() const { return d_data->zoomRectIndex; } /*! \brief Zoom in Clears all rectangles above the current position of the zoom stack and pushs the normalized rect on it. \note If the maximal stack depth is reached, zoom is ignored. \note The zoomed signal is emitted. */ void QwtPlotZoomer::zoom( const QRectF &rect ) { if ( d_data->maxStackDepth >= 0 && int( d_data->zoomRectIndex ) >= d_data->maxStackDepth ) { return; } const QRectF zoomRect = rect.normalized(); if ( zoomRect != d_data->zoomStack[d_data->zoomRectIndex] ) { for ( uint i = int( d_data->zoomStack.count() ) - 1; i > d_data->zoomRectIndex; i-- ) { ( void )d_data->zoomStack.pop(); } d_data->zoomStack.push( zoomRect ); d_data->zoomRectIndex++; rescale(); Q_EMIT zoomed( zoomRect ); } } /*! \brief Zoom in or out Activate a rectangle on the zoom stack with an offset relative to the current position. Negative values of offest will zoom out, positive zoom in. A value of 0 zooms out to the zoom base. \param offset Offset relative to the current position of the zoom stack. \note The zoomed signal is emitted. \sa zoomRectIndex() */ void QwtPlotZoomer::zoom( int offset ) { if ( offset == 0 ) d_data->zoomRectIndex = 0; else { int newIndex = d_data->zoomRectIndex + offset; newIndex = qMax( 0, newIndex ); newIndex = qMin( int( d_data->zoomStack.count() ) - 1, newIndex ); d_data->zoomRectIndex = uint( newIndex ); } rescale(); Q_EMIT zoomed( zoomRect() ); } /*! \brief Assign a zoom stack In combination with other types of navigation it might be useful to modify to manipulate the complete zoom stack. \param zoomStack New zoom stack \param zoomRectIndex Index of the current position of zoom stack. In case of -1 the current position is at the top of the stack. \note The zoomed signal might be emitted. \sa zoomStack(), zoomRectIndex() */ void QwtPlotZoomer::setZoomStack( const QStack &zoomStack, int zoomRectIndex ) { if ( zoomStack.isEmpty() ) return; if ( d_data->maxStackDepth >= 0 && int( zoomStack.count() ) > d_data->maxStackDepth ) { return; } if ( zoomRectIndex < 0 || zoomRectIndex > int( zoomStack.count() ) ) zoomRectIndex = zoomStack.count() - 1; const bool doRescale = zoomStack[zoomRectIndex] != zoomRect(); d_data->zoomStack = zoomStack; d_data->zoomRectIndex = uint( zoomRectIndex ); if ( doRescale ) { rescale(); Q_EMIT zoomed( zoomRect() ); } } /*! Adjust the observed plot to zoomRect() \note Initiates QwtPlot::replot */ void QwtPlotZoomer::rescale() { QwtPlot *plt = plot(); if ( !plt ) return; const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex]; if ( rect != scaleRect() ) { const bool doReplot = plt->autoReplot(); plt->setAutoReplot( false ); double x1 = rect.left(); double x2 = rect.right(); if ( plt->axisScaleDiv( xAxis() )->lowerBound() > plt->axisScaleDiv( xAxis() )->upperBound() ) { qSwap( x1, x2 ); } plt->setAxisScale( xAxis(), x1, x2 ); double y1 = rect.top(); double y2 = rect.bottom(); if ( plt->axisScaleDiv( yAxis() )->lowerBound() > plt->axisScaleDiv( yAxis() )->upperBound() ) { qSwap( y1, y2 ); } plt->setAxisScale( yAxis(), y1, y2 ); plt->setAutoReplot( doReplot ); plt->replot(); } } /*! Reinitialize the axes, and set the zoom base to their scales. \param xAxis X axis \param yAxis Y axis */ void QwtPlotZoomer::setAxis( int xAxis, int yAxis ) { if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() ) { QwtPlotPicker::setAxis( xAxis, yAxis ); setZoomBase( scaleRect() ); } } /*! Qt::MidButton zooms out one position on the zoom stack, Qt::RightButton to the zoom base. Changes the current position on the stack, but doesn't pop any rectangle. \note The mouse events can be changed, using QwtEventPattern::setMousePattern: 2, 1 */ void QwtPlotZoomer::widgetMouseReleaseEvent( QMouseEvent *me ) { if ( mouseMatch( MouseSelect2, me ) ) zoom( 0 ); else if ( mouseMatch( MouseSelect3, me ) ) zoom( -1 ); else if ( mouseMatch( MouseSelect6, me ) ) zoom( +1 ); else QwtPlotPicker::widgetMouseReleaseEvent( me ); } /*! Qt::Key_Plus zooms in, Qt::Key_Minus zooms out one position on the zoom stack, Qt::Key_Escape zooms out to the zoom base. Changes the current position on the stack, but doesn't pop any rectangle. \note The keys codes can be changed, using QwtEventPattern::setKeyPattern: 3, 4, 5 */ void QwtPlotZoomer::widgetKeyPressEvent( QKeyEvent *ke ) { if ( !isActive() ) { if ( keyMatch( KeyUndo, ke ) ) zoom( -1 ); else if ( keyMatch( KeyRedo, ke ) ) zoom( +1 ); else if ( keyMatch( KeyHome, ke ) ) zoom( 0 ); } QwtPlotPicker::widgetKeyPressEvent( ke ); } /*! Move the current zoom rectangle. \param dx X offset \param dy Y offset \note The changed rectangle is limited by the zoom base */ void QwtPlotZoomer::moveBy( double dx, double dy ) { const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex]; moveTo( QPointF( rect.left() + dx, rect.top() + dy ) ); } /*! Move the the current zoom rectangle. \param pos New position \sa QRectF::moveTo() \note The changed rectangle is limited by the zoom base */ void QwtPlotZoomer::moveTo( const QPointF &pos ) { double x = pos.x(); double y = pos.y(); if ( x < zoomBase().left() ) x = zoomBase().left(); if ( x > zoomBase().right() - zoomRect().width() ) x = zoomBase().right() - zoomRect().width(); if ( y < zoomBase().top() ) y = zoomBase().top(); if ( y > zoomBase().bottom() - zoomRect().height() ) y = zoomBase().bottom() - zoomRect().height(); if ( x != zoomRect().left() || y != zoomRect().top() ) { d_data->zoomStack[d_data->zoomRectIndex].moveTo( x, y ); rescale(); } } /*! \brief Check and correct a selected rectangle Reject rectangles with a hight or width < 2, otherwise expand the selected rectangle to a minimum size of 11x11 and accept it. \return true If rect is accepted, or has been changed to a accepted rectangle. */ bool QwtPlotZoomer::accept( QPolygon &pa ) const { if ( pa.count() < 2 ) return false; QRect rect = QRect( pa[0], pa[int( pa.count() ) - 1] ); rect = rect.normalized(); const int minSize = 2; if ( rect.width() < minSize && rect.height() < minSize ) return false; const int minZoomSize = 11; const QPoint center = rect.center(); rect.setSize( rect.size().expandedTo( QSize( minZoomSize, minZoomSize ) ) ); rect.moveCenter( center ); pa.resize( 2 ); pa[0] = rect.topLeft(); pa[1] = rect.bottomRight(); return true; } /*! \brief Limit zooming by a minimum rectangle \return zoomBase().width() / 10e4, zoomBase().height() / 10e4 */ QSizeF QwtPlotZoomer::minZoomSize() const { return QSizeF( d_data->zoomStack[0].width() / 10e4, d_data->zoomStack[0].height() / 10e4 ); } /*! Rejects selections, when the stack depth is too deep, or the zoomed rectangle is minZoomSize(). \sa minZoomSize(), maxStackDepth() */ void QwtPlotZoomer::begin() { if ( d_data->maxStackDepth >= 0 ) { if ( d_data->zoomRectIndex >= uint( d_data->maxStackDepth ) ) return; } const QSizeF minSize = minZoomSize(); if ( minSize.isValid() ) { const QSizeF sz = d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999; if ( minSize.width() >= sz.width() && minSize.height() >= sz.height() ) { return; } } QwtPlotPicker::begin(); } /*! Expand the selected rectangle to minZoomSize() and zoom in if accepted. \sa accept(), minZoomSize() */ bool QwtPlotZoomer::end( bool ok ) { ok = QwtPlotPicker::end( ok ); if ( !ok ) return false; QwtPlot *plot = QwtPlotZoomer::plot(); if ( !plot ) return false; const QPolygon &pa = selection(); if ( pa.count() < 2 ) return false; QRect rect = QRect( pa[0], pa[int( pa.count() - 1 )] ); rect = rect.normalized(); QRectF zoomRect = invTransform( rect ).normalized(); const QSizeF minSize = minZoomSize(); if ( minSize.isValid() ) { const QPointF center = zoomRect.center(); zoomRect.setSize( zoomRect.size().expandedTo( minZoomSize() ) ); zoomRect.moveCenter( center ); } zoom( zoomRect ); return true; } pcp-gui-1.5.11/src/libqwt/qwt_point_3d.cpp0000644000000000000000000000120612176111212015231 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_point_3d.h" #ifndef QT_NO_DEBUG_STREAM QDebug operator<<( QDebug debug, const QwtPoint3D &point ) { debug.nospace() << "QwtPoint3D(" << point.x() << "," << point.y() << "," << point.z() << ")"; return debug.space(); } #endif pcp-gui-1.5.11/src/libqwt/qwt_point_polar.cpp0000644000000000000000000000571412176111212016050 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * QwtPolar Widget Library * Copyright (C) 2008 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_point_polar.h" #include "qwt_math.h" #if QT_VERSION < 0x040601 #define qAtan2(y, x) ::atan2(y, x) #endif /*! Convert and assign values from a point in Cartesian coordinates \param p Point in Cartesian coordinates \sa setPoint(), toPoint() */ QwtPointPolar::QwtPointPolar( const QPointF &p ) { d_radius = qSqrt( qwtSqr( p.x() ) + qwtSqr( p.y() ) ); d_azimuth = qAtan2( p.y(), p.x() ); } /*! Convert and assign values from a point in Cartesian coordinates \param p Point in Cartesian coordinates */ void QwtPointPolar::setPoint( const QPointF &p ) { d_radius = qSqrt( qwtSqr( p.x() ) + qwtSqr( p.y() ) ); d_azimuth = qAtan2( p.y(), p.x() ); } /*! Convert and return values in Cartesian coordinates \note Invalid or null points will be returned as QPointF(0.0, 0.0) \sa isValid(), isNull() */ QPointF QwtPointPolar::toPoint() const { if ( d_radius <= 0.0 ) return QPointF( 0.0, 0.0 ); const double x = d_radius * qCos( d_azimuth ); const double y = d_radius * qSin( d_azimuth ); return QPointF( x, y ); } /*! Returns true if point1 is equal to point2; otherwise returns false. Two points are equal to each other if radius and azimuth-coordinates are the same. Points are not equal, when the azimuth differs, but other.azimuth() == azimuth() % (2 * PI). \sa normalized() */ bool QwtPointPolar::operator==( const QwtPointPolar &other ) const { return d_radius == other.d_radius && d_azimuth == other.d_azimuth; } /*! Returns true if point1 is not equal to point2; otherwise returns false. Two points are equal to each other if radius and azimuth-coordinates are the same. Points are not equal, when the azimuth differs, but other.azimuth() == azimuth() % (2 * PI). \sa normalized() */ bool QwtPointPolar::operator!=( const QwtPointPolar &other ) const { return d_radius != other.d_radius || d_azimuth != other.d_azimuth; } /*! Normalize radius and azimuth When the radius is < 0.0 it is set to 0.0. The azimuth is a value >= 0.0 and < 2 * M_PI. */ QwtPointPolar QwtPointPolar::normalized() const { const double radius = qMax( d_radius, 0.0 ); double azimuth = d_azimuth; if ( azimuth < -2.0 * M_PI || azimuth >= 2 * M_PI ) azimuth = ::fmod( d_azimuth, 2 * M_PI ); if ( azimuth < 0.0 ) azimuth += 2 * M_PI; return QwtPointPolar( azimuth, radius ); } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<( QDebug debug, const QwtPointPolar &point ) { debug.nospace() << "QwtPointPolar(" << point.azimuth() << "," << point.radius() << ")"; return debug.space(); } #endif pcp-gui-1.5.11/src/libqwt/qwt_raster_data.cpp0000644000000000000000000002607612176111212016017 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_raster_data.h" #include "qwt_point_3d.h" class QwtRasterData::ContourPlane { public: inline ContourPlane( double z ): d_z( z ) { } inline bool intersect( const QwtPoint3D vertex[3], QPointF line[2], bool ignoreOnPlane ) const; inline double z() const { return d_z; } private: inline int compare( double z ) const; inline QPointF intersection( const QwtPoint3D& p1, const QwtPoint3D &p2 ) const; double d_z; }; inline bool QwtRasterData::ContourPlane::intersect( const QwtPoint3D vertex[3], QPointF line[2], bool ignoreOnPlane ) const { bool found = true; // Are the vertices below (-1), on (0) or above (1) the plan ? const int eq1 = compare( vertex[0].z() ); const int eq2 = compare( vertex[1].z() ); const int eq3 = compare( vertex[2].z() ); /* (a) All the vertices lie below the contour level. (b) Two vertices lie below and one on the contour level. (c) Two vertices lie below and one above the contour level. (d) One vertex lies below and two on the contour level. (e) One vertex lies below, one on and one above the contour level. (f) One vertex lies below and two above the contour level. (g) Three vertices lie on the contour level. (h) Two vertices lie on and one above the contour level. (i) One vertex lies on and two above the contour level. (j) All the vertices lie above the contour level. */ static const int tab[3][3][3] = { // jump table to avoid nested case statements { { 0, 0, 8 }, { 0, 2, 5 }, { 7, 6, 9 } }, { { 0, 3, 4 }, { 1, 10, 1 }, { 4, 3, 0 } }, { { 9, 6, 7 }, { 5, 2, 0 }, { 8, 0, 0 } } }; const int edgeType = tab[eq1+1][eq2+1][eq3+1]; switch ( edgeType ) { case 1: // d(0,0,-1), h(0,0,1) line[0] = vertex[0].toPoint(); line[1] = vertex[1].toPoint(); break; case 2: // d(-1,0,0), h(1,0,0) line[0] = vertex[1].toPoint(); line[1] = vertex[2].toPoint(); break; case 3: // d(0,-1,0), h(0,1,0) line[0] = vertex[2].toPoint(); line[1] = vertex[0].toPoint(); break; case 4: // e(0,-1,1), e(0,1,-1) line[0] = vertex[0].toPoint(); line[1] = intersection( vertex[1], vertex[2] ); break; case 5: // e(-1,0,1), e(1,0,-1) line[0] = vertex[1].toPoint(); line[1] = intersection( vertex[2], vertex[0] ); break; case 6: // e(-1,1,0), e(1,0,-1) line[0] = vertex[2].toPoint(); line[1] = intersection( vertex[0], vertex[1] ); break; case 7: // c(-1,1,-1), f(1,1,-1) line[0] = intersection( vertex[0], vertex[1] ); line[1] = intersection( vertex[1], vertex[2] ); break; case 8: // c(-1,-1,1), f(1,1,-1) line[0] = intersection( vertex[1], vertex[2] ); line[1] = intersection( vertex[2], vertex[0] ); break; case 9: // f(-1,1,1), c(1,-1,-1) line[0] = intersection( vertex[2], vertex[0] ); line[1] = intersection( vertex[0], vertex[1] ); break; case 10: // g(0,0,0) // The CONREC algorithm has no satisfying solution for // what to do, when all vertices are on the plane. if ( ignoreOnPlane ) found = false; else { line[0] = vertex[2].toPoint(); line[1] = vertex[0].toPoint(); } break; default: found = false; } return found; } inline int QwtRasterData::ContourPlane::compare( double z ) const { if ( z > d_z ) return 1; if ( z < d_z ) return -1; return 0; } inline QPointF QwtRasterData::ContourPlane::intersection( const QwtPoint3D& p1, const QwtPoint3D &p2 ) const { const double h1 = p1.z() - d_z; const double h2 = p2.z() - d_z; const double x = ( h2 * p1.x() - h1 * p2.x() ) / ( h2 - h1 ); const double y = ( h2 * p1.y() - h1 * p2.y() ) / ( h2 - h1 ); return QPointF( x, y ); } //! Constructor QwtRasterData::QwtRasterData() { } //! Destructor QwtRasterData::~QwtRasterData() { } /*! Set the bounding interval for the x, y or z coordinates. \param axis Axis \param interval Bounding interval \sa interval() */ void QwtRasterData::setInterval( Qt::Axis axis, const QwtInterval &interval ) { d_intervals[axis] = interval; } /*! \brief Initialize a raster Before the composition of an image QwtPlotSpectrogram calls initRaster, announcing the area and its resolution that will be requested. The default implementation does nothing, but for data sets that are stored in files, it might be good idea to reimplement initRaster, where the data is resampled and loaded into memory. \param area Area of the raster \param raster Number of horizontal and vertical pixels \sa initRaster(), value() */ void QwtRasterData::initRaster( const QRectF &area, const QSize &raster ) { Q_UNUSED( area ); Q_UNUSED( raster ); } /*! \brief Discard a raster After the composition of an image QwtPlotSpectrogram calls discardRaster(). The default implementation does nothing, but if data has been loaded in initRaster(), it could deleted now. \sa initRaster(), value() */ void QwtRasterData::discardRaster() { } /*! \brief Pixel hint pixelHint() returns the geometry of a pixel, that can be used to calculate the resolution and alignment of the plot item, that is representing the data. Width and height of the hint need to be the horizontal and vertical distances between 2 neighboured points. The center of the hint has to be the position of any point ( it doesn't matter which one ). An empty hint indicates, that there are values for any detail level. Limiting the resolution of the image might significantly improve the performance and heavily reduce the amount of memory when rendering a QImage from the raster data. The default implementation returns an empty rectangle recommending to render in target device ( f.e. screen ) resolution. \param area In most implementations the resolution of the data doesn't depend on the requested area. \return Bounding rectangle of a pixel */ QRectF QwtRasterData::pixelHint( const QRectF &area ) const { Q_UNUSED( area ); return QRectF(); } /*! Calculate contour lines An adaption of CONREC, a simple contouring algorithm. http://local.wasp.uwa.edu.au/~pbourke/papers/conrec/ */ QwtRasterData::ContourLines QwtRasterData::contourLines( const QRectF &rect, const QSize &raster, const QList &levels, ConrecFlags flags ) const { ContourLines contourLines; if ( levels.size() == 0 || !rect.isValid() || !raster.isValid() ) return contourLines; const double dx = rect.width() / raster.width(); const double dy = rect.height() / raster.height(); const bool ignoreOnPlane = flags & QwtRasterData::IgnoreAllVerticesOnLevel; const QwtInterval range = interval( Qt::ZAxis ); bool ignoreOutOfRange = false; if ( range.isValid() ) ignoreOutOfRange = flags & IgnoreOutOfRange; QwtRasterData *that = const_cast( this ); that->initRaster( rect, raster ); for ( int y = 0; y < raster.height() - 1; y++ ) { enum Position { Center, TopLeft, TopRight, BottomRight, BottomLeft, NumPositions }; QwtPoint3D xy[NumPositions]; for ( int x = 0; x < raster.width() - 1; x++ ) { const QPointF pos( rect.x() + x * dx, rect.y() + y * dy ); if ( x == 0 ) { xy[TopRight].setX( pos.x() ); xy[TopRight].setY( pos.y() ); xy[TopRight].setZ( value( xy[TopRight].x(), xy[TopRight].y() ) ); xy[BottomRight].setX( pos.x() ); xy[BottomRight].setY( pos.y() + dy ); xy[BottomRight].setZ( value( xy[BottomRight].x(), xy[BottomRight].y() ) ); } xy[TopLeft] = xy[TopRight]; xy[BottomLeft] = xy[BottomRight]; xy[TopRight].setX( pos.x() + dx ); xy[TopRight].setY( pos.y() ); xy[BottomRight].setX( pos.x() + dx ); xy[BottomRight].setY( pos.y() + dy ); xy[TopRight].setZ( value( xy[TopRight].x(), xy[TopRight].y() ) ); xy[BottomRight].setZ( value( xy[BottomRight].x(), xy[BottomRight].y() ) ); double zMin = xy[TopLeft].z(); double zMax = zMin; double zSum = zMin; for ( int i = TopRight; i <= BottomLeft; i++ ) { const double z = xy[i].z(); zSum += z; if ( z < zMin ) zMin = z; if ( z > zMax ) zMax = z; } if ( ignoreOutOfRange ) { if ( !range.contains( zMin ) || !range.contains( zMax ) ) continue; } if ( zMax < levels[0] || zMin > levels[levels.size() - 1] ) { continue; } xy[Center].setX( pos.x() + 0.5 * dx ); xy[Center].setY( pos.y() + 0.5 * dy ); xy[Center].setZ( 0.25 * zSum ); const int numLevels = levels.size(); for ( int l = 0; l < numLevels; l++ ) { const double level = levels[l]; if ( level < zMin || level > zMax ) continue; QPolygonF &lines = contourLines[level]; const ContourPlane plane( level ); QPointF line[2]; QwtPoint3D vertex[3]; for ( int m = TopLeft; m < NumPositions; m++ ) { vertex[0] = xy[m]; vertex[1] = xy[0]; vertex[2] = xy[m != BottomLeft ? m + 1 : TopLeft]; const bool intersects = plane.intersect( vertex, line, ignoreOnPlane ); if ( intersects ) { lines += line[0]; lines += line[1]; } } } } } that->discardRaster(); return contourLines; } pcp-gui-1.5.11/src/libqwt/qwt_round_scale_draw.cpp0000644000000000000000000002011112176111212017021 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_round_scale_draw.h" #include "qwt_painter.h" #include "qwt_scale_div.h" #include "qwt_scale_map.h" #include #include #include #include class QwtRoundScaleDraw::PrivateData { public: PrivateData(): center( 50.0, 50.0 ), radius( 50.0 ), startAngle( -135 * 16 ), endAngle( 135 * 16 ) { } QPointF center; double radius; double startAngle; double endAngle; }; /*! \brief Constructor The range of the scale is initialized to [0, 100], The center is set to (50, 50) with a radius of 50. The angle range is set to [-135, 135]. */ QwtRoundScaleDraw::QwtRoundScaleDraw() { d_data = new QwtRoundScaleDraw::PrivateData; setRadius( 50 ); scaleMap().setPaintInterval( d_data->startAngle, d_data->endAngle ); } //! Destructor QwtRoundScaleDraw::~QwtRoundScaleDraw() { delete d_data; } /*! Change of radius the scale Radius is the radius of the backbone without ticks and labels. \param radius New Radius \sa moveCenter() */ void QwtRoundScaleDraw::setRadius( int radius ) { d_data->radius = radius; } /*! Get the radius Radius is the radius of the backbone without ticks and labels. \sa setRadius(), extent() */ int QwtRoundScaleDraw::radius() const { return qCeil( d_data->radius ); } /*! Move the center of the scale draw, leaving the radius unchanged \param center New center \sa setRadius() */ void QwtRoundScaleDraw::moveCenter( const QPointF ¢er ) { d_data->center = center; } //! Get the center of the scale QPointF QwtRoundScaleDraw::center() const { return d_data->center; } /*! \brief Adjust the baseline circle segment for round scales. The baseline will be drawn from min(angle1,angle2) to max(angle1, angle2). The default setting is [ -135, 135 ]. An angle of 0 degrees corresponds to the 12 o'clock position, and positive angles count in a clockwise direction. \param angle1 \param angle2 boundaries of the angle interval in degrees. \warning
  • The angle range is limited to [-360, 360] degrees. Angles exceeding this range will be clipped.
  • For angles more than 359 degrees above or below min(angle1, angle2), scale marks will not be drawn.
  • If you need a counterclockwise scale, use QwtScaleDiv::setRange
*/ void QwtRoundScaleDraw::setAngleRange( double angle1, double angle2 ) { angle1 = qBound( -360.0, angle1, 360.0 ); angle2 = qBound( -360.0, angle2, 360.0 ); d_data->startAngle = angle1 * 16.0; d_data->endAngle = angle2 * 16.0; if ( d_data->startAngle == d_data->endAngle ) { d_data->startAngle -= 1; d_data->endAngle += 1; } scaleMap().setPaintInterval( d_data->startAngle, d_data->endAngle ); } /*! Draws the label for a major scale tick \param painter Painter \param value Value \sa drawTick(), drawBackbone() */ void QwtRoundScaleDraw::drawLabel( QPainter *painter, double value ) const { const QwtText label = tickLabel( painter->font(), value ); if ( label.isEmpty() ) return; const double tval = scaleMap().transform( value ); if ( ( tval > d_data->startAngle + 359 * 16 ) || ( tval < d_data->startAngle - 359 * 16 ) ) { return; } double radius = d_data->radius; if ( hasComponent( QwtAbstractScaleDraw::Ticks ) || hasComponent( QwtAbstractScaleDraw::Backbone ) ) { radius += spacing(); } if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) radius += tickLength( QwtScaleDiv::MajorTick ); const QSizeF sz = label.textSize( painter->font() ); const double arc = tval / 16.0 / 360.0 * 2 * M_PI; const double x = d_data->center.x() + ( radius + sz.width() / 2.0 ) * qSin( arc ); const double y = d_data->center.y() - ( radius + sz.height() / 2.0 ) * cos( arc ); const QRectF r( x - sz.width() / 2, y - sz.height() / 2, sz.width(), sz.height() ); label.draw( painter, r ); } /*! Draw a tick \param painter Painter \param value Value of the tick \param len Lenght of the tick \sa drawBackbone(), drawLabel() */ void QwtRoundScaleDraw::drawTick( QPainter *painter, double value, double len ) const { if ( len <= 0 ) return; const double tval = scaleMap().transform( value ); const double cx = d_data->center.x(); const double cy = d_data->center.y(); const double radius = d_data->radius; if ( ( tval <= d_data->startAngle + 359 * 16 ) || ( tval >= d_data->startAngle - 359 * 16 ) ) { const double arc = double( tval ) / 16.0 * M_PI / 180.0; const double sinArc = qSin( arc ); const double cosArc = qCos( arc ); const double x1 = cx + radius * sinArc; const double x2 = cx + ( radius + len ) * sinArc; const double y1 = cy - radius * cosArc; const double y2 = cy - ( radius + len ) * cosArc; QwtPainter::drawLine( painter, x1, y1, x2, y2 ); } } /*! Draws the baseline of the scale \param painter Painter \sa drawTick(), drawLabel() */ void QwtRoundScaleDraw::drawBackbone( QPainter *painter ) const { const double deg1 = scaleMap().p1(); const double deg2 = scaleMap().p2(); const int a1 = qRound( qMin( deg1, deg2 ) - 90 * 16 ); const int a2 = qRound( qMax( deg1, deg2 ) - 90 * 16 ); const double radius = d_data->radius; const double x = d_data->center.x() - radius; const double y = d_data->center.y() - radius; painter->drawArc( QRectF( x, y, 2 * radius, 2 * radius ), -a2, a2 - a1 + 1 ); // counterclockwise } /*! Calculate the extent of the scale The extent is the distance between the baseline to the outermost pixel of the scale draw. radius() + extent() is an upper limit for the radius of the bounding circle. \param font Font used for painting the labels \sa setMinimumExtent(), minimumExtent() \warning The implemented algo is not too smart and calculates only an upper limit, that might be a few pixels too large */ double QwtRoundScaleDraw::extent( const QFont &font ) const { double d = 0.0; if ( hasComponent( QwtAbstractScaleDraw::Labels ) ) { const QwtScaleDiv &sd = scaleDiv(); const QList &ticks = sd.ticks( QwtScaleDiv::MajorTick ); for ( int i = 0; i < ticks.count(); i++ ) { const double value = ticks[i]; if ( !sd.contains( value ) ) continue; const QwtText label = tickLabel( font, value ); if ( label.isEmpty() ) continue; const double tval = scaleMap().transform( value ); if ( ( tval < d_data->startAngle + 360 * 16 ) && ( tval > d_data->startAngle - 360 * 16 ) ) { const double arc = tval / 16.0 / 360.0 * 2 * M_PI; const QSizeF sz = label.textSize( font ); const double off = qMax( sz.width(), sz.height() ); double x = off * qSin( arc ); double y = off * qCos( arc ); const double dist = qSqrt( x * x + y * y ); if ( dist > d ) d = dist; } } } if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) { d += maxTickLength(); } if ( hasComponent( QwtAbstractScaleDraw::Backbone ) ) { const double pw = qMax( 1, penWidth() ); // penwidth can be zero d += pw; } if ( hasComponent( QwtAbstractScaleDraw::Labels ) && ( hasComponent( QwtAbstractScaleDraw::Ticks ) || hasComponent( QwtAbstractScaleDraw::Backbone ) ) ) { d += spacing(); } d = qMax( d, minimumExtent() ); return d; } pcp-gui-1.5.11/src/libqwt/qwt_sampling_thread.cpp0000644000000000000000000000426712176111212016665 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_sampling_thread.h" #include "qwt_system_clock.h" class QwtSamplingThread::PrivateData { public: QwtSystemClock clock; double interval; bool isStopped; }; //! Constructor QwtSamplingThread::QwtSamplingThread( QObject *parent ): QThread( parent ) { d_data = new PrivateData; d_data->interval = 1000; // 1 second d_data->isStopped = true; } //! Destructor QwtSamplingThread::~QwtSamplingThread() { delete d_data; } /*! Change the interval (in ms), when sample() is called. The default interval is 1000.0 ( = 1s ) \param interval Interval \sa interval() */ void QwtSamplingThread::setInterval( double interval ) { if ( interval < 0.0 ) interval = 0.0; d_data->interval = interval; } /*! \return Interval (in ms), between 2 calls of sample() \sa setInterval() */ double QwtSamplingThread::interval() const { return d_data->interval; } /*! \return Time (in ms) since the thread was started \sa QThread::start(), run() */ double QwtSamplingThread::elapsed() const { if ( d_data->isStopped ) return 0.0; return d_data->clock.elapsed(); } /*! Terminate the collecting thread \sa QThread::start(), run() */ void QwtSamplingThread::stop() { d_data->isStopped = true; } /*! Loop collecting samples started from QThread::start() \sa stop() */ void QwtSamplingThread::run() { d_data->clock.start(); d_data->isStopped = false; while ( !d_data->isStopped ) { const double elapsed = d_data->clock.elapsed(); sample( elapsed / 1000.0 ); if ( d_data->interval > 0.0 ) { const double msecs = d_data->interval - ( d_data->clock.elapsed() - elapsed ); if ( msecs > 0.0 ) usleep( qRound( 1000.0 * msecs ) ); } } } pcp-gui-1.5.11/src/libqwt/qwt_scale_div.cpp0000644000000000000000000000753212176111212015453 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_scale_div.h" #include "qwt_math.h" #include "qwt_interval.h" #include //! Construct an invalid QwtScaleDiv instance. QwtScaleDiv::QwtScaleDiv(): d_lowerBound( 0.0 ), d_upperBound( 0.0 ), d_isValid( false ) { } /*! Construct QwtScaleDiv instance. \param interval Interval \param ticks List of major, medium and minor ticks */ QwtScaleDiv::QwtScaleDiv( const QwtInterval &interval, QList ticks[NTickTypes] ): d_lowerBound( interval.minValue() ), d_upperBound( interval.maxValue() ), d_isValid( true ) { for ( int i = 0; i < NTickTypes; i++ ) d_ticks[i] = ticks[i]; } /*! Construct QwtScaleDiv instance. \param lowerBound First interval limit \param upperBound Second interval limit \param ticks List of major, medium and minor ticks */ QwtScaleDiv::QwtScaleDiv( double lowerBound, double upperBound, QList ticks[NTickTypes] ): d_lowerBound( lowerBound ), d_upperBound( upperBound ), d_isValid( true ) { for ( int i = 0; i < NTickTypes; i++ ) d_ticks[i] = ticks[i]; } /*! Change the interval \param interval Interval */ void QwtScaleDiv::setInterval( const QwtInterval &interval ) { setInterval( interval.minValue(), interval.maxValue() ); } /*! \brief Equality operator \return true if this instance is equal to other */ bool QwtScaleDiv::operator==( const QwtScaleDiv &other ) const { if ( d_lowerBound != other.d_lowerBound || d_upperBound != other.d_upperBound || d_isValid != other.d_isValid ) { return false; } for ( int i = 0; i < NTickTypes; i++ ) { if ( d_ticks[i] != other.d_ticks[i] ) return false; } return true; } /*! \brief Inequality \return true if this instance is not equal to s */ bool QwtScaleDiv::operator!=( const QwtScaleDiv &s ) const { return ( !( *this == s ) ); } //! Invalidate the scale division void QwtScaleDiv::invalidate() { d_isValid = false; // detach arrays for ( int i = 0; i < NTickTypes; i++ ) d_ticks[i].clear(); d_lowerBound = d_upperBound = 0; } //! Check if the scale division is valid bool QwtScaleDiv::isValid() const { return d_isValid; } /*! Return if a value is between lowerBound() and upperBound() \param value Value \return true/false */ bool QwtScaleDiv::contains( double value ) const { if ( !d_isValid ) return false; const double min = qMin( d_lowerBound, d_upperBound ); const double max = qMax( d_lowerBound, d_upperBound ); return value >= min && value <= max; } //! Invert the scale divison void QwtScaleDiv::invert() { qSwap( d_lowerBound, d_upperBound ); for ( int i = 0; i < NTickTypes; i++ ) { QList& ticks = d_ticks[i]; const int size = ticks.count(); const int size2 = size / 2; for ( int i = 0; i < size2; i++ ) qSwap( ticks[i], ticks[size - 1 - i] ); } } /*! Assign ticks \param type MinorTick, MediumTick or MajorTick \param ticks Values of the tick positions */ void QwtScaleDiv::setTicks( int type, const QList &ticks ) { if ( type >= 0 && type < NTickTypes ) d_ticks[type] = ticks; } /*! Return a list of ticks \param type MinorTick, MediumTick or MajorTick */ const QList &QwtScaleDiv::ticks( int type ) const { if ( type >= 0 && type < NTickTypes ) return d_ticks[type]; static QList noTicks; return noTicks; } pcp-gui-1.5.11/src/libqwt/qwt_scale_draw.cpp0000644000000000000000000005313112176111212015622 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_scale_draw.h" #include "qwt_scale_div.h" #include "qwt_scale_map.h" #include "qwt_math.h" #include "qwt_painter.h" #include #include #include #if QT_VERSION < 0x040601 #define qFastSin(x) qSin(x) #define qFastCos(x) qCos(x) #endif class QwtScaleDraw::PrivateData { public: PrivateData(): len( 0 ), alignment( QwtScaleDraw::BottomScale ), labelAlignment( 0 ), labelRotation( 0.0 ) { } QPointF pos; double len; Alignment alignment; Qt::Alignment labelAlignment; double labelRotation; }; /*! \brief Constructor The range of the scale is initialized to [0, 100], The position is at (0, 0) with a length of 100. The orientation is QwtAbstractScaleDraw::Bottom. */ QwtScaleDraw::QwtScaleDraw() { d_data = new QwtScaleDraw::PrivateData; setLength( 100 ); } //! Destructor QwtScaleDraw::~QwtScaleDraw() { delete d_data; } /*! Return alignment of the scale \sa setAlignment() */ QwtScaleDraw::Alignment QwtScaleDraw::alignment() const { return d_data->alignment; } /*! Set the alignment of the scale The default alignment is QwtScaleDraw::BottomScale \sa alignment() */ void QwtScaleDraw::setAlignment( Alignment align ) { d_data->alignment = align; } /*! Return the orientation TopScale, BottomScale are horizontal (Qt::Horizontal) scales, LeftScale, RightScale are vertical (Qt::Vertical) scales. \sa alignment() */ Qt::Orientation QwtScaleDraw::orientation() const { switch ( d_data->alignment ) { case TopScale: case BottomScale: return Qt::Horizontal; case LeftScale: case RightScale: default: return Qt::Vertical; } } /*! \brief Determine the minimum border distance This member function returns the minimum space needed to draw the mark labels at the scale's endpoints. \param font Font \param start Start border distance \param end End border distance */ void QwtScaleDraw::getBorderDistHint( const QFont &font, int &start, int &end ) const { start = 0; end = 0; if ( !hasComponent( QwtAbstractScaleDraw::Labels ) ) return; const QList &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick ); if ( ticks.count() == 0 ) return; // Find the ticks, that are mapped to the borders. // minTick is the tick, that is mapped to the top/left-most position // in widget coordinates. double minTick = ticks[0]; double minPos = scaleMap().transform( minTick ); double maxTick = minTick; double maxPos = minPos; for ( int i = 1; i < ticks.count(); i++ ) { const double tickPos = scaleMap().transform( ticks[i] ); if ( tickPos < minPos ) { minTick = ticks[i]; minPos = tickPos; } if ( tickPos > scaleMap().transform( maxTick ) ) { maxTick = ticks[i]; maxPos = tickPos; } } double e = 0.0; double s = 0.0; if ( orientation() == Qt::Vertical ) { s = -labelRect( font, minTick ).top(); s -= qAbs( minPos - qRound( scaleMap().p2() ) ); e = labelRect( font, maxTick ).bottom(); e -= qAbs( maxPos - scaleMap().p1() ); } else { s = -labelRect( font, minTick ).left(); s -= qAbs( minPos - scaleMap().p1() ); e = labelRect( font, maxTick ).right(); e -= qAbs( maxPos - scaleMap().p2() ); } if ( s < 0.0 ) s = 0.0; if ( e < 0.0 ) e = 0.0; start = qCeil( s ); end = qCeil( e ); } /*! Determine the minimum distance between two labels, that is necessary that the texts don't overlap. \param font Font \return The maximum width of a label \sa getBorderDistHint() */ int QwtScaleDraw::minLabelDist( const QFont &font ) const { if ( !hasComponent( QwtAbstractScaleDraw::Labels ) ) return 0; const QList &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick ); if ( ticks.isEmpty() ) return 0; const QFontMetrics fm( font ); const bool vertical = ( orientation() == Qt::Vertical ); QRectF bRect1; QRectF bRect2 = labelRect( font, ticks[0] ); if ( vertical ) { bRect2.setRect( -bRect2.bottom(), 0.0, bRect2.height(), bRect2.width() ); } double maxDist = 0.0; for ( int i = 1; i < ticks.count(); i++ ) { bRect1 = bRect2; bRect2 = labelRect( font, ticks[i] ); if ( vertical ) { bRect2.setRect( -bRect2.bottom(), 0.0, bRect2.height(), bRect2.width() ); } double dist = fm.leading(); // space between the labels if ( bRect1.right() > 0 ) dist += bRect1.right(); if ( bRect2.left() < 0 ) dist += -bRect2.left(); if ( dist > maxDist ) maxDist = dist; } double angle = labelRotation() / 180.0 * M_PI; if ( vertical ) angle += M_PI / 2; const double sinA = qFastSin( angle ); // qreal -> double if ( qFuzzyCompare( sinA + 1.0, 1.0 ) ) return qCeil( maxDist ); const int fmHeight = fm.ascent() - 2; // The distance we need until there is // the height of the label font. This height is needed // for the neighbour labal. double labelDist = fmHeight / qFastSin( angle ) * qFastCos( angle ); if ( labelDist < 0 ) labelDist = -labelDist; // For text orientations close to the scale orientation if ( labelDist > maxDist ) labelDist = maxDist; // For text orientations close to the opposite of the // scale orientation if ( labelDist < fmHeight ) labelDist = fmHeight; return qCeil( labelDist ); } /*! Calculate the width/height that is needed for a vertical/horizontal scale. The extent is calculated from the pen width of the backbone, the major tick length, the spacing and the maximum width/height of the labels. \param font Font used for painting the labels \sa minLength() */ double QwtScaleDraw::extent( const QFont &font ) const { double d = 0; if ( hasComponent( QwtAbstractScaleDraw::Labels ) ) { if ( orientation() == Qt::Vertical ) d = maxLabelWidth( font ); else d = maxLabelHeight( font ); if ( d > 0 ) d += spacing(); } if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) { d += maxTickLength(); } if ( hasComponent( QwtAbstractScaleDraw::Backbone ) ) { const double pw = qMax( 1, penWidth() ); // penwidth can be zero d += pw; } d = qMax( d, minimumExtent() ); return d; } /*! Calculate the minimum length that is needed to draw the scale \param font Font used for painting the labels \sa extent() */ int QwtScaleDraw::minLength( const QFont &font ) const { int startDist, endDist; getBorderDistHint( font, startDist, endDist ); const QwtScaleDiv &sd = scaleDiv(); const uint minorCount = sd.ticks( QwtScaleDiv::MinorTick ).count() + sd.ticks( QwtScaleDiv::MediumTick ).count(); const uint majorCount = sd.ticks( QwtScaleDiv::MajorTick ).count(); int lengthForLabels = 0; if ( hasComponent( QwtAbstractScaleDraw::Labels ) ) lengthForLabels = minLabelDist( font ) * majorCount; int lengthForTicks = 0; if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) { const double pw = qMax( 1, penWidth() ); // penwidth can be zero lengthForTicks = qCeil( ( majorCount + minorCount ) * ( pw + 1.0 ) ); } return startDist + endDist + qMax( lengthForLabels, lengthForTicks ); } /*! Find the position, where to paint a label The position has a distance of majTickLength() + spacing() + 1 from the backbone. The direction depends on the alignment() \param value Value */ QPointF QwtScaleDraw::labelPosition( double value ) const { const double tval = scaleMap().transform( value ); double dist = spacing(); if ( hasComponent( QwtAbstractScaleDraw::Backbone ) ) dist += qMax( 1, penWidth() ); if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) dist += tickLength( QwtScaleDiv::MajorTick ); double px = 0; double py = 0; switch ( alignment() ) { case RightScale: { px = d_data->pos.x() + dist; py = tval; break; } case LeftScale: { px = d_data->pos.x() - dist; py = tval; break; } case BottomScale: { px = tval; py = d_data->pos.y() + dist; break; } case TopScale: { px = tval; py = d_data->pos.y() - dist; break; } } return QPointF( px, py ); } /*! Draw a tick \param painter Painter \param value Value of the tick \param len Lenght of the tick \sa drawBackbone(), drawLabel() */ void QwtScaleDraw::drawTick( QPainter *painter, double value, double len ) const { if ( len <= 0 ) return; const bool roundingAlignment = QwtPainter::roundingAlignment( painter ); QPointF pos = d_data->pos; double tval = scaleMap().transform( value ); if ( roundingAlignment ) tval = qRound( tval ); const int pw = penWidth(); int a = 0; if ( pw > 1 && roundingAlignment ) a = 1; switch ( alignment() ) { case LeftScale: { double x1 = pos.x() + a; double x2 = pos.x() + a - pw - len; if ( roundingAlignment ) { x1 = qRound( x1 ); x2 = qRound( x2 ); } QwtPainter::drawLine( painter, x1, tval, x2, tval ); break; } case RightScale: { double x1 = pos.x(); double x2 = pos.x() + pw + len; if ( roundingAlignment ) { x1 = qRound( x1 ); x2 = qRound( x2 ); } QwtPainter::drawLine( painter, x1, tval, x2, tval ); break; } case BottomScale: { double y1 = pos.y(); double y2 = pos.y() + pw + len; if ( roundingAlignment ) { y1 = qRound( y1 ); y2 = qRound( y2 ); } QwtPainter::drawLine( painter, tval, y1, tval, y2 ); break; } case TopScale: { double y1 = pos.y() + a; double y2 = pos.y() - pw - len + a; if ( roundingAlignment ) { y1 = qRound( y1 ); y2 = qRound( y2 ); } QwtPainter::drawLine( painter, tval, y1, tval, y2 ); break; } } } /*! Draws the baseline of the scale \param painter Painter \sa drawTick(), drawLabel() */ void QwtScaleDraw::drawBackbone( QPainter *painter ) const { const bool doAlign = QwtPainter::roundingAlignment( painter ); const QPointF &pos = d_data->pos; const double len = d_data->len; const int pw = qMax( penWidth(), 1 ); // pos indicates a border not the center of the backbone line // so we need to shift its position depending on the pen width // and the alignment of the scale double off; if ( doAlign ) { if ( alignment() == LeftScale || alignment() == TopScale ) off = ( pw - 1 ) / 2; else off = pw / 2; } else { off = 0.5 * penWidth(); } switch ( alignment() ) { case LeftScale: { double x = pos.x() - off; if ( doAlign ) x = qRound( x ); QwtPainter::drawLine( painter, x, pos.y(), x, pos.y() + len ); break; } case RightScale: { double x = pos.x() + off; if ( doAlign ) x = qRound( x ); QwtPainter::drawLine( painter, x, pos.y(), x, pos.y() + len ); break; } case TopScale: { double y = pos.y() - off; if ( doAlign ) y = qRound( y ); QwtPainter::drawLine( painter, pos.x(), y, pos.x() + len, y ); break; } case BottomScale: { double y = pos.y() + off; if ( doAlign ) y = qRound( y ); QwtPainter::drawLine( painter, pos.x(), y, pos.x() + len, y ); break; } } } /*! \brief Move the position of the scale The meaning of the parameter pos depends on the alignment:
QwtScaleDraw::LeftScale
The origin is the topmost point of the backbone. The backbone is a vertical line. Scale marks and labels are drawn at the left of the backbone.
QwtScaleDraw::RightScale
The origin is the topmost point of the backbone. The backbone is a vertical line. Scale marks and labels are drawn at the right of the backbone.
QwtScaleDraw::TopScale
The origin is the leftmost point of the backbone. The backbone is a horizontal line. Scale marks and labels are drawn above the backbone.
QwtScaleDraw::BottomScale
The origin is the leftmost point of the backbone. The backbone is a horizontal line Scale marks and labels are drawn below the backbone.
\param pos Origin of the scale \sa pos(), setLength() */ void QwtScaleDraw::move( const QPointF &pos ) { d_data->pos = pos; updateMap(); } /*! \return Origin of the scale \sa move(), length() */ QPointF QwtScaleDraw::pos() const { return d_data->pos; } /*! Set the length of the backbone. The length doesn't include the space needed for overlapping labels. \sa move(), minLabelDist() */ void QwtScaleDraw::setLength( double length ) { if ( length >= 0 && length < 10 ) length = 10; if ( length < 0 && length > -10 ) length = -10; d_data->len = length; updateMap(); } /*! \return the length of the backbone \sa setLength(), pos() */ double QwtScaleDraw::length() const { return d_data->len; } /*! Draws the label for a major scale tick \param painter Painter \param value Value \sa drawTick(), drawBackbone(), boundingLabelRect() */ void QwtScaleDraw::drawLabel( QPainter *painter, double value ) const { QwtText lbl = tickLabel( painter->font(), value ); if ( lbl.isEmpty() ) return; QPointF pos = labelPosition( value ); QSizeF labelSize = lbl.textSize( painter->font() ); const QTransform transform = labelTransformation( pos, labelSize ); painter->save(); painter->setWorldTransform( transform, true ); lbl.draw ( painter, QRect( QPoint( 0, 0 ), labelSize.toSize() ) ); painter->restore(); } /*! Find the bounding rect for the label. The coordinates of the rect are absolute coordinates ( calculated from pos() ). in direction of the tick. \param font Font used for painting \param value Value \sa labelRect() */ QRect QwtScaleDraw::boundingLabelRect( const QFont &font, double value ) const { QwtText lbl = tickLabel( font, value ); if ( lbl.isEmpty() ) return QRect(); const QPointF pos = labelPosition( value ); QSizeF labelSize = lbl.textSize( font ); const QTransform transform = labelTransformation( pos, labelSize ); return transform.mapRect( QRect( QPoint( 0, 0 ), labelSize.toSize() ) ); } /*! Calculate the transformation that is needed to paint a label depending on its alignment and rotation. \param pos Position where to paint the label \param size Size of the label \sa setLabelAlignment(), setLabelRotation() */ QTransform QwtScaleDraw::labelTransformation( const QPointF &pos, const QSizeF &size ) const { QTransform transform; transform.translate( pos.x(), pos.y() ); transform.rotate( labelRotation() ); int flags = labelAlignment(); if ( flags == 0 ) { switch ( alignment() ) { case RightScale: { if ( flags == 0 ) flags = Qt::AlignRight | Qt::AlignVCenter; break; } case LeftScale: { if ( flags == 0 ) flags = Qt::AlignLeft | Qt::AlignVCenter; break; } case BottomScale: { if ( flags == 0 ) flags = Qt::AlignHCenter | Qt::AlignBottom; break; } case TopScale: { if ( flags == 0 ) flags = Qt::AlignHCenter | Qt::AlignTop; break; } } } double x, y; if ( flags & Qt::AlignLeft ) x = -size.width(); else if ( flags & Qt::AlignRight ) x = 0.0; else // Qt::AlignHCenter x = -( 0.5 * size.width() ); if ( flags & Qt::AlignTop ) y = -size.height(); else if ( flags & Qt::AlignBottom ) y = 0; else // Qt::AlignVCenter y = -( 0.5 * size.height() ); transform.translate( x, y ); return transform; } /*! Find the bounding rect for the label. The coordinates of the rect are relative to spacing + ticklength from the backbone in direction of the tick. \param font Font used for painting \param value Value */ QRectF QwtScaleDraw::labelRect( const QFont &font, double value ) const { QwtText lbl = tickLabel( font, value ); if ( lbl.isEmpty() ) return QRectF( 0.0, 0.0, 0.0, 0.0 ); const QPointF pos = labelPosition( value ); const QSizeF labelSize = lbl.textSize( font ); const QTransform transform = labelTransformation( pos, labelSize ); QRectF br = transform.mapRect( QRectF( QPointF( 0, 0 ), labelSize ) ); br.translate( -pos.x(), -pos.y() ); return br; } /*! Calculate the size that is needed to draw a label \param font Label font \param value Value */ QSizeF QwtScaleDraw::labelSize( const QFont &font, double value ) const { return labelRect( font, value ).size(); } /*! Rotate all labels. When changing the rotation, it might be necessary to adjust the label flags too. Finding a useful combination is often the result of try and error. \param rotation Angle in degrees. When changing the label rotation, the label flags often needs to be adjusted too. \sa setLabelAlignment(), labelRotation(), labelAlignment(). */ void QwtScaleDraw::setLabelRotation( double rotation ) { d_data->labelRotation = rotation; } /*! \return the label rotation \sa setLabelRotation(), labelAlignment() */ double QwtScaleDraw::labelRotation() const { return d_data->labelRotation; } /*! \brief Change the label flags Labels are aligned to the point ticklength + spacing away from the backbone. The alignment is relative to the orientation of the label text. In case of an flags of 0 the label will be aligned depending on the orientation of the scale: QwtScaleDraw::TopScale: Qt::AlignHCenter | Qt::AlignTop\n QwtScaleDraw::BottomScale: Qt::AlignHCenter | Qt::AlignBottom\n QwtScaleDraw::LeftScale: Qt::AlignLeft | Qt::AlignVCenter\n QwtScaleDraw::RightScale: Qt::AlignRight | Qt::AlignVCenter\n Changing the alignment is often necessary for rotated labels. \param alignment Or'd Qt::AlignmentFlags see \sa setLabelRotation(), labelRotation(), labelAlignment() \warning The various alignments might be confusing. The alignment of the label is not the alignment of the scale and is not the alignment of the flags (QwtText::flags()) returned from QwtAbstractScaleDraw::label(). */ void QwtScaleDraw::setLabelAlignment( Qt::Alignment alignment ) { d_data->labelAlignment = alignment; } /*! \return the label flags \sa setLabelAlignment(), labelRotation() */ Qt::Alignment QwtScaleDraw::labelAlignment() const { return d_data->labelAlignment; } /*! \param font Font \return the maximum width of a label */ int QwtScaleDraw::maxLabelWidth( const QFont &font ) const { double maxWidth = 0.0; const QList &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick ); for ( int i = 0; i < ticks.count(); i++ ) { const double v = ticks[i]; if ( scaleDiv().contains( v ) ) { const double w = labelSize( font, ticks[i] ).width(); if ( w > maxWidth ) maxWidth = w; } } return qCeil( maxWidth ); } /*! \param font Font \return the maximum height of a label */ int QwtScaleDraw::maxLabelHeight( const QFont &font ) const { double maxHeight = 0.0; const QList &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick ); for ( int i = 0; i < ticks.count(); i++ ) { const double v = ticks[i]; if ( scaleDiv().contains( v ) ) { const double h = labelSize( font, ticks[i] ).height(); if ( h > maxHeight ) maxHeight = h; } } return qCeil( maxHeight ); } void QwtScaleDraw::updateMap() { const QPointF pos = d_data->pos; double len = d_data->len; QwtScaleMap &sm = scaleMap(); if ( orientation() == Qt::Vertical ) sm.setPaintInterval( pos.y() + len, pos.y() ); else sm.setPaintInterval( pos.x(), pos.x() + len ); } pcp-gui-1.5.11/src/libqwt/qwt_scale_engine.cpp0000644000000000000000000005733212176111212016141 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_scale_engine.h" #include "qwt_math.h" #include "qwt_scale_map.h" #include #include #include #if QT_VERSION < 0x040601 #define qFabs(x) ::fabs(x) #define qExp(x) ::exp(x) #endif static const double _eps = 1.0e-6; /*! Ceil a value, relative to an interval \param value Value to ceil \param intervalSize Interval size \sa floorEps() */ double QwtScaleArithmetic::ceilEps( double value, double intervalSize ) { const double eps = _eps * intervalSize; value = ( value - eps ) / intervalSize; return ::ceil( value ) * intervalSize; } /*! Floor a value, relative to an interval \param value Value to floor \param intervalSize Interval size \sa floorEps() */ double QwtScaleArithmetic::floorEps( double value, double intervalSize ) { const double eps = _eps * intervalSize; value = ( value + eps ) / intervalSize; return ::floor( value ) * intervalSize; } /*! \brief Divide an interval into steps \f$stepSize = (intervalSize - intervalSize * 10e^{-6}) / numSteps\f$ \param intervalSize Interval size \param numSteps Number of steps \return Step size */ double QwtScaleArithmetic::divideEps( double intervalSize, double numSteps ) { if ( numSteps == 0.0 || intervalSize == 0.0 ) return 0.0; return ( intervalSize - ( _eps * intervalSize ) ) / numSteps; } /*! Find the smallest value out of {1,2,5}*10^n with an integer number n which is greater than or equal to x \param x Input value */ double QwtScaleArithmetic::ceil125( double x ) { if ( x == 0.0 ) return 0.0; const double sign = ( x > 0 ) ? 1.0 : -1.0; const double lx = ::log10( qFabs( x ) ); const double p10 = ::floor( lx ); double fr = qPow( 10.0, lx - p10 ); if ( fr <= 1.0 ) fr = 1.0; else if ( fr <= 2.0 ) fr = 2.0; else if ( fr <= 5.0 ) fr = 5.0; else fr = 10.0; return sign * fr * qPow( 10.0, p10 ); } /*! \brief Find the largest value out of {1,2,5}*10^n with an integer number n which is smaller than or equal to x \param x Input value */ double QwtScaleArithmetic::floor125( double x ) { if ( x == 0.0 ) return 0.0; double sign = ( x > 0 ) ? 1.0 : -1.0; const double lx = ::log10( qFabs( x ) ); const double p10 = ::floor( lx ); double fr = qPow( 10.0, lx - p10 ); if ( fr >= 10.0 ) fr = 10.0; else if ( fr >= 5.0 ) fr = 5.0; else if ( fr >= 2.0 ) fr = 2.0; else fr = 1.0; return sign * fr * qPow( 10.0, p10 ); } class QwtScaleEngine::PrivateData { public: PrivateData(): attributes( QwtScaleEngine::NoAttribute ), lowerMargin( 0.0 ), upperMargin( 0.0 ), referenceValue( 0.0 ) { } QwtScaleEngine::Attributes attributes; // scale attributes double lowerMargin; // margins double upperMargin; double referenceValue; // reference value }; //! Constructor QwtScaleEngine::QwtScaleEngine() { d_data = new PrivateData; } //! Destructor QwtScaleEngine::~QwtScaleEngine () { delete d_data; } /*! \return the margin at the lower end of the scale The default margin is 0. \sa setMargins() */ double QwtScaleEngine::lowerMargin() const { return d_data->lowerMargin; } /*! \return the margin at the upper end of the scale The default margin is 0. \sa setMargins() */ double QwtScaleEngine::upperMargin() const { return d_data->upperMargin; } /*! \brief Specify margins at the scale's endpoints \param lower minimum distance between the scale's lower boundary and the smallest enclosed value \param upper minimum distance between the scale's upper boundary and the greatest enclosed value Margins can be used to leave a minimum amount of space between the enclosed intervals and the boundaries of the scale. \warning \li QwtLog10ScaleEngine measures the margins in decades. \sa upperMargin(), lowerMargin() */ void QwtScaleEngine::setMargins( double lower, double upper ) { d_data->lowerMargin = qMax( lower, 0.0 ); d_data->upperMargin = qMax( upper, 0.0 ); } /*! Calculate a step size for an interval size \param intervalSize Interval size \param numSteps Number of steps \return Step size */ double QwtScaleEngine::divideInterval( double intervalSize, int numSteps ) const { if ( numSteps <= 0 ) return 0.0; double v = QwtScaleArithmetic::divideEps( intervalSize, numSteps ); return QwtScaleArithmetic::ceil125( v ); } /*! Check if an interval "contains" a value \param interval Interval \param value Value \sa QwtScaleArithmetic::compareEps() */ bool QwtScaleEngine::contains( const QwtInterval &interval, double value ) const { if ( !interval.isValid() ) return false; if ( qwtFuzzyCompare( value, interval.minValue(), interval.width() ) < 0 ) return false; if ( qwtFuzzyCompare( value, interval.maxValue(), interval.width() ) > 0 ) return false; return true; } /*! Remove ticks from a list, that are not inside an interval \param ticks Tick list \param interval Interval \return Stripped tick list */ QList QwtScaleEngine::strip( const QList& ticks, const QwtInterval &interval ) const { if ( !interval.isValid() || ticks.count() == 0 ) return QList(); if ( contains( interval, ticks.first() ) && contains( interval, ticks.last() ) ) { return ticks; } QList strippedTicks; for ( int i = 0; i < ticks.count(); i++ ) { if ( contains( interval, ticks[i] ) ) strippedTicks += ticks[i]; } return strippedTicks; } /*! \brief Build an interval for a value In case of v == 0.0 the interval is [-0.5, 0.5], otherwide it is [0.5 * v, 1.5 * v] */ QwtInterval QwtScaleEngine::buildInterval( double v ) const { const double delta = ( v == 0.0 ) ? 0.5 : qAbs( 0.5 * v ); if ( DBL_MAX - delta < v ) return QwtInterval( DBL_MAX - delta, DBL_MAX ); if ( -DBL_MAX + delta > v ) return QwtInterval( -DBL_MAX, -DBL_MAX + delta ); return QwtInterval( v - delta, v + delta ); } /*! Change a scale attribute \param attribute Attribute to change \param on On/Off \sa Attribute, testAttribute() */ void QwtScaleEngine::setAttribute( Attribute attribute, bool on ) { if ( on ) d_data->attributes |= attribute; else d_data->attributes &= ~attribute; } /*! Check if a attribute is set. \param attribute Attribute to be tested \sa Attribute, setAttribute() */ bool QwtScaleEngine::testAttribute( Attribute attribute ) const { return ( d_data->attributes & attribute ); } /*! Change the scale attribute \param attributes Set scale attributes \sa Attribute, attributes() */ void QwtScaleEngine::setAttributes( Attributes attributes ) { d_data->attributes = attributes; } /*! Return the scale attributes \sa Attribute, setAttributes(), testAttribute() */ QwtScaleEngine::Attributes QwtScaleEngine::attributes() const { return d_data->attributes; } /*! \brief Specify a reference point \param r new reference value The reference point is needed if options IncludeReference or Symmetric are active. Its default value is 0.0. \sa Attribute */ void QwtScaleEngine::setReference( double r ) { d_data->referenceValue = r; } /*! \return the reference value \sa setReference(), setAttribute() */ double QwtScaleEngine::reference() const { return d_data->referenceValue; } /*! Return a transformation, for linear scales */ QwtScaleTransformation *QwtLinearScaleEngine::transformation() const { return new QwtScaleTransformation( QwtScaleTransformation::Linear ); } /*! Align and divide an interval \param maxNumSteps Max. number of steps \param x1 First limit of the interval (In/Out) \param x2 Second limit of the interval (In/Out) \param stepSize Step size (Out) \sa setAttribute() */ void QwtLinearScaleEngine::autoScale( int maxNumSteps, double &x1, double &x2, double &stepSize ) const { QwtInterval interval( x1, x2 ); interval = interval.normalized(); interval.setMinValue( interval.minValue() - lowerMargin() ); interval.setMaxValue( interval.maxValue() + upperMargin() ); if ( testAttribute( QwtScaleEngine::Symmetric ) ) interval = interval.symmetrize( reference() ); if ( testAttribute( QwtScaleEngine::IncludeReference ) ) interval = interval.extend( reference() ); if ( interval.width() == 0.0 ) interval = buildInterval( interval.minValue() ); stepSize = divideInterval( interval.width(), qMax( maxNumSteps, 1 ) ); if ( !testAttribute( QwtScaleEngine::Floating ) ) interval = align( interval, stepSize ); x1 = interval.minValue(); x2 = interval.maxValue(); if ( testAttribute( QwtScaleEngine::Inverted ) ) { qSwap( x1, x2 ); stepSize = -stepSize; } } /*! \brief Calculate a scale division \param x1 First interval limit \param x2 Second interval limit \param maxMajSteps Maximum for the number of major steps \param maxMinSteps Maximum number of minor steps \param stepSize Step size. If stepSize == 0, the scaleEngine calculates one. \sa QwtScaleEngine::stepSize(), QwtScaleEngine::subDivide() */ QwtScaleDiv QwtLinearScaleEngine::divideScale( double x1, double x2, int maxMajSteps, int maxMinSteps, double stepSize ) const { QwtInterval interval = QwtInterval( x1, x2 ).normalized(); if ( interval.width() <= 0 ) return QwtScaleDiv(); stepSize = qAbs( stepSize ); if ( stepSize == 0.0 ) { if ( maxMajSteps < 1 ) maxMajSteps = 1; stepSize = divideInterval( interval.width(), maxMajSteps ); } QwtScaleDiv scaleDiv; if ( stepSize != 0.0 ) { QList ticks[QwtScaleDiv::NTickTypes]; buildTicks( interval, stepSize, maxMinSteps, ticks ); scaleDiv = QwtScaleDiv( interval, ticks ); } if ( x1 > x2 ) scaleDiv.invert(); return scaleDiv; } /*! \brief Calculate ticks for an interval \param interval Interval \param stepSize Step size \param maxMinSteps Maximum number of minor steps \param ticks Arrays to be filled with the calculated ticks \sa buildMajorTicks(), buildMinorTicks */ void QwtLinearScaleEngine::buildTicks( const QwtInterval& interval, double stepSize, int maxMinSteps, QList ticks[QwtScaleDiv::NTickTypes] ) const { const QwtInterval boundingInterval = align( interval, stepSize ); ticks[QwtScaleDiv::MajorTick] = buildMajorTicks( boundingInterval, stepSize ); if ( maxMinSteps > 0 ) { buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize, ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick] ); } for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ ) { ticks[i] = strip( ticks[i], interval ); // ticks very close to 0.0 are // explicitely set to 0.0 for ( int j = 0; j < ticks[i].count(); j++ ) { if ( qwtFuzzyCompare( ticks[i][j], 0.0, stepSize ) == 0 ) ticks[i][j] = 0.0; } } } /*! \brief Calculate major ticks for an interval \param interval Interval \param stepSize Step size \return Calculated ticks */ QList QwtLinearScaleEngine::buildMajorTicks( const QwtInterval &interval, double stepSize ) const { int numTicks = qRound( interval.width() / stepSize ) + 1; if ( numTicks > 10000 ) numTicks = 10000; QList ticks; ticks += interval.minValue(); for ( int i = 1; i < numTicks - 1; i++ ) ticks += interval.minValue() + i * stepSize; ticks += interval.maxValue(); return ticks; } /*! \brief Calculate minor/medium ticks for major ticks \param majorTicks Major ticks \param maxMinSteps Maximum number of minor steps \param stepSize Step size \param minorTicks Array to be filled with the calculated minor ticks \param mediumTicks Array to be filled with the calculated medium ticks */ void QwtLinearScaleEngine::buildMinorTicks( const QList& majorTicks, int maxMinSteps, double stepSize, QList &minorTicks, QList &mediumTicks ) const { double minStep = divideInterval( stepSize, maxMinSteps ); if ( minStep == 0.0 ) return; // # ticks per interval int numTicks = qCeil( qAbs( stepSize / minStep ) ) - 1; // Do the minor steps fit into the interval? if ( qwtFuzzyCompare( ( numTicks + 1 ) * qAbs( minStep ), qAbs( stepSize ), stepSize ) > 0 ) { numTicks = 1; minStep = stepSize * 0.5; } int medIndex = -1; if ( numTicks % 2 ) medIndex = numTicks / 2; // calculate minor ticks for ( int i = 0; i < majorTicks.count(); i++ ) { double val = majorTicks[i]; for ( int k = 0; k < numTicks; k++ ) { val += minStep; double alignedValue = val; if ( qwtFuzzyCompare( val, 0.0, stepSize ) == 0 ) alignedValue = 0.0; if ( k == medIndex ) mediumTicks += alignedValue; else minorTicks += alignedValue; } } } /*! \brief Align an interval to a step size The limits of an interval are aligned that both are integer multiples of the step size. \param interval Interval \param stepSize Step size \return Aligned interval */ QwtInterval QwtLinearScaleEngine::align( const QwtInterval &interval, double stepSize ) const { double x1 = interval.minValue(); double x2 = interval.maxValue(); if ( -DBL_MAX + stepSize <= x1 ) { const double x = QwtScaleArithmetic::floorEps( x1, stepSize ); if ( qwtFuzzyCompare( x1, x, stepSize ) != 0 ) x1 = x; } if ( DBL_MAX - stepSize >= x2 ) { const double x = QwtScaleArithmetic::ceilEps( x2, stepSize ); if ( qwtFuzzyCompare( x2, x, stepSize ) != 0 ) x2 = x; } return QwtInterval( x1, x2 ); } /*! Return a transformation, for logarithmic (base 10) scales */ QwtScaleTransformation *QwtLog10ScaleEngine::transformation() const { return new QwtScaleTransformation( QwtScaleTransformation::Log10 ); } /*! Align and divide an interval \param maxNumSteps Max. number of steps \param x1 First limit of the interval (In/Out) \param x2 Second limit of the interval (In/Out) \param stepSize Step size (Out) \sa QwtScaleEngine::setAttribute() */ void QwtLog10ScaleEngine::autoScale( int maxNumSteps, double &x1, double &x2, double &stepSize ) const { if ( x1 > x2 ) qSwap( x1, x2 ); QwtInterval interval( x1 / qPow( 10.0, lowerMargin() ), x2 * qPow( 10.0, upperMargin() ) ); if ( interval.maxValue() / interval.minValue() < 10.0 ) { // scale width is less than one decade -> build linear scale QwtLinearScaleEngine linearScaler; linearScaler.setAttributes( attributes() ); linearScaler.setReference( reference() ); linearScaler.setMargins( lowerMargin(), upperMargin() ); linearScaler.autoScale( maxNumSteps, x1, x2, stepSize ); if ( stepSize < 0.0 ) stepSize = -::log10( qAbs( stepSize ) ); else stepSize = ::log10( stepSize ); return; } double logRef = 1.0; if ( reference() > LOG_MIN / 2 ) logRef = qMin( reference(), LOG_MAX / 2 ); if ( testAttribute( QwtScaleEngine::Symmetric ) ) { const double delta = qMax( interval.maxValue() / logRef, logRef / interval.minValue() ); interval.setInterval( logRef / delta, logRef * delta ); } if ( testAttribute( QwtScaleEngine::IncludeReference ) ) interval = interval.extend( logRef ); interval = interval.limited( LOG_MIN, LOG_MAX ); if ( interval.width() == 0.0 ) interval = buildInterval( interval.minValue() ); stepSize = divideInterval( log10( interval ).width(), qMax( maxNumSteps, 1 ) ); if ( stepSize < 1.0 ) stepSize = 1.0; if ( !testAttribute( QwtScaleEngine::Floating ) ) interval = align( interval, stepSize ); x1 = interval.minValue(); x2 = interval.maxValue(); if ( testAttribute( QwtScaleEngine::Inverted ) ) { qSwap( x1, x2 ); stepSize = -stepSize; } } /*! \brief Calculate a scale division \param x1 First interval limit \param x2 Second interval limit \param maxMajSteps Maximum for the number of major steps \param maxMinSteps Maximum number of minor steps \param stepSize Step size. If stepSize == 0, the scaleEngine calculates one. \sa QwtScaleEngine::stepSize(), QwtLog10ScaleEngine::subDivide() */ QwtScaleDiv QwtLog10ScaleEngine::divideScale( double x1, double x2, int maxMajSteps, int maxMinSteps, double stepSize ) const { QwtInterval interval = QwtInterval( x1, x2 ).normalized(); interval = interval.limited( LOG_MIN, LOG_MAX ); if ( interval.width() <= 0 ) return QwtScaleDiv(); if ( interval.maxValue() / interval.minValue() < 10.0 ) { // scale width is less than one decade -> build linear scale QwtLinearScaleEngine linearScaler; linearScaler.setAttributes( attributes() ); linearScaler.setReference( reference() ); linearScaler.setMargins( lowerMargin(), upperMargin() ); if ( stepSize != 0.0 ) { if ( stepSize < 0.0 ) stepSize = -qPow( 10.0, -stepSize ); else stepSize = qPow( 10.0, stepSize ); } return linearScaler.divideScale( x1, x2, maxMajSteps, maxMinSteps, stepSize ); } stepSize = qAbs( stepSize ); if ( stepSize == 0.0 ) { if ( maxMajSteps < 1 ) maxMajSteps = 1; stepSize = divideInterval( log10( interval ).width(), maxMajSteps ); if ( stepSize < 1.0 ) stepSize = 1.0; // major step must be >= 1 decade } QwtScaleDiv scaleDiv; if ( stepSize != 0.0 ) { QList ticks[QwtScaleDiv::NTickTypes]; buildTicks( interval, stepSize, maxMinSteps, ticks ); scaleDiv = QwtScaleDiv( interval, ticks ); } if ( x1 > x2 ) scaleDiv.invert(); return scaleDiv; } /*! \brief Calculate ticks for an interval \param interval Interval \param maxMinSteps Maximum number of minor steps \param stepSize Step size \param ticks Arrays to be filled with the calculated ticks \sa buildMajorTicks(), buildMinorTicks */ void QwtLog10ScaleEngine::buildTicks( const QwtInterval& interval, double stepSize, int maxMinSteps, QList ticks[QwtScaleDiv::NTickTypes] ) const { const QwtInterval boundingInterval = align( interval, stepSize ); ticks[QwtScaleDiv::MajorTick] = buildMajorTicks( boundingInterval, stepSize ); if ( maxMinSteps > 0 ) { ticks[QwtScaleDiv::MinorTick] = buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize ); } for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ ) ticks[i] = strip( ticks[i], interval ); } /*! \brief Calculate major ticks for an interval \param interval Interval \param stepSize Step size \return Calculated ticks */ QList QwtLog10ScaleEngine::buildMajorTicks( const QwtInterval &interval, double stepSize ) const { double width = log10( interval ).width(); int numTicks = qRound( width / stepSize ) + 1; if ( numTicks > 10000 ) numTicks = 10000; const double lxmin = ::log( interval.minValue() ); const double lxmax = ::log( interval.maxValue() ); const double lstep = ( lxmax - lxmin ) / double( numTicks - 1 ); QList ticks; ticks += interval.minValue(); for ( int i = 1; i < numTicks - 1; i++ ) ticks += qExp( lxmin + double( i ) * lstep ); ticks += interval.maxValue(); return ticks; } /*! \brief Calculate minor/medium ticks for major ticks \param majorTicks Major ticks \param maxMinSteps Maximum number of minor steps \param stepSize Step size */ QList QwtLog10ScaleEngine::buildMinorTicks( const QList &majorTicks, int maxMinSteps, double stepSize ) const { if ( stepSize < 1.1 ) // major step width is one decade { if ( maxMinSteps < 1 ) return QList(); int k0, kstep, kmax; if ( maxMinSteps >= 8 ) { k0 = 2; kmax = 9; kstep = 1; } else if ( maxMinSteps >= 4 ) { k0 = 2; kmax = 8; kstep = 2; } else if ( maxMinSteps >= 2 ) { k0 = 2; kmax = 5; kstep = 3; } else { k0 = 5; kmax = 5; kstep = 1; } QList minorTicks; for ( int i = 0; i < majorTicks.count(); i++ ) { const double v = majorTicks[i]; for ( int k = k0; k <= kmax; k += kstep ) minorTicks += v * double( k ); } return minorTicks; } else // major step > one decade { double minStep = divideInterval( stepSize, maxMinSteps ); if ( minStep == 0.0 ) return QList(); if ( minStep < 1.0 ) minStep = 1.0; // # subticks per interval int nMin = qRound( stepSize / minStep ) - 1; // Do the minor steps fit into the interval? if ( qwtFuzzyCompare( ( nMin + 1 ) * minStep, qAbs( stepSize ), stepSize ) > 0 ) { nMin = 0; } if ( nMin < 1 ) return QList(); // no subticks // substep factor = 10^substeps const qreal minFactor = qMax( qPow( 10.0, minStep ), qreal( 10.0 ) ); QList minorTicks; for ( int i = 0; i < majorTicks.count(); i++ ) { double val = majorTicks[i]; for ( int k = 0; k < nMin; k++ ) { val *= minFactor; minorTicks += val; } } return minorTicks; } } /*! \brief Align an interval to a step size The limits of an interval are aligned that both are integer multiples of the step size. \param interval Interval \param stepSize Step size \return Aligned interval */ QwtInterval QwtLog10ScaleEngine::align( const QwtInterval &interval, double stepSize ) const { const QwtInterval intv = log10( interval ); double x1 = QwtScaleArithmetic::floorEps( intv.minValue(), stepSize ); if ( qwtFuzzyCompare( interval.minValue(), x1, stepSize ) == 0 ) x1 = interval.minValue(); double x2 = QwtScaleArithmetic::ceilEps( intv.maxValue(), stepSize ); if ( qwtFuzzyCompare( interval.maxValue(), x2, stepSize ) == 0 ) x2 = interval.maxValue(); return pow10( QwtInterval( x1, x2 ) ); } /*! Return the interval [log10(interval.minValue(), log10(interval.maxValue] */ QwtInterval QwtLog10ScaleEngine::log10( const QwtInterval &interval ) const { return QwtInterval( ::log10( interval.minValue() ), ::log10( interval.maxValue() ) ); } /*! Return the interval [pow10(interval.minValue(), pow10(interval.maxValue] */ QwtInterval QwtLog10ScaleEngine::pow10( const QwtInterval &interval ) const { return QwtInterval( qPow( 10.0, interval.minValue() ), qPow( 10.0, interval.maxValue() ) ); } pcp-gui-1.5.11/src/libqwt/qwt_scale_map.cpp0000644000000000000000000002100412176111212015434 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_scale_map.h" #include #include #include #include #if QT_VERSION < 0x040601 #define qExp(x) ::exp(x) #endif //! Smallest allowed value for logarithmic scales: 1.0e-150 QT_STATIC_CONST_IMPL double QwtScaleMap::LogMin = 1.0e-150; //! Largest allowed value for logarithmic scales: 1.0e150 QT_STATIC_CONST_IMPL double QwtScaleMap::LogMax = 1.0e150; //! Constructor for a linear transformation QwtScaleTransformation::QwtScaleTransformation( Type type ): d_type( type ) { } //! Destructor QwtScaleTransformation::~QwtScaleTransformation() { } //! Create a clone of the transformation QwtScaleTransformation *QwtScaleTransformation::copy() const { return new QwtScaleTransformation( d_type ); } /*! \brief Transform a value from the coordinate system of a scale into the coordinate system of the paint device \param s Value related to the coordinate system of the scale \param s1 First border of the coordinate system of the scale \param s2 Second border of the coordinate system of the scale \param p1 First border of the coordinate system of the paint device \param p2 Second border of the coordinate system of the paint device \return
linear mapping:
p1 + (p2 - p1) / (s2 - s1) * (s - s1);
log10 mapping:
p1 + (p2 - p1) / log(s2 / s1) * log(s / s1);
*/ double QwtScaleTransformation::xForm( double s, double s1, double s2, double p1, double p2 ) const { if ( d_type == Log10 ) return p1 + ( p2 - p1 ) / log( s2 / s1 ) * log( s / s1 ); else return p1 + ( p2 - p1 ) / ( s2 - s1 ) * ( s - s1 ); } /*! \brief Transform a value from the coordinate system of the paint device into the coordinate system of a scale. \param p Value related to the coordinate system of the paint device \param p1 First border of the coordinate system of the paint device \param p2 Second border of the coordinate system of the paint device \param s1 First border of the coordinate system of the scale \param s2 Second border of the coordinate system of the scale \return
linear mapping:
s1 + ( s2 - s1 ) / ( p2 - p1 ) * ( p - p1 );
log10 mapping:
exp((p - p1) / (p2 - p1) * log(s2 / s1)) * s1;
*/ double QwtScaleTransformation::invXForm( double p, double p1, double p2, double s1, double s2 ) const { if ( d_type == Log10 ) return qExp( ( p - p1 ) / ( p2 - p1 ) * log( s2 / s1 ) ) * s1; else return s1 + ( s2 - s1 ) / ( p2 - p1 ) * ( p - p1 ); } /*! \brief Constructor The scale and paint device intervals are both set to [0,1]. */ QwtScaleMap::QwtScaleMap(): d_s1( 0.0 ), d_s2( 1.0 ), d_p1( 0.0 ), d_p2( 1.0 ), d_cnv( 1.0 ) { d_transformation = new QwtScaleTransformation( QwtScaleTransformation::Linear ); } //! Copy constructor QwtScaleMap::QwtScaleMap( const QwtScaleMap& other ): d_s1( other.d_s1 ), d_s2( other.d_s2 ), d_p1( other.d_p1 ), d_p2( other.d_p2 ), d_cnv( other.d_cnv ) { d_transformation = other.d_transformation->copy(); } /*! Destructor */ QwtScaleMap::~QwtScaleMap() { delete d_transformation; } //! Assignment operator QwtScaleMap &QwtScaleMap::operator=( const QwtScaleMap & other ) { d_s1 = other.d_s1; d_s2 = other.d_s2; d_p1 = other.d_p1; d_p2 = other.d_p2; d_cnv = other.d_cnv; delete d_transformation; d_transformation = other.d_transformation->copy(); return *this; } /*! Initialize the map with a transformation */ void QwtScaleMap::setTransformation( QwtScaleTransformation *transformation ) { if ( transformation == NULL ) return; if ( transformation != d_transformation ) { delete d_transformation; d_transformation = transformation; } setScaleInterval( d_s1, d_s2 ); } //! Get the transformation const QwtScaleTransformation *QwtScaleMap::transformation() const { return d_transformation; } /*! \brief Specify the borders of the scale interval \param s1 first border \param s2 second border \warning logarithmic scales might be aligned to [LogMin, LogMax] */ void QwtScaleMap::setScaleInterval( double s1, double s2 ) { if ( d_transformation->type() == QwtScaleTransformation::Log10 ) { if ( s1 < LogMin ) s1 = LogMin; else if ( s1 > LogMax ) s1 = LogMax; if ( s2 < LogMin ) s2 = LogMin; else if ( s2 > LogMax ) s2 = LogMax; } d_s1 = s1; d_s2 = s2; if ( d_transformation->type() != QwtScaleTransformation::Other ) newFactor(); } /*! \brief Specify the borders of the paint device interval \param p1 first border \param p2 second border */ void QwtScaleMap::setPaintInterval( double p1, double p2 ) { d_p1 = p1; d_p2 = p2; if ( d_transformation->type() != QwtScaleTransformation::Other ) newFactor(); } /*! \brief Re-calculate the conversion factor. */ void QwtScaleMap::newFactor() { d_cnv = 0.0; switch ( d_transformation->type() ) { case QwtScaleTransformation::Linear: { if ( d_s2 != d_s1 ) d_cnv = ( d_p2 - d_p1 ) / ( d_s2 - d_s1 ); break; } case QwtScaleTransformation::Log10: { if ( d_s1 != 0 ) d_cnv = ( d_p2 - d_p1 ) / log( d_s2 / d_s1 ); break; } default:; } } /*! Transform a rectangle from scale to paint coordinates \param xMap X map \param yMap Y map \param rect Rectangle in scale coordinates \return Rectangle in paint coordinates \sa invTransform() */ QRectF QwtScaleMap::transform( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect ) { double x1 = xMap.transform( rect.left() ); double x2 = xMap.transform( rect.right() ); double y1 = yMap.transform( rect.top() ); double y2 = yMap.transform( rect.bottom() ); if ( x2 < x1 ) qSwap( x1, x2 ); if ( y2 < y1 ) qSwap( y1, y2 ); if ( qwtFuzzyCompare( x1, 0.0, x2 - x1 ) == 0 ) x1 = 0.0; if ( qwtFuzzyCompare( x2, 0.0, x2 - x1 ) == 0 ) x2 = 0.0; if ( qwtFuzzyCompare( y1, 0.0, y2 - y1 ) == 0 ) y1 = 0.0; if ( qwtFuzzyCompare( y2, 0.0, y2 - y1 ) == 0 ) y2 = 0.0; return QRectF( x1, y1, x2 - x1 + 1, y2 - y1 + 1 ); } /*! Transform a rectangle from paint to scale coordinates \param xMap X map \param yMap Y map \param pos Position in paint coordinates \return Position in scale coordinates \sa transform() */ QPointF QwtScaleMap::invTransform( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QPointF &pos ) { return QPointF( xMap.invTransform( pos.x() ), yMap.invTransform( pos.y() ) ); } /*! Transform a point from scale to paint coordinates \param xMap X map \param yMap Y map \param pos Position in scale coordinates \return Position in paint coordinates \sa invTransform() */ QPointF QwtScaleMap::transform( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QPointF &pos ) { return QPointF( xMap.transform( pos.x() ), yMap.transform( pos.y() ) ); } /*! Transform a rectangle from paint to scale coordinates \param xMap X map \param yMap Y map \param rect Rectangle in paint coordinates \return Rectangle in scale coordinates \sa transform() */ QRectF QwtScaleMap::invTransform( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect ) { const double x1 = xMap.invTransform( rect.left() ); const double x2 = xMap.invTransform( rect.right() - 1 ); const double y1 = yMap.invTransform( rect.top() ); const double y2 = yMap.invTransform( rect.bottom() - 1 ); const QRectF r( x1, y1, x2 - x1, y2 - y1 ); return r.normalized(); } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<( QDebug debug, const QwtScaleMap &map ) { debug.nospace() << "QwtScaleMap(" << static_cast( map.transformation()->type() ) << ", s:" << map.s1() << "->" << map.s2() << ", p:" << map.p1() << "->" << map.p2() << ")"; return debug.space(); } #endif pcp-gui-1.5.11/src/libqwt/qwt_scale_widget.cpp0000644000000000000000000005267212176111212016161 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_scale_widget.h" #include "qwt_painter.h" #include "qwt_color_map.h" #include "qwt_scale_map.h" #include "qwt_math.h" #include "qwt_scale_div.h" #include "qwt_text.h" #include #include #include #include #include class QwtScaleWidget::PrivateData { public: PrivateData(): scaleDraw( NULL ) { colorBar.colorMap = NULL; } ~PrivateData() { delete scaleDraw; delete colorBar.colorMap; } QwtScaleDraw *scaleDraw; int borderDist[2]; int minBorderDist[2]; int scaleLength; int margin; int titleOffset; int spacing; QwtText title; QwtScaleWidget::LayoutFlags layoutFlags; struct t_colorBar { bool isEnabled; int width; QwtInterval interval; QwtColorMap *colorMap; } colorBar; }; /*! \brief Create a scale with the position QwtScaleWidget::Left \param parent Parent widget */ QwtScaleWidget::QwtScaleWidget( QWidget *parent ): QWidget( parent ) { initScale( QwtScaleDraw::LeftScale ); } /*! \brief Constructor \param align Alignment. \param parent Parent widget */ QwtScaleWidget::QwtScaleWidget( QwtScaleDraw::Alignment align, QWidget *parent ): QWidget( parent ) { initScale( align ); } //! Destructor QwtScaleWidget::~QwtScaleWidget() { delete d_data; } //! Initialize the scale void QwtScaleWidget::initScale( QwtScaleDraw::Alignment align ) { d_data = new PrivateData; d_data->layoutFlags = 0; if ( align == QwtScaleDraw::RightScale ) d_data->layoutFlags |= TitleInverted; d_data->borderDist[0] = 0; d_data->borderDist[1] = 0; d_data->minBorderDist[0] = 0; d_data->minBorderDist[1] = 0; d_data->margin = 4; d_data->titleOffset = 0; d_data->spacing = 2; d_data->scaleDraw = new QwtScaleDraw; d_data->scaleDraw->setAlignment( align ); d_data->scaleDraw->setLength( 10 ); d_data->colorBar.colorMap = new QwtLinearColorMap(); d_data->colorBar.isEnabled = false; d_data->colorBar.width = 10; const int flags = Qt::AlignHCenter | Qt::TextExpandTabs | Qt::TextWordWrap; d_data->title.setRenderFlags( flags ); d_data->title.setFont( font() ); QSizePolicy policy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ); if ( d_data->scaleDraw->orientation() == Qt::Vertical ) policy.transpose(); setSizePolicy( policy ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); } /*! Toggle an layout flag \param flag Layout flag \param on true/false \sa testLayoutFlag(), LayoutFlag */ void QwtScaleWidget::setLayoutFlag( LayoutFlag flag, bool on ) { if ( ( ( d_data->layoutFlags & flag ) != 0 ) != on ) { if ( on ) d_data->layoutFlags |= flag; else d_data->layoutFlags &= ~flag; } } /*! Test a layout flag \param flag Layout flag \return true/false \sa setLayoutFlag(), LayoutFlag */ bool QwtScaleWidget::testLayoutFlag( LayoutFlag flag ) const { return ( d_data->layoutFlags & flag ); } /*! Give title new text contents \param title New title \sa title(), setTitle(const QwtText &); */ void QwtScaleWidget::setTitle( const QString &title ) { if ( d_data->title.text() != title ) { d_data->title.setText( title ); layoutScale(); } } /*! Give title new text contents \param title New title \sa title() \warning The title flags are interpreted in direction of the label, AlignTop, AlignBottom can't be set as the title will always be aligned to the scale. */ void QwtScaleWidget::setTitle( const QwtText &title ) { QwtText t = title; const int flags = title.renderFlags() & ~( Qt::AlignTop | Qt::AlignBottom ); t.setRenderFlags( flags ); if ( t != d_data->title ) { d_data->title = t; layoutScale(); } } /*! Change the alignment \param alignment New alignment \sa alignment() */ void QwtScaleWidget::setAlignment( QwtScaleDraw::Alignment alignment ) { if ( d_data->scaleDraw ) d_data->scaleDraw->setAlignment( alignment ); if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) ) { QSizePolicy policy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ); if ( d_data->scaleDraw->orientation() == Qt::Vertical ) policy.transpose(); setSizePolicy( policy ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); } layoutScale(); } /*! \return position \sa setPosition() */ QwtScaleDraw::Alignment QwtScaleWidget::alignment() const { if ( !scaleDraw() ) return QwtScaleDraw::LeftScale; return scaleDraw()->alignment(); } /*! Specify distances of the scale's endpoints from the widget's borders. The actual borders will never be less than minimum border distance. \param dist1 Left or top Distance \param dist2 Right or bottom distance \sa borderDist() */ void QwtScaleWidget::setBorderDist( int dist1, int dist2 ) { if ( dist1 != d_data->borderDist[0] || dist2 != d_data->borderDist[1] ) { d_data->borderDist[0] = dist1; d_data->borderDist[1] = dist2; layoutScale(); } } /*! \brief Specify the margin to the colorBar/base line. \param margin Margin \sa margin() */ void QwtScaleWidget::setMargin( int margin ) { margin = qMax( 0, margin ); if ( margin != d_data->margin ) { d_data->margin = margin; layoutScale(); } } /*! \brief Specify the distance between color bar, scale and title \param spacing Spacing \sa spacing() */ void QwtScaleWidget::setSpacing( int spacing ) { spacing = qMax( 0, spacing ); if ( spacing != d_data->spacing ) { d_data->spacing = spacing; layoutScale(); } } /*! \brief Change the alignment for the labels. \sa QwtScaleDraw::setLabelAlignment(), setLabelRotation() */ void QwtScaleWidget::setLabelAlignment( Qt::Alignment alignment ) { d_data->scaleDraw->setLabelAlignment( alignment ); layoutScale(); } /*! \brief Change the rotation for the labels. See QwtScaleDraw::setLabelRotation(). \param rotation Rotation \sa QwtScaleDraw::setLabelRotation(), setLabelFlags() */ void QwtScaleWidget::setLabelRotation( double rotation ) { d_data->scaleDraw->setLabelRotation( rotation ); layoutScale(); } /*! Set a scale draw sd has to be created with new and will be deleted in ~QwtScaleWidget() or the next call of setScaleDraw(). \param sd ScaleDraw object \sa scaleDraw() */ void QwtScaleWidget::setScaleDraw( QwtScaleDraw *sd ) { if ( sd == NULL || sd == d_data->scaleDraw ) return; if ( d_data->scaleDraw ) sd->setAlignment( d_data->scaleDraw->alignment() ); delete d_data->scaleDraw; d_data->scaleDraw = sd; layoutScale(); } /*! scaleDraw of this scale \sa setScaleDraw(), QwtScaleDraw::setScaleDraw() */ const QwtScaleDraw *QwtScaleWidget::scaleDraw() const { return d_data->scaleDraw; } /*! scaleDraw of this scale \sa QwtScaleDraw::setScaleDraw() */ QwtScaleDraw *QwtScaleWidget::scaleDraw() { return d_data->scaleDraw; } /*! \return title \sa setTitle() */ QwtText QwtScaleWidget::title() const { return d_data->title; } /*! \return start border distance \sa setBorderDist() */ int QwtScaleWidget::startBorderDist() const { return d_data->borderDist[0]; } /*! \return end border distance \sa setBorderDist() */ int QwtScaleWidget::endBorderDist() const { return d_data->borderDist[1]; } /*! \return margin \sa setMargin() */ int QwtScaleWidget::margin() const { return d_data->margin; } /*! \return distance between scale and title \sa setMargin() */ int QwtScaleWidget::spacing() const { return d_data->spacing; } /*! \brief paintEvent */ void QwtScaleWidget::paintEvent( QPaintEvent *event ) { QPainter painter( this ); painter.setClipRegion( event->region() ); QStyleOption opt; opt.init(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); draw( &painter ); } /*! \brief draw the scale */ void QwtScaleWidget::draw( QPainter *painter ) const { d_data->scaleDraw->draw( painter, palette() ); if ( d_data->colorBar.isEnabled && d_data->colorBar.width > 0 && d_data->colorBar.interval.isValid() ) { drawColorBar( painter, colorBarRect( contentsRect() ) ); } QRect r = contentsRect(); if ( d_data->scaleDraw->orientation() == Qt::Horizontal ) { r.setLeft( r.left() + d_data->borderDist[0] ); r.setWidth( r.width() - d_data->borderDist[1] ); } else { r.setTop( r.top() + d_data->borderDist[0] ); r.setHeight( r.height() - d_data->borderDist[1] ); } if ( !d_data->title.isEmpty() ) drawTitle( painter, d_data->scaleDraw->alignment(), r ); } /*! Calculate the the rectangle for the color bar \param rect Bounding rectangle for all components of the scale \return Rectabgle for the color bar */ QRectF QwtScaleWidget::colorBarRect( const QRectF& rect ) const { QRectF cr = rect; if ( d_data->scaleDraw->orientation() == Qt::Horizontal ) { cr.setLeft( cr.left() + d_data->borderDist[0] ); cr.setWidth( cr.width() - d_data->borderDist[1] + 1 ); } else { cr.setTop( cr.top() + d_data->borderDist[0] ); cr.setHeight( cr.height() - d_data->borderDist[1] + 1 ); } switch ( d_data->scaleDraw->alignment() ) { case QwtScaleDraw::LeftScale: { cr.setLeft( cr.right() - d_data->margin - d_data->colorBar.width ); cr.setWidth( d_data->colorBar.width ); break; } case QwtScaleDraw::RightScale: { cr.setLeft( cr.left() + d_data->margin ); cr.setWidth( d_data->colorBar.width ); break; } case QwtScaleDraw::BottomScale: { cr.setTop( cr.top() + d_data->margin ); cr.setHeight( d_data->colorBar.width ); break; } case QwtScaleDraw::TopScale: { cr.setTop( cr.bottom() - d_data->margin - d_data->colorBar.width ); cr.setHeight( d_data->colorBar.width ); break; } } return cr; } /*! Event handler for resize event \param event Resize event */ void QwtScaleWidget::resizeEvent( QResizeEvent *event ) { Q_UNUSED( event ); layoutScale( false ); } /*! Recalculate the scale's geometry and layout based on the current rect and fonts. \param update_geometry Notify the layout system and call update to redraw the scale */ void QwtScaleWidget::layoutScale( bool update_geometry ) { int bd0, bd1; getBorderDistHint( bd0, bd1 ); if ( d_data->borderDist[0] > bd0 ) bd0 = d_data->borderDist[0]; if ( d_data->borderDist[1] > bd1 ) bd1 = d_data->borderDist[1]; int colorBarWidth = 0; if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() ) colorBarWidth = d_data->colorBar.width + d_data->spacing; const QRectF r = contentsRect(); double x, y, length; if ( d_data->scaleDraw->orientation() == Qt::Vertical ) { y = r.top() + bd0; length = r.height() - ( bd0 + bd1 ); if ( d_data->scaleDraw->alignment() == QwtScaleDraw::LeftScale ) x = r.right() - 1.0 - d_data->margin - colorBarWidth; else x = r.left() + d_data->margin + colorBarWidth; } else { x = r.left() + bd0; length = r.width() - ( bd0 + bd1 ); if ( d_data->scaleDraw->alignment() == QwtScaleDraw::BottomScale ) y = r.top() + d_data->margin + colorBarWidth; else y = r.bottom() - 1.0 - d_data->margin - colorBarWidth; } d_data->scaleDraw->move( x, y ); d_data->scaleDraw->setLength( length ); const int extent = qCeil( d_data->scaleDraw->extent( font() ) ); d_data->titleOffset = d_data->margin + d_data->spacing + colorBarWidth + extent; if ( update_geometry ) { updateGeometry(); update(); } } /*! Draw the color bar of the scale widget \param painter Painter \param rect Bounding rectangle for the color bar \sa setColorBarEnabled() */ void QwtScaleWidget::drawColorBar( QPainter *painter, const QRectF& rect ) const { if ( !d_data->colorBar.interval.isValid() ) return; const QwtScaleDraw* sd = d_data->scaleDraw; QwtPainter::drawColorBar( painter, *d_data->colorBar.colorMap, d_data->colorBar.interval.normalized(), sd->scaleMap(), sd->orientation(), rect ); } /*! Rotate and paint a title according to its position into a given rectangle. \param painter Painter \param align Alignment \param rect Bounding rectangle */ void QwtScaleWidget::drawTitle( QPainter *painter, QwtScaleDraw::Alignment align, const QRectF &rect ) const { QRectF r = rect; double angle; int flags = d_data->title.renderFlags() & ~( Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter ); switch ( align ) { case QwtScaleDraw::LeftScale: angle = -90.0; flags |= Qt::AlignTop; r.setRect( r.left(), r.bottom(), r.height(), r.width() - d_data->titleOffset ); break; case QwtScaleDraw::RightScale: angle = -90.0; flags |= Qt::AlignTop; r.setRect( r.left() + d_data->titleOffset, r.bottom(), r.height(), r.width() - d_data->titleOffset ); break; case QwtScaleDraw::BottomScale: angle = 0.0; flags |= Qt::AlignBottom; r.setTop( r.top() + d_data->titleOffset ); break; case QwtScaleDraw::TopScale: default: angle = 0.0; flags |= Qt::AlignTop; r.setBottom( r.bottom() - d_data->titleOffset ); break; } if ( d_data->layoutFlags & TitleInverted ) { if ( align == QwtScaleDraw::LeftScale || align == QwtScaleDraw::RightScale ) { angle = -angle; r.setRect( r.x() + r.height(), r.y() - r.width(), r.width(), r.height() ); } } painter->save(); painter->setFont( font() ); painter->setPen( palette().color( QPalette::Text ) ); painter->translate( r.x(), r.y() ); if ( angle != 0.0 ) painter->rotate( angle ); QwtText title = d_data->title; title.setRenderFlags( flags ); title.draw( painter, QRectF( 0.0, 0.0, r.width(), r.height() ) ); painter->restore(); } /*! \brief Notify a change of the scale This virtual function can be overloaded by derived classes. The default implementation updates the geometry and repaints the widget. */ void QwtScaleWidget::scaleChange() { layoutScale(); } /*! \return a size hint */ QSize QwtScaleWidget::sizeHint() const { return minimumSizeHint(); } /*! \return a minimum size hint */ QSize QwtScaleWidget::minimumSizeHint() const { const Qt::Orientation o = d_data->scaleDraw->orientation(); // Border Distance cannot be less than the scale borderDistHint // Note, the borderDistHint is already included in minHeight/minWidth int length = 0; int mbd1, mbd2; getBorderDistHint( mbd1, mbd2 ); length += qMax( 0, d_data->borderDist[0] - mbd1 ); length += qMax( 0, d_data->borderDist[1] - mbd2 ); length += d_data->scaleDraw->minLength( font() ); int dim = dimForLength( length, font() ); if ( length < dim ) { // compensate for long titles length = dim; dim = dimForLength( length, font() ); } QSize size( length + 2, dim ); if ( o == Qt::Vertical ) size.transpose(); int left, right, top, bottom; getContentsMargins( &left, &top, &right, &bottom ); return size + QSize( left + right, top + bottom ); } /*! \brief Find the height of the title for a given width. \param width Width \return height Height */ int QwtScaleWidget::titleHeightForWidth( int width ) const { return qCeil( d_data->title.heightForWidth( width, font() ) ); } /*! \brief Find the minimum dimension for a given length. dim is the height, length the width seen in direction of the title. \param length width for horizontal, height for vertical scales \param scaleFont Font of the scale \return height for horizontal, width for vertical scales */ int QwtScaleWidget::dimForLength( int length, const QFont &scaleFont ) const { const int extent = qCeil( d_data->scaleDraw->extent( scaleFont ) ); int dim = d_data->margin + extent + 1; if ( !d_data->title.isEmpty() ) dim += titleHeightForWidth( length ) + d_data->spacing; if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() ) dim += d_data->colorBar.width + d_data->spacing; return dim; } /*! \brief Calculate a hint for the border distances. This member function calculates the distance of the scale's endpoints from the widget borders which is required for the mark labels to fit into the widget. The maximum of this distance an the minimum border distance is returned. \warning
  • The minimum border distance depends on the font.
\sa setMinBorderDist(), getMinBorderDist(), setBorderDist() */ void QwtScaleWidget::getBorderDistHint( int &start, int &end ) const { d_data->scaleDraw->getBorderDistHint( font(), start, end ); if ( start < d_data->minBorderDist[0] ) start = d_data->minBorderDist[0]; if ( end < d_data->minBorderDist[1] ) end = d_data->minBorderDist[1]; } /*! Set a minimum value for the distances of the scale's endpoints from the widget borders. This is useful to avoid that the scales are "jumping", when the tick labels or their positions change often. \param start Minimum for the start border \param end Minimum for the end border \sa getMinBorderDist(), getBorderDistHint() */ void QwtScaleWidget::setMinBorderDist( int start, int end ) { d_data->minBorderDist[0] = start; d_data->minBorderDist[1] = end; } /*! Get the minimum value for the distances of the scale's endpoints from the widget borders. \sa setMinBorderDist(), getBorderDistHint() */ void QwtScaleWidget::getMinBorderDist( int &start, int &end ) const { start = d_data->minBorderDist[0]; end = d_data->minBorderDist[1]; } /*! \brief Assign a scale division The scale division determines where to set the tick marks. \param transformation Transformation, needed to translate between scale and pixal values \param scaleDiv Scale Division \sa For more information about scale divisions, see QwtScaleDiv. */ void QwtScaleWidget::setScaleDiv( QwtScaleTransformation *transformation, const QwtScaleDiv &scaleDiv ) { QwtScaleDraw *sd = d_data->scaleDraw; if ( sd->scaleDiv() != scaleDiv || sd->scaleMap().transformation()->type() != transformation->type() ) { sd->setTransformation( transformation ); sd->setScaleDiv( scaleDiv ); layoutScale(); Q_EMIT scaleDivChanged(); } else { /* The transformation doesn't anything different as the previous one. So we better throw it silently away instead of initiating heavy updates */ delete transformation; } } /*! En/disable a color bar associated to the scale \sa isColorBarEnabled(), setColorBarWidth() */ void QwtScaleWidget::setColorBarEnabled( bool on ) { if ( on != d_data->colorBar.isEnabled ) { d_data->colorBar.isEnabled = on; layoutScale(); } } /*! \return true, when the color bar is enabled \sa setColorBarEnabled(), setColorBarWidth() */ bool QwtScaleWidget::isColorBarEnabled() const { return d_data->colorBar.isEnabled; } /*! Set the width of the color bar \param width Width \sa colorBarWidth(), setColorBarEnabled() */ void QwtScaleWidget::setColorBarWidth( int width ) { if ( width != d_data->colorBar.width ) { d_data->colorBar.width = width; if ( isColorBarEnabled() ) layoutScale(); } } /*! \return Width of the color bar \sa setColorBarEnabled(), setColorBarEnabled() */ int QwtScaleWidget::colorBarWidth() const { return d_data->colorBar.width; } /*! \return Value interval for the color bar \sa setColorMap(), colorMap() */ QwtInterval QwtScaleWidget::colorBarInterval() const { return d_data->colorBar.interval; } /*! Set the color map and value interval, that are used for displaying the color bar. \param interval Value interval \param colorMap Color map \sa colorMap(), colorBarInterval() */ void QwtScaleWidget::setColorMap( const QwtInterval &interval, QwtColorMap *colorMap ) { d_data->colorBar.interval = interval; if ( colorMap != d_data->colorBar.colorMap ) { delete d_data->colorBar.colorMap; d_data->colorBar.colorMap = colorMap; } if ( isColorBarEnabled() ) layoutScale(); } /*! \return Color map \sa setColorMap(), colorBarInterval() */ const QwtColorMap *QwtScaleWidget::colorMap() const { return d_data->colorBar.colorMap; } pcp-gui-1.5.11/src/libqwt/qwt_series_data.cpp0000644000000000000000000003312612176111212016003 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_series_data.h" #include "qwt_math.h" #include static inline QRectF qwtBoundingRect( const QPointF &sample ) { return QRectF( sample.x(), sample.y(), 0.0, 0.0 ); } static inline QRectF qwtBoundingRect( const QwtPoint3D &sample ) { return QRectF( sample.x(), sample.y(), 0.0, 0.0 ); } static inline QRectF qwtBoundingRect( const QwtPointPolar &sample ) { return QRectF( sample.azimuth(), sample.radius(), 0.0, 0.0 ); } static inline QRectF qwtBoundingRect( const QwtIntervalSample &sample ) { return QRectF( sample.interval.minValue(), sample.value, sample.interval.maxValue() - sample.interval.minValue(), 0.0 ); } static inline QRectF qwtBoundingRect( const QwtSetSample &sample ) { double minX = sample.set[0]; double maxX = sample.set[0]; for ( int i = 1; i < sample.set.size(); i++ ) { if ( sample.set[i] < minX ) minX = sample.set[i]; if ( sample.set[i] > maxX ) maxX = sample.set[i]; } double minY = sample.value; double maxY = sample.value; return QRectF( minX, minY, maxX - minX, maxY - minY ); } /*! \brief Calculate the bounding rect of a series subset Slow implementation, that iterates over the series. \param series Series \param from Index of the first sample, <= 0 means from the beginning \param to Index of the last sample, < 0 means to the end \return Bounding rectangle */ template QRectF qwtBoundingRectT( const QwtSeriesData& series, int from, int to ) { QRectF boundingRect( 1.0, 1.0, -2.0, -2.0 ); // invalid; if ( from < 0 ) from = 0; if ( to < 0 ) to = series.size() - 1; if ( to < from ) return boundingRect; int i; for ( i = from; i <= to; i++ ) { const QRectF rect = qwtBoundingRect( series.sample( i ) ); if ( rect.width() >= 0.0 && rect.height() >= 0.0 ) { boundingRect = rect; i++; break; } } for ( ; i <= to; i++ ) { const QRectF rect = qwtBoundingRect( series.sample( i ) ); if ( rect.width() >= 0.0 && rect.height() >= 0.0 ) { if (!qIsNaN(rect.left())) boundingRect.setLeft( qMin( boundingRect.left(), rect.left() ) ); if (!qIsNaN(rect.right())) boundingRect.setRight( qMax( boundingRect.right(), rect.right() ) ); if (!qIsNaN(rect.top())) boundingRect.setTop( qMin( boundingRect.top(), rect.top() ) ); if (!qIsNaN(rect.bottom())) boundingRect.setBottom( qMax( boundingRect.bottom(), rect.bottom() ) ); } } return boundingRect; } /*! \brief Calculate the bounding rect of a series subset Slow implementation, that iterates over the series. \param series Series \param from Index of the first sample, <= 0 means from the beginning \param to Index of the last sample, < 0 means to the end \return Bounding rectangle */ QRectF qwtBoundingRect( const QwtSeriesData &series, int from, int to ) { return qwtBoundingRectT( series, from, to ); } /*! \brief Calculate the bounding rect of a series subset Slow implementation, that iterates over the series. \param series Series \param from Index of the first sample, <= 0 means from the beginning \param to Index of the last sample, < 0 means to the end \return Bounding rectangle */ QRectF qwtBoundingRect( const QwtSeriesData &series, int from, int to ) { return qwtBoundingRectT( series, from, to ); } /*! \brief Calculate the bounding rect of a series subset The horizontal coordinates represent the azimuth, the vertical coordinates the radius. Slow implementation, that iterates over the series. \param series Series \param from Index of the first sample, <= 0 means from the beginning \param to Index of the last sample, < 0 means to the end \return Bounding rectangle */ QRectF qwtBoundingRect( const QwtSeriesData &series, int from, int to ) { return qwtBoundingRectT( series, from, to ); } /*! \brief Calculate the bounding rect of a series subset Slow implementation, that iterates over the series. \param series Series \param from Index of the first sample, <= 0 means from the beginning \param to Index of the last sample, < 0 means to the end \return Bounding rectangle */ QRectF qwtBoundingRect( const QwtSeriesData& series, int from, int to ) { return qwtBoundingRectT( series, from, to ); } /*! \brief Calculate the bounding rect of a series subset Slow implementation, that iterates over the series. \param series Series \param from Index of the first sample, <= 0 means from the beginning \param to Index of the last sample, < 0 means to the end \return Bounding rectangle */ QRectF qwtBoundingRect( const QwtSeriesData& series, int from, int to ) { return qwtBoundingRectT( series, from, to ); } /*! Constructor \param samples Samples */ QwtPointSeriesData::QwtPointSeriesData( const QVector &samples ): QwtArraySeriesData( samples ) { } /*! \brief Calculate the bounding rect The bounding rectangle is calculated once by iterating over all points and is stored for all following requests. \return Bounding rectangle */ QRectF QwtPointSeriesData::boundingRect() const { if ( d_boundingRect.width() < 0.0 ) d_boundingRect = qwtBoundingRect( *this ); return d_boundingRect; } /*! Constructor \param samples Samples */ QwtPoint3DSeriesData::QwtPoint3DSeriesData( const QVector &samples ): QwtArraySeriesData( samples ) { } /*! \brief Calculate the bounding rect The bounding rectangle is calculated once by iterating over all points and is stored for all following requests. \return Bounding rectangle */ QRectF QwtPoint3DSeriesData::boundingRect() const { if ( d_boundingRect.width() < 0.0 ) d_boundingRect = qwtBoundingRect( *this ); return d_boundingRect; } /*! Constructor \param samples Samples */ QwtIntervalSeriesData::QwtIntervalSeriesData( const QVector &samples ): QwtArraySeriesData( samples ) { } /*! \brief Calculate the bounding rect The bounding rectangle is calculated once by iterating over all points and is stored for all following requests. \return Bounding rectangle */ QRectF QwtIntervalSeriesData::boundingRect() const { if ( d_boundingRect.width() < 0.0 ) d_boundingRect = qwtBoundingRect( *this ); return d_boundingRect; } /*! Constructor \param samples Samples */ QwtSetSeriesData::QwtSetSeriesData( const QVector &samples ): QwtArraySeriesData( samples ) { } /*! \brief Calculate the bounding rect The bounding rectangle is calculated once by iterating over all points and is stored for all following requests. \return Bounding rectangle */ QRectF QwtSetSeriesData::boundingRect() const { if ( d_boundingRect.width() < 0.0 ) d_boundingRect = qwtBoundingRect( *this ); return d_boundingRect; } /*! Constructor \param x Array of x values \param y Array of y values \sa QwtPlotCurve::setData(), QwtPlotCurve::setSamples() */ QwtPointArrayData::QwtPointArrayData( const QVector &x, const QVector &y ): d_x( x ), d_y( y ) { } /*! Constructor \param x Array of x values \param y Array of y values \param size Size of the x and y arrays \sa QwtPlotCurve::setData(), QwtPlotCurve::setSamples() */ QwtPointArrayData::QwtPointArrayData( const double *x, const double *y, size_t size ) { d_x.resize( size ); qMemCopy( d_x.data(), x, size * sizeof( double ) ); d_y.resize( size ); qMemCopy( d_y.data(), y, size * sizeof( double ) ); } /*! \brief Calculate the bounding rect The bounding rectangle is calculated once by iterating over all points and is stored for all following requests. \return Bounding rectangle */ QRectF QwtPointArrayData::boundingRect() const { if ( d_boundingRect.width() < 0 ) d_boundingRect = qwtBoundingRect( *this ); return d_boundingRect; } //! \return Size of the data set size_t QwtPointArrayData::size() const { return qMin( d_x.size(), d_y.size() ); } /*! Return the sample at position i \param i Index \return Sample at position i */ QPointF QwtPointArrayData::sample( size_t i ) const { return QPointF( d_x[int( i )], d_y[int( i )] ); } //! \return Array of the x-values const QVector &QwtPointArrayData::xData() const { return d_x; } //! \return Array of the y-values const QVector &QwtPointArrayData::yData() const { return d_y; } /*! Constructor \param x Array of x values \param y Array of y values \param size Size of the x and y arrays \warning The programmer must assure that the memory blocks referenced by the pointers remain valid during the lifetime of the QwtPlotCPointer object. \sa QwtPlotCurve::setData(), QwtPlotCurve::setRawSamples() */ QwtCPointerData::QwtCPointerData( const double *x, const double *y, size_t size ): d_x( x ), d_y( y ), d_size( size ) { } /*! \brief Calculate the bounding rect The bounding rectangle is calculated once by iterating over all points and is stored for all following requests. \return Bounding rectangle */ QRectF QwtCPointerData::boundingRect() const { if ( d_boundingRect.width() < 0 ) d_boundingRect = qwtBoundingRect( *this ); return d_boundingRect; } //! \return Size of the data set size_t QwtCPointerData::size() const { return d_size; } /*! Return the sample at position i \param i Index \return Sample at position i */ QPointF QwtCPointerData::sample( size_t i ) const { return QPointF( d_x[int( i )], d_y[int( i )] ); } //! \return Array of the x-values const double *QwtCPointerData::xData() const { return d_x; } //! \return Array of the y-values const double *QwtCPointerData::yData() const { return d_y; } /*! Constructor \param size Number of points \param interval Bounding interval for the points \sa setInterval(), setSize() */ QwtSyntheticPointData::QwtSyntheticPointData( size_t size, const QwtInterval &interval ): d_size( size ), d_interval( interval ) { } /*! Change the number of points \param size Number of points \sa size(), setInterval() */ void QwtSyntheticPointData::setSize( size_t size ) { d_size = size; } /*! \return Number of points \sa setSize(), interval() */ size_t QwtSyntheticPointData::size() const { return d_size; } /*! Set the bounding interval \param interval Interval \sa interval(), setSize() */ void QwtSyntheticPointData::setInterval( const QwtInterval &interval ) { d_interval = interval.normalized(); } /*! \return Bounding interval \sa setInterval(), size() */ QwtInterval QwtSyntheticPointData::interval() const { return d_interval; } /*! Set a the "rect of interest" QwtPlotSeriesItem defines the current area of the plot canvas as "rect of interest" ( QwtPlotSeriesItem::updateScaleDiv() ). If interval().isValid() == false the x values are calculated in the interval rect.left() -> rect.right(). \sa rectOfInterest() */ void QwtSyntheticPointData::setRectOfInterest( const QRectF &rect ) { d_rectOfInterest = rect; d_intervalOfInterest = QwtInterval( rect.left(), rect.right() ).normalized(); } /*! \return "rect of interest" \sa setRectOfInterest() */ QRectF QwtSyntheticPointData::rectOfInterest() const { return d_rectOfInterest; } /*! \brief Calculate the bounding rect This implementation iterates over all points, what could often be implemented much faster using the characteristics of the series. When there are many points it is recommended to overload and reimplement this method using the characteristics of the series ( if possible ). \return Bounding rectangle */ QRectF QwtSyntheticPointData::boundingRect() const { if ( d_size == 0 || !( d_interval.isValid() || d_intervalOfInterest.isValid() ) ) { return QRectF( 1.0, 1.0, -2.0, -2.0 ); // something invalid } return qwtBoundingRect( *this ); } /*! Calculate the point from an index \param index Index \return QPointF(x(index), y(x(index))); \warning For invalid indices ( index < 0 || index >= size() ) (0, 0) is returned. */ QPointF QwtSyntheticPointData::sample( size_t index ) const { if ( index >= d_size ) return QPointF( 0, 0 ); const double xValue = x( index ); const double yValue = y( xValue ); return QPointF( xValue, yValue ); } /*! Calculate a x-value from an index x values are calculated by deviding an interval into equidistant steps. If !interval().isValid() the interval is calculated from the "rect of interest". \sa interval(), rectOfInterest(), y() */ double QwtSyntheticPointData::x( uint index ) const { const QwtInterval &interval = d_interval.isValid() ? d_interval : d_intervalOfInterest; if ( !interval.isValid() || d_size == 0 || index >= d_size ) return 0.0; const double dx = interval.width() / d_size; return interval.minValue() + index * dx; } pcp-gui-1.5.11/src/libqwt/qwt_slider.cpp0000644000000000000000000005015412176111212015002 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_slider.h" #include "qwt_painter.h" #include "qwt_scale_draw.h" #include "qwt_scale_map.h" #include #include #include #include #include #include #include #include class QwtSlider::PrivateData { public: QRect sliderRect; QSize handleSize; int borderWidth; int spacing; QwtSlider::ScalePos scalePos; QwtSlider::BackgroundStyles bgStyle; /* Scale and values might have different maps. This is confusing and I can't see strong arguments for such a feature. TODO ... */ QwtScaleMap map; // linear map mutable QSize sizeHintCache; }; /*! \brief Constructor \param parent parent widget \param orientation Orientation of the slider. Can be Qt::Horizontal or Qt::Vertical. Defaults to Qt::Horizontal. \param scalePos Position of the scale. Defaults to QwtSlider::NoScale. \param bgStyle Background style. QwtSlider::Trough draws the slider button in a trough, QwtSlider::Slot draws a slot underneath the button. An or-combination of both may also be used. The default is QwtSlider::Trough. QwtSlider enforces valid combinations of its orientation and scale position. If the combination is invalid, the scale position will be set to NoScale. Valid combinations are: - Qt::Horizonal with NoScale, TopScale, or BottomScale; - Qt::Vertical with NoScale, LeftScale, or RightScale. */ QwtSlider::QwtSlider( QWidget *parent, Qt::Orientation orientation, ScalePos scalePos, BackgroundStyles bgStyle ): QwtAbstractSlider( orientation, parent ) { initSlider( orientation, scalePos, bgStyle ); } void QwtSlider::initSlider( Qt::Orientation orientation, ScalePos scalePos, BackgroundStyles bgStyle ) { if ( orientation == Qt::Vertical ) setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding ); else setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); d_data = new QwtSlider::PrivateData; d_data->borderWidth = 2; d_data->spacing = 4; d_data->scalePos = scalePos; d_data->bgStyle = bgStyle; const int handleThickness = 16; d_data->handleSize.setWidth( 2 * handleThickness ); d_data->handleSize.setHeight( handleThickness ); if ( !( bgStyle & QwtSlider::Trough ) ) d_data->handleSize.transpose(); if ( orientation == Qt::Vertical ) d_data->handleSize.transpose(); d_data->sliderRect.setRect( 0, 0, 8, 8 ); QwtScaleDraw::Alignment align; if ( orientation == Qt::Vertical ) { // enforce a valid combination of scale position and orientation if ( ( d_data->scalePos == QwtSlider::BottomScale ) || ( d_data->scalePos == QwtSlider::TopScale ) ) { d_data->scalePos = NoScale; } // adopt the policy of layoutSlider (NoScale lays out like Left) if ( d_data->scalePos == QwtSlider::RightScale ) align = QwtScaleDraw::RightScale; else align = QwtScaleDraw::LeftScale; } else { // enforce a valid combination of scale position and orientation if ( ( d_data->scalePos == QwtSlider::LeftScale ) || ( d_data->scalePos == QwtSlider::RightScale ) ) { d_data->scalePos = QwtSlider::NoScale; } // adopt the policy of layoutSlider (NoScale lays out like Bottom) if ( d_data->scalePos == QwtSlider::TopScale ) align = QwtScaleDraw::TopScale; else align = QwtScaleDraw::BottomScale; } scaleDraw()->setAlignment( align ); scaleDraw()->setLength( 100 ); setRange( 0.0, 100.0, 1.0 ); setValue( 0.0 ); } QwtSlider::~QwtSlider() { delete d_data; } /*! \brief Set the orientation. \param o Orientation. Allowed values are Qt::Horizontal and Qt::Vertical. If the new orientation and the old scale position are an invalid combination, the scale position will be set to QwtSlider::NoScale. \sa QwtAbstractSlider::orientation() */ void QwtSlider::setOrientation( Qt::Orientation o ) { if ( o == orientation() ) return; if ( o == Qt::Horizontal ) { if ( d_data->scalePos == LeftScale || d_data->scalePos == RightScale ) { d_data->scalePos = NoScale; } } else // if (o == Qt::Vertical) { if ( d_data->scalePos == BottomScale || d_data->scalePos == TopScale ) { d_data->scalePos = NoScale; } } if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) ) { QSizePolicy sp = sizePolicy(); sp.transpose(); setSizePolicy( sp ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); } QwtAbstractSlider::setOrientation( o ); layoutSlider( true ); } /*! \brief Change the scale position (and slider orientation). \param scalePos Position of the scale. A valid combination of scale position and orientation is enforced: - if the new scale position is Left or Right, the scale orientation will become Qt::Vertical; - if the new scale position is Bottom or Top the scale orientation will become Qt::Horizontal; - if the new scale position is QwtSlider::NoScale, the scale orientation will not change. */ void QwtSlider::setScalePosition( ScalePos scalePos ) { if ( d_data->scalePos == scalePos ) return; d_data->scalePos = scalePos; switch ( d_data->scalePos ) { case QwtSlider::BottomScale: { setOrientation( Qt::Horizontal ); scaleDraw()->setAlignment( QwtScaleDraw::BottomScale ); break; } case QwtSlider::TopScale: { setOrientation( Qt::Horizontal ); scaleDraw()->setAlignment( QwtScaleDraw::TopScale ); break; } case QwtSlider::LeftScale: { setOrientation( Qt::Vertical ); scaleDraw()->setAlignment( QwtScaleDraw::LeftScale ); break; } case RightScale: { QwtSlider::setOrientation( Qt::Vertical ); scaleDraw()->setAlignment( QwtScaleDraw::RightScale ); break; } default: { // nothing } } layoutSlider( true ); } //! Return the scale position. QwtSlider::ScalePos QwtSlider::scalePosition() const { return d_data->scalePos; } /*! \brief Change the slider's border width \param width Border width */ void QwtSlider::setBorderWidth( int width ) { if ( width < 0 ) width = 0; if ( width != d_data->borderWidth ) { d_data->borderWidth = width; layoutSlider( true ); } } /*! \return the border width. \sa setBorderWidth() */ int QwtSlider::borderWidth() const { return d_data->borderWidth; } /*! \brief Change the spacing between pipe and scale A spacing of 0 means, that the backbone of the scale is below the trough. The default setting is 4 pixels. \param spacing Number of pixels \sa spacing(); */ void QwtSlider::setSpacing( int spacing ) { if ( spacing <= 0 ) spacing = 0; if ( spacing != d_data->spacing ) { d_data->spacing = spacing; layoutSlider( true ); } } /*! \return Number of pixels between slider and scale \sa setSpacing() */ int QwtSlider::spacing() const { return d_data->spacing; } /*! \brief Set the slider's handle size \param width Width \param height Height \sa handleSize() */ void QwtSlider::setHandleSize( int width, int height ) { setHandleSize( QSize( width, height ) ); } /*! \brief Set the slider's handle size \param size New size \sa handleSize() */ void QwtSlider::setHandleSize( const QSize &size ) { const QSize handleSize = size.expandedTo( QSize( 8, 4 ) ); if ( handleSize != d_data->handleSize ) { d_data->handleSize = handleSize; layoutSlider( true ); } } /*! \return Size of the handle. \sa setHandleSize() */ QSize QwtSlider::handleSize() const { return d_data->handleSize; } /*! \brief Set a scale draw For changing the labels of the scales, it is necessary to derive from QwtScaleDraw and overload QwtScaleDraw::label(). \param scaleDraw ScaleDraw object, that has to be created with new and will be deleted in ~QwtSlider or the next call of setScaleDraw(). \sa scaleDraw() */ void QwtSlider::setScaleDraw( QwtScaleDraw *scaleDraw ) { const QwtScaleDraw *previousScaleDraw = this->scaleDraw(); if ( scaleDraw == NULL || scaleDraw == previousScaleDraw ) return; if ( previousScaleDraw ) scaleDraw->setAlignment( previousScaleDraw->alignment() ); setAbstractScaleDraw( scaleDraw ); layoutSlider( true ); } /*! \return the scale draw of the slider \sa setScaleDraw() */ const QwtScaleDraw *QwtSlider::scaleDraw() const { return static_cast( abstractScaleDraw() ); } /*! \return the scale draw of the slider \sa setScaleDraw() */ QwtScaleDraw *QwtSlider::scaleDraw() { return static_cast( abstractScaleDraw() ); } //! Notify changed scale void QwtSlider::scaleChange() { layoutSlider( true ); } /*! Draw the slider into the specified rectangle. \param painter Painter \param sliderRect Bounding rectangle of the slider */ void QwtSlider::drawSlider( QPainter *painter, const QRect &sliderRect ) const { QRect innerRect( sliderRect ); if ( d_data->bgStyle & QwtSlider::Trough ) { const int bw = d_data->borderWidth; qDrawShadePanel( painter, sliderRect, palette(), true, bw, NULL ); innerRect = sliderRect.adjusted( bw, bw, -bw, -bw ); painter->fillRect( innerRect, palette().brush( QPalette::Mid ) ); } if ( d_data->bgStyle & QwtSlider::Groove ) { int ws = 4; int ds = d_data->handleSize.width() / 2 - 4; if ( ds < 1 ) ds = 1; QRect rSlot; if ( orientation() == Qt::Horizontal ) { if ( innerRect.height() & 1 ) ws++; rSlot = QRect( innerRect.x() + ds, innerRect.y() + ( innerRect.height() - ws ) / 2, innerRect.width() - 2 * ds, ws ); } else { if ( innerRect.width() & 1 ) ws++; rSlot = QRect( innerRect.x() + ( innerRect.width() - ws ) / 2, innerRect.y() + ds, ws, innerRect.height() - 2 * ds ); } QBrush brush = palette().brush( QPalette::Dark ); qDrawShadePanel( painter, rSlot, palette(), true, 1 , &brush ); } if ( isValid() ) drawHandle( painter, innerRect, transform( value() ) ); } /*! Draw the thumb at a position \param painter Painter \param sliderRect Bounding rectangle of the slider \param pos Position of the slider thumb */ void QwtSlider::drawHandle( QPainter *painter, const QRect &sliderRect, int pos ) const { const int bw = d_data->borderWidth; pos++; // shade line points one pixel below if ( orientation() == Qt::Horizontal ) { QRect handleRect( pos - d_data->handleSize.width() / 2, sliderRect.y(), d_data->handleSize.width(), sliderRect.height() ); qDrawShadePanel( painter, handleRect, palette(), false, bw, &palette().brush( QPalette::Button ) ); qDrawShadeLine( painter, pos, sliderRect.top() + bw, pos, sliderRect.bottom() - bw, palette(), true, 1 ); } else // Vertical { QRect handleRect( sliderRect.left(), pos - d_data->handleSize.height() / 2, sliderRect.width(), d_data->handleSize.height() ); qDrawShadePanel( painter, handleRect, palette(), false, bw, &palette().brush( QPalette::Button ) ); qDrawShadeLine( painter, sliderRect.left() + bw, pos, sliderRect.right() - bw, pos, palette(), true, 1 ); } } /*! Map and round a value into widget coordinates \param value Value */ int QwtSlider::transform( double value ) const { return qRound( d_data->map.transform( value ) ); } /*! Determine the value corresponding to a specified mouse location. \param pos Mouse position */ double QwtSlider::getValue( const QPoint &pos ) { return d_data->map.invTransform( orientation() == Qt::Horizontal ? pos.x() : pos.y() ); } /*! \brief Determine scrolling mode and direction \param p point \param scrollMode Scrolling mode \param direction Direction */ void QwtSlider::getScrollMode( const QPoint &p, QwtAbstractSlider::ScrollMode &scrollMode, int &direction ) const { if ( !d_data->sliderRect.contains( p ) ) { scrollMode = QwtAbstractSlider::ScrNone; direction = 0; return; } const int pos = ( orientation() == Qt::Horizontal ) ? p.x() : p.y(); const int markerPos = transform( value() ); if ( ( pos > markerPos - d_data->handleSize.width() / 2 ) && ( pos < markerPos + d_data->handleSize.width() / 2 ) ) { scrollMode = QwtAbstractSlider::ScrMouse; direction = 0; return; } scrollMode = QwtAbstractSlider::ScrPage; direction = ( pos > markerPos ) ? 1 : -1; if ( scaleDraw()->scaleMap().p1() > scaleDraw()->scaleMap().p2() ) direction = -direction; } /*! Qt paint event \param event Paint event */ void QwtSlider::paintEvent( QPaintEvent *event ) { QPainter painter( this ); painter.setClipRegion( event->region() ); QStyleOption opt; opt.init(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); if ( d_data->scalePos != QwtSlider::NoScale ) { if ( !d_data->sliderRect.contains( event->rect() ) ) scaleDraw()->draw( &painter, palette() ); } drawSlider( &painter, d_data->sliderRect ); if ( hasFocus() ) QwtPainter::drawFocusRect( &painter, this, d_data->sliderRect ); } //! Qt resize event void QwtSlider::resizeEvent( QResizeEvent * ) { layoutSlider( false ); } //! Qt change event handler void QwtSlider::changeEvent( QEvent *event ) { switch( event->type() ) { case QEvent::StyleChange: case QEvent::FontChange: layoutSlider( true ); break; default: break; } } /*! Recalculate the slider's geometry and layout based on the current rect and fonts. \param update_geometry notify the layout system and call update to redraw the scale */ void QwtSlider::layoutSlider( bool update_geometry ) { int handleThickness; if ( orientation() == Qt::Horizontal ) handleThickness = d_data->handleSize.width(); else handleThickness = d_data->handleSize.height(); int sld1 = handleThickness / 2 - 1; int sld2 = handleThickness / 2 + handleThickness % 2; if ( d_data->bgStyle & QwtSlider::Trough ) { sld1 += d_data->borderWidth; sld2 += d_data->borderWidth; } int scd = 0; if ( d_data->scalePos != QwtSlider::NoScale ) { int d1, d2; scaleDraw()->getBorderDistHint( font(), d1, d2 ); scd = qMax( d1, d2 ); } int slo = scd - sld1; if ( slo < 0 ) slo = 0; int x, y, length; QRect sliderRect; length = x = y = 0; const QRect cr = contentsRect(); if ( orientation() == Qt::Horizontal ) { int sh = d_data->handleSize.height(); if ( d_data->bgStyle & QwtSlider::Trough ) sh += 2 * d_data->borderWidth; sliderRect.setLeft( cr.left() + slo ); sliderRect.setRight( cr.right() - slo ); sliderRect.setTop( cr.top() ); sliderRect.setBottom( cr.top() + sh - 1); if ( d_data->scalePos == QwtSlider::BottomScale ) { y = sliderRect.bottom() + d_data->spacing; } else if ( d_data->scalePos == QwtSlider::TopScale ) { sliderRect.setTop( cr.bottom() - sh + 1 ); sliderRect.setBottom( cr.bottom() ); y = sliderRect.top() - d_data->spacing; } x = sliderRect.left() + sld1; length = sliderRect.width() - ( sld1 + sld2 ); } else // Qt::Vertical { int sw = d_data->handleSize.width(); if ( d_data->bgStyle & QwtSlider::Trough ) sw += 2 * d_data->borderWidth; sliderRect.setLeft( cr.right() - sw + 1 ); sliderRect.setRight( cr.right() ); sliderRect.setTop( cr.top() + slo ); sliderRect.setBottom( cr.bottom() - slo ); if ( d_data->scalePos == QwtSlider::LeftScale ) { x = sliderRect.left() - d_data->spacing; } else if ( d_data->scalePos == QwtSlider::RightScale ) { sliderRect.setLeft( cr.left() ); sliderRect.setRight( cr.left() + sw - 1); x = sliderRect.right() + d_data->spacing; } y = sliderRect.top() + sld1; length = sliderRect.height() - ( sld1 + sld2 ); } d_data->sliderRect = sliderRect; scaleDraw()->move( x, y ); scaleDraw()->setLength( length ); d_data->map.setPaintInterval( scaleDraw()->scaleMap().p1(), scaleDraw()->scaleMap().p2() ); if ( update_geometry ) { d_data->sizeHintCache = QSize(); // invalidate updateGeometry(); update(); } } //! Notify change of value void QwtSlider::valueChange() { QwtAbstractSlider::valueChange(); update(); } //! Notify change of range void QwtSlider::rangeChange() { d_data->map.setScaleInterval( minValue(), maxValue() ); if ( autoScale() ) rescale( minValue(), maxValue() ); QwtAbstractSlider::rangeChange(); layoutSlider( true ); } /*! Set the background style. */ void QwtSlider::setBackgroundStyle( BackgroundStyles style ) { d_data->bgStyle = style; layoutSlider( true ); } /*! \return the background style. */ QwtSlider::BackgroundStyles QwtSlider::backgroundStyle() const { return d_data->bgStyle; } /*! \return QwtSlider::minimumSizeHint() */ QSize QwtSlider::sizeHint() const { const QSize hint = minimumSizeHint(); return hint.expandedTo( QApplication::globalStrut() ); } /*! \brief Return a minimum size hint \warning The return value of QwtSlider::minimumSizeHint() depends on the font and the scale. */ QSize QwtSlider::minimumSizeHint() const { if ( !d_data->sizeHintCache.isEmpty() ) return d_data->sizeHintCache; const int minLength = 84; // from QSlider int handleLength = d_data->handleSize.width(); int handleThickness = d_data->handleSize.height(); if ( orientation() == Qt::Vertical ) qSwap( handleLength, handleThickness ); int w = minLength; int h = handleThickness; if ( d_data->scalePos != QwtSlider::NoScale ) { int d1, d2; scaleDraw()->getBorderDistHint( font(), d1, d2 ); const int sdBorderDist = 2 * qMax( d1, d2 ); const int sdExtent = qCeil( scaleDraw()->extent( font() ) ); const int sdLength = scaleDraw()->minLength( font() ); int l = sdLength; if ( handleLength > sdBorderDist ) { // We need additional space for the overlapping handle l += handleLength - sdBorderDist; } w = qMax( l, w ); h += sdExtent + d_data->spacing; } if ( d_data->bgStyle & QwtSlider::Trough ) h += 2 * d_data->borderWidth; if ( orientation() == Qt::Vertical ) qSwap( w, h ); int left, right, top, bottom; getContentsMargins( &left, &top, &right, &bottom ); w += left + right; h += top + bottom; d_data->sizeHintCache = QSize( w, h ); return d_data->sizeHintCache; } pcp-gui-1.5.11/src/libqwt/qwt_spline.cpp0000644000000000000000000002026212176111212015007 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_spline.h" #include "qwt_math.h" class QwtSpline::PrivateData { public: PrivateData(): splineType( QwtSpline::Natural ) { } QwtSpline::SplineType splineType; // coefficient vectors QVector a; QVector b; QVector c; // control points QPolygonF points; }; static int lookup( double x, const QPolygonF &values ) { #if 0 //qLowerBound/qHigherBound ??? #endif int i1; const int size = values.size(); if ( x <= values[0].x() ) i1 = 0; else if ( x >= values[size - 2].x() ) i1 = size - 2; else { i1 = 0; int i2 = size - 2; int i3 = 0; while ( i2 - i1 > 1 ) { i3 = i1 + ( ( i2 - i1 ) >> 1 ); if ( values[i3].x() > x ) i2 = i3; else i1 = i3; } } return i1; } //! Constructor QwtSpline::QwtSpline() { d_data = new PrivateData; } /*! Copy constructor \param other Spline used for initilization */ QwtSpline::QwtSpline( const QwtSpline& other ) { d_data = new PrivateData( *other.d_data ); } /*! Assignment operator \param other Spline used for initilization */ QwtSpline &QwtSpline::operator=( const QwtSpline & other ) { *d_data = *other.d_data; return *this; } //! Destructor QwtSpline::~QwtSpline() { delete d_data; } /*! Select the algorithm used for calculating the spline \param splineType Spline type \sa splineType() */ void QwtSpline::setSplineType( SplineType splineType ) { d_data->splineType = splineType; } /*! \return the spline type \sa setSplineType() */ QwtSpline::SplineType QwtSpline::splineType() const { return d_data->splineType; } /*! \brief Calculate the spline coefficients Depending on the value of \a periodic, this function will determine the coefficients for a natural or a periodic spline and store them internally. \param points Points \return true if successful \warning The sequence of x (but not y) values has to be strictly monotone increasing, which means points[i].x() < points[i+1].x(). If this is not the case, the function will return false */ bool QwtSpline::setPoints( const QPolygonF& points ) { const int size = points.size(); if ( size <= 2 ) { reset(); return false; } d_data->points = points; d_data->a.resize( size - 1 ); d_data->b.resize( size - 1 ); d_data->c.resize( size - 1 ); bool ok; if ( d_data->splineType == Periodic ) ok = buildPeriodicSpline( points ); else ok = buildNaturalSpline( points ); if ( !ok ) reset(); return ok; } /*! Return points passed by setPoints */ QPolygonF QwtSpline::points() const { return d_data->points; } //! \return A coefficients const QVector &QwtSpline::coefficientsA() const { return d_data->a; } //! \return B coefficients const QVector &QwtSpline::coefficientsB() const { return d_data->b; } //! \return C coefficients const QVector &QwtSpline::coefficientsC() const { return d_data->c; } //! Free allocated memory and set size to 0 void QwtSpline::reset() { d_data->a.resize( 0 ); d_data->b.resize( 0 ); d_data->c.resize( 0 ); d_data->points.resize( 0 ); } //! True if valid bool QwtSpline::isValid() const { return d_data->a.size() > 0; } /*! Calculate the interpolated function value corresponding to a given argument x. */ double QwtSpline::value( double x ) const { if ( d_data->a.size() == 0 ) return 0.0; const int i = lookup( x, d_data->points ); const double delta = x - d_data->points[i].x(); return( ( ( ( d_data->a[i] * delta ) + d_data->b[i] ) * delta + d_data->c[i] ) * delta + d_data->points[i].y() ); } /*! \brief Determines the coefficients for a natural spline \return true if successful */ bool QwtSpline::buildNaturalSpline( const QPolygonF &points ) { int i; const QPointF *p = points.data(); const int size = points.size(); double *a = d_data->a.data(); double *b = d_data->b.data(); double *c = d_data->c.data(); // set up tridiagonal equation system; use coefficient // vectors as temporary buffers QVector h( size - 1 ); for ( i = 0; i < size - 1; i++ ) { h[i] = p[i+1].x() - p[i].x(); if ( h[i] <= 0 ) return false; } QVector d( size - 1 ); double dy1 = ( p[1].y() - p[0].y() ) / h[0]; for ( i = 1; i < size - 1; i++ ) { b[i] = c[i] = h[i]; a[i] = 2.0 * ( h[i-1] + h[i] ); const double dy2 = ( p[i+1].y() - p[i].y() ) / h[i]; d[i] = 6.0 * ( dy1 - dy2 ); dy1 = dy2; } // // solve it // // L-U Factorization for ( i = 1; i < size - 2; i++ ) { c[i] /= a[i]; a[i+1] -= b[i] * c[i]; } // forward elimination QVector s( size ); s[1] = d[1]; for ( i = 2; i < size - 1; i++ ) s[i] = d[i] - c[i-1] * s[i-1]; // backward elimination s[size - 2] = - s[size - 2] / a[size - 2]; for ( i = size - 3; i > 0; i-- ) s[i] = - ( s[i] + b[i] * s[i+1] ) / a[i]; s[size - 1] = s[0] = 0.0; // // Finally, determine the spline coefficients // for ( i = 0; i < size - 1; i++ ) { a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i] ); b[i] = 0.5 * s[i]; c[i] = ( p[i+1].y() - p[i].y() ) / h[i] - ( s[i+1] + 2.0 * s[i] ) * h[i] / 6.0; } return true; } /*! \brief Determines the coefficients for a periodic spline \return true if successful */ bool QwtSpline::buildPeriodicSpline( const QPolygonF &points ) { int i; const QPointF *p = points.data(); const int size = points.size(); double *a = d_data->a.data(); double *b = d_data->b.data(); double *c = d_data->c.data(); QVector d( size - 1 ); QVector h( size - 1 ); QVector s( size ); // // setup equation system; use coefficient // vectors as temporary buffers // for ( i = 0; i < size - 1; i++ ) { h[i] = p[i+1].x() - p[i].x(); if ( h[i] <= 0.0 ) return false; } const int imax = size - 2; double htmp = h[imax]; double dy1 = ( p[0].y() - p[imax].y() ) / htmp; for ( i = 0; i <= imax; i++ ) { b[i] = c[i] = h[i]; a[i] = 2.0 * ( htmp + h[i] ); const double dy2 = ( p[i+1].y() - p[i].y() ) / h[i]; d[i] = 6.0 * ( dy1 - dy2 ); dy1 = dy2; htmp = h[i]; } // // solve it // // L-U Factorization a[0] = qSqrt( a[0] ); c[0] = h[imax] / a[0]; double sum = 0; for ( i = 0; i < imax - 1; i++ ) { b[i] /= a[i]; if ( i > 0 ) c[i] = - c[i-1] * b[i-1] / a[i]; a[i+1] = qSqrt( a[i+1] - qwtSqr( b[i] ) ); sum += qwtSqr( c[i] ); } b[imax-1] = ( b[imax-1] - c[imax-2] * b[imax-2] ) / a[imax-1]; a[imax] = qSqrt( a[imax] - qwtSqr( b[imax-1] ) - sum ); // forward elimination s[0] = d[0] / a[0]; sum = 0; for ( i = 1; i < imax; i++ ) { s[i] = ( d[i] - b[i-1] * s[i-1] ) / a[i]; sum += c[i-1] * s[i-1]; } s[imax] = ( d[imax] - b[imax-1] * s[imax-1] - sum ) / a[imax]; // backward elimination s[imax] = - s[imax] / a[imax]; s[imax-1] = -( s[imax-1] + b[imax-1] * s[imax] ) / a[imax-1]; for ( i = imax - 2; i >= 0; i-- ) s[i] = - ( s[i] + b[i] * s[i+1] + c[i] * s[imax] ) / a[i]; // // Finally, determine the spline coefficients // s[size-1] = s[0]; for ( i = 0; i < size - 1; i++ ) { a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i] ); b[i] = 0.5 * s[i]; c[i] = ( p[i+1].y() - p[i].y() ) / h[i] - ( s[i+1] + 2.0 * s[i] ) * h[i] / 6.0; } return true; } pcp-gui-1.5.11/src/libqwt/qwt_symbol.cpp0000644000000000000000000006204512176111212015027 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_symbol.h" #include "qwt_painter.h" #include #include #include namespace QwtTriangle { enum Type { Left, Right, Up, Down }; } static inline void qwtDrawEllipseSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { painter->setBrush( symbol.brush() ); painter->setPen( symbol.pen() ); const QSize size = symbol.size(); if ( QwtPainter::roundingAlignment( painter ) ) { const int sw = size.width(); const int sh = size.height(); const int sw2 = size.width() / 2; const int sh2 = size.height() / 2; for ( int i = 0; i < numPoints; i++ ) { const int x = qRound( points[i].x() ); const int y = qRound( points[i].y() ); const QRectF r( x - sw2, y - sh2, sw, sh ); QwtPainter::drawEllipse( painter, r ); } } else { const double sw = size.width(); const double sh = size.height(); const double sw2 = 0.5 * size.width(); const double sh2 = 0.5 * size.height(); for ( int i = 0; i < numPoints; i++ ) { const double x = points[i].x(); const double y = points[i].y(); const QRectF r( x - sw2, y - sh2, sw, sh ); QwtPainter::drawEllipse( painter, r ); } } } static inline void qwtDrawRectSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); QPen pen = symbol.pen(); pen.setJoinStyle( Qt::MiterJoin ); painter->setPen( pen ); painter->setBrush( symbol.brush() ); painter->setRenderHint( QPainter::Antialiasing, false ); if ( QwtPainter::roundingAlignment( painter ) ) { const int sw = size.width(); const int sh = size.height(); const int sw2 = size.width() / 2; const int sh2 = size.height() / 2; for ( int i = 0; i < numPoints; i++ ) { const int x = qRound( points[i].x() ); const int y = qRound( points[i].y() ); const QRect r( x - sw2, y - sh2, sw, sh ); QwtPainter::drawRect( painter, r ); } } else { const double sw = size.width(); const double sh = size.height(); const double sw2 = 0.5 * size.width(); const double sh2 = 0.5 * size.height(); for ( int i = 0; i < numPoints; i++ ) { const double x = points[i].x(); const double y = points[i].y(); const QRectF r( x - sw2, y - sh2, sw, sh ); QwtPainter::drawRect( painter, r ); } } } static inline void qwtDrawDiamondSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); QPen pen = symbol.pen(); pen.setJoinStyle( Qt::MiterJoin ); painter->setPen( pen ); painter->setBrush( symbol.brush() ); if ( QwtPainter::roundingAlignment( painter ) ) { for ( int i = 0; i < numPoints; i++ ) { const int x = qRound( points[i].x() ); const int y = qRound( points[i].y() ); const int x1 = x - size.width() / 2; const int y1 = y - size.height() / 2; const int x2 = x1 + size.width(); const int y2 = y1 + size.height(); QPolygonF polygon; polygon += QPointF( x, y1 ); polygon += QPointF( x1, y ); polygon += QPointF( x, y2 ); polygon += QPointF( x2, y ); QwtPainter::drawPolygon( painter, polygon ); } } else { for ( int i = 0; i < numPoints; i++ ) { const QPointF &pos = points[i]; const double x1 = pos.x() - 0.5 * size.width(); const double y1 = pos.y() - 0.5 * size.height(); const double x2 = x1 + size.width(); const double y2 = y1 + size.height(); QPolygonF polygon; polygon += QPointF( pos.x(), y1 ); polygon += QPointF( x2, pos.y() ); polygon += QPointF( pos.x(), y2 ); polygon += QPointF( x1, pos.y() ); QwtPainter::drawPolygon( painter, polygon ); } } } static inline void qwtDrawTriangleSymbols( QPainter *painter, QwtTriangle::Type type, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); QPen pen = symbol.pen(); pen.setJoinStyle( Qt::MiterJoin ); painter->setPen( pen ); painter->setBrush( symbol.brush() ); const bool doAlign = QwtPainter::roundingAlignment( painter ); double sw2 = 0.5 * size.width(); double sh2 = 0.5 * size.height(); if ( doAlign ) { sw2 = qFloor( sw2 ); sh2 = qFloor( sh2 ); } QPolygonF triangle( 3 ); QPointF *trianglePoints = triangle.data(); for ( int i = 0; i < numPoints; i++ ) { const QPointF &pos = points[i]; double x = pos.x(); double y = pos.y(); if ( doAlign ) { x = qRound( x ); y = qRound( y ); } const double x1 = x - sw2; const double x2 = x1 + size.width(); const double y1 = y - sh2; const double y2 = y1 + size.height(); switch ( type ) { case QwtTriangle::Left: { trianglePoints[0].rx() = x2; trianglePoints[0].ry() = y1; trianglePoints[1].rx() = x1; trianglePoints[1].ry() = y; trianglePoints[2].rx() = x2; trianglePoints[2].ry() = y2; break; } case QwtTriangle::Right: { trianglePoints[0].rx() = x1; trianglePoints[0].ry() = y1; trianglePoints[1].rx() = x2; trianglePoints[1].ry() = y; trianglePoints[2].rx() = x1; trianglePoints[2].ry() = y2; break; } case QwtTriangle::Up: { trianglePoints[0].rx() = x1; trianglePoints[0].ry() = y2; trianglePoints[1].rx() = x; trianglePoints[1].ry() = y1; trianglePoints[2].rx() = x2; trianglePoints[2].ry() = y2; break; } case QwtTriangle::Down: { trianglePoints[0].rx() = x1; trianglePoints[0].ry() = y1; trianglePoints[1].rx() = x; trianglePoints[1].ry() = y2; trianglePoints[2].rx() = x2; trianglePoints[2].ry() = y1; break; } } QwtPainter::drawPolygon( painter, triangle ); } } static inline void qwtDrawLineSymbols( QPainter *painter, int orientations, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); int off = 0; QPen pen = symbol.pen(); if ( pen.width() > 1 ) { pen.setCapStyle( Qt::FlatCap ); off = 1; } painter->setPen( pen ); painter->setRenderHint( QPainter::Antialiasing, false ); if ( QwtPainter::roundingAlignment( painter ) ) { const int sw = qFloor( size.width() ); const int sh = qFloor( size.height() ); const int sw2 = size.width() / 2; const int sh2 = size.height() / 2; for ( int i = 0; i < numPoints; i++ ) { if ( orientations & Qt::Horizontal ) { const int x = qRound( points[i].x() ) - sw2; const int y = qRound( points[i].y() ); QwtPainter::drawLine( painter, x, y, x + sw + off, y ); } if ( orientations & Qt::Vertical ) { const int x = qRound( points[i].x() ); const int y = qRound( points[i].y() ) - sh2; QwtPainter::drawLine( painter, x, y, x, y + sh + off ); } } } else { const double sw = size.width(); const double sh = size.height(); const double sw2 = 0.5 * size.width(); const double sh2 = 0.5 * size.height(); for ( int i = 0; i < numPoints; i++ ) { if ( orientations & Qt::Horizontal ) { const double x = points[i].x() - sw2; const double y = points[i].y(); QwtPainter::drawLine( painter, x, y, x + sw, y ); } if ( orientations & Qt::Vertical ) { const double y = points[i].y() - sh2; const double x = points[i].x(); QwtPainter::drawLine( painter, x, y, x, y + sh ); } } } } static inline void qwtDrawXCrossSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); int off = 0; QPen pen = symbol.pen(); if ( pen.width() > 1 ) { pen.setCapStyle( Qt::FlatCap ); off = 1; } painter->setPen( pen ); if ( QwtPainter::roundingAlignment( painter ) ) { const int sw = size.width(); const int sh = size.height(); const int sw2 = size.width() / 2; const int sh2 = size.height() / 2; for ( int i = 0; i < numPoints; i++ ) { const QPointF &pos = points[i]; const int x = qRound( pos.x() ); const int y = qRound( pos.y() ); const int x1 = x - sw2; const int x2 = x1 + sw + off; const int y1 = y - sh2; const int y2 = y1 + sh + off; QwtPainter::drawLine( painter, x1, y1, x2, y2 ); QwtPainter::drawLine( painter, x2, y1, x1, y2 ); } } else { const double sw = size.width(); const double sh = size.height(); const double sw2 = 0.5 * size.width(); const double sh2 = 0.5 * size.height(); for ( int i = 0; i < numPoints; i++ ) { const QPointF &pos = points[i]; const double x1 = pos.x() - sw2; const double x2 = x1 + sw; const double y1 = pos.y() - sh2; const double y2 = y1 + sh; QwtPainter::drawLine( painter, x1, y1, x2, y2 ); QwtPainter::drawLine( painter, x1, y2, x2, y1 ); } } } static inline void qwtDrawStar1Symbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); painter->setPen( symbol.pen() ); if ( QwtPainter::roundingAlignment( painter ) ) { QRect r( 0, 0, size.width(), size.height() ); for ( int i = 0; i < numPoints; i++ ) { r.moveCenter( points[i].toPoint() ); const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */ const double d1 = r.width() / 2.0 * ( 1.0 - sqrt1_2 ); QwtPainter::drawLine( painter, qRound( r.left() + d1 ), qRound( r.top() + d1 ), qRound( r.right() - d1 ), qRound( r.bottom() - d1 ) ); QwtPainter::drawLine( painter, qRound( r.left() + d1 ), qRound( r.bottom() - d1 ), qRound( r .right() - d1), qRound( r.top() + d1 ) ); const QPoint c = r.center(); QwtPainter::drawLine( painter, c.x(), r.top(), c.x(), r.bottom() ); QwtPainter::drawLine( painter, r.left(), c.y(), r.right(), c.y() ); } } else { QRectF r( 0, 0, size.width(), size.height() ); for ( int i = 0; i < numPoints; i++ ) { r.moveCenter( points[i] ); const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */ const QPointF c = r.center(); const double d1 = r.width() / 2.0 * ( 1.0 - sqrt1_2 ); QwtPainter::drawLine( painter, r.left() + d1, r.top() + d1, r.right() - d1, r.bottom() - d1 ); QwtPainter::drawLine( painter, r.left() + d1, r.bottom() - d1, r.right() - d1, r.top() + d1 ); QwtPainter::drawLine( painter, c.x(), r.top(), c.x(), r.bottom() ); QwtPainter::drawLine( painter, r.left(), c.y(), r.right(), c.y() ); } } } static inline void qwtDrawStar2Symbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { QPen pen = symbol.pen(); if ( pen.width() > 1 ) pen.setCapStyle( Qt::FlatCap ); pen.setJoinStyle( Qt::MiterJoin ); painter->setPen( pen ); painter->setBrush( symbol.brush() ); const double cos30 = 0.866025; // cos(30°) const double dy = 0.25 * symbol.size().height(); const double dx = 0.5 * symbol.size().width() * cos30 / 3.0; QPolygonF star( 12 ); QPointF *starPoints = star.data(); const bool doAlign = QwtPainter::roundingAlignment( painter ); for ( int i = 0; i < numPoints; i++ ) { double x = points[i].x(); double y = points[i].y(); if ( doAlign ) { x = qRound( x ); y = qRound( y ); } double x1 = x - 3 * dx; double y1 = y - 2 * dy; if ( doAlign ) { x1 = qRound( x - 3 * dx ); y1 = qRound( y - 2 * dy ); } const double x2 = x1 + 1 * dx; const double x3 = x1 + 2 * dx; const double x4 = x1 + 3 * dx; const double x5 = x1 + 4 * dx; const double x6 = x1 + 5 * dx; const double x7 = x1 + 6 * dx; const double y2 = y1 + 1 * dy; const double y3 = y1 + 2 * dy; const double y4 = y1 + 3 * dy; const double y5 = y1 + 4 * dy; starPoints[0].rx() = x4; starPoints[0].ry() = y1; starPoints[1].rx() = x5; starPoints[1].ry() = y2; starPoints[2].rx() = x7; starPoints[2].ry() = y2; starPoints[3].rx() = x6; starPoints[3].ry() = y3; starPoints[4].rx() = x7; starPoints[4].ry() = y4; starPoints[5].rx() = x5; starPoints[5].ry() = y4; starPoints[6].rx() = x4; starPoints[6].ry() = y5; starPoints[7].rx() = x3; starPoints[7].ry() = y4; starPoints[8].rx() = x1; starPoints[8].ry() = y4; starPoints[9].rx() = x2; starPoints[9].ry() = y3; starPoints[10].rx() = x1; starPoints[10].ry() = y2; starPoints[11].rx() = x3; starPoints[11].ry() = y2; QwtPainter::drawPolygon( painter, star ); } } static inline void qwtDrawHexagonSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { painter->setBrush( symbol.brush() ); painter->setPen( symbol.pen() ); const double cos30 = 0.866025; // cos(30°) const double dx = 0.5 * ( symbol.size().width() - cos30 ); const double dy = 0.25 * symbol.size().height(); QPolygonF hexaPolygon( 6 ); QPointF *hexaPoints = hexaPolygon.data(); const bool doAlign = QwtPainter::roundingAlignment( painter ); for ( int i = 0; i < numPoints; i++ ) { double x = points[i].x(); double y = points[i].y(); if ( doAlign ) { x = qRound( x ); y = qRound( y ); } double x1 = x - dx; double y1 = y - 2 * dy; if ( doAlign ) { x1 = qCeil( x1 ); y1 = qCeil( y1 ); } const double x2 = x1 + 1 * dx; const double x3 = x1 + 2 * dx; const double y2 = y1 + 1 * dy; const double y3 = y1 + 3 * dy; const double y4 = y1 + 4 * dy; hexaPoints[0].rx() = x2; hexaPoints[0].ry() = y1; hexaPoints[1].rx() = x3; hexaPoints[1].ry() = y2; hexaPoints[2].rx() = x3; hexaPoints[2].ry() = y3; hexaPoints[3].rx() = x2; hexaPoints[3].ry() = y4; hexaPoints[4].rx() = x1; hexaPoints[4].ry() = y3; hexaPoints[5].rx() = x1; hexaPoints[5].ry() = y2; QwtPainter::drawPolygon( painter, hexaPolygon ); } } class QwtSymbol::PrivateData { public: PrivateData( QwtSymbol::Style st, const QBrush &br, const QPen &pn, const QSize &sz ): style( st ), size( sz ), brush( br ), pen( pn ) { } bool operator==( const PrivateData &other ) const { return ( style == other.style ) && ( size == other.size ) && ( brush == other.brush ) && ( pen == other.pen ); } Style style; QSize size; QBrush brush; QPen pen; }; /*! Default Constructor \param style Symbol Style The symbol is constructed with gray interior, black outline with zero width, no size and style 'NoSymbol'. */ QwtSymbol::QwtSymbol( Style style ) { d_data = new PrivateData( style, QBrush( Qt::gray ), QPen( Qt::black ), QSize( 0.0, 0.0 ) ); } /*! \brief Constructor \param style Symbol Style \param brush brush to fill the interior \param pen outline pen \param size size \sa setStyle(), setBrush(), setPen(), setSize() */ QwtSymbol::QwtSymbol( QwtSymbol::Style style, const QBrush &brush, const QPen &pen, const QSize &size ) { d_data = new PrivateData( style, brush, pen, size ); } /*! \brief Copy constructor \param other Symbol */ QwtSymbol::QwtSymbol( const QwtSymbol &other ) { d_data = new PrivateData( other.style(), other.brush(), other.pen(), other.size() ); }; //! Destructor QwtSymbol::~QwtSymbol() { delete d_data; } //! \brief Assignment operator QwtSymbol &QwtSymbol::operator=( const QwtSymbol &other ) { *d_data = *other.d_data; return *this; } //! \brief Compare two symbols bool QwtSymbol::operator==( const QwtSymbol &other ) const { return *d_data == *other.d_data; } //! \brief Compare two symbols bool QwtSymbol::operator!=( const QwtSymbol &other ) const { return !( *d_data == *other.d_data ); } /*! \brief Specify the symbol's size If the 'h' parameter is left out or less than 0, and the 'w' parameter is greater than or equal to 0, the symbol size will be set to (w,w). \param width Width \param height Height (defaults to -1) \sa size() */ void QwtSymbol::setSize( int width, int height ) { if ( ( width >= 0 ) && ( height < 0 ) ) height = width; d_data->size = QSize( width, height ); } /*! Set the symbol's size \param size Size \sa size() */ void QwtSymbol::setSize( const QSize &size ) { if ( size.isValid() ) d_data->size = size; } /*! \return Size \sa setSize() */ const QSize& QwtSymbol::size() const { return d_data->size; } /*! \brief Assign a brush The brush is used to draw the interior of the symbol. \param brush Brush \sa brush() */ void QwtSymbol::setBrush( const QBrush &brush ) { d_data->brush = brush; } /*! \return Brush \sa setBrush() */ const QBrush& QwtSymbol::brush() const { return d_data->brush; } /*! Assign a pen The pen is used to draw the symbol's outline. \param pen Pen \sa pen(), setBrush() */ void QwtSymbol::setPen( const QPen &pen ) { d_data->pen = pen; } /*! \return Pen \sa setPen(), brush() */ const QPen& QwtSymbol::pen() const { return d_data->pen; } /*! \brief Set the color of the symbol Change the color of the brush for symbol types with a filled area. For all other symbol types the color will be assigned to the pen. \param color Color \sa setBrush(), setPen(), brush(), pen() */ void QwtSymbol::setColor( const QColor &color ) { switch ( d_data->style ) { case QwtSymbol::Ellipse: case QwtSymbol::Rect: case QwtSymbol::Diamond: case QwtSymbol::Triangle: case QwtSymbol::UTriangle: case QwtSymbol::DTriangle: case QwtSymbol::RTriangle: case QwtSymbol::LTriangle: case QwtSymbol::Star2: case QwtSymbol::Hexagon: { d_data->brush.setColor( color ); break; } case QwtSymbol::Cross: case QwtSymbol::XCross: case QwtSymbol::HLine: case QwtSymbol::VLine: case QwtSymbol::Star1: { d_data->pen.setColor( color ); break; } default: { d_data->brush.setColor( color ); d_data->pen.setColor( color ); } } } /*! Draw an array of symbols Painting several symbols is more effective than drawing symbols one by one, as a couple of layout calculations and setting of pen/brush can be done once for the complete array. \param painter Painter \param points Array of points \param numPoints Number of points */ void QwtSymbol::drawSymbols( QPainter *painter, const QPointF *points, int numPoints ) const { if ( numPoints <= 0 ) return; painter->save(); switch ( d_data->style ) { case QwtSymbol::Ellipse: { qwtDrawEllipseSymbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Rect: { qwtDrawRectSymbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Diamond: { qwtDrawDiamondSymbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Cross: { qwtDrawLineSymbols( painter, Qt::Horizontal | Qt::Vertical, points, numPoints, *this ); break; } case QwtSymbol::XCross: { qwtDrawXCrossSymbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Triangle: case QwtSymbol::UTriangle: { qwtDrawTriangleSymbols( painter, QwtTriangle::Up, points, numPoints, *this ); break; } case QwtSymbol::DTriangle: { qwtDrawTriangleSymbols( painter, QwtTriangle::Down, points, numPoints, *this ); break; } case QwtSymbol::RTriangle: { qwtDrawTriangleSymbols( painter, QwtTriangle::Right, points, numPoints, *this ); break; } case QwtSymbol::LTriangle: { qwtDrawTriangleSymbols( painter, QwtTriangle::Left, points, numPoints, *this ); break; } case QwtSymbol::HLine: { qwtDrawLineSymbols( painter, Qt::Horizontal, points, numPoints, *this ); break; } case QwtSymbol::VLine: { qwtDrawLineSymbols( painter, Qt::Vertical, points, numPoints, *this ); break; } case QwtSymbol::Star1: { qwtDrawStar1Symbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Star2: { qwtDrawStar2Symbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Hexagon: { qwtDrawHexagonSymbols( painter, points, numPoints, *this ); break; } default:; } painter->restore(); } //! \return Size of the bounding rectangle of a symbol QSize QwtSymbol::boundingSize() const { QSizeF size; switch ( d_data->style ) { case QwtSymbol::Ellipse: case QwtSymbol::Rect: case QwtSymbol::Hexagon: { qreal pw = 0.0; if ( d_data->pen.style() != Qt::NoPen ) pw = qMax( d_data->pen.widthF(), qreal( 1.0 ) ); size = d_data->size + QSizeF( pw, pw ); break; } case QwtSymbol::XCross: case QwtSymbol::Diamond: case QwtSymbol::Triangle: case QwtSymbol::UTriangle: case QwtSymbol::DTriangle: case QwtSymbol::RTriangle: case QwtSymbol::LTriangle: case QwtSymbol::Star1: case QwtSymbol::Star2: { qreal pw = 0.0; if ( d_data->pen.style() != Qt::NoPen ) pw = qMax( d_data->pen.widthF(), qreal( 1.0 ) ); size = d_data->size + QSizeF( 2 * pw, 2 * pw ); break; } default: { size = d_data->size; } } size += QSizeF( 1.0, 1.0 ); // for antialiasing return QSize( qCeil( size.width() ), qCeil( size.height() ) ); } /*! Specify the symbol style \param style Style \sa style() */ void QwtSymbol::setStyle( QwtSymbol::Style style ) { d_data->style = style; } /*! \return Current symbol style \sa setStyle() */ QwtSymbol::Style QwtSymbol::style() const { return d_data->style; } pcp-gui-1.5.11/src/libqwt/qwt_system_clock.cpp0000644000000000000000000001701012176111212016211 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_system_clock.h" #include #if !defined(Q_OS_WIN) #include #endif #if defined(Q_OS_MAC) #include #include #define QWT_HIGH_RESOLUTION_CLOCK #elif defined(_POSIX_TIMERS) #include #define QWT_HIGH_RESOLUTION_CLOCK #elif defined(Q_OS_WIN) #define QWT_HIGH_RESOLUTION_CLOCK #include #endif #if defined(QWT_HIGH_RESOLUTION_CLOCK) class QwtHighResolutionClock { public: QwtHighResolutionClock(); void start(); double restart(); double elapsed() const; bool isNull() const; static double precision(); private: #if defined(Q_OS_MAC) static double msecsTo( uint64_t, uint64_t ); uint64_t d_timeStamp; #elif defined(_POSIX_TIMERS) static double msecsTo( const struct timespec &, const struct timespec & ); static bool isMonotonic(); struct timespec d_timeStamp; clockid_t d_clockId; #elif defined(Q_OS_WIN) LARGE_INTEGER d_startTicks; LARGE_INTEGER d_ticksPerSecond; #endif }; #if defined(Q_OS_MAC) QwtHighResolutionClock::QwtHighResolutionClock(): d_timeStamp( 0 ) { } double QwtHighResolutionClock::precision() { return 1e-6; } void QwtHighResolutionClock::start() { d_timeStamp = mach_absolute_time(); } double QwtHighResolutionClock::restart() { const uint64_t timeStamp = mach_absolute_time(); const double elapsed = msecsTo( d_timeStamp, timeStamp ); d_timeStamp = timeStamp; return elapsed; } double QwtHighResolutionClock::elapsed() const { return msecsTo( d_timeStamp, mach_absolute_time() ); } bool QwtHighResolutionClock::isNull() const { return d_timeStamp == 0; } double QwtHighResolutionClock::msecsTo( uint64_t from, uint64_t to ) { const uint64_t difference = to - from; static double conversion = 0.0; if ( conversion == 0.0 ) { mach_timebase_info_data_t info; kern_return_t err = mach_timebase_info( &info ); //Convert the timebase into ms if ( err == 0 ) conversion = 1e-6 * ( double ) info.numer / ( double ) info.denom; } return conversion * ( double ) difference; } #elif defined(_POSIX_TIMERS) QwtHighResolutionClock::QwtHighResolutionClock() { d_clockId = isMonotonic() ? CLOCK_MONOTONIC : CLOCK_REALTIME; d_timeStamp.tv_sec = d_timeStamp.tv_nsec = 0; } double QwtHighResolutionClock::precision() { struct timespec resolution; int clockId = isMonotonic() ? CLOCK_MONOTONIC : CLOCK_REALTIME; ::clock_getres( clockId, &resolution ); return resolution.tv_nsec / 1e3; } inline bool QwtHighResolutionClock::isNull() const { return d_timeStamp.tv_sec <= 0 && d_timeStamp.tv_nsec <= 0; } inline void QwtHighResolutionClock::start() { ::clock_gettime( d_clockId, &d_timeStamp ); } double QwtHighResolutionClock::restart() { struct timespec timeStamp; ::clock_gettime( d_clockId, &timeStamp ); const double elapsed = msecsTo( d_timeStamp, timeStamp ); d_timeStamp = timeStamp; return elapsed; } inline double QwtHighResolutionClock::elapsed() const { struct timespec timeStamp; ::clock_gettime( d_clockId, &timeStamp ); return msecsTo( d_timeStamp, timeStamp ); } inline double QwtHighResolutionClock::msecsTo( const struct timespec &t1, const struct timespec &t2 ) { return ( t2.tv_sec - t1.tv_sec ) * 1e3 + ( t2.tv_nsec - t1.tv_nsec ) * 1e-6; } bool QwtHighResolutionClock::isMonotonic() { // code copied from qcore_unix.cpp #if (_POSIX_MONOTONIC_CLOCK-0 > 0) return true; #else static int returnValue = 0; if ( returnValue == 0 ) { #if (_POSIX_MONOTONIC_CLOCK-0 < 0) || !defined(_SC_MONOTONIC_CLOCK) returnValue = -1; #elif (_POSIX_MONOTONIC_CLOCK == 0) // detect if the system support monotonic timers const long x = sysconf( _SC_MONOTONIC_CLOCK ); returnValue = ( x >= 200112L ) ? 1 : -1; #endif } return returnValue != -1; #endif } #elif defined(Q_OS_WIN) QwtHighResolutionClock::QwtHighResolutionClock() { d_startTicks.QuadPart = 0; QueryPerformanceFrequency( &d_ticksPerSecond ); } double QwtHighResolutionClock::precision() { LARGE_INTEGER ticks; if ( QueryPerformanceFrequency( &ticks ) && ticks.QuadPart > 0 ) return 1e3 / ticks.QuadPart; return 0.0; } inline bool QwtHighResolutionClock::isNull() const { return d_startTicks.QuadPart <= 0; } inline void QwtHighResolutionClock::start() { QueryPerformanceCounter( &d_startTicks ); } inline double QwtHighResolutionClock::restart() { LARGE_INTEGER ticks; QueryPerformanceCounter( &ticks ); const double dt = ticks.QuadPart - d_startTicks.QuadPart; d_startTicks = ticks; return dt / d_ticksPerSecond.QuadPart * 1e3; } inline double QwtHighResolutionClock::elapsed() const { LARGE_INTEGER ticks; QueryPerformanceCounter( &ticks ); const double dt = ticks.QuadPart - d_startTicks.QuadPart; return dt / d_ticksPerSecond.QuadPart * 1e3; } #endif #endif // QWT_HIGH_RESOLUTION_CLOCK class QwtSystemClock::PrivateData { public: #if defined(QWT_HIGH_RESOLUTION_CLOCK) QwtHighResolutionClock *clock; #endif QTime time; }; //! Constructs a null clock object. QwtSystemClock::QwtSystemClock() { d_data = new PrivateData; #if defined(QWT_HIGH_RESOLUTION_CLOCK) d_data->clock = NULL; if ( QwtHighResolutionClock::precision() > 0.0 ) d_data->clock = new QwtHighResolutionClock; #endif } //! Destructor QwtSystemClock::~QwtSystemClock() { #if defined(QWT_HIGH_RESOLUTION_CLOCK) delete d_data->clock; #endif delete d_data; } /*! \return true if the clock has never been started. */ bool QwtSystemClock::isNull() const { #if defined(QWT_HIGH_RESOLUTION_CLOCK) if ( d_data->clock ) return d_data->clock->isNull(); #endif return d_data->time.isNull(); } /*! Sets the start time to the current time. */ void QwtSystemClock::start() { #if defined(QWT_HIGH_RESOLUTION_CLOCK) if ( d_data->clock ) { d_data->clock->start(); return; } #endif d_data->time.start(); } /*! The start time to the current time and return the time, that is elapsed since the previous start time. */ double QwtSystemClock::restart() { #if defined(QWT_HIGH_RESOLUTION_CLOCK) if ( d_data->clock ) return d_data->clock->restart(); #endif return d_data->time.restart(); } /*! \return Number of milliseconds that have elapsed since the last time start() or restart() was called or 0.0 for null clocks. */ double QwtSystemClock::elapsed() const { double elapsed = 0.0; #if defined(QWT_HIGH_RESOLUTION_CLOCK) if ( d_data->clock ) { if ( !d_data->clock->isNull() ) elapsed = d_data->clock->elapsed(); return elapsed; } #endif if ( !d_data->time.isNull() ) elapsed = d_data->time.elapsed(); return elapsed; } /*! \return Accuracy of the system clock in milliseconds. */ double QwtSystemClock::precision() { static double prec = 0.0; if ( prec <= 0.0 ) { #if defined(QWT_HIGH_RESOLUTION_CLOCK) prec = QwtHighResolutionClock::precision(); #endif if ( prec <= 0.0 ) prec = 1.0; // QTime offers 1 ms } return prec; } pcp-gui-1.5.11/src/libqwt/qwt_text.cpp0000644000000000000000000003533212176111212014505 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2003 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_text.h" #include "qwt_painter.h" #include "qwt_text_engine.h" #include #include #include #include #include #include #include #include #include class QwtTextEngineDict { public: static QwtTextEngineDict &dict(); void setTextEngine( QwtText::TextFormat, QwtTextEngine * ); const QwtTextEngine *textEngine( QwtText::TextFormat ) const; const QwtTextEngine *textEngine( const QString &, QwtText::TextFormat ) const; private: QwtTextEngineDict(); ~QwtTextEngineDict(); typedef QMap EngineMap; inline const QwtTextEngine *engine( EngineMap::const_iterator &it ) const { return it.value(); } EngineMap d_map; }; QwtTextEngineDict &QwtTextEngineDict::dict() { static QwtTextEngineDict engineDict; return engineDict; } QwtTextEngineDict::QwtTextEngineDict() { d_map.insert( QwtText::PlainText, new QwtPlainTextEngine() ); #ifndef QT_NO_RICHTEXT d_map.insert( QwtText::RichText, new QwtRichTextEngine() ); #endif } QwtTextEngineDict::~QwtTextEngineDict() { for ( EngineMap::const_iterator it = d_map.begin(); it != d_map.end(); ++it ) { const QwtTextEngine *textEngine = engine( it ); delete textEngine; } } const QwtTextEngine *QwtTextEngineDict::textEngine( const QString& text, QwtText::TextFormat format ) const { if ( format == QwtText::AutoText ) { for ( EngineMap::const_iterator it = d_map.begin(); it != d_map.end(); ++it ) { if ( it.key() != QwtText::PlainText ) { const QwtTextEngine *e = engine( it ); if ( e && e->mightRender( text ) ) return e; } } } EngineMap::const_iterator it = d_map.find( format ); if ( it != d_map.end() ) { const QwtTextEngine *e = engine( it ); if ( e ) return e; } it = d_map.find( QwtText::PlainText ); return engine( it ); } void QwtTextEngineDict::setTextEngine( QwtText::TextFormat format, QwtTextEngine *engine ) { if ( format == QwtText::AutoText ) return; if ( format == QwtText::PlainText && engine == NULL ) return; EngineMap::const_iterator it = d_map.find( format ); if ( it != d_map.end() ) { const QwtTextEngine *e = this->engine( it ); if ( e ) delete e; d_map.remove( format ); } if ( engine != NULL ) d_map.insert( format, engine ); } const QwtTextEngine *QwtTextEngineDict::textEngine( QwtText::TextFormat format ) const { const QwtTextEngine *e = NULL; EngineMap::const_iterator it = d_map.find( format ); if ( it != d_map.end() ) e = engine( it ); return e; } class QwtText::PrivateData { public: PrivateData(): renderFlags( Qt::AlignCenter ), backgroundPen( Qt::NoPen ), backgroundBrush( Qt::NoBrush ), paintAttributes( 0 ), layoutAttributes( 0 ), textEngine( NULL ) { } int renderFlags; QString text; QFont font; QColor color; QPen backgroundPen; QBrush backgroundBrush; QwtText::PaintAttributes paintAttributes; QwtText::LayoutAttributes layoutAttributes; const QwtTextEngine *textEngine; }; class QwtText::LayoutCache { public: void invalidate() { textSize = QSizeF(); } QFont font; QSizeF textSize; }; /*! Constructor \param text Text content \param textFormat Text format */ QwtText::QwtText( const QString &text, QwtText::TextFormat textFormat ) { d_data = new PrivateData; d_data->text = text; d_data->textEngine = textEngine( text, textFormat ); d_layoutCache = new LayoutCache; } //! Copy constructor QwtText::QwtText( const QwtText &other ) { d_data = new PrivateData; *d_data = *other.d_data; d_layoutCache = new LayoutCache; *d_layoutCache = *other.d_layoutCache; } //! Destructor QwtText::~QwtText() { delete d_data; delete d_layoutCache; } //! Assignment operator QwtText &QwtText::operator=( const QwtText & other ) { *d_data = *other.d_data; *d_layoutCache = *other.d_layoutCache; return *this; } //! Relational operator bool QwtText::operator==( const QwtText &other ) const { return d_data->renderFlags == other.d_data->renderFlags && d_data->text == other.d_data->text && d_data->font == other.d_data->font && d_data->color == other.d_data->color && d_data->backgroundPen == other.d_data->backgroundPen && d_data->backgroundBrush == other.d_data->backgroundBrush && d_data->paintAttributes == other.d_data->paintAttributes && d_data->textEngine == other.d_data->textEngine; } //! Relational operator bool QwtText::operator!=( const QwtText &other ) const // invalidate { return !( other == *this ); } /*! Assign a new text content \param text Text content \param textFormat Text format \sa text() */ void QwtText::setText( const QString &text, QwtText::TextFormat textFormat ) { d_data->text = text; d_data->textEngine = textEngine( text, textFormat ); d_layoutCache->invalidate(); } /*! Return the text. \sa setText() */ QString QwtText::text() const { return d_data->text; } /*! \brief Change the render flags The default setting is Qt::AlignCenter \param renderFlags Bitwise OR of the flags used like in QPainter::drawText \sa renderFlags(), QwtTextEngine::draw() \note Some renderFlags might have no effect, depending on the text format. */ void QwtText::setRenderFlags( int renderFlags ) { if ( renderFlags != d_data->renderFlags ) { d_data->renderFlags = renderFlags; d_layoutCache->invalidate(); } } /*! \return Render flags \sa setRenderFlags() */ int QwtText::renderFlags() const { return d_data->renderFlags; } /*! Set the font. \param font Font \note Setting the font might have no effect, when the text contains control sequences for setting fonts. */ void QwtText::setFont( const QFont &font ) { d_data->font = font; setPaintAttribute( PaintUsingTextFont ); } //! Return the font. QFont QwtText::font() const { return d_data->font; } /*! Return the font of the text, if it has one. Otherwise return defaultFont. \param defaultFont Default font \sa setFont(), font(), PaintAttributes */ QFont QwtText::usedFont( const QFont &defaultFont ) const { if ( d_data->paintAttributes & PaintUsingTextFont ) return d_data->font; return defaultFont; } /*! Set the pen color used for painting the text. \param color Color \note Setting the color might have no effect, when the text contains control sequences for setting colors. */ void QwtText::setColor( const QColor &color ) { d_data->color = color; setPaintAttribute( PaintUsingTextColor ); } //! Return the pen color, used for painting the text QColor QwtText::color() const { return d_data->color; } /*! Return the color of the text, if it has one. Otherwise return defaultColor. \param defaultColor Default color \sa setColor(), color(), PaintAttributes */ QColor QwtText::usedColor( const QColor &defaultColor ) const { if ( d_data->paintAttributes & PaintUsingTextColor ) return d_data->color; return defaultColor; } /*! Set the background pen \param pen Background pen \sa backgroundPen(), setBackgroundBrush() */ void QwtText::setBackgroundPen( const QPen &pen ) { d_data->backgroundPen = pen; setPaintAttribute( PaintBackground ); } /*! \return Background pen \sa setBackgroundPen(), backgroundBrush() */ QPen QwtText::backgroundPen() const { return d_data->backgroundPen; } /*! Set the background brush \param brush Background brush \sa backgroundBrush(), setBackgroundPen() */ void QwtText::setBackgroundBrush( const QBrush &brush ) { d_data->backgroundBrush = brush; setPaintAttribute( PaintBackground ); } /*! \return Background brush \sa setBackgroundBrush(), backgroundPen() */ QBrush QwtText::backgroundBrush() const { return d_data->backgroundBrush; } /*! Change a paint attribute \param attribute Paint attribute \param on On/Off \note Used by setFont(), setColor(), setBackgroundPen() and setBackgroundBrush() \sa testPaintAttribute() */ void QwtText::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; } /*! Test a paint attribute \param attribute Paint attribute \return true, if attribute is enabled \sa setPaintAttribute() */ bool QwtText::testPaintAttribute( PaintAttribute attribute ) const { return d_data->paintAttributes & attribute; } /*! Change a layout attribute \param attribute Layout attribute \param on On/Off \sa testLayoutAttribute() */ void QwtText::setLayoutAttribute( LayoutAttribute attribute, bool on ) { if ( on ) d_data->layoutAttributes |= attribute; else d_data->layoutAttributes &= ~attribute; } /*! Test a layout attribute \param attribute Layout attribute \return true, if attribute is enabled \sa setLayoutAttribute() */ bool QwtText::testLayoutAttribute( LayoutAttribute attribute ) const { return d_data->layoutAttributes | attribute; } /*! Find the height for a given width \param defaultFont Font, used for the calculation if the text has no font \param width Width \return Calculated height */ double QwtText::heightForWidth( double width, const QFont &defaultFont ) const { // We want to calculate in screen metrics. So // we need a font that uses screen metrics const QFont font( usedFont( defaultFont ), QApplication::desktop() ); double h = 0; if ( d_data->layoutAttributes & MinimumLayout ) { double left, right, top, bottom; d_data->textEngine->textMargins( font, d_data->text, left, right, top, bottom ); h = d_data->textEngine->heightForWidth( font, d_data->renderFlags, d_data->text, width + left + right ); h -= top + bottom; } else { h = d_data->textEngine->heightForWidth( font, d_data->renderFlags, d_data->text, width ); } return h; } /*! Find the height for a given width \param defaultFont Font, used for the calculation if the text has no font \return Calculated height */ /*! Returns the size, that is needed to render text \param defaultFont Font of the text \return Caluclated size */ QSizeF QwtText::textSize( const QFont &defaultFont ) const { // We want to calculate in screen metrics. So // we need a font that uses screen metrics const QFont font( usedFont( defaultFont ), QApplication::desktop() ); if ( !d_layoutCache->textSize.isValid() || d_layoutCache->font != font ) { d_layoutCache->textSize = d_data->textEngine->textSize( font, d_data->renderFlags, d_data->text ); d_layoutCache->font = font; } QSizeF sz = d_layoutCache->textSize; if ( d_data->layoutAttributes & MinimumLayout ) { double left, right, top, bottom; d_data->textEngine->textMargins( font, d_data->text, left, right, top, bottom ); sz -= QSizeF( left + right, top + bottom ); } return sz; } /*! Draw a text into a rectangle \param painter Painter \param rect Rectangle */ void QwtText::draw( QPainter *painter, const QRectF &rect ) const { if ( d_data->paintAttributes & PaintBackground ) { if ( d_data->backgroundPen != Qt::NoPen || d_data->backgroundBrush != Qt::NoBrush ) { painter->save(); painter->setPen( d_data->backgroundPen ); painter->setBrush( d_data->backgroundBrush ); QwtPainter::drawRect( painter, rect ); painter->restore(); } } painter->save(); if ( d_data->paintAttributes & PaintUsingTextFont ) { painter->setFont( d_data->font ); } if ( d_data->paintAttributes & PaintUsingTextColor ) { if ( d_data->color.isValid() ) painter->setPen( d_data->color ); } QRectF expandedRect = rect; if ( d_data->layoutAttributes & MinimumLayout ) { // We want to calculate in screen metrics. So // we need a font that uses screen metrics const QFont font( painter->font(), QApplication::desktop() ); double left, right, top, bottom; d_data->textEngine->textMargins( font, d_data->text, left, right, top, bottom ); expandedRect.setTop( rect.top() - top ); expandedRect.setBottom( rect.bottom() + bottom ); expandedRect.setLeft( rect.left() - left ); expandedRect.setRight( rect.right() + right ); } d_data->textEngine->draw( painter, expandedRect, d_data->renderFlags, d_data->text ); painter->restore(); } /*! Find the text engine for a text format In case of QwtText::AutoText the first text engine (beside QwtPlainTextEngine) is returned, where QwtTextEngine::mightRender returns true. If there is none QwtPlainTextEngine is returnd. If no text engine is registered for the format QwtPlainTextEngine is returnd. \param text Text, needed in case of AutoText \param format Text format */ const QwtTextEngine *QwtText::textEngine( const QString &text, QwtText::TextFormat format ) { return QwtTextEngineDict::dict().textEngine( text, format ); } /*! Assign/Replace a text engine for a text format With setTextEngine it is possible to extend Qwt with other types of text formats. For QwtText::PlainText it is not allowed to assign a engine == NULL. \param format Text format \param engine Text engine \sa QwtMathMLTextEngine \warning Using QwtText::AutoText does nothing. */ void QwtText::setTextEngine( QwtText::TextFormat format, QwtTextEngine *engine ) { QwtTextEngineDict::dict().setTextEngine( format, engine ); } /*! \brief Find the text engine for a text format textEngine can be used to find out if a text format is supported. \param format Text format \return The text engine, or NULL if no engine is available. */ const QwtTextEngine *QwtText::textEngine( QwtText::TextFormat format ) { return QwtTextEngineDict::dict().textEngine( format ); } pcp-gui-1.5.11/src/libqwt/qwt_text_engine.cpp0000644000000000000000000002105512176111212016027 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2003 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_text_engine.h" #include "qwt_math.h" #include "qwt_painter.h" #include #include #include #include #include #include #include #include static QString taggedRichText( const QString &text, int flags ) { QString richText = text; // By default QSimpleRichText is Qt::AlignLeft if ( flags & Qt::AlignJustify ) { richText.prepend( QString::fromLatin1( "
" ) ); richText.append( QString::fromLatin1( "
" ) ); } else if ( flags & Qt::AlignRight ) { richText.prepend( QString::fromLatin1( "
" ) ); richText.append( QString::fromLatin1( "
" ) ); } else if ( flags & Qt::AlignHCenter ) { richText.prepend( QString::fromLatin1( "
" ) ); richText.append( QString::fromLatin1( "
" ) ); } return richText; } class QwtRichTextDocument: public QTextDocument { public: QwtRichTextDocument( const QString &text, int flags, const QFont &font ) { setUndoRedoEnabled( false ); setDefaultFont( font ); setHtml( text ); // make sure we have a document layout ( void )documentLayout(); QTextOption option = defaultTextOption(); if ( flags & Qt::TextWordWrap ) option.setWrapMode( QTextOption::WordWrap ); else option.setWrapMode( QTextOption::NoWrap ); option.setAlignment( ( Qt::Alignment ) flags ); setDefaultTextOption( option ); QTextFrame *root = rootFrame(); QTextFrameFormat fm = root->frameFormat(); fm.setBorder( 0 ); fm.setMargin( 0 ); fm.setPadding( 0 ); fm.setBottomMargin( 0 ); fm.setLeftMargin( 0 ); root->setFrameFormat( fm ); adjustSize(); } }; class QwtPlainTextEngine::PrivateData { public: int effectiveAscent( const QFont &font ) const { const QString fontKey = font.key(); QMap::const_iterator it = d_ascentCache.find( fontKey ); if ( it == d_ascentCache.end() ) { int ascent = findAscent( font ); it = d_ascentCache.insert( fontKey, ascent ); } return ( *it ); } private: int findAscent( const QFont &font ) const { static const QString dummy( "E" ); static const QColor white( Qt::white ); const QFontMetrics fm( font ); QPixmap pm( fm.width( dummy ), fm.height() ); pm.fill( white ); QPainter p( &pm ); p.setFont( font ); p.drawText( 0, 0, pm.width(), pm.height(), 0, dummy ); p.end(); const QImage img = pm.toImage(); int row = 0; for ( row = 0; row < img.height(); row++ ) { const QRgb *line = ( const QRgb * )img.scanLine( row ); const int w = pm.width(); for ( int col = 0; col < w; col++ ) { if ( line[col] != white.rgb() ) return fm.ascent() - row + 1; } } return fm.ascent(); } mutable QMap d_ascentCache; }; //! Constructor QwtTextEngine::QwtTextEngine() { } //! Destructor QwtTextEngine::~QwtTextEngine() { } //! Constructor QwtPlainTextEngine::QwtPlainTextEngine() { d_data = new PrivateData; } //! Destructor QwtPlainTextEngine::~QwtPlainTextEngine() { delete d_data; } /*! Find the height for a given width \param font Font of the text \param flags Bitwise OR of the flags used like in QPainter::drawText \param text Text to be rendered \param width Width \return Calculated height */ double QwtPlainTextEngine::heightForWidth( const QFont& font, int flags, const QString& text, double width ) const { const QFontMetricsF fm( font ); const QRectF rect = fm.boundingRect( QRectF( 0, 0, width, QWIDGETSIZE_MAX ), flags, text ); return rect.height(); } /*! Returns the size, that is needed to render text \param font Font of the text \param flags Bitwise OR of the flags used like in QPainter::drawText \param text Text to be rendered \return Caluclated size */ QSizeF QwtPlainTextEngine::textSize( const QFont &font, int flags, const QString& text ) const { const QFontMetricsF fm( font ); const QRectF rect = fm.boundingRect( QRectF( 0, 0, QWIDGETSIZE_MAX, QWIDGETSIZE_MAX ), flags, text ); return rect.size(); } /*! Return margins around the texts \param font Font of the text \param left Return 0 \param right Return 0 \param top Return value for the top margin \param bottom Return value for the bottom margin */ void QwtPlainTextEngine::textMargins( const QFont &font, const QString &, double &left, double &right, double &top, double &bottom ) const { left = right = top = 0; const QFontMetricsF fm( font ); top = fm.ascent() - d_data->effectiveAscent( font ); bottom = fm.descent(); } /*! \brief Draw the text in a clipping rectangle A wrapper for QPainter::drawText. \param painter Painter \param rect Clipping rectangle \param flags Bitwise OR of the flags used like in QPainter::drawText \param text Text to be rendered */ void QwtPlainTextEngine::draw( QPainter *painter, const QRectF &rect, int flags, const QString& text ) const { QwtPainter::drawText( painter, rect, flags, text ); } /*! Test if a string can be rendered by this text engine. \return Always true. All texts can be rendered by QwtPlainTextEngine */ bool QwtPlainTextEngine::mightRender( const QString & ) const { return true; } #ifndef QT_NO_RICHTEXT //! Constructor QwtRichTextEngine::QwtRichTextEngine() { } /*! Find the height for a given width \param font Font of the text \param flags Bitwise OR of the flags used like in QPainter::drawText \param text Text to be rendered \param width Width \return Calculated height */ double QwtRichTextEngine::heightForWidth( const QFont& font, int flags, const QString& text, double width ) const { QwtRichTextDocument doc( text, flags, font ); doc.setPageSize( QSizeF( width, QWIDGETSIZE_MAX ) ); return doc.documentLayout()->documentSize().height(); } /*! Returns the size, that is needed to render text \param font Font of the text \param flags Bitwise OR of the flags used like in QPainter::drawText \param text Text to be rendered \return Caluclated size */ QSizeF QwtRichTextEngine::textSize( const QFont &font, int flags, const QString& text ) const { QwtRichTextDocument doc( text, flags, font ); QTextOption option = doc.defaultTextOption(); if ( option.wrapMode() != QTextOption::NoWrap ) { option.setWrapMode( QTextOption::NoWrap ); doc.setDefaultTextOption( option ); doc.adjustSize(); } return doc.size(); } /*! Draw the text in a clipping rectangle \param painter Painter \param rect Clipping rectangle \param flags Bitwise OR of the flags like in for QPainter::drawText \param text Text to be rendered */ void QwtRichTextEngine::draw( QPainter *painter, const QRectF &rect, int flags, const QString& text ) const { QwtRichTextDocument doc( text, flags, painter->font() ); QwtPainter::drawSimpleRichText( painter, rect, flags, doc ); } /*! Wrap text into
tags according flags \param text Text \param flags Bitwise OR of the flags like in for QPainter::drawText \return Tagged text */ QString QwtRichTextEngine::taggedText( const QString &text, int flags ) const { return taggedRichText( text, flags ); } /*! Test if a string can be rendered by this text engine \param text Text to be tested \return QStyleSheet::mightBeRichText(text); */ bool QwtRichTextEngine::mightRender( const QString &text ) const { return Qt::mightBeRichText( text ); } /*! Return margins around the texts \param left Return 0 \param right Return 0 \param top Return 0 \param bottom Return 0 */ void QwtRichTextEngine::textMargins( const QFont &, const QString &, double &left, double &right, double &top, double &bottom ) const { left = right = top = bottom = 0; } #endif // !QT_NO_RICHTEXT pcp-gui-1.5.11/src/libqwt/qwt_text_label.cpp0000644000000000000000000001475212176111212015647 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_text_label.h" #include "qwt_text.h" #include "qwt_painter.h" #include #include #include class QwtTextLabel::PrivateData { public: PrivateData(): indent( 4 ), margin( 0 ) { } int indent; int margin; QwtText text; }; /*! Constructs an empty label. \param parent Parent widget */ QwtTextLabel::QwtTextLabel( QWidget *parent ): QFrame( parent ) { init(); } /*! Constructs a label that displays the text, text \param parent Parent widget \param text Text */ QwtTextLabel::QwtTextLabel( const QwtText &text, QWidget *parent ): QFrame( parent ) { init(); d_data->text = text; } //! Destructor QwtTextLabel::~QwtTextLabel() { delete d_data; } void QwtTextLabel::init() { d_data = new PrivateData(); setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); } /*! Change the label's text, keeping all other QwtText attributes \param text New text \param textFormat Format of text \sa QwtText */ void QwtTextLabel::setText( const QString &text, QwtText::TextFormat textFormat ) { d_data->text.setText( text, textFormat ); update(); updateGeometry(); } /*! Change the label's text \param text New text */ void QwtTextLabel::setText( const QwtText &text ) { d_data->text = text; update(); updateGeometry(); } //! Return the text const QwtText &QwtTextLabel::text() const { return d_data->text; } //! Clear the text and all QwtText attributes void QwtTextLabel::clear() { d_data->text = QwtText(); update(); updateGeometry(); } //! Return label's text indent in pixels int QwtTextLabel::indent() const { return d_data->indent; } /*! Set label's text indent in pixels \param indent Indentation in pixels */ void QwtTextLabel::setIndent( int indent ) { if ( indent < 0 ) indent = 0; d_data->indent = indent; update(); updateGeometry(); } //! Return label's text indent in pixels int QwtTextLabel::margin() const { return d_data->margin; } /*! Set label's margin in pixels \param margin Margin in pixels */ void QwtTextLabel::setMargin( int margin ) { d_data->margin = margin; update(); updateGeometry(); } //! Return label's margin in pixels QSize QwtTextLabel::sizeHint() const { return minimumSizeHint(); } //! Return a minimum size hint QSize QwtTextLabel::minimumSizeHint() const { QSizeF sz = d_data->text.textSize( font() ); int mw = 2 * ( frameWidth() + d_data->margin ); int mh = mw; int indent = d_data->indent; if ( indent <= 0 ) indent = defaultIndent(); if ( indent > 0 ) { const int align = d_data->text.renderFlags(); if ( align & Qt::AlignLeft || align & Qt::AlignRight ) mw += d_data->indent; else if ( align & Qt::AlignTop || align & Qt::AlignBottom ) mh += d_data->indent; } sz += QSizeF( mw, mh ); return QSize( qCeil( sz.width() ), qCeil( sz.height() ) ); } /*! \param width Width \return Preferred height for this widget, given the width. */ int QwtTextLabel::heightForWidth( int width ) const { const int renderFlags = d_data->text.renderFlags(); int indent = d_data->indent; if ( indent <= 0 ) indent = defaultIndent(); width -= 2 * frameWidth(); if ( renderFlags & Qt::AlignLeft || renderFlags & Qt::AlignRight ) width -= indent; int height = qCeil( d_data->text.heightForWidth( width, font() ) ); if ( ( renderFlags & Qt::AlignTop ) || ( renderFlags & Qt::AlignBottom ) ) height += indent; height += 2 * frameWidth(); return height; } /*! Qt paint event \param event Paint event */ void QwtTextLabel::paintEvent( QPaintEvent *event ) { QPainter painter( this ); if ( !contentsRect().contains( event->rect() ) ) { painter.save(); painter.setClipRegion( event->region() & frameRect() ); drawFrame( &painter ); painter.restore(); } painter.setClipRegion( event->region() & contentsRect() ); drawContents( &painter ); } //! Redraw the text and focus indicator void QwtTextLabel::drawContents( QPainter *painter ) { const QRect r = textRect(); if ( r.isEmpty() ) return; painter->setFont( font() ); painter->setPen( palette().color( QPalette::Active, QPalette::Text ) ); drawText( painter, r ); if ( hasFocus() ) { const int margin = 2; QRect focusRect = contentsRect(); focusRect.setRect( focusRect.x() + margin, focusRect.y() + margin, focusRect.width() - 2 * margin - 2, focusRect.height() - 2 * margin - 2 ); QwtPainter::drawFocusRect( painter, this, focusRect ); } } //! Redraw the text void QwtTextLabel::drawText( QPainter *painter, const QRect &textRect ) { d_data->text.draw( painter, textRect ); } /*! Calculate the rect for the text in widget coordinates \return Text rect */ QRect QwtTextLabel::textRect() const { QRect r = contentsRect(); if ( !r.isEmpty() && d_data->margin > 0 ) { r.setRect( r.x() + d_data->margin, r.y() + d_data->margin, r.width() - 2 * d_data->margin, r.height() - 2 * d_data->margin ); } if ( !r.isEmpty() ) { int indent = d_data->indent; if ( indent <= 0 ) indent = defaultIndent(); if ( indent > 0 ) { const int renderFlags = d_data->text.renderFlags(); if ( renderFlags & Qt::AlignLeft ) r.setX( r.x() + indent ); else if ( renderFlags & Qt::AlignRight ) r.setWidth( r.width() - indent ); else if ( renderFlags & Qt::AlignTop ) r.setY( r.y() + indent ); else if ( renderFlags & Qt::AlignBottom ) r.setHeight( r.height() - indent ); } } return r; } int QwtTextLabel::defaultIndent() const { if ( frameWidth() <= 0 ) return 0; QFont fnt; if ( d_data->text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) fnt = d_data->text.font(); else fnt = font(); return QFontMetrics( fnt ).width( 'x' ) / 2; } pcp-gui-1.5.11/src/libqwt/qwt_thermo.cpp0000644000000000000000000006037312176111212015022 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_thermo.h" #include "qwt_scale_engine.h" #include "qwt_scale_draw.h" #include "qwt_scale_map.h" #include "qwt_color_map.h" #include #include #include #include #include static inline bool qwtIsLogarithmic( const QwtThermo *thermo ) { const QwtScaleTransformation::Type scaleType = thermo->scaleEngine()->transformation()->type(); return ( scaleType == QwtScaleTransformation::Log10 ); } static inline void qwtDrawLine( QPainter *painter, int pos, const QColor &color, const QRect pipeRect, Qt::Orientation orientation ) { painter->setPen( color ); if ( orientation == Qt::Horizontal ) painter->drawLine( pos, pipeRect.top(), pos, pipeRect.bottom() ); else painter->drawLine( pipeRect.left(), pos, pipeRect.right(), pos ); } QVector qwtTickList( const QwtScaleDiv &scaleDiv, double value ) { QVector values; double lowerLimit = scaleDiv.interval().minValue(); double upperLimit = scaleDiv.interval().maxValue(); if ( upperLimit < lowerLimit ) qSwap( lowerLimit, upperLimit ); if ( value < lowerLimit ) return values; if ( value < upperLimit ) upperLimit = value; values += lowerLimit; for ( int tickType = QwtScaleDiv::MinorTick; tickType < QwtScaleDiv::NTickTypes; tickType++ ) { const QList ticks = scaleDiv.ticks( tickType ); for ( int i = 0; i < ticks.count(); i++ ) { const double v = ticks[i]; if ( v > lowerLimit && v < upperLimit ) values += v; } } values += upperLimit; return values; } class QwtThermo::PrivateData { public: PrivateData(): orientation( Qt::Vertical ), scalePos( QwtThermo::LeftScale ), spacing( 3 ), borderWidth( 2 ), pipeWidth( 10 ), minValue( 0.0 ), maxValue( 0.0 ), value( 0.0 ), alarmLevel( 0.0 ), alarmEnabled( false ), autoFillPipe( true ), colorMap( NULL ) { rangeFlags = QwtInterval::IncludeBorders; } ~PrivateData() { delete colorMap; } QwtScaleMap map; Qt::Orientation orientation; ScalePos scalePos; int spacing; int borderWidth; int pipeWidth; double minValue; double maxValue; QwtInterval::BorderFlags rangeFlags; double value; double alarmLevel; bool alarmEnabled; bool autoFillPipe; QwtColorMap *colorMap; }; /*! Constructor \param parent Parent widget */ QwtThermo::QwtThermo( QWidget *parent ): QWidget( parent ) { d_data = new PrivateData; setRange( 0.0, 1.0, false ); QSizePolicy policy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ); if ( d_data->orientation == Qt::Vertical ) policy.transpose(); setSizePolicy( policy ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); } //! Destructor QwtThermo::~QwtThermo() { delete d_data; } /*! \brief Exclude/Include min/max values According to the flags minValue() and maxValue() are included/excluded from the pipe. In case of an excluded value the corresponding tick is painted 1 pixel off of the pipeRect(). F.e. when a minimum of 0.0 has to be displayed as an empty pipe the minValue() needs to be excluded. \param flags Range flags \sa rangeFlags() */ void QwtThermo::setRangeFlags( QwtInterval::BorderFlags flags ) { if ( d_data->rangeFlags != flags ) { d_data->rangeFlags = flags; update(); } } /*! \return Range flags \sa setRangeFlags() */ QwtInterval::BorderFlags QwtThermo::rangeFlags() const { return d_data->rangeFlags; } /*! Set the maximum value. \param maxValue Maximum value \sa maxValue(), setMinValue(), setRange() */ void QwtThermo::setMaxValue( double maxValue ) { setRange( d_data->minValue, maxValue, qwtIsLogarithmic( this ) ); } //! Return the maximum value. double QwtThermo::maxValue() const { return d_data->maxValue; } /*! Set the minimum value. \param minValue Minimum value \sa minValue(), setMaxValue(), setRange() */ void QwtThermo::setMinValue( double minValue ) { setRange( minValue, d_data->maxValue, qwtIsLogarithmic( this ) ); } //! Return the minimum value. double QwtThermo::minValue() const { return d_data->minValue; } /*! Set the current value. \param value New Value \sa value() */ void QwtThermo::setValue( double value ) { if ( d_data->value != value ) { d_data->value = value; update(); } } //! Return the value. double QwtThermo::value() const { return d_data->value; } /*! \brief Set a scale draw For changing the labels of the scales, it is necessary to derive from QwtScaleDraw and overload QwtScaleDraw::label(). \param scaleDraw ScaleDraw object, that has to be created with new and will be deleted in ~QwtThermo or the next call of setScaleDraw(). */ void QwtThermo::setScaleDraw( QwtScaleDraw *scaleDraw ) { setAbstractScaleDraw( scaleDraw ); } /*! \return the scale draw of the thermo \sa setScaleDraw() */ const QwtScaleDraw *QwtThermo::scaleDraw() const { return static_cast( abstractScaleDraw() ); } /*! \return the scale draw of the thermo \sa setScaleDraw() */ QwtScaleDraw *QwtThermo::scaleDraw() { return static_cast( abstractScaleDraw() ); } /*! Qt paint event. \param event Paint event */ void QwtThermo::paintEvent( QPaintEvent *event ) { QPainter painter( this ); painter.setClipRegion( event->region() ); QStyleOption opt; opt.init(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); const QRect tRect = pipeRect(); if ( !tRect.contains( event->rect() ) ) { if ( d_data->scalePos != NoScale ) scaleDraw()->draw( &painter, palette() ); } const int bw = d_data->borderWidth; const QBrush brush = palette().brush( QPalette::Base ); qDrawShadePanel( &painter, tRect.adjusted( -bw, -bw, bw, bw ), palette(), true, bw, d_data->autoFillPipe ? &brush : NULL ); drawLiquid( &painter, tRect ); } /*! Qt resize event handler \param event Resize event */ void QwtThermo::resizeEvent( QResizeEvent *event ) { Q_UNUSED( event ); layoutThermo( false ); } /*! Qt change event handler \param event Event */ void QwtThermo::changeEvent( QEvent *event ) { switch( event->type() ) { case QEvent::StyleChange: case QEvent::FontChange: { layoutThermo( true ); break; } default: break; } } /*! Recalculate the QwtThermo geometry and layout based on the QwtThermo::contentsRect() and the fonts. \param update_geometry notify the layout system and call update to redraw the scale */ void QwtThermo::layoutThermo( bool update_geometry ) { const QRect tRect = pipeRect(); const int bw = d_data->borderWidth + d_data->spacing; const bool inverted = ( maxValue() < minValue() ); int from, to; if ( d_data->orientation == Qt::Horizontal ) { from = tRect.left(); to = tRect.right(); if ( d_data->rangeFlags & QwtInterval::ExcludeMinimum ) { if ( inverted ) to++; else from--; } if ( d_data->rangeFlags & QwtInterval::ExcludeMaximum ) { if ( inverted ) from--; else to++; } switch ( d_data->scalePos ) { case TopScale: { scaleDraw()->setAlignment( QwtScaleDraw::TopScale ); scaleDraw()->move( from, tRect.top() - bw ); scaleDraw()->setLength( to - from ); break; } case BottomScale: case NoScale: default: { scaleDraw()->setAlignment( QwtScaleDraw::BottomScale ); scaleDraw()->move( from, tRect.bottom() + bw ); scaleDraw()->setLength( to - from ); break; } } d_data->map.setPaintInterval( from, to ); } else // Qt::Vertical { from = tRect.top(); to = tRect.bottom(); if ( d_data->rangeFlags & QwtInterval::ExcludeMinimum ) { if ( inverted ) from--; else to++; } if ( d_data->rangeFlags & QwtInterval::ExcludeMaximum ) { if ( inverted ) to++; else from--; } switch ( d_data->scalePos ) { case RightScale: { scaleDraw()->setAlignment( QwtScaleDraw::RightScale ); scaleDraw()->move( tRect.right() + bw, from ); scaleDraw()->setLength( to - from ); break; } case LeftScale: case NoScale: default: { scaleDraw()->setAlignment( QwtScaleDraw::LeftScale ); scaleDraw()->move( tRect.left() - bw, from ); scaleDraw()->setLength( to - from ); break; } } d_data->map.setPaintInterval( to, from ); } if ( update_geometry ) { updateGeometry(); update(); } } /*! \return Bounding rectangle of the pipe ( without borders ) in widget coordinates */ QRect QwtThermo::pipeRect() const { const QRect cr = contentsRect(); int mbd = 0; if ( d_data->scalePos != NoScale ) { int d1, d2; scaleDraw()->getBorderDistHint( font(), d1, d2 ); mbd = qMax( d1, d2 ); } const int bw = d_data->borderWidth; QRect tRect; if ( d_data->orientation == Qt::Horizontal ) { switch ( d_data->scalePos ) { case TopScale: { tRect.setRect( cr.x() + mbd + bw, cr.y() + cr.height() - d_data->pipeWidth - bw, cr.width() - 2 * ( bw + mbd ), d_data->pipeWidth ); break; } case BottomScale: case NoScale: default: { tRect.setRect( cr.x() + mbd + bw, cr.y() + bw, cr.width() - 2 * ( bw + mbd ), d_data->pipeWidth ); break; } } } else // Qt::Vertical { switch ( d_data->scalePos ) { case RightScale: { tRect.setRect( cr.x() + bw, cr.y() + mbd + bw, d_data->pipeWidth, cr.height() - 2 * ( bw + mbd ) ); break; } case LeftScale: case NoScale: default: { tRect.setRect( cr.x() + cr.width() - bw - d_data->pipeWidth, cr.y() + mbd + bw, d_data->pipeWidth, cr.height() - 2 * ( bw + mbd ) ); break; } } } return tRect; } /*! \brief Set the thermometer orientation and the scale position. The scale position NoScale disables the scale. \param o orientation. Possible values are Qt::Horizontal and Qt::Vertical. The default value is Qt::Vertical. \param s Position of the scale. The default value is NoScale. A valid combination of scale position and orientation is enforced: - a horizontal thermometer can have the scale positions TopScale, BottomScale or NoScale; - a vertical thermometer can have the scale positions LeftScale, RightScale or NoScale; - an invalid scale position will default to NoScale. \sa setScalePosition() */ void QwtThermo::setOrientation( Qt::Orientation o, ScalePos s ) { if ( o == d_data->orientation && s == d_data->scalePos ) return; switch ( o ) { case Qt::Horizontal: { if ( ( s == NoScale ) || ( s == BottomScale ) || ( s == TopScale ) ) d_data->scalePos = s; else d_data->scalePos = NoScale; break; } case Qt::Vertical: { if ( ( s == NoScale ) || ( s == LeftScale ) || ( s == RightScale ) ) d_data->scalePos = s; else d_data->scalePos = NoScale; break; } } if ( o != d_data->orientation ) { if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) ) { QSizePolicy sp = sizePolicy(); sp.transpose(); setSizePolicy( sp ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); } } d_data->orientation = o; layoutThermo( true ); } /*! \brief Change the scale position (and thermometer orientation). \param scalePos Position of the scale. A valid combination of scale position and orientation is enforced: - if the new scale position is LeftScale or RightScale, the scale orientation will become Qt::Vertical; - if the new scale position is BottomScale or TopScale, the scale orientation will become Qt::Horizontal; - if the new scale position is NoScale, the scale orientation will not change. \sa setOrientation(), scalePosition() */ void QwtThermo::setScalePosition( ScalePos scalePos ) { if ( ( scalePos == BottomScale ) || ( scalePos == TopScale ) ) setOrientation( Qt::Horizontal, scalePos ); else if ( ( scalePos == LeftScale ) || ( scalePos == RightScale ) ) setOrientation( Qt::Vertical, scalePos ); else setOrientation( d_data->orientation, NoScale ); } /*! Return the scale position. \sa setScalePosition() */ QwtThermo::ScalePos QwtThermo::scalePosition() const { return d_data->scalePos; } //! Notify a scale change. void QwtThermo::scaleChange() { layoutThermo( true ); } /*! Redraw the liquid in thermometer pipe. \param painter Painter \param pipeRect Bounding rectangle of the pipe without borders */ void QwtThermo::drawLiquid( QPainter *painter, const QRect &pipeRect ) const { painter->save(); painter->setClipRect( pipeRect, Qt::IntersectClip ); const bool inverted = ( maxValue() < minValue() ); if ( d_data->colorMap != NULL ) { QwtInterval interval( d_data->minValue, d_data->maxValue ); interval = interval.normalized(); // Because the positions of the ticks are rounded // we calculate the colors for the rounded tick values QVector values = qwtTickList( scaleDraw()->scaleDiv(), d_data->value ); if ( d_data->map.isInverting() ) qSort( values.begin(), values.end(), qGreater() ); else qSort( values.begin(), values.end(), qLess() ); int from; if ( !values.isEmpty() ) { from = qRound( d_data->map.transform( values[0] ) ); qwtDrawLine( painter, from, d_data->colorMap->color( interval, values[0] ), pipeRect, d_data->orientation ); } for ( int i = 1; i < values.size(); i++ ) { const int to = qRound( d_data->map.transform( values[i] ) ); for ( int pos = from + 1; pos < to; pos++ ) { const double v = d_data->map.invTransform( pos ); qwtDrawLine( painter, pos, d_data->colorMap->color( interval, v ), pipeRect, d_data->orientation ); } qwtDrawLine( painter, to, d_data->colorMap->color( interval, values[i] ), pipeRect, d_data->orientation ); from = to; } } else { const int tval = qRound( d_data->map.transform( d_data->value ) ); QRect fillRect = pipeRect; if ( d_data->orientation == Qt::Horizontal ) { if ( inverted ) fillRect.setLeft( tval ); else fillRect.setRight( tval ); } else // Qt::Vertical { if ( inverted ) fillRect.setBottom( tval ); else fillRect.setTop( tval ); } if ( d_data->alarmEnabled && d_data->value >= d_data->alarmLevel ) { QRect alarmRect = fillRect; const int taval = qRound( d_data->map.transform( d_data->alarmLevel ) ); if ( d_data->orientation == Qt::Horizontal ) { if ( inverted ) alarmRect.setRight( taval ); else alarmRect.setLeft( taval ); } else { if ( inverted ) alarmRect.setTop( taval ); else alarmRect.setBottom( taval ); } fillRect = QRegion( fillRect ).subtracted( alarmRect ).boundingRect(); painter->fillRect( alarmRect, palette().brush( QPalette::Highlight ) ); } painter->fillRect( fillRect, palette().brush( QPalette::ButtonText ) ); } painter->restore(); } /*! \brief Change the spacing between pipe and scale A spacing of 0 means, that the backbone of the scale is below the pipe. The default setting is 3 pixels. \param spacing Number of pixels \sa spacing(); */ void QwtThermo::setSpacing( int spacing ) { if ( spacing <= 0 ) spacing = 0; if ( spacing != d_data->spacing ) { d_data->spacing = spacing; layoutThermo( true ); } } /*! \return Number of pixels between pipe and scale \sa setSpacing() */ int QwtThermo::spacing() const { return d_data->spacing; } /*! Set the border width of the pipe. \param width Border width \sa borderWidth() */ void QwtThermo::setBorderWidth( int width ) { if ( width <= 0 ) width = 0; if ( width != d_data->borderWidth ) { d_data->borderWidth = width; layoutThermo( true ); } } /*! Return the border width of the thermometer pipe. \sa setBorderWidth() */ int QwtThermo::borderWidth() const { return d_data->borderWidth; } /*! \brief Set the range \param minValue value corresponding lower or left end of the thermometer \param maxValue value corresponding to the upper or right end of the thermometer \param logarithmic logarithmic mapping, true or false */ void QwtThermo::setRange( double minValue, double maxValue, bool logarithmic ) { if ( minValue == d_data->minValue && maxValue == d_data->maxValue && logarithmic == qwtIsLogarithmic( this ) ) { return; } if ( logarithmic != qwtIsLogarithmic( this ) ) { if ( logarithmic ) setScaleEngine( new QwtLog10ScaleEngine ); else setScaleEngine( new QwtLinearScaleEngine ); } d_data->minValue = minValue; d_data->maxValue = maxValue; /* There are two different maps, one for the scale, the other for the values. This is confusing and will be changed in the future. TODO ... */ d_data->map.setTransformation( scaleEngine()->transformation() ); d_data->map.setScaleInterval( minValue, maxValue ); if ( autoScale() ) rescale( minValue, maxValue ); layoutThermo( true ); } /*! \brief Assign a color map for the fill color \param colorMap Color map \warning The alarm threshold has no effect, when a color map has been assigned */ void QwtThermo::setColorMap( QwtColorMap *colorMap ) { if ( colorMap != d_data->colorMap ) { delete d_data->colorMap; d_data->colorMap = colorMap; } } /*! \return Color map for the fill color \warning The alarm threshold has no effect, when a color map has been assigned */ QwtColorMap *QwtThermo::colorMap() { return d_data->colorMap; } /*! \return Color map for the fill color \warning The alarm threshold has no effect, when a color map has been assigned */ const QwtColorMap *QwtThermo::colorMap() const { return d_data->colorMap; } /*! \brief Change the brush of the liquid. Changes the QPalette::ButtonText brush of the palette. \param brush New brush. \sa fillBrush(), QWidget::setPalette() */ void QwtThermo::setFillBrush( const QBrush& brush ) { QPalette pal = palette(); pal.setBrush( QPalette::ButtonText, brush ); setPalette( pal ); } /*! Return the liquid ( QPalette::ButtonText ) brush. \sa setFillBrush(), QWidget::palette() */ const QBrush& QwtThermo::fillBrush() const { return palette().brush( QPalette::ButtonText ); } /*! \brief Specify the liquid brush above the alarm threshold Changes the QPalette::Highlight brush of the palette. \param brush New brush. \sa alarmBrush(), QWidget::setPalette() \warning The alarm threshold has no effect, when a color map has been assigned */ void QwtThermo::setAlarmBrush( const QBrush& brush ) { QPalette pal = palette(); pal.setBrush( QPalette::Highlight, brush ); setPalette( pal ); } /*! Return the liquid brush ( QPalette::Highlight ) above the alarm threshold. \sa setAlarmBrush(), QWidget::palette() \warning The alarm threshold has no effect, when a color map has been assigned */ const QBrush& QwtThermo::alarmBrush() const { return palette().brush( QPalette::Highlight ); } /*! Specify the alarm threshold. \param level Alarm threshold \sa alarmLevel() \warning The alarm threshold has no effect, when a color map has been assigned */ void QwtThermo::setAlarmLevel( double level ) { d_data->alarmLevel = level; d_data->alarmEnabled = 1; update(); } /*! Return the alarm threshold. \sa setAlarmLevel() \warning The alarm threshold has no effect, when a color map has been assigned */ double QwtThermo::alarmLevel() const { return d_data->alarmLevel; } /*! Change the width of the pipe. \param width Width of the pipe \sa pipeWidth() */ void QwtThermo::setPipeWidth( int width ) { if ( width > 0 ) { d_data->pipeWidth = width; layoutThermo( true ); } } /*! Return the width of the pipe. \sa setPipeWidth() */ int QwtThermo::pipeWidth() const { return d_data->pipeWidth; } /*! \brief Enable or disable the alarm threshold \param tf true (disabled) or false (enabled) \warning The alarm threshold has no effect, when a color map has been assigned */ void QwtThermo::setAlarmEnabled( bool tf ) { d_data->alarmEnabled = tf; update(); } /*! \return True, when the alarm threshold is enabled. \warning The alarm threshold has no effect, when a color map has been assigned */ bool QwtThermo::alarmEnabled() const { return d_data->alarmEnabled; } /*! \return the minimum size hint \sa minimumSizeHint() */ QSize QwtThermo::sizeHint() const { return minimumSizeHint(); } /*! \brief Return a minimum size hint \warning The return value depends on the font and the scale. \sa sizeHint() */ QSize QwtThermo::minimumSizeHint() const { int w = 0, h = 0; if ( d_data->scalePos != NoScale ) { const int sdExtent = qCeil( scaleDraw()->extent( font() ) ); const int sdLength = scaleDraw()->minLength( font() ); w = sdLength; h = d_data->pipeWidth + sdExtent + d_data->spacing; } else // no scale { w = 200; h = d_data->pipeWidth; } if ( d_data->orientation == Qt::Vertical ) qSwap( w, h ); w += 2 * d_data->borderWidth; h += 2 * d_data->borderWidth; // finally add the margins int left, right, top, bottom; getContentsMargins( &left, &top, &right, &bottom ); w += left + right; h += top + bottom; return QSize( w, h ); } pcp-gui-1.5.11/src/libqwt/qwt_wheel.cpp0000644000000000000000000003267312176111212014632 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_wheel.h" #include "qwt_math.h" #include "qwt_painter.h" #include #include #include #include #include #include #if QT_VERSION < 0x040601 #define qFastSin(x) ::sin(x) #endif class QwtWheel::PrivateData { public: PrivateData() { viewAngle = 175.0; totalAngle = 360.0; tickCnt = 10; wheelBorderWidth = 2; borderWidth = 2; wheelWidth = 20; }; double viewAngle; double totalAngle; int tickCnt; int wheelBorderWidth; int borderWidth; int wheelWidth; }; //! Constructor QwtWheel::QwtWheel( QWidget *parent ): QwtAbstractSlider( Qt::Horizontal, parent ) { d_data = new PrivateData; setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); setUpdateTime( 50 ); } //! Destructor QwtWheel::~QwtWheel() { delete d_data; } /*! \brief Adjust the number of grooves in the wheel's surface. The number of grooves is limited to 6 <= cnt <= 50. Values outside this range will be clipped. The default value is 10. \param cnt Number of grooves per 360 degrees \sa tickCnt() */ void QwtWheel::setTickCnt( int cnt ) { d_data->tickCnt = qBound( 6, cnt, 50 ); update(); } /*! \return Number of grooves in the wheel's surface. \sa setTickCnt() */ int QwtWheel::tickCnt() const { return d_data->tickCnt; } /*! \return mass */ double QwtWheel::mass() const { return QwtAbstractSlider::mass(); } /*! \brief Set the wheel border width of the wheel. The wheel border must not be smaller than 1 and is limited in dependence on the wheel's size. Values outside the allowed range will be clipped. The wheel border defaults to 2. \param borderWidth Border width \sa internalBorder() */ void QwtWheel::setWheelBorderWidth( int borderWidth ) { const int d = qMin( width(), height() ) / 3; borderWidth = qMin( borderWidth, d ); d_data->wheelBorderWidth = qMax( borderWidth, 1 ); update(); } /*! \return Wheel border width \sa setWheelBorderWidth() */ int QwtWheel::wheelBorderWidth() const { return d_data->wheelBorderWidth; } /*! \brief Set the border width The border defaults to 2. \param width Border width \sa borderWidth() */ void QwtWheel::setBorderWidth( int width ) { d_data->borderWidth = qMax( width, 0 ); update(); } /*! \return Border width \sa setBorderWidth() */ int QwtWheel::borderWidth() const { return d_data->borderWidth; } /*! \return Rectangle of the wheel without the outer border */ QRect QwtWheel::wheelRect() const { const int bw = d_data->borderWidth; return contentsRect().adjusted( bw, bw, -bw, -bw ); } /*! \brief Set the total angle which the wheel can be turned. One full turn of the wheel corresponds to an angle of 360 degrees. A total angle of n*360 degrees means that the wheel has to be turned n times around its axis to get from the minimum value to the maximum value. The default setting of the total angle is 360 degrees. \param angle total angle in degrees \sa totalAngle() */ void QwtWheel::setTotalAngle( double angle ) { if ( angle < 0.0 ) angle = 0.0; d_data->totalAngle = angle; update(); } /*! \return Total angle which the wheel can be turned. \sa setTotalAngle() */ double QwtWheel::totalAngle() const { return d_data->totalAngle; } /*! \brief Set the wheel's orientation. \param o Orientation. Allowed values are Qt::Horizontal and Qt::Vertical. Defaults to Qt::Horizontal. \sa QwtAbstractSlider::orientation() */ void QwtWheel::setOrientation( Qt::Orientation o ) { if ( orientation() == o ) return; if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) ) { QSizePolicy sp = sizePolicy(); sp.transpose(); setSizePolicy( sp ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); } QwtAbstractSlider::setOrientation( o ); update(); } /*! \brief Specify the visible portion of the wheel. You may use this function for fine-tuning the appearance of the wheel. The default value is 175 degrees. The value is limited from 10 to 175 degrees. \param angle Visible angle in degrees \sa viewAngle(), setTotalAngle() */ void QwtWheel::setViewAngle( double angle ) { d_data->viewAngle = qBound( 10.0, angle, 175.0 ); update(); } /*! \return Visible portion of the wheel \sa setViewAngle(), totalAngle() */ double QwtWheel::viewAngle() const { return d_data->viewAngle; } //! Determine the value corresponding to a specified point double QwtWheel::getValue( const QPoint &p ) { const QRectF rect = wheelRect(); // The reference position is arbitrary, but the // sign of the offset is important double w, dx; if ( orientation() == Qt::Vertical ) { w = rect.height(); dx = rect.y() - p.y(); } else { w = rect.width(); dx = p.x() - rect.x(); } if ( w == 0.0 ) return 0.0; // w pixels is an arc of viewAngle degrees, // so we convert change in pixels to change in angle const double ang = dx * d_data->viewAngle / w; // value range maps to totalAngle degrees, // so convert the change in angle to a change in value const double val = ang * ( maxValue() - minValue() ) / d_data->totalAngle; // Note, range clamping and rasterizing to step is automatically // handled by QwtAbstractSlider, so we simply return the change in value return val; } /*! \brief Qt Resize Event \param event Resize event */ void QwtWheel::resizeEvent( QResizeEvent *event ) { QwtAbstractSlider::resizeEvent( event ); } /*! \brief Qt Paint Event \param event Paint event */ void QwtWheel::paintEvent( QPaintEvent *event ) { QPainter painter( this ); painter.setClipRegion( event->region() ); QStyleOption opt; opt.init(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); qDrawShadePanel( &painter, contentsRect(), palette(), true, d_data->borderWidth ); drawWheelBackground( &painter, wheelRect() ); drawTicks( &painter, wheelRect() ); if ( hasFocus() ) QwtPainter::drawFocusRect( &painter, this ); } /*! Draw the Wheel's background gradient \param painter Painter \param rect Rectangle for the wheel */ void QwtWheel::drawWheelBackground( QPainter *painter, const QRectF &rect ) { painter->save(); QPalette pal = palette(); // draw shaded background QLinearGradient gradient( rect.topLeft(), ( orientation() == Qt::Horizontal ) ? rect.topRight() : rect.bottomLeft() ); gradient.setColorAt( 0.0, pal.color( QPalette::Button ) ); gradient.setColorAt( 0.2, pal.color( QPalette::Light ) ); gradient.setColorAt( 0.7, pal.color( QPalette::Mid ) ); gradient.setColorAt( 1.0, pal.color( QPalette::Dark ) ); painter->fillRect( rect, gradient ); // draw internal border const QPen lightPen( palette().color( QPalette::Light ), d_data->wheelBorderWidth, Qt::SolidLine, Qt::FlatCap ); const QPen darkPen( pal.color( QPalette::Dark ), d_data->wheelBorderWidth, Qt::SolidLine, Qt::FlatCap ); const double bw2 = 0.5 * d_data->wheelBorderWidth; if ( orientation() == Qt::Horizontal ) { painter->setPen( lightPen ); painter->drawLine( QPointF( rect.left(), rect.top() + bw2 ), QPointF( rect.right(), rect.top() + bw2 ) ); painter->setPen( darkPen ); painter->drawLine( QPointF( rect.left(), rect.bottom() - bw2 ), QPointF( rect.right(), rect.bottom() - bw2 ) ); } else // Qt::Vertical { painter->setPen( lightPen ); painter->drawLine( QPointF( rect.left() + bw2, rect.top() ), QPointF( rect.left() + bw2, rect.bottom() ) ); painter->setPen( darkPen ); painter->drawLine( QPointF( rect.right() - bw2, rect.top() ), QPointF( rect.right() - bw2, rect.bottom() ) ); } painter->restore(); } /*! Draw the Wheel's ticks \param painter Painter \param rect Rectangle for the wheel */ void QwtWheel::drawTicks( QPainter *painter, const QRectF &rect ) { if ( maxValue() == minValue() || d_data->totalAngle == 0.0 ) { return; } const QPen lightPen( palette().color( QPalette::Light ), 0, Qt::SolidLine, Qt::FlatCap ); const QPen darkPen( palette().color( QPalette::Dark ), 0, Qt::SolidLine, Qt::FlatCap ); const double sign = ( minValue() < maxValue() ) ? 1.0 : -1.0; const double cnvFactor = qAbs( d_data->totalAngle / ( maxValue() - minValue() ) ); const double halfIntv = 0.5 * d_data->viewAngle / cnvFactor; const double loValue = value() - halfIntv; const double hiValue = value() + halfIntv; const double tickWidth = 360.0 / double( d_data->tickCnt ) / cnvFactor; const double sinArc = qFastSin( d_data->viewAngle * M_PI / 360.0 ); if ( orientation() == Qt::Horizontal ) { const double halfSize = rect.width() * 0.5; double l1 = rect.top() + d_data->wheelBorderWidth; double l2 = rect.bottom() - d_data->wheelBorderWidth - 1; // draw one point over the border if border > 1 if ( d_data->wheelBorderWidth > 1 ) { l1--; l2++; } const double maxpos = rect.right() - 2; const double minpos = rect.left() + 2; // draw tick marks for ( double tickValue = ::ceil( loValue / tickWidth ) * tickWidth; tickValue < hiValue; tickValue += tickWidth ) { const double angle = ( tickValue - value() ) * M_PI / 180.0; const double s = qFastSin( angle * cnvFactor ); const double tickPos = rect.right() - halfSize * ( sinArc + sign * s ) / sinArc; if ( ( tickPos <= maxpos ) && ( tickPos > minpos ) ) { painter->setPen( darkPen ); painter->drawLine( QPointF( tickPos - 1 , l1 ), QPointF( tickPos - 1, l2 ) ); painter->setPen( lightPen ); painter->drawLine( QPointF( tickPos, l1 ), QPointF( tickPos, l2 ) ); } } } else // Qt::Vertical { const double halfSize = rect.height() * 0.5; double l1 = rect.left() + d_data->wheelBorderWidth; double l2 = rect.right() - d_data->wheelBorderWidth - 1; if ( d_data->wheelBorderWidth > 1 ) { l1--; l2++; } const double maxpos = rect.bottom() - 2; const double minpos = rect.top() + 2; for ( double tickValue = ::ceil( loValue / tickWidth ) * tickWidth; tickValue < hiValue; tickValue += tickWidth ) { const double angle = ( tickValue - value() ) * M_PI / 180.0; const double s = qFastSin( angle * cnvFactor ); const double tickPos = rect.y() + halfSize * ( sinArc + sign * s ) / sinArc; if ( ( tickPos <= maxpos ) && ( tickPos > minpos ) ) { painter->setPen( darkPen ); painter->drawLine( QPointF( l1, tickPos - 1 ), QPointF( l2, tickPos - 1 ) ); painter->setPen( lightPen ); painter->drawLine( QPointF( l1, tickPos ), QPointF( l2, tickPos ) ); } } } } //! Notify value change void QwtWheel::valueChange() { QwtAbstractSlider::valueChange(); update(); } /*! \brief Determine the scrolling mode and direction corresponding to a specified point \param p point \param scrollMode scrolling mode \param direction direction */ void QwtWheel::getScrollMode( const QPoint &p, QwtAbstractSlider::ScrollMode &scrollMode, int &direction ) const { if ( wheelRect().contains( p ) ) scrollMode = QwtAbstractSlider::ScrMouse; else scrollMode = QwtAbstractSlider::ScrNone; direction = 0; } /*! \brief Set the mass of the wheel Assigning a mass turns the wheel into a flywheel. \param mass The wheel's mass */ void QwtWheel::setMass( double mass ) { QwtAbstractSlider::setMass( mass ); } /*! \brief Set the width of the wheel Corresponds to the wheel height for horizontal orientation, and the wheel width for vertical orientation. \param width the wheel's width \sa wheelWidth() */ void QwtWheel::setWheelWidth( int width ) { d_data->wheelWidth = width; update(); } /*! \return Width of the wheel \sa setWheelWidth() */ int QwtWheel::wheelWidth() const { return d_data->wheelWidth; } /*! \return a size hint */ QSize QwtWheel::sizeHint() const { const QSize hint = minimumSizeHint(); return hint.expandedTo( QApplication::globalStrut() ); } /*! \brief Return a minimum size hint \warning The return value is based on the wheel width. */ QSize QwtWheel::minimumSizeHint() const { QSize sz( 3 * d_data->wheelWidth + 2 * d_data->borderWidth, d_data->wheelWidth + 2 * d_data->borderWidth ); if ( orientation() != Qt::Horizontal ) sz.transpose(); return sz; } pcp-gui-1.5.11/src/libqwt/qwt.h0000644000000000000000000000077712176111212013113 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_H #define QWT_H #include "qwt_global.h" /*! Some constants for use within Qwt. */ namespace Qwt { }; #endif pcp-gui-1.5.11/src/libqwt/qwt_abstract_scale.h0000644000000000000000000000344312176111212016136 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ABSTRACT_SCALE_H #define QWT_ABSTRACT_SCALE_H #include "qwt_global.h" class QwtScaleEngine; class QwtAbstractScaleDraw; class QwtScaleDiv; class QwtScaleMap; class QwtInterval; /*! \brief An abstract base class for classes containing a scale QwtAbstractScale is used to provide classes with a QwtScaleDraw, and a QwtScaleDiv. The QwtScaleDiv might be set explicitely or calculated by a QwtScaleEngine. */ class QWT_EXPORT QwtAbstractScale { public: QwtAbstractScale(); virtual ~QwtAbstractScale(); void setScale( double vmin, double vmax, double step = 0.0 ); void setScale( const QwtInterval &, double step = 0.0 ); void setScale( const QwtScaleDiv & ); void setAutoScale(); bool autoScale() const; void setScaleMaxMajor( int ticks ); int scaleMaxMinor() const; void setScaleMaxMinor( int ticks ); int scaleMaxMajor() const; void setScaleEngine( QwtScaleEngine * ); const QwtScaleEngine *scaleEngine() const; QwtScaleEngine *scaleEngine(); const QwtScaleMap &scaleMap() const; protected: void rescale( double vmin, double vmax, double step = 0.0 ); void setAbstractScaleDraw( QwtAbstractScaleDraw * ); const QwtAbstractScaleDraw *abstractScaleDraw() const; QwtAbstractScaleDraw *abstractScaleDraw(); virtual void scaleChange(); private: void updateScaleDraw(); class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_abstract_scale_draw.h0000644000000000000000000000703112176111212017150 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ABSTRACT_SCALE_DRAW_H #define QWT_ABSTRACT_SCALE_DRAW_H #include "qwt_global.h" #include "qwt_scale_div.h" #include "qwt_text.h" class QPalette; class QPainter; class QFont; class QwtScaleTransformation; class QwtScaleMap; /*! \brief A abstract base class for drawing scales QwtAbstractScaleDraw can be used to draw linear or logarithmic scales. After a scale division has been specified as a QwtScaleDiv object using QwtAbstractScaleDraw::setScaleDiv(const QwtScaleDiv &s), the scale can be drawn with the QwtAbstractScaleDraw::draw() member. */ class QWT_EXPORT QwtAbstractScaleDraw { public: /*! Components of a scale \sa enableComponent(), hasComponent */ enum ScaleComponent { //! Backbone = the line where the ticks are located Backbone = 0x01, //! Ticks Ticks = 0x02, //! Labels Labels = 0x04 }; //! Scale components typedef QFlags ScaleComponents; QwtAbstractScaleDraw(); virtual ~QwtAbstractScaleDraw(); void setScaleDiv( const QwtScaleDiv &s ); const QwtScaleDiv& scaleDiv() const; void setTransformation( QwtScaleTransformation * ); const QwtScaleMap &scaleMap() const; QwtScaleMap &scaleMap(); void enableComponent( ScaleComponent, bool enable = true ); bool hasComponent( ScaleComponent ) const; void setTickLength( QwtScaleDiv::TickType, double length ); double tickLength( QwtScaleDiv::TickType ) const; double maxTickLength() const; void setSpacing( double margin ); double spacing() const; void setPenWidth( int width ); int penWidth() const; virtual void draw( QPainter *, const QPalette & ) const; virtual QwtText label( double ) const; /*! Calculate the extent The extent is the distcance from the baseline to the outermost pixel of the scale draw in opposite to its orientation. It is at least minimumExtent() pixels. \sa setMinimumExtent(), minimumExtent() */ virtual double extent( const QFont & ) const = 0; void setMinimumExtent( double ); double minimumExtent() const; protected: /*! Draw a tick \param painter Painter \param value Value of the tick \param len Lenght of the tick \sa drawBackbone(), drawLabel() */ virtual void drawTick( QPainter *painter, double value, double len ) const = 0; /*! Draws the baseline of the scale \param painter Painter \sa drawTick(), drawLabel() */ virtual void drawBackbone( QPainter *painter ) const = 0; /*! Draws the label for a major scale tick \param painter Painter \param value Value \sa drawTick(), drawBackbone() */ virtual void drawLabel( QPainter *painter, double value ) const = 0; void invalidateCache(); const QwtText &tickLabel( const QFont &, double value ) const; private: QwtAbstractScaleDraw( const QwtAbstractScaleDraw & ); QwtAbstractScaleDraw &operator=( const QwtAbstractScaleDraw & ); class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtAbstractScaleDraw::ScaleComponents ) #endif pcp-gui-1.5.11/src/libqwt/qwt_abstract_slider.h0000644000000000000000000001205412176111212016327 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ABSTRACT_SLIDER_H #define QWT_ABSTRACT_SLIDER_H #include "qwt_global.h" #include "qwt_double_range.h" #include /*! \brief An abstract base class for slider widgets QwtAbstractSlider is a base class for slider widgets. It handles mouse events and updates the slider's value accordingly. Derived classes only have to implement the getValue() and getScrollMode() members, and should react to a valueChange(), which normally requires repainting. */ class QWT_EXPORT QwtAbstractSlider : public QWidget, public QwtDoubleRange { Q_OBJECT Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly ) Q_PROPERTY( bool valid READ isValid WRITE setValid ) Q_PROPERTY( double mass READ mass WRITE setMass ) Q_PROPERTY( Qt::Orientation orientation READ orientation WRITE setOrientation ) public: /*! Scroll mode \sa getScrollMode() */ enum ScrollMode { //! Scrolling switched off. Don't change the value. ScrNone, /*! Change the value while the user keeps the button pressed and moves the mouse. */ ScrMouse, /*! Automatic scrolling. Increment the value in the specified direction as long as the user keeps the button pressed. */ ScrTimer, ScrDirect, //! Automatic scrolling. Same as ScrTimer, but increment by page size. ScrPage }; explicit QwtAbstractSlider( Qt::Orientation, QWidget *parent = NULL ); virtual ~QwtAbstractSlider(); void setUpdateTime( int t ); void stopMoving(); void setTracking( bool enable ); virtual void setMass( double val ); virtual double mass() const; virtual void setOrientation( Qt::Orientation o ); Qt::Orientation orientation() const; bool isReadOnly() const; /* Wrappers for QwtDblRange::isValid/QwtDblRange::setValid made to be available as Q_PROPERTY in the designer. */ /*! \sa QwtDblRange::isValid() */ bool isValid() const { return QwtDoubleRange::isValid(); } /*! \param valid true/false \sa QwtDblRange::isValid() */ void setValid( bool valid ) { QwtDoubleRange::setValid( valid ); } public Q_SLOTS: virtual void setValue( double val ); virtual void fitValue( double val ); virtual void incValue( int steps ); virtual void setReadOnly( bool ); Q_SIGNALS: /*! \brief Notify a change of value. In the default setting (tracking enabled), this signal will be emitted every time the value changes ( see setTracking() ). \param value new value */ void valueChanged( double value ); /*! This signal is emitted when the user presses the movable part of the slider (start ScrMouse Mode). */ void sliderPressed(); /*! This signal is emitted when the user releases the movable part of the slider. */ void sliderReleased(); /*! This signal is emitted when the user moves the slider with the mouse. \param value new value */ void sliderMoved( double value ); protected: virtual void setPosition( const QPoint & ); virtual void valueChange(); virtual void timerEvent( QTimerEvent *e ); virtual void mousePressEvent( QMouseEvent *e ); virtual void mouseReleaseEvent( QMouseEvent *e ); virtual void mouseMoveEvent( QMouseEvent *e ); virtual void keyPressEvent( QKeyEvent *e ); virtual void wheelEvent( QWheelEvent *e ); /*! \brief Determine the value corresponding to a specified poind This is an abstract virtual function which is called when the user presses or releases a mouse button or moves the mouse. It has to be implemented by the derived class. \param p point */ virtual double getValue( const QPoint & p ) = 0; /*! \brief Determine what to do when the user presses a mouse button. This function is abstract and has to be implemented by derived classes. It is called on a mousePress event. The derived class can determine what should happen next in dependence of the position where the mouse was pressed by returning scrolling mode and direction. \param pos point where the mouse was pressed \retval scrollMode The scrolling mode \retval direction direction: 1, 0, or -1. */ virtual void getScrollMode( const QPoint &pos, ScrollMode &scrollMode, int &direction ) const = 0; void setMouseOffset( double ); double mouseOffset() const; int scrollMode() const; private: void buttonReleased(); class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_analog_clock.h0000644000000000000000000000444112176111212015577 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ANALOG_CLOCK_H #define QWT_ANALOG_CLOCK_H #include "qwt_global.h" #include "qwt_dial.h" #include "qwt_dial_needle.h" #include /*! \brief An analog clock \image html analogclock.png \par Example \verbatim #include QwtAnalogClock *clock = new QwtAnalogClock(...); clock->scaleDraw()->setPenWidth(3); clock->setLineWidth(6); clock->setFrameShadow(QwtDial::Sunken); clock->setTime(); // update the clock every second QTimer *timer = new QTimer(clock); timer->connect(timer, SIGNAL(timeout()), clock, SLOT(setCurrentTime())); timer->start(1000); \endverbatim Qwt is missing a set of good looking hands. Contributions are very welcome. \note The examples/dials example shows how to use QwtAnalogClock. */ class QWT_EXPORT QwtAnalogClock: public QwtDial { Q_OBJECT public: /*! Hand type \sa setHand(), hand() */ enum Hand { //! Needle displaying the seconds SecondHand, //! Needle displaying the minutes MinuteHand, //! Needle displaying the hours HourHand, //! Number of needles NHands }; explicit QwtAnalogClock( QWidget* parent = NULL ); virtual ~QwtAnalogClock(); virtual void setHand( Hand, QwtDialNeedle * ); const QwtDialNeedle *hand( Hand ) const; QwtDialNeedle *hand( Hand ); public Q_SLOTS: void setCurrentTime(); void setTime( const QTime & = QTime::currentTime() ); protected: virtual QwtText scaleLabel( double ) const; virtual void drawNeedle( QPainter *, const QPointF &, double radius, double direction, QPalette::ColorGroup ) const; virtual void drawHand( QPainter *, Hand, const QPointF &, double radius, double direction, QPalette::ColorGroup ) const; private: virtual void setNeedle( QwtDialNeedle * ); void initClock(); QwtDialNeedle *d_hand[NHands]; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_arrow_button.h0000644000000000000000000000262112176111212015706 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ARROW_BUTTON_H #define QWT_ARROW_BUTTON_H #include "qwt_global.h" #include /*! \brief Arrow Button A push button with one or more filled triangles on its front. An Arrow button can have 1 to 3 arrows in a row, pointing up, down, left or right. */ class QWT_EXPORT QwtArrowButton : public QPushButton { public: explicit QwtArrowButton ( int num, Qt::ArrowType, QWidget *parent = NULL ); virtual ~QwtArrowButton(); Qt::ArrowType arrowType() const; int num() const; virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; protected: virtual void paintEvent( QPaintEvent *event ); virtual void drawButtonLabel( QPainter *p ); virtual void drawArrow( QPainter *, const QRect &, Qt::ArrowType ) const; virtual QRect labelRect() const; virtual QSize arrowSize( Qt::ArrowType, const QSize &boundingSize ) const; virtual void keyPressEvent( QKeyEvent * ); private: class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_clipper.h0000644000000000000000000000167212176111212014624 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_CLIPPER_H #define QWT_CLIPPER_H #include "qwt_global.h" #include "qwt_interval.h" #include #include class QRect; class QRectF; /*! \brief Some clipping algos */ class QWT_EXPORT QwtClipper { public: static QPolygon clipPolygon( const QRect &, const QPolygon &, bool closePolygon = false ); static QPolygonF clipPolygonF( const QRectF &, const QPolygonF &, bool closePolygon = false ); static QVector clipCircle( const QRectF &, const QPointF &, double radius ); }; #endif pcp-gui-1.5.11/src/libqwt/qwt_color_map.h0000644000000000000000000001166312176111212015142 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_COLOR_MAP_H #define QWT_COLOR_MAP_H #include "qwt_global.h" #include "qwt_interval.h" #include #include /*! \brief QwtColorMap is used to map values into colors. For displaying 3D data on a 2D plane the 3rd dimension is often displayed using colors, like f.e in a spectrogram. Each color map is optimized to return colors for only one of the following image formats: - QImage::Format_Indexed8\n - QImage::Format_ARGB32\n \sa QwtPlotSpectrogram, QwtScaleWidget */ class QWT_EXPORT QwtColorMap { public: /*! Format for color mapping \sa rgb(), colorIndex(), colorTable() */ enum Format { //! The map is intended to map into QRgb values. RGB, /*! The map is intended to map into 8 bit values, that are indices into the color table. */ Indexed }; QwtColorMap( Format = QwtColorMap::RGB ); virtual ~QwtColorMap(); Format format() const; /*! Map a value of a given interval into a rgb value. \param interval Range for the values \param value Value \return rgb value, corresponding to value */ virtual QRgb rgb( const QwtInterval &interval, double value ) const = 0; /*! Map a value of a given interval into a color index \param interval Range for the values \param value Value \return color index, corresponding to value */ virtual unsigned char colorIndex( const QwtInterval &interval, double value ) const = 0; QColor color( const QwtInterval &, double value ) const; virtual QVector colorTable( const QwtInterval & ) const; private: Format d_format; }; /*! \brief QwtLinearColorMap builds a color map from color stops. A color stop is a color at a specific position. The valid range for the positions is [0.0, 1.0]. When mapping a value into a color it is translated into this interval according to mode(). */ class QWT_EXPORT QwtLinearColorMap: public QwtColorMap { public: /*! Mode of color map \sa setMode(), mode() */ enum Mode { //! Return the color from the next lower color stop FixedColors, //! Interpolating the colors of the adjacent stops. ScaledColors }; QwtLinearColorMap( QwtColorMap::Format = QwtColorMap::RGB ); QwtLinearColorMap( const QColor &from, const QColor &to, QwtColorMap::Format = QwtColorMap::RGB ); virtual ~QwtLinearColorMap(); void setMode( Mode ); Mode mode() const; void setColorInterval( const QColor &color1, const QColor &color2 ); void addColorStop( double value, const QColor& ); QVector colorStops() const; QColor color1() const; QColor color2() const; virtual QRgb rgb( const QwtInterval &, double value ) const; virtual unsigned char colorIndex( const QwtInterval &, double value ) const; class ColorStops; private: // Disabled copy constructor and operator= QwtLinearColorMap( const QwtLinearColorMap & ); QwtLinearColorMap &operator=( const QwtLinearColorMap & ); class PrivateData; PrivateData *d_data; }; /*! \brief QwtAlphaColorMap variies the alpha value of a color */ class QWT_EXPORT QwtAlphaColorMap: public QwtColorMap { public: QwtAlphaColorMap( const QColor & = QColor( Qt::gray ) ); virtual ~QwtAlphaColorMap(); void setColor( const QColor & ); QColor color() const; virtual QRgb rgb( const QwtInterval &, double value ) const; private: QwtAlphaColorMap( const QwtAlphaColorMap & ); QwtAlphaColorMap &operator=( const QwtAlphaColorMap & ); virtual unsigned char colorIndex( const QwtInterval &, double value ) const; class PrivateData; PrivateData *d_data; }; /*! Map a value into a color \param interval Valid interval for values \param value Value \return Color corresponding to value \warning This method is slow for Indexed color maps. If it is necessary to map many values, its better to get the color table once and find the color using colorIndex(). */ inline QColor QwtColorMap::color( const QwtInterval &interval, double value ) const { if ( d_format == RGB ) { return QColor( rgb( interval, value ) ); } else { const unsigned int index = colorIndex( interval, value ); return colorTable( interval )[index]; // slow } } /*! \return Intended format of the color map \sa Format */ inline QwtColorMap::Format QwtColorMap::format() const { return d_format; } #endif pcp-gui-1.5.11/src/libqwt/qwt_column_symbol.h0000644000000000000000000000736012176111212016050 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_COLUMN_SYMBOL_H #define QWT_COLUMN_SYMBOL_H #include "qwt_global.h" #include "qwt_interval.h" #include #include #include class QPainter; class QPalette; class QRect; class QwtText; /*! \brief Directed rectangle representing bounding rectangle und orientation of a column. */ class QWT_EXPORT QwtColumnRect { public: //! Direction of the column enum Direction { //! From left to right LeftToRight, //! From right to left RightToLeft, //! From bottom to top BottomToTop, //! From top to bottom TopToBottom }; //! Build an rectangle with invalid intervals directed BottomToTop. QwtColumnRect(): direction( BottomToTop ) { } //! \return A normalized QRect built from the intervals QRectF toRect() const { QRectF r( hInterval.minValue(), vInterval.minValue(), hInterval.maxValue() - hInterval.minValue(), vInterval.maxValue() - vInterval.minValue() ); r = r.normalized(); if ( hInterval.borderFlags() & QwtInterval::ExcludeMinimum ) r.adjust( 1, 0, 0, 0 ); if ( hInterval.borderFlags() & QwtInterval::ExcludeMaximum ) r.adjust( 0, 0, -1, 0 ); if ( vInterval.borderFlags() & QwtInterval::ExcludeMinimum ) r.adjust( 0, 1, 0, 0 ); if ( vInterval.borderFlags() & QwtInterval::ExcludeMaximum ) r.adjust( 0, 0, 0, -1 ); return r; } //! \return Orientation Qt::Orientation orientation() const { if ( direction == LeftToRight || direction == RightToLeft ) return Qt::Horizontal; return Qt::Vertical; } //! Interval for the horizontal coordinates QwtInterval hInterval; //! Interval for the vertical coordinates QwtInterval vInterval; //! Direction Direction direction; }; //! A drawing primitive for columns class QWT_EXPORT QwtColumnSymbol { public: /*! Style \sa setStyle(), style() */ enum Style { //! No Style, the symbol draws nothing NoStyle = -1, /*! The column is painted with a frame depending on the frameStyle() and lineWidth() using the palette(). */ Box, /*! Styles >= QwtColumnSymbol::UserStyle are reserved for derived classes of QwtColumnSymbol that overload draw() with additional application specific symbol types. */ UserStyle = 1000 }; /*! Frame Style used in Box style(). \sa Style, setFrameStyle(), frameStyle(), setStyle(), setPalette() */ enum FrameStyle { //! No frame NoFrame, //! A plain frame style Plain, //! A raised frame style Raised }; public: QwtColumnSymbol( Style = NoStyle ); virtual ~QwtColumnSymbol(); void setFrameStyle( FrameStyle style ); FrameStyle frameStyle() const; void setLineWidth( int width ); int lineWidth() const; void setPalette( const QPalette & ); const QPalette &palette() const; void setStyle( Style ); Style style() const; virtual void draw( QPainter *, const QwtColumnRect & ) const; protected: void drawBox( QPainter *, const QwtColumnRect & ) const; private: class PrivateData; PrivateData* d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_compass.h0000644000000000000000000000313412176111212014626 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_COMPASS_H #define QWT_COMPASS_H 1 #include "qwt_global.h" #include "qwt_dial.h" #include #include class QwtCompassRose; /*! \brief A Compass Widget QwtCompass is a widget to display and enter directions. It consists of a scale, an optional needle and rose. \image html dials1.png \note The examples/dials example shows how to use QwtCompass. */ class QWT_EXPORT QwtCompass: public QwtDial { Q_OBJECT public: explicit QwtCompass( QWidget* parent = NULL ); virtual ~QwtCompass(); void setRose( QwtCompassRose *rose ); const QwtCompassRose *rose() const; QwtCompassRose *rose(); const QMap &labelMap() const; QMap &labelMap(); void setLabelMap( const QMap &map ); protected: virtual QwtText scaleLabel( double value ) const; virtual void drawRose( QPainter *, const QPointF ¢er, double radius, double north, QPalette::ColorGroup ) const; virtual void drawScaleContents( QPainter *, const QPointF ¢er, double radius ) const; virtual void keyPressEvent( QKeyEvent * ); private: void initCompass(); class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_compass_rose.h0000644000000000000000000000424512176111212015662 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_COMPASS_ROSE_H #define QWT_COMPASS_ROSE_H 1 #include "qwt_global.h" #include class QPainter; /*! \brief Abstract base class for a compass rose */ class QWT_EXPORT QwtCompassRose { public: //! Destructor virtual ~QwtCompassRose() {}; //! Assign a palette virtual void setPalette( const QPalette &p ) { d_palette = p; } //! \return Current palette const QPalette &palette() const { return d_palette; } /*! Draw the rose \param painter Painter \param center Center point \param radius Radius of the rose \param north Position \param colorGroup Color group */ virtual void draw( QPainter *painter, const QPointF ¢er, double radius, double north, QPalette::ColorGroup colorGroup = QPalette::Active ) const = 0; private: QPalette d_palette; }; /*! \brief A simple rose for QwtCompass */ class QWT_EXPORT QwtSimpleCompassRose: public QwtCompassRose { public: QwtSimpleCompassRose( int numThorns = 8, int numThornLevels = -1 ); virtual ~QwtSimpleCompassRose(); void setWidth( double w ); double width() const; void setNumThorns( int count ); int numThorns() const; void setNumThornLevels( int count ); int numThornLevels() const; void setShrinkFactor( double factor ); double shrinkFactor() const; virtual void draw( QPainter *, const QPointF ¢er, double radius, double north, QPalette::ColorGroup = QPalette::Active ) const; static void drawRose( QPainter *, const QPalette &, const QPointF ¢er, double radius, double origin, double width, int numThorns, int numThornLevels, double shrinkFactor ); private: class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_compat.h0000644000000000000000000000205012176111212014440 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef _QWT_COMPAT_H_ #define _QWT_COMPAT_H_ #include "qwt_global.h" #include "qwt_interval.h" #include "qwt_point_3d.h" #include #include #include #include #include #include // A couple of definition for Qwt5 compatibility #define qwtMax qMax #define qwtMin qMin #define qwtAbs qAbs #define qwtRound qRound #define QwtArray QVector typedef QList QwtValueList; typedef QPointF QwtDoublePoint; typedef QSizeF QwtDoubleSize; typedef QRectF QwtDoubleRect; typedef QPolygon QwtPolygon; typedef QPolygonF QwtPolygonF; typedef QwtInterval QwtDoubleInterval; typedef QwtPoint3D QwtDoublePoint3D; #endif pcp-gui-1.5.11/src/libqwt/qwt_counter.h0000644000000000000000000001005312176111212014636 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_COUNTER_H #define QWT_COUNTER_H #include "qwt_global.h" #include "qwt_double_range.h" #include /*! \brief The Counter Widget A Counter consists of a lineEdit displaying a number and one ore more (up to three) push buttons on each side of the lineEdit which can be used to increment or decrement the counter's value. A Counter has a range from a minimum value to a maximum value and a step size. The range can be specified using setRange(). The number of steps by which a button increments or decrements the value can be specified using setIncSteps(). The number of buttons can be changed with setNumButtons(). Example: \code #include QwtCounter *counter = new QwtCounter(parent); counter->setRange(0.0, 100.0, 1.0); // From 0.0 to 100, step 1.0 counter->setNumButtons(2); // Two buttons each side counter->setIncSteps(QwtCounter::Button1, 1); // Button 1 increments 1 step counter->setIncSteps(QwtCounter::Button2, 20); // Button 2 increments 20 steps connect(counter, SIGNAL(valueChanged(double)), my_class, SLOT(newValue(double))); \endcode */ class QWT_EXPORT QwtCounter : public QWidget, public QwtDoubleRange { Q_OBJECT Q_PROPERTY( int numButtons READ numButtons WRITE setNumButtons ) Q_PROPERTY( double basicstep READ step WRITE setStep ) Q_PROPERTY( double minValue READ minValue WRITE setMinValue ) Q_PROPERTY( double maxValue READ maxValue WRITE setMaxValue ) Q_PROPERTY( int stepButton1 READ stepButton1 WRITE setStepButton1 ) Q_PROPERTY( int stepButton2 READ stepButton2 WRITE setStepButton2 ) Q_PROPERTY( int stepButton3 READ stepButton3 WRITE setStepButton3 ) Q_PROPERTY( double value READ value WRITE setValue ) Q_PROPERTY( bool editable READ editable WRITE setEditable ) public: //! Button index enum Button { //! Button intended for minor steps Button1, //! Button intended for medium steps Button2, //! Button intended for large steps Button3, //! Number of buttons ButtonCnt }; explicit QwtCounter( QWidget *parent = NULL ); virtual ~QwtCounter(); bool editable() const; void setEditable( bool ); void setNumButtons( int n ); int numButtons() const; void setIncSteps( QwtCounter::Button btn, int nSteps ); int incSteps( QwtCounter::Button btn ) const; virtual void setValue( double ); virtual QSize sizeHint() const; // a set of dummies to help the designer double step() const; void setStep( double s ); double minValue() const; void setMinValue( double m ); double maxValue() const; void setMaxValue( double m ); void setStepButton1( int nSteps ); int stepButton1() const; void setStepButton2( int nSteps ); int stepButton2() const; void setStepButton3( int nSteps ); int stepButton3() const; virtual double value() const; Q_SIGNALS: /*! This signal is emitted when a button has been released \param value The new value */ void buttonReleased ( double value ); /*! This signal is emitted when the counter's value has changed \param value The new value */ void valueChanged ( double value ); protected: virtual bool event( QEvent * ); virtual void wheelEvent( QWheelEvent * ); virtual void keyPressEvent( QKeyEvent * ); virtual void rangeChange(); private Q_SLOTS: void btnReleased(); void btnClicked(); void textChanged(); private: void initCounter(); void updateButtons(); void showNum( double ); virtual void valueChange(); class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_curve_fitter.h0000644000000000000000000000633312176111212015666 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_CURVE_FITTER_H #define QWT_CURVE_FITTER_H #include "qwt_global.h" #include #include class QwtSpline; /*! \brief Abstract base class for a curve fitter */ class QWT_EXPORT QwtCurveFitter { public: virtual ~QwtCurveFitter(); /*! Find a curve which has the best fit to a series of data points \param polygon Series of data points \return Curve points */ virtual QPolygonF fitCurve( const QPolygonF &polygon ) const = 0; protected: QwtCurveFitter(); private: QwtCurveFitter( const QwtCurveFitter & ); QwtCurveFitter &operator=( const QwtCurveFitter & ); }; /*! \brief A curve fitter using cubic splines */ class QWT_EXPORT QwtSplineCurveFitter: public QwtCurveFitter { public: /*! Spline type The default setting is Auto \sa setFitMode(), FitMode() */ enum FitMode { /*! Use the default spline algorithm for polygons with increasing x values ( p[i-1] < p[i] ), otherwise use a parametric spline algorithm. */ Auto, //! Use a default spline algorithm Spline, //! Use a parametric spline algorithm ParametricSpline }; QwtSplineCurveFitter(); virtual ~QwtSplineCurveFitter(); void setFitMode( FitMode ); FitMode fitMode() const; void setSpline( const QwtSpline& ); const QwtSpline &spline() const; QwtSpline &spline(); void setSplineSize( int size ); int splineSize() const; virtual QPolygonF fitCurve( const QPolygonF & ) const; private: QPolygonF fitSpline( const QPolygonF & ) const; QPolygonF fitParametric( const QPolygonF & ) const; class PrivateData; PrivateData *d_data; }; /*! \brief A curve fitter implementing Douglas and Peucker algorithm The purpose of the Douglas and Peucker algorithm is that given a 'curve' composed of line segments to find a curve not too dissimilar but that has fewer points. The algorithm defines 'too dissimilar' based on the maximum distance (tolerance) between the original curve and the smoothed curve. The smoothed curve consists of a subset of the points that defined the original curve. In opposite to QwtSplineCurveFitter the Douglas and Peucker algorithm reduces the number of points. By adjusting the tolerance parameter according to the axis scales QwtSplineCurveFitter can be used to implement different level of details to speed up painting of curves of many points. */ class QWT_EXPORT QwtWeedingCurveFitter: public QwtCurveFitter { public: QwtWeedingCurveFitter( double tolerance = 1.0 ); virtual ~QwtWeedingCurveFitter(); void setTolerance( double ); double tolerance() const; virtual QPolygonF fitCurve( const QPolygonF & ) const; private: class Line; class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_dial.h0000644000000000000000000001325612176111212014100 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_DIAL_H #define QWT_DIAL_H 1 #include "qwt_global.h" #include "qwt_abstract_slider.h" #include "qwt_round_scale_draw.h" #include #include class QwtDialNeedle; class QwtDial; /*! \brief A special scale draw made for QwtDial \sa QwtDial, QwtCompass */ class QWT_EXPORT QwtDialScaleDraw: public QwtRoundScaleDraw { public: explicit QwtDialScaleDraw( QwtDial * ); virtual QwtText label( double value ) const; void setPenWidth( double ); double penWidth() const; private: QwtDial *d_parent; double d_penWidth; }; /*! \brief QwtDial class provides a rounded range control. QwtDial is intended as base class for dial widgets like speedometers, compass widgets, clocks ... \image html dials2.png A dial contains a scale and a needle indicating the current value of the dial. Depending on Mode one of them is fixed and the other is rotating. If not isReadOnly() the dial can be rotated by dragging the mouse or using keyboard inputs (see keyPressEvent()). A dial might be wrapping, what means a rotation below/above one limit continues on the other limit (f.e compass). The scale might cover any arc of the dial, its values are related to the origin() of the dial. Qwt is missing a set of good looking needles (QwtDialNeedle). Contributions are very welcome. \sa QwtCompass, QwtAnalogClock, QwtDialNeedle \note The examples/dials example shows different types of dials. */ class QWT_EXPORT QwtDial: public QwtAbstractSlider { Q_OBJECT Q_ENUMS( Shadow ) Q_ENUMS( Mode ) Q_ENUMS( Direction ) Q_PROPERTY( int lineWidth READ lineWidth WRITE setLineWidth ) Q_PROPERTY( Shadow frameShadow READ frameShadow WRITE setFrameShadow ) Q_PROPERTY( Mode mode READ mode WRITE setMode ) Q_PROPERTY( double origin READ origin WRITE setOrigin ) Q_PROPERTY( bool wrapping READ wrapping WRITE setWrapping ) Q_PROPERTY( Direction direction READ direction WRITE setDirection ) friend class QwtDialScaleDraw; public: /*! \brief Frame shadow Unfortunately it is not possible to use QFrame::Shadow as a property of a widget that is not derived from QFrame. The following enum is made for the designer only. It is safe to use QFrame::Shadow instead. */ enum Shadow { //! QFrame::Plain Plain = QFrame::Plain, //! QFrame::Raised Raised = QFrame::Raised, //! QFrame::Sunken Sunken = QFrame::Sunken }; //! Mode controlling wether the needle or the scale is rotating enum Mode { //! The needle is rotating RotateNeedle, //! The needle is fixed, the scales are rotating RotateScale }; //! Direction of the dial enum Direction { //! Clockwise Clockwise, //! Counter clockwise CounterClockwise }; explicit QwtDial( QWidget *parent = NULL ); virtual ~QwtDial(); void setFrameShadow( Shadow ); Shadow frameShadow() const; void setLineWidth( int ); int lineWidth() const; void setMode( Mode ); Mode mode() const; virtual void setWrapping( bool ); bool wrapping() const; virtual void setScale( int maxMajIntv, int maxMinIntv, double step = 0.0 ); void setScaleArc( double min, double max ); void setScaleComponents( QwtAbstractScaleDraw::ScaleComponents ); void setScaleTicks( int minLen, int medLen, int majLen, int penWidth = 1 ); double minScaleArc() const; double maxScaleArc() const; virtual void setOrigin( double ); double origin() const; void setDirection( Direction ); Direction direction() const; virtual void setNeedle( QwtDialNeedle * ); const QwtDialNeedle *needle() const; QwtDialNeedle *needle(); QRectF boundingRect() const; QRectF innerRect() const; virtual QRectF scaleInnerRect() const; virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; virtual void setScaleDraw( QwtDialScaleDraw * ); QwtDialScaleDraw *scaleDraw(); const QwtDialScaleDraw *scaleDraw() const; protected: virtual void paintEvent( QPaintEvent * ); virtual void keyPressEvent( QKeyEvent * ); virtual void drawFrame( QPainter *p ); virtual void drawContents( QPainter * ) const; virtual void drawFocusIndicator( QPainter * ) const; virtual void drawScale( QPainter *, const QPointF ¢er, double radius, double origin, double arcMin, double arcMax ) const; /*! Draw the contents inside the scale Paints nothing. \param painter Painter \param center Center of the contents circle \param radius Radius of the contents circle */ virtual void drawScaleContents( QPainter *painter, const QPointF ¢er, double radius ) const; virtual void drawNeedle( QPainter *, const QPointF &, double radius, double direction, QPalette::ColorGroup ) const; virtual QwtText scaleLabel( double ) const; void updateScale(); virtual void rangeChange(); virtual void valueChange(); virtual double getValue( const QPoint & ); virtual void getScrollMode( const QPoint &, QwtAbstractSlider::ScrollMode &, int &direction ) const; private: void initDial(); class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_dial_needle.h0000644000000000000000000001011512176111212015403 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_DIAL_NEEDLE_H #define QWT_DIAL_NEEDLE_H 1 #include "qwt_global.h" #include class QPainter; class QPoint; /*! \brief Base class for needles that can be used in a QwtDial. QwtDialNeedle is a pointer that indicates a value by pointing to a specific direction. Qwt is missing a set of good looking needles. Contributions are very welcome. \sa QwtDial, QwtCompass */ class QWT_EXPORT QwtDialNeedle { public: QwtDialNeedle(); virtual ~QwtDialNeedle(); virtual void setPalette( const QPalette & ); const QPalette &palette() const; virtual void draw( QPainter *painter, const QPointF ¢er, double length, double direction, QPalette::ColorGroup = QPalette::Active ) const; protected: /*! \brief Draw the needle The origin of the needle is at position (0.0, 0.0 ) pointing in direction 0.0 ( = east ). The painter is already initilaized with translation and rotation. \param painter Painter \param length Length of the needle \param colorGroup Color group, used for painting \sa setPalette(), palette() */ virtual void drawNeedle( QPainter *painter, double length, QPalette::ColorGroup colorGroup ) const = 0; virtual void drawKnob( QPainter *, double width, const QBrush &, bool sunken ) const; private: QPalette d_palette; }; /*! \brief A needle for dial widgets The following colors are used: - QPalette::Mid\n Pointer - QPalette::Base\n Knob \sa QwtDial, QwtCompass */ class QWT_EXPORT QwtDialSimpleNeedle: public QwtDialNeedle { public: //! Style of the needle enum Style { //! Arrow Arrow, //! A straight line from the center Ray }; QwtDialSimpleNeedle( Style, bool hasKnob = true, const QColor &mid = Qt::gray, const QColor &base = Qt::darkGray ); void setWidth( double width ); double width() const; protected: virtual void drawNeedle( QPainter *, double length, QPalette::ColorGroup ) const; private: Style d_style; bool d_hasKnob; double d_width; }; /*! \brief A magnet needle for compass widgets A magnet needle points to two opposite directions indicating north and south. The following colors are used: - QPalette::Light\n Used for pointing south - QPalette::Dark\n Used for pointing north - QPalette::Base\n Knob (ThinStyle only) \sa QwtDial, QwtCompass */ class QWT_EXPORT QwtCompassMagnetNeedle: public QwtDialNeedle { public: //! Style of the needle enum Style { //! A needle with a triangular shape TriangleStyle, //! A thin needle ThinStyle }; QwtCompassMagnetNeedle( Style = TriangleStyle, const QColor &light = Qt::white, const QColor &dark = Qt::red ); protected: virtual void drawNeedle( QPainter *, double length, QPalette::ColorGroup ) const; private: Style d_style; }; /*! \brief An indicator for the wind direction QwtCompassWindArrow shows the direction where the wind comes from. - QPalette::Light\n Used for Style1, or the light half of Style2 - QPalette::Dark\n Used for the dark half of Style2 \sa QwtDial, QwtCompass */ class QWT_EXPORT QwtCompassWindArrow: public QwtDialNeedle { public: //! Style of the arrow enum Style { //! A needle pointing to the center Style1, //! A needle pointing to the center Style2 }; QwtCompassWindArrow( Style, const QColor &light = Qt::white, const QColor &dark = Qt::gray ); protected: virtual void drawNeedle( QPainter *, double length, QPalette::ColorGroup ) const; private: Style d_style; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_double_range.h0000644000000000000000000000407712176111212015616 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_DOUBLE_RANGE_H #define QWT_DOUBLE_RANGE_H #include "qwt_global.h" /*! \brief A class which controls a value within an interval This class is useful as a base class or a member for sliders. It represents an interval of type double within which a value can be moved. The value can be either an arbitrary point inside the interval (see QwtDoubleRange::setValue), or it can be fitted into a step raster (see QwtDoubleRange::fitValue and QwtDoubleRange::incValue). As a special case, a QwtDoubleRange can be periodic, which means that a value outside the interval will be mapped to a value inside the interval when QwtDoubleRange::setValue(), QwtDoubleRange::fitValue(), QwtDoubleRange::incValue() or QwtDoubleRange::incPages() are called. */ class QWT_EXPORT QwtDoubleRange { public: QwtDoubleRange(); virtual ~QwtDoubleRange(); void setRange( double vmin, double vmax, double vstep = 0.0, int pagesize = 1 ); void setValid( bool ); bool isValid() const; virtual void setValue( double ); double value() const; void setPeriodic( bool tf ); bool periodic() const; void setStep( double ); double step() const; double maxValue() const; double minValue() const; int pageSize() const; virtual void incValue( int ); virtual void incPages( int ); virtual void fitValue( double ); protected: double exactValue() const; double exactPrevValue() const; double prevValue() const; virtual void valueChange(); virtual void stepChange(); virtual void rangeChange(); private: void setNewValue( double value, bool align = false ); class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_dyngrid_layout.h0000644000000000000000000000443412176111212016222 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_DYNGRID_LAYOUT_H #define QWT_DYNGRID_LAYOUT_H #include "qwt_global.h" #include #include #include /*! \brief The QwtDynGridLayout class lays out widgets in a grid, adjusting the number of columns and rows to the current size. QwtDynGridLayout takes the space it gets, divides it up into rows and columns, and puts each of the widgets it manages into the correct cell(s). It lays out as many number of columns as possible (limited by maxCols()). */ class QWT_EXPORT QwtDynGridLayout : public QLayout { Q_OBJECT public: explicit QwtDynGridLayout( QWidget *, int margin = 0, int space = -1 ); explicit QwtDynGridLayout( int space = -1 ); virtual ~QwtDynGridLayout(); virtual void invalidate(); void setMaxCols( uint maxCols ); uint maxCols() const; uint numRows () const; uint numCols () const; virtual void addItem( QLayoutItem * ); virtual QLayoutItem *itemAt( int index ) const; virtual QLayoutItem *takeAt( int index ); virtual int count() const; void setExpandingDirections( Qt::Orientations ); virtual Qt::Orientations expandingDirections() const; QList layoutItems( const QRect &, uint numCols ) const; virtual int maxItemWidth() const; virtual void setGeometry( const QRect &rect ); virtual bool hasHeightForWidth() const; virtual int heightForWidth( int ) const; virtual QSize sizeHint() const; virtual bool isEmpty() const; uint itemCount() const; virtual uint columnsForWidth( int width ) const; protected: void layoutGrid( uint numCols, QVector& rowHeight, QVector& colWidth ) const; void stretchGrid( const QRect &rect, uint numCols, QVector& rowHeight, QVector& colWidth ) const; private: void init(); int maxRowWidth( int numCols ) const; class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_event_pattern.h0000644000000000000000000001222512176111212016040 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_EVENT_PATTERN #define QWT_EVENT_PATTERN 1 #include "qwt_global.h" #include #include class QMouseEvent; class QKeyEvent; /*! \brief A collection of event patterns QwtEventPattern introduces an level of indirection for mouse and keyboard inputs. Those are represented by symbolic names, so the application code can be configured by individual mappings. \sa QwtPicker, QwtPickerMachine, QwtPlotZoomer */ class QWT_EXPORT QwtEventPattern { public: /*! \brief Symbolic mouse input codes The default initialization for 3 button mice is: - MouseSelect1\n Qt::LeftButton - MouseSelect2\n Qt::RightButton - MouseSelect3\n Qt::MidButton - MouseSelect4\n Qt::LeftButton + Qt::ShiftButton - MouseSelect5\n Qt::RightButton + Qt::ShiftButton - MouseSelect6\n Qt::MidButton + Qt::ShiftButton The default initialization for 2 button mice is: - MouseSelect1\n Qt::LeftButton - MouseSelect2\n Qt::RightButton - MouseSelect3\n Qt::LeftButton + Qt::AltButton - MouseSelect4\n Qt::LeftButton + Qt::ShiftButton - MouseSelect5\n Qt::RightButton + Qt::ShiftButton - MouseSelect6\n Qt::LeftButton + Qt::AltButton + Qt::ShiftButton The default initialization for 1 button mice is: - MouseSelect1\n Qt::LeftButton - MouseSelect2\n Qt::LeftButton + Qt::ControlButton - MouseSelect3\n Qt::LeftButton + Qt::AltButton - MouseSelect4\n Qt::LeftButton + Qt::ShiftButton - MouseSelect5\n Qt::LeftButton + Qt::ControlButton + Qt::ShiftButton - MouseSelect6\n Qt::LeftButton + Qt::AltButton + Qt::ShiftButton \sa initMousePattern() */ enum MousePatternCode { MouseSelect1, MouseSelect2, MouseSelect3, MouseSelect4, MouseSelect5, MouseSelect6, MousePatternCount }; /*! \brief Symbolic keyboard input codes Default initialization: - KeySelect1\n Qt::Key_Return - KeySelect2\n Qt::Key_Space - KeyAbort\n Qt::Key_Escape - KeyLeft\n Qt::Key_Left - KeyRight\n Qt::Key_Right - KeyUp\n Qt::Key_Up - KeyDown\n Qt::Key_Down - KeyUndo\n Qt::Key_Minus - KeyRedo\n Qt::Key_Plus - KeyHome\n Qt::Key_Escape */ enum KeyPatternCode { KeySelect1, KeySelect2, KeyAbort, KeyLeft, KeyRight, KeyUp, KeyDown, KeyRedo, KeyUndo, KeyHome, KeyPatternCount }; //! A pattern for mouse events class MousePattern { public: //! Constructor MousePattern( int btn = Qt::NoButton, int st = Qt::NoButton ) { button = btn; state = st; } //! Button code int button; //! State int state; }; //! A pattern for key events class KeyPattern { public: //! Constructor KeyPattern( int k = 0, int st = Qt::NoButton ) { key = k; state = st; } //! Key code int key; //! State int state; }; QwtEventPattern(); virtual ~QwtEventPattern(); void initMousePattern( int numButtons ); void initKeyPattern(); void setMousePattern( uint pattern, int button, int state = Qt::NoButton ); void setKeyPattern( uint pattern, int key, int state = Qt::NoButton ); void setMousePattern( const QVector & ); void setKeyPattern( const QVector & ); const QVector &mousePattern() const; const QVector &keyPattern() const; QVector &mousePattern(); QVector &keyPattern(); bool mouseMatch( uint pattern, const QMouseEvent * ) const; bool keyMatch( uint pattern, const QKeyEvent * ) const; protected: virtual bool mouseMatch( const MousePattern &, const QMouseEvent * ) const; virtual bool keyMatch( const KeyPattern &, const QKeyEvent * ) const; private: #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable: 4251) #endif QVector d_mousePattern; QVector d_keyPattern; #if defined(_MSC_VER) #pragma warning(pop) #endif }; //! Compare operator inline bool operator==( QwtEventPattern::MousePattern b1, QwtEventPattern::MousePattern b2 ) { return b1.button == b2.button && b1.state == b2.state; } //! Compare operator inline bool operator==( QwtEventPattern::KeyPattern b1, QwtEventPattern::KeyPattern b2 ) { return b1.key == b2.key && b1.state == b2.state; } #endif pcp-gui-1.5.11/src/libqwt/qwt_global.h0000644000000000000000000000207312176111212014422 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_GLOBAL_H #define QWT_GLOBAL_H #include // QWT_VERSION is (major << 16) + (minor << 8) + patch. #define QWT_VERSION 0x060002 #define QWT_VERSION_STR "6.0.2" #if defined(_MSC_VER) /* MSVC Compiler */ /* template-class specialization 'identifier' is already instantiated */ #pragma warning(disable: 4660) #endif // _MSC_VER #ifdef QWT_DLL #if defined(QWT_MAKEDLL) // create a Qwt DLL library #define QWT_EXPORT Q_DECL_EXPORT #else // use a Qwt DLL library #define QWT_EXPORT Q_DECL_IMPORT #endif #endif // QWT_DLL #ifndef QWT_EXPORT #define QWT_EXPORT #endif // #define QWT_NO_COMPAT 1 // disable withdrawn functionality #endif pcp-gui-1.5.11/src/libqwt/qwt_interval.h0000644000000000000000000001500512176111212015005 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_INTERVAL_H #define QWT_INTERVAL_H #include "qwt_global.h" #ifndef QT_NO_DEBUG_STREAM #include #endif /*! \brief A class representing an interval The interval is represented by 2 doubles, the lower and the upper limit. */ class QWT_EXPORT QwtInterval { public: /*! Flag indicating if a border is included or excluded \sa setBorderFlags(), borderFlags() */ enum BorderFlag { //! Min/Max values are inside the interval IncludeBorders = 0x00, //! Min value is not included in the interval ExcludeMinimum = 0x01, //! Max value is not included in the interval ExcludeMaximum = 0x02, //! Min/Max values are not included in the interval ExcludeBorders = ExcludeMinimum | ExcludeMaximum }; //! Border flags typedef QFlags BorderFlags; QwtInterval(); QwtInterval( double minValue, double maxValue, BorderFlags = IncludeBorders ); void setInterval( double minValue, double maxValue, BorderFlags = IncludeBorders ); QwtInterval normalized() const; QwtInterval inverted() const; QwtInterval limited( double minValue, double maxValue ) const; bool operator==( const QwtInterval & ) const; bool operator!=( const QwtInterval & ) const; void setBorderFlags( BorderFlags ); BorderFlags borderFlags() const; double minValue() const; double maxValue() const; double width() const; void setMinValue( double ); void setMaxValue( double ); bool contains( double value ) const; bool intersects( const QwtInterval & ) const; QwtInterval intersect( const QwtInterval & ) const; QwtInterval unite( const QwtInterval & ) const; QwtInterval operator|( const QwtInterval & ) const; QwtInterval operator&( const QwtInterval & ) const; QwtInterval &operator|=( const QwtInterval & ); QwtInterval &operator&=( const QwtInterval & ); QwtInterval extend( double value ) const; QwtInterval operator|( double ) const; QwtInterval &operator|=( double ); bool isValid() const; bool isNull() const; void invalidate(); QwtInterval symmetrize( double value ) const; private: double d_minValue; double d_maxValue; BorderFlags d_borderFlags; }; Q_DECLARE_TYPEINFO(QwtInterval, Q_MOVABLE_TYPE); /*! \brief Default Constructor Creates an invalid interval [0.0, -1.0] \sa setInterval(), isValid() */ inline QwtInterval::QwtInterval(): d_minValue( 0.0 ), d_maxValue( -1.0 ), d_borderFlags( IncludeBorders ) { } /*! Constructor Build an interval with from min/max values \param minValue Minimum value \param maxValue Maximum value \param borderFlags Include/Exclude borders */ inline QwtInterval::QwtInterval( double minValue, double maxValue, BorderFlags borderFlags ): d_minValue( minValue ), d_maxValue( maxValue ), d_borderFlags( borderFlags ) { } /*! Assign the limits of the interval \param minValue Minimum value \param maxValue Maximum value \param borderFlags Include/Exclude borders */ inline void QwtInterval::setInterval( double minValue, double maxValue, BorderFlags borderFlags ) { d_minValue = minValue; d_maxValue = maxValue; d_borderFlags = borderFlags; } /*! Change the border flags \param borderFlags Or'd BorderMode flags \sa borderFlags() */ inline void QwtInterval::setBorderFlags( BorderFlags borderFlags ) { d_borderFlags = borderFlags; } /*! \return Border flags \sa setBorderFlags() */ inline QwtInterval::BorderFlags QwtInterval::borderFlags() const { return d_borderFlags; } /*! Assign the lower limit of the interval \param minValue Minimum value */ inline void QwtInterval::setMinValue( double minValue ) { d_minValue = minValue; } /*! Assign the upper limit of the interval \param maxValue Maximum value */ inline void QwtInterval::setMaxValue( double maxValue ) { d_maxValue = maxValue; } //! \return Lower limit of the interval inline double QwtInterval::minValue() const { return d_minValue; } //! \return Upper limit of the interval inline double QwtInterval::maxValue() const { return d_maxValue; } /*! A interval is valid when minValue() <= maxValue(). In case of QwtInterval::ExcludeBorders it is true when minValue() < maxValue() */ inline bool QwtInterval::isValid() const { if ( ( d_borderFlags & ExcludeBorders ) == 0 ) return d_minValue <= d_maxValue; else return d_minValue < d_maxValue; } /*! Return the width of an interval The width of invalid intervals is 0.0, otherwise the result is maxValue() - minValue(). \sa isValid() */ inline double QwtInterval::width() const { return isValid() ? ( d_maxValue - d_minValue ) : 0.0; } /*! Intersection of two intervals \sa intersect() */ inline QwtInterval QwtInterval::operator&( const QwtInterval &interval ) const { return intersect( interval ); } /*! Union of two intervals \sa unite() */ inline QwtInterval QwtInterval::operator|( const QwtInterval &interval ) const { return unite( interval ); } //! Compare two intervals inline bool QwtInterval::operator==( const QwtInterval &other ) const { return ( d_minValue == other.d_minValue ) && ( d_maxValue == other.d_maxValue ) && ( d_borderFlags == other.d_borderFlags ); } //! Compare two intervals inline bool QwtInterval::operator!=( const QwtInterval &other ) const { return ( !( *this == other ) ); } /*! Extend an interval \param value Value \return Extended interval \sa extend() */ inline QwtInterval QwtInterval::operator|( double value ) const { return extend( value ); } //! \return true, if isValid() && (minValue() >= maxValue()) inline bool QwtInterval::isNull() const { return isValid() && d_minValue >= d_maxValue; } /*! Invalidate the interval The limits are set to interval [0.0, -1.0] \sa isValid() */ inline void QwtInterval::invalidate() { d_minValue = 0.0; d_maxValue = -1.0; } Q_DECLARE_OPERATORS_FOR_FLAGS( QwtInterval::BorderFlags ) #ifndef QT_NO_DEBUG_STREAM QWT_EXPORT QDebug operator<<( QDebug, const QwtInterval & ); #endif #endif pcp-gui-1.5.11/src/libqwt/qwt_interval_symbol.h0000644000000000000000000000417012176111212016373 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_INTERVAL_SYMBOL_H #define QWT_INTERVAL_SYMBOL_H #include "qwt_global.h" #include #include class QPainter; class QRect; class QPointF; /*! \brief A drawing primitive for displaying an interval like an error bar \sa QwtPlotIntervalCurve */ class QWT_EXPORT QwtIntervalSymbol { public: //! Symbol style enum Style { //! No Style. The symbol cannot be drawn. NoSymbol = -1, /*! The symbol displays a line with caps at the beginning/end. The size of the caps depends on the symbol width(). */ Bar, /*! The symbol displays a plain rectangle using pen() and brush(). The size of the rectangle depends on the translated interval and the width(), */ Box, /*! Styles >= UserSymbol are reserved for derived classes of QwtIntervalSymbol that overload draw() with additional application specific symbol types. */ UserSymbol = 1000 }; public: QwtIntervalSymbol( Style = NoSymbol ); QwtIntervalSymbol( const QwtIntervalSymbol & ); virtual ~QwtIntervalSymbol(); QwtIntervalSymbol &operator=( const QwtIntervalSymbol & ); bool operator==( const QwtIntervalSymbol & ) const; bool operator!=( const QwtIntervalSymbol & ) const; void setWidth( int ); int width() const; void setBrush( const QBrush& b ); const QBrush& brush() const; void setPen( const QPen & ); const QPen& pen() const; void setStyle( Style ); Style style() const; virtual void draw( QPainter *, Qt::Orientation, const QPointF& from, const QPointF& to ) const; private: class PrivateData; PrivateData* d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_knob.h0000644000000000000000000001050412176111212014111 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_KNOB_H #define QWT_KNOB_H #include "qwt_global.h" #include "qwt_abstract_slider.h" #include "qwt_abstract_scale.h" class QwtRoundScaleDraw; /*! \brief The Knob Widget The QwtKnob widget imitates look and behaviour of a volume knob on a radio. It contains a scale around the knob which is set up automatically or can be configured manually (see QwtAbstractScale). Automatic scrolling is enabled when the user presses a mouse button on the scale. For a description of signals, slots and other members, see QwtAbstractSlider. \image html knob.png \sa QwtAbstractSlider and QwtAbstractScale for the descriptions of the inherited members. */ class QWT_EXPORT QwtKnob : public QwtAbstractSlider, public QwtAbstractScale { Q_OBJECT Q_ENUMS ( KnobStyle ) Q_ENUMS ( MarkerStyle ) Q_PROPERTY( KnobStyle knobStyle READ knobStyle WRITE setKnobStyle ) Q_PROPERTY( MarkerStyle markerStyle READ markerStyle WRITE setMarkerStyle ) Q_PROPERTY( int knobWidth READ knobWidth WRITE setKnobWidth ) Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth ) Q_PROPERTY( double totalAngle READ totalAngle WRITE setTotalAngle ) Q_PROPERTY( int markerSize READ markerSize WRITE setMarkerSize ) Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth ) public: /*! \brief Style of the knob surface Depending on the KnobStyle the surface of the knob is filled from the brushes of the widget palette(). \sa setKnobStyle(), knobStyle() */ enum KnobStyle { //! Fill the knob with a brush from QPalette::Button. NoStyle = -1, //! Build a gradient from QPalette::Midlight and QPalette::Button Raised, /*! Build a gradient from QPalette::Midlight, QPalette::Button and QPalette::Midlight */ Sunken }; /*! \brief Marker type The marker indicates the current value on the knob The default setting is a Notch marker. \sa setMarkerStyle(), setMarkerSize() */ enum MarkerStyle { //! Don't paint any marker NoMarker = -1, //! Paint a single tick in QPalette::ButtonText color Tick, //! Paint a circle in QPalette::ButtonText color Dot, /*! Draw a raised ellipse with a gradient build from QPalette::Light and QPalette::Mid */ Nub, /*! Draw a sunken ellipse with a gradient build from QPalette::Light and QPalette::Mid */ Notch }; explicit QwtKnob( QWidget* parent = NULL ); virtual ~QwtKnob(); void setKnobWidth( int w ); int knobWidth() const; void setTotalAngle ( double angle ); double totalAngle() const; void setKnobStyle( KnobStyle ); KnobStyle knobStyle() const; void setBorderWidth( int bw ); int borderWidth() const; void setMarkerStyle( MarkerStyle ); MarkerStyle markerStyle() const; void setMarkerSize( int ); int markerSize() const; virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; void setScaleDraw( QwtRoundScaleDraw * ); const QwtRoundScaleDraw *scaleDraw() const; QwtRoundScaleDraw *scaleDraw(); protected: virtual void paintEvent( QPaintEvent * ); virtual void resizeEvent( QResizeEvent * ); virtual void changeEvent( QEvent * ); virtual void drawKnob( QPainter *, const QRectF & ) const; virtual void drawMarker( QPainter *, const QRectF &, double arc ) const; virtual double getValue( const QPoint &p ); virtual void getScrollMode( const QPoint &, QwtAbstractSlider::ScrollMode &, int &direction ) const; private: void initKnob(); void layoutKnob( bool update ); void recalcAngle(); virtual void valueChange(); virtual void rangeChange(); virtual void scaleChange(); class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_legend.h0000644000000000000000000000451212176111212014420 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_LEGEND_H #define QWT_LEGEND_H #include "qwt_global.h" #include #include class QScrollBar; class QwtLegendItemManager; /*! \brief The legend widget The QwtLegend widget is a tabular arrangement of legend items. Legend items might be any type of widget, but in general they will be a QwtLegendItem. \sa QwtLegendItem, QwtLegendItemManager QwtPlot */ class QWT_EXPORT QwtLegend : public QFrame { Q_OBJECT public: /*! \brief Interaction mode for the legend items The default is QwtLegend::ReadOnlyItem. \sa setItemMode(), itemMode(), QwtLegendItem::IdentifierMode QwtLegendItem::clicked(), QwtLegendItem::checked(), QwtPlot::legendClicked(), QwtPlot::legendChecked() */ enum LegendItemMode { //! The legend item is not interactive, like a label ReadOnlyItem, //! The legend item is clickable, like a push button ClickableItem, //! The legend item is checkable, like a checkable button CheckableItem }; explicit QwtLegend( QWidget *parent = NULL ); virtual ~QwtLegend(); void setItemMode( LegendItemMode ); LegendItemMode itemMode() const; QWidget *contentsWidget(); const QWidget *contentsWidget() const; void insert( const QwtLegendItemManager *, QWidget * ); void remove( const QwtLegendItemManager * ); QWidget *find( const QwtLegendItemManager * ) const; QwtLegendItemManager *find( const QWidget * ) const; virtual QList legendItems() const; void clear(); bool isEmpty() const; uint itemCount() const; virtual bool eventFilter( QObject *, QEvent * ); virtual QSize sizeHint() const; virtual int heightForWidth( int w ) const; QScrollBar *horizontalScrollBar() const; QScrollBar *verticalScrollBar() const; protected: virtual void layoutContents(); private: class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_legend_item.h0000644000000000000000000000364612176111212015445 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_LEGEND_ITEM_H #define QWT_LEGEND_ITEM_H #include "qwt_global.h" #include "qwt_legend.h" #include "qwt_text.h" #include "qwt_text_label.h" #include /*! \brief A widget representing something on a QwtLegend(). */ class QWT_EXPORT QwtLegendItem: public QwtTextLabel { Q_OBJECT public: explicit QwtLegendItem( QWidget *parent = 0 ); virtual ~QwtLegendItem(); void setItemMode( QwtLegend::LegendItemMode ); QwtLegend::LegendItemMode itemMode() const; void setSpacing( int spacing ); int spacing() const; virtual void setText( const QwtText & ); void setIdentifier( const QPixmap & ); QPixmap identifier() const; void setIdentifierSize( const QSize & ); QSize identifierSize() const; virtual QSize sizeHint() const; bool isChecked() const; public Q_SLOTS: void setChecked( bool on ); Q_SIGNALS: //! Signal, when the legend item has been clicked void clicked(); //! Signal, when the legend item has been pressed void pressed(); //! Signal, when the legend item has been relased void released(); //! Signal, when the legend item has been toggled void checked( bool ); protected: void setDown( bool ); bool isDown() const; virtual void paintEvent( QPaintEvent * ); virtual void mousePressEvent( QMouseEvent * ); virtual void mouseReleaseEvent( QMouseEvent * ); virtual void keyPressEvent( QKeyEvent * ); virtual void keyReleaseEvent( QKeyEvent * ); private: class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_legend_itemmanager.h0000644000000000000000000000300412176111212016764 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_LEGEND_ITEM_MANAGER_H #define QWT_LEGEND_ITEM_MANAGER_H #include "qwt_global.h" class QwtLegend; class QWidget; class QRectF; class QPainter; /*! \brief Abstract API to bind plot items to the legend */ class QWT_EXPORT QwtLegendItemManager { public: //! Constructor QwtLegendItemManager() { } //! Destructor virtual ~QwtLegendItemManager() { } /*! Update the widget that represents the item on the legend \param legend Legend \sa legendItem() */ virtual void updateLegend( QwtLegend *legend ) const = 0; /*! Allocate the widget that represents the item on the legend \return Allocated widget \sa updateLegend() QwtLegend() */ virtual QWidget *legendItem() const = 0; /*! QwtLegendItem can display an icon-identifier followed by a text. The icon helps to identify a plot item on the plot canvas and depends on the type of information, that is displayed. The default implementation paints nothing. */ virtual void drawLegendIdentifier( QPainter *, const QRectF & ) const { } }; #endif pcp-gui-1.5.11/src/libqwt/qwt_magnifier.h0000644000000000000000000000441012176111212015120 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_MAGNIFIER_H #define QWT_MAGNIFIER_H 1 #include "qwt_global.h" #include class QWidget; class QMouseEvent; class QWheelEvent; class QKeyEvent; /*! \brief QwtMagnifier provides zooming, by magnifying in steps. Using QwtMagnifier a plot can be zoomed in/out in steps using keys, the mouse wheel or moving a mouse button in vertical direction. */ class QWT_EXPORT QwtMagnifier: public QObject { Q_OBJECT public: explicit QwtMagnifier( QWidget * ); virtual ~QwtMagnifier(); QWidget *parentWidget(); const QWidget *parentWidget() const; void setEnabled( bool ); bool isEnabled() const; // mouse void setMouseFactor( double ); double mouseFactor() const; void setMouseButton( int button, int buttonState = Qt::NoButton ); void getMouseButton( int &button, int &buttonState ) const; // mouse wheel void setWheelFactor( double ); double wheelFactor() const; void setWheelButtonState( int buttonState ); int wheelButtonState() const; // keyboard void setKeyFactor( double ); double keyFactor() const; void setZoomInKey( int key, int modifiers ); void getZoomInKey( int &key, int &modifiers ) const; void setZoomOutKey( int key, int modifiers ); void getZoomOutKey( int &key, int &modifiers ) const; virtual bool eventFilter( QObject *, QEvent * ); protected: /*! Rescale the parent widget \param factor Scale factor */ virtual void rescale( double factor ) = 0; virtual void widgetMousePressEvent( QMouseEvent * ); virtual void widgetMouseReleaseEvent( QMouseEvent * ); virtual void widgetMouseMoveEvent( QMouseEvent * ); virtual void widgetWheelEvent( QWheelEvent * ); virtual void widgetKeyPressEvent( QKeyEvent * ); virtual void widgetKeyReleaseEvent( QKeyEvent * ); private: class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_math.h0000644000000000000000000000756712176111212014130 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_MATH_H #define QWT_MATH_H #include "qwt_global.h" #if defined(_MSC_VER) /* Microsoft says: Define _USE_MATH_DEFINES before including math.h to expose these macro definitions for common math constants. These are placed under an #ifdef since these commonly-defined names are not part of the C/C++ standards. */ #define _USE_MATH_DEFINES 1 #endif #include #include #include "qwt_global.h" #ifndef LOG10_2 #define LOG10_2 0.30102999566398119802 /* log10(2) */ #endif #ifndef LOG10_3 #define LOG10_3 0.47712125471966243540 /* log10(3) */ #endif #ifndef LOG10_5 #define LOG10_5 0.69897000433601885749 /* log10(5) */ #endif #ifndef M_2PI #define M_2PI 6.28318530717958623200 /* 2 pi */ #endif #ifndef LOG_MIN //! Mininum value for logarithmic scales #define LOG_MIN 1.0e-100 #endif #ifndef LOG_MAX //! Maximum value for logarithmic scales #define LOG_MAX 1.0e100 #endif #ifndef M_E #define M_E 2.7182818284590452354 /* e */ #endif #ifndef M_LOG2E #define M_LOG2E 1.4426950408889634074 /* log_2 e */ #endif #ifndef M_LOG10E #define M_LOG10E 0.43429448190325182765 /* log_10 e */ #endif #ifndef M_LN2 #define M_LN2 0.69314718055994530942 /* log_e 2 */ #endif #ifndef M_LN10 #define M_LN10 2.30258509299404568402 /* log_e 10 */ #endif #ifndef M_PI #define M_PI 3.14159265358979323846 /* pi */ #endif #ifndef M_PI_2 #define M_PI_2 1.57079632679489661923 /* pi/2 */ #endif #ifndef M_PI_4 #define M_PI_4 0.78539816339744830962 /* pi/4 */ #endif #ifndef M_1_PI #define M_1_PI 0.31830988618379067154 /* 1/pi */ #endif #ifndef M_2_PI #define M_2_PI 0.63661977236758134308 /* 2/pi */ #endif #ifndef M_2_SQRTPI #define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ #endif #ifndef M_SQRT2 #define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ #endif #ifndef M_SQRT1_2 #define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ #endif QWT_EXPORT double qwtGetMin( const double *array, int size ); QWT_EXPORT double qwtGetMax( const double *array, int size ); /*! \brief Compare 2 values, relative to an interval Values are "equal", when : \f$\cdot value2 - value1 <= abs(intervalSize * 10e^{-6})\f$ \param value1 First value to compare \param value2 Second value to compare \param intervalSize interval size \return 0: if equal, -1: if value2 > value1, 1: if value1 > value2 */ inline int qwtFuzzyCompare( double value1, double value2, double intervalSize ) { const double eps = qAbs( 1.0e-6 * intervalSize ); if ( value2 - value1 > eps ) return -1; if ( value1 - value2 > eps ) return 1; return 0; } inline bool qwtFuzzyGreaterOrEqual( double d1, double d2 ) { return ( d1 >= d2 ) || qFuzzyCompare( d1, d2 ); } inline bool qwtFuzzyLessOrEqual( double d1, double d2 ) { return ( d1 <= d2 ) || qFuzzyCompare( d1, d2 ); } //! Return the sign inline int qwtSign( double x ) { if ( x > 0.0 ) return 1; else if ( x < 0.0 ) return ( -1 ); else return 0; } //! Return the square of a number inline double qwtSqr( double x ) { return x * x; } //! Like qRound, but without converting the result to an int inline double qwtRoundF(double d) { return ::floor( d + 0.5 ); } //! Like qFloor, but without converting the result to an int inline double qwtFloorF(double d) { return ::floor( d ); } //! Like qCeil, but without converting the result to an int inline double qwtCeilF(double d) { return ::ceil( d ); } #endif pcp-gui-1.5.11/src/libqwt/qwt_matrix_raster_data.h0000644000000000000000000000366112176111212017043 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_MATRIX_RASTER_DATA_H #define QWT_MATRIX_RASTER_DATA_H 1 #include "qwt_global.h" #include "qwt_raster_data.h" #include /*! \brief A class representing a matrix of values as raster data QwtMatrixRasterData implements an interface for a matrix of equidistant values, that can be used by a QwtPlotRasterItem. It implements a couple of resampling algorithms, to provide values for positions, that or not on the value matrix. */ class QWT_EXPORT QwtMatrixRasterData: public QwtRasterData { public: /*! \brief Resampling algorithm The default setting is NearestNeighbour; */ enum ResampleMode { /*! Return the value from the matrix, that is nearest to the the requested position. */ NearestNeighbour, /*! Interpolate the value from the distances and values of the 4 surrounding values in the matrix, */ BilinearInterpolation }; QwtMatrixRasterData(); virtual ~QwtMatrixRasterData(); void setResampleMode(ResampleMode mode); ResampleMode resampleMode() const; virtual void setInterval( Qt::Axis, const QwtInterval & ); void setValueMatrix( const QVector &values, size_t numColumns ); const QVector valueMatrix() const; size_t numColumns() const; size_t numRows() const; virtual QRectF pixelHint( const QRectF & ) const; virtual double value( double x, double y ) const; private: void update(); class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_null_paintdevice.h0000644000000000000000000000511412176111212016506 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_NULL_PAINT_DEVICE_H #define QWT_NULL_PAINT_DEVICE_H 1 #include "qwt_global.h" #include #include /*! \brief A null paint device doing nothing Sometimes important layout/rendering geometries are not available or changable from the public Qt class interface. ( f.e hidden in the style implementation ). QwtNullPaintDevice can be used to manipulate or filter out these informations by analyzing the stream of paint primitives. F.e. QwtNullPaintDevice is used by QwtPlotCanvas to identify styled backgrounds with rounded corners. */ class QWT_EXPORT QwtNullPaintDevice: public QPaintDevice { public: QwtNullPaintDevice( QPaintEngine::PaintEngineFeatures ); QwtNullPaintDevice( const QSize &size, QPaintEngine::PaintEngineFeatures ); virtual ~QwtNullPaintDevice(); void setSize( const QSize &); QSize size() const; virtual QPaintEngine *paintEngine() const; virtual int metric( PaintDeviceMetric metric ) const; virtual void drawRects(const QRect *, int ); virtual void drawRects(const QRectF *, int ); virtual void drawLines(const QLine *, int ); virtual void drawLines(const QLineF *, int ); virtual void drawEllipse(const QRectF &); virtual void drawEllipse(const QRect &); virtual void drawPath(const QPainterPath &); virtual void drawPoints(const QPointF *, int ); virtual void drawPoints(const QPoint *, int ); virtual void drawPolygon( const QPointF *, int , QPaintEngine::PolygonDrawMode ); virtual void drawPolygon( const QPoint *, int , QPaintEngine::PolygonDrawMode ); virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &); virtual void drawTextItem(const QPointF &, const QTextItem &); virtual void drawTiledPixmap(const QRectF &, const QPixmap &, const QPointF &s); virtual void drawImage(const QRectF &, const QImage &, const QRectF &, Qt::ImageConversionFlags ); virtual void updateState( const QPaintEngineState &state ); private: void init( QPaintEngine::PaintEngineFeatures ); class PaintEngine; PaintEngine *d_engine; class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_painter.h0000644000000000000000000001114012176111212014617 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PAINTER_H #define QWT_PAINTER_H #include "qwt_global.h" #include #include #include #include class QPainter; class QBrush; class QColor; class QWidget; class QPolygonF; class QRectF; class QImage; class QPixmap; class QwtScaleMap; class QwtColorMap; class QwtInterval; class QPalette; class QTextDocument; class QPainterPath; /*! \brief A collection of QPainter workarounds */ class QWT_EXPORT QwtPainter { public: static void setPolylineSplitting( bool ); static bool polylineSplitting(); static void setRoundingAlignment( bool ); static bool roundingAlignment(); static bool roundingAlignment(QPainter *); static void drawText( QPainter *, double x, double y, const QString & ); static void drawText( QPainter *, const QPointF &, const QString & ); static void drawText( QPainter *, double x, double y, double w, double h, int flags, const QString & ); static void drawText( QPainter *, const QRectF &, int flags, const QString & ); #ifndef QT_NO_RICHTEXT static void drawSimpleRichText( QPainter *, const QRectF &, int flags, const QTextDocument & ); #endif static void drawRect( QPainter *, double x, double y, double w, double h ); static void drawRect( QPainter *, const QRectF &rect ); static void fillRect( QPainter *, const QRectF &, const QBrush & ); static void drawEllipse( QPainter *, const QRectF & ); static void drawPie( QPainter *, const QRectF & r, int a, int alen ); static void drawLine( QPainter *, double x1, double y1, double x2, double y2 ); static void drawLine( QPainter *, const QPointF &p1, const QPointF &p2 ); static void drawLine( QPainter *, const QLineF & ); static void drawPolygon( QPainter *, const QPolygonF &pa ); static void drawPolyline( QPainter *, const QPolygonF &pa ); static void drawPolyline( QPainter *, const QPointF *, int pointCount ); static void drawPoint( QPainter *, double x, double y ); static void drawPoint( QPainter *, const QPointF & ); static void drawPath( QPainter *, const QPainterPath & ); static void drawImage( QPainter *, const QRectF &, const QImage & ); static void drawPixmap( QPainter *, const QRectF &, const QPixmap & ); static void drawRoundedFrame( QPainter *, const QRectF &, double xRadius, double yRadius, const QPalette &, int lineWidth, int frameStyle ); static void drawFocusRect( QPainter *, QWidget * ); static void drawFocusRect( QPainter *, QWidget *, const QRect & ); static void drawColorBar( QPainter *painter, const QwtColorMap &, const QwtInterval &, const QwtScaleMap &, Qt::Orientation, const QRectF & ); static bool isAligning( QPainter *painter ); #if QT_VERSION >= 0x050000 static void fillPixmap( const QWidget *, QPixmap &, const QPoint &offset = QPoint() ); #endif private: static bool d_polylineSplitting; static bool d_roundingAlignment; }; //! Wrapper for QPainter::drawPoint() inline void QwtPainter::drawPoint( QPainter *painter, double x, double y ) { QwtPainter::drawPoint( painter, QPointF( x, y ) ); } //! Wrapper for QPainter::drawLine() inline void QwtPainter::drawLine( QPainter *painter, double x1, double y1, double x2, double y2 ) { QwtPainter::drawLine( painter, QPointF( x1, y1 ), QPointF( x2, y2 ) ); } //! Wrapper for QPainter::drawLine() inline void QwtPainter::drawLine( QPainter *painter, const QLineF &line ) { QwtPainter::drawLine( painter, line.p1(), line.p2() ); } /*! Returns whether line splitting for the raster paint engine is enabled. \sa setPolylineSplitting() */ inline bool QwtPainter::polylineSplitting() { return d_polylineSplitting; } /*! Returns whether coordinates should be rounded, before they are painted to a paint engine that floors to integer values. For other paint engines this ( Pdf, SVG ), this flag has no effect. \sa setRoundingAlignment(), isAligning() */ inline bool QwtPainter::roundingAlignment() { return d_roundingAlignment; } /*! \return roundingAlignment() && isAligning(painter); \param painter Painter */ inline bool QwtPainter::roundingAlignment(QPainter *painter) { return d_roundingAlignment && isAligning(painter); } #endif pcp-gui-1.5.11/src/libqwt/qwt_panner.h0000644000000000000000000000545612176111212014455 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PANNER_H #define QWT_PANNER_H 1 #include "qwt_global.h" #include #include class QCursor; /*! \brief QwtPanner provides panning of a widget QwtPanner grabs the contents of a widget, that can be dragged in all directions. The offset between the start and the end position is emitted by the panned signal. QwtPanner grabs the content of the widget into a pixmap and moves the pixmap around, without initiating any repaint events for the widget. Areas, that are not part of content are not painted while panning. This makes panning fast enough for widgets, where repaints are too slow for mouse movements. For widgets, where repaints are very fast it might be better to implement panning manually by mapping mouse events into paint events. */ class QWT_EXPORT QwtPanner: public QWidget { Q_OBJECT public: QwtPanner( QWidget* parent ); virtual ~QwtPanner(); void setEnabled( bool ); bool isEnabled() const; void setMouseButton( int button, int buttonState = Qt::NoButton ); void getMouseButton( int &button, int &buttonState ) const; void setAbortKey( int key, int state = Qt::NoButton ); void getAbortKey( int &key, int &state ) const; void setCursor( const QCursor & ); const QCursor cursor() const; void setOrientations( Qt::Orientations ); Qt::Orientations orientations() const; bool isOrientationEnabled( Qt::Orientation ) const; virtual bool eventFilter( QObject *, QEvent * ); Q_SIGNALS: /*! Signal emitted, when panning is done \param dx Offset in horizontal direction \param dy Offset in vertical direction */ void panned( int dx, int dy ); /*! Signal emitted, while the widget moved, but panning is not finished. \param dx Offset in horizontal direction \param dy Offset in vertical direction */ void moved( int dx, int dy ); protected: virtual void widgetMousePressEvent( QMouseEvent * ); virtual void widgetMouseReleaseEvent( QMouseEvent * ); virtual void widgetMouseMoveEvent( QMouseEvent * ); virtual void widgetKeyPressEvent( QKeyEvent * ); virtual void widgetKeyReleaseEvent( QKeyEvent * ); virtual void paintEvent( QPaintEvent * ); virtual QBitmap contentsMask() const; virtual QPixmap grab() const; private: #ifndef QT_NO_CURSOR void showCursor( bool ); #endif class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_picker.h0000644000000000000000000002221312176111212014435 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PICKER #define QWT_PICKER 1 #include "qwt_global.h" #include "qwt_text.h" #include "qwt_event_pattern.h" #include #include #include #include class QWidget; class QMouseEvent; class QWheelEvent; class QKeyEvent; class QwtPickerMachine; /*! \brief QwtPicker provides selections on a widget QwtPicker filters all enter, leave, mouse and keyboard events of a widget and translates them into an array of selected points. The way how the points are collected depends on type of state machine that is connected to the picker. Qwt offers a couple of predefined state machines for selecting: - Nothing\n QwtPickerTrackerMachine - Single points\n QwtPickerClickPointMachine, QwtPickerDragPointMachine - Rectangles\n QwtPickerClickRectMachine, QwtPickerDragRectMachine - Polygons\n QwtPickerPolygonMachine While these state machines cover the most common ways to collect points it is also possible to implement individual machines as well. QwtPicker translates the picked points into a selection using the adjustedPoints method. adjustedPoints is intended to be reimplemented to fixup the selection according to application specific requirements. (F.e. when an application accepts rectangles of a fixed aspect ratio only.) Optionally QwtPicker support the process of collecting points by a rubberband and tracker displaying a text for the current mouse position. \par Example \verbatim #include #include QwtPicker *picker = new QwtPicker(widget); picker->setStateMachine(new QwtPickerDragRectMachine); picker->setTrackerMode(QwtPicker::ActiveOnly); picker->setRubberBand(QwtPicker::RectRubberBand); \endverbatim\n The state machine triggers the following commands: - begin()\n Activate/Initialize the selection. - append()\n Add a new point - move() \n Change the position of the last point. - remove()\n Remove the last point. - end()\n Terminate the selection and call accept to validate the picked points. The picker is active (isActive()), between begin() and end(). In active state the rubberband is displayed, and the tracker is visible in case of trackerMode is ActiveOnly or AlwaysOn. The cursor can be moved using the arrow keys. All selections can be aborted using the abort key. (QwtEventPattern::KeyPatternCode) \warning In case of QWidget::NoFocus the focus policy of the observed widget is set to QWidget::WheelFocus and mouse tracking will be manipulated while the picker is active, or if trackerMode() is AlwayOn. */ class QWT_EXPORT QwtPicker: public QObject, public QwtEventPattern { Q_OBJECT Q_ENUMS( RubberBand ) Q_ENUMS( DisplayMode ) Q_ENUMS( ResizeMode ) Q_PROPERTY( bool isEnabled READ isEnabled WRITE setEnabled ) Q_PROPERTY( ResizeMode resizeMode READ resizeMode WRITE setResizeMode ) Q_PROPERTY( DisplayMode trackerMode READ trackerMode WRITE setTrackerMode ) Q_PROPERTY( QPen trackerPen READ trackerPen WRITE setTrackerPen ) Q_PROPERTY( QFont trackerFont READ trackerFont WRITE setTrackerFont ) Q_PROPERTY( RubberBand rubberBand READ rubberBand WRITE setRubberBand ) Q_PROPERTY( QPen rubberBandPen READ rubberBandPen WRITE setRubberBandPen ) public: /*! Rubberband style The default value is QwtPicker::NoRubberBand. \sa setRubberBand(), rubberBand() */ enum RubberBand { //! No rubberband. NoRubberBand = 0, //! A horizontal line ( only for QwtPicker::PointSelection ) HLineRubberBand, //! A vertical line ( only for QwtPicker::PointSelection ) VLineRubberBand, //! A crosshair ( only for QwtPicker::PointSelection ) CrossRubberBand, //! A rectangle ( only for QwtPicker::RectSelection ) RectRubberBand, //! An ellipse ( only for QwtPicker::RectSelection ) EllipseRubberBand, //! A polygon ( only for QwtPicker::&PolygonSelection ) PolygonRubberBand, /*! Values >= UserRubberBand can be used to define additional rubber bands. */ UserRubberBand = 100 }; /*! \brief Display mode \sa setTrackerMode(), trackerMode(), isActive() */ enum DisplayMode { //! Display never AlwaysOff, //! Display always AlwaysOn, //! Display only when the selection is active ActiveOnly }; /*! Controls what to do with the selected points of an active selection when the observed widget is resized. The default value is QwtPicker::Stretch. \sa setResizeMode() */ enum ResizeMode { //! All points are scaled according to the new size, Stretch, //! All points remain unchanged. KeepSize }; explicit QwtPicker( QWidget *parent ); explicit QwtPicker( RubberBand rubberBand, DisplayMode trackerMode, QWidget * ); virtual ~QwtPicker(); void setStateMachine( QwtPickerMachine * ); const QwtPickerMachine *stateMachine() const; QwtPickerMachine *stateMachine(); void setRubberBand( RubberBand ); RubberBand rubberBand() const; void setTrackerMode( DisplayMode ); DisplayMode trackerMode() const; void setResizeMode( ResizeMode ); ResizeMode resizeMode() const; void setRubberBandPen( const QPen & ); QPen rubberBandPen() const; void setTrackerPen( const QPen & ); QPen trackerPen() const; void setTrackerFont( const QFont & ); QFont trackerFont() const; bool isEnabled() const; bool isActive() const; virtual bool eventFilter( QObject *, QEvent * ); QWidget *parentWidget(); const QWidget *parentWidget() const; virtual QRect pickRect() const; virtual void drawRubberBand( QPainter * ) const; virtual void drawTracker( QPainter * ) const; virtual QwtText trackerText( const QPoint &pos ) const; QPoint trackerPosition() const; virtual QRect trackerRect( const QFont & ) const; QPolygon selection() const; public Q_SLOTS: void setEnabled( bool ); Q_SIGNALS: /*! A signal indicating, when the picker has been activated. Together with setEnabled() it can be used to implement selections with more than one picker. \param on True, when the picker has been activated */ void activated( bool on ); /*! A signal emitting the selected points, at the end of a selection. \param polygon Selected points */ void selected( const QPolygon &polygon ); /*! A signal emitted when a point has been appended to the selection \param pos Position of the appended point. \sa append(). moved() */ void appended( const QPoint &pos ); /*! A signal emitted whenever the last appended point of the selection has been moved. \param pos Position of the moved last point of the selection. \sa move(), appended() */ void moved( const QPoint &pos ); /*! A signal emitted whenever the last appended point of the selection has been removed. \sa remove(), appended() */ void removed( const QPoint &pos ); /*! A signal emitted when the active selection has been changed. This might happen when the observed widget is resized. \param selection Changed selection \sa stretchSelection() */ void changed( const QPolygon &selection ); protected: virtual QPolygon adjustedPoints( const QPolygon & ) const; virtual void transition( const QEvent * ); virtual void begin(); virtual void append( const QPoint & ); virtual void move( const QPoint & ); virtual void remove(); virtual bool end( bool ok = true ); virtual bool accept( QPolygon & ) const; virtual void reset(); virtual void widgetMousePressEvent( QMouseEvent * ); virtual void widgetMouseReleaseEvent( QMouseEvent * ); virtual void widgetMouseDoubleClickEvent( QMouseEvent * ); virtual void widgetMouseMoveEvent( QMouseEvent * ); virtual void widgetWheelEvent( QWheelEvent * ); virtual void widgetKeyPressEvent( QKeyEvent * ); virtual void widgetKeyReleaseEvent( QKeyEvent * ); virtual void widgetEnterEvent( QEvent * ); virtual void widgetLeaveEvent( QEvent * ); virtual void stretchSelection( const QSize &oldSize, const QSize &newSize ); virtual void updateDisplay(); const QWidget *rubberBandWidget() const; const QWidget *trackerWidget() const; const QPolygon &pickedPoints() const; private: void init( QWidget *, RubberBand rubberBand, DisplayMode trackerMode ); void setMouseTracking( bool ); class PickerWidget; class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_picker_machine.h0000644000000000000000000001163612176111212016130 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PICKER_MACHINE #define QWT_PICKER_MACHINE 1 #include "qwt_global.h" #include class QEvent; class QwtEventPattern; /*! \brief A state machine for QwtPicker selections QwtPickerMachine accepts key and mouse events and translates them into selection commands. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerMachine { public: /*! Type of a selection. \sa selectionType() */ enum SelectionType { //! The state machine not usable for any type of selection. NoSelection = -1, //! The state machine is for selecting a single point. PointSelection, //! The state machine is for selecting a rectangle (2 points). RectSelection, //! The state machine is for selecting a polygon (many points). PolygonSelection }; //! Commands - the output of a state machine enum Command { Begin, Append, Move, Remove, End }; QwtPickerMachine( SelectionType ); virtual ~QwtPickerMachine(); //! Transition virtual QList transition( const QwtEventPattern &, const QEvent * ) = 0; void reset(); int state() const; void setState( int ); SelectionType selectionType() const; private: const SelectionType d_selectionType; int d_state; }; /*! \brief A state machine for indicating mouse movements QwtPickerTrackerMachine supports displaying information corresponding to mouse movements, but is not intended for selecting anything. Begin/End are related to Enter/Leave events. */ class QWT_EXPORT QwtPickerTrackerMachine: public QwtPickerMachine { public: QwtPickerTrackerMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for point selections Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1 selects a point. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerClickPointMachine: public QwtPickerMachine { public: QwtPickerClickPointMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for point selections Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1 starts the selection, releasing QwtEventPattern::MouseSelect1 or a second press of QwtEventPattern::KeySelect1 terminates it. */ class QWT_EXPORT QwtPickerDragPointMachine: public QwtPickerMachine { public: QwtPickerDragPointMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for rectangle selections Pressing QwtEventPattern::MouseSelect1 starts the selection, releasing it selects the first point. Pressing it again selects the second point and terminates the selection. Pressing QwtEventPattern::KeySelect1 also starts the selection, a second press selects the first point. A third one selects the second point and terminates the selection. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerClickRectMachine: public QwtPickerMachine { public: QwtPickerClickRectMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for rectangle selections Pressing QwtEventPattern::MouseSelect1 selects the first point, releasing it the second point. Pressing QwtEventPattern::KeySelect1 also selects the first point, a second press selects the second point and terminates the selection. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerDragRectMachine: public QwtPickerMachine { public: QwtPickerDragRectMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for polygon selections Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1 starts the selection and selects the first point, or appends a point. Pressing QwtEventPattern::MouseSelect2 or QwtEventPattern::KeySelect2 appends the last point and terminates the selection. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerPolygonMachine: public QwtPickerMachine { public: QwtPickerPolygonMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; #endif pcp-gui-1.5.11/src/libqwt/qwt_plot.h0000644000000000000000000001716412176111212014147 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_H #define QWT_PLOT_H #include "qwt_global.h" #include "qwt_text.h" #include "qwt_plot_dict.h" #include "qwt_scale_map.h" #include "qwt_interval.h" #include class QwtPlotLayout; class QwtLegend; class QwtScaleWidget; class QwtScaleEngine; class QwtScaleDiv; class QwtScaleDraw; class QwtTextLabel; class QwtPlotCanvas; /*! \brief A 2-D plotting widget QwtPlot is a widget for plotting two-dimensional graphs. An unlimited number of plot items can be displayed on its canvas. Plot items might be curves (QwtPlotCurve), markers (QwtPlotMarker), the grid (QwtPlotGrid), or anything else derived from QwtPlotItem. A plot can have up to four axes, with each plot item attached to an x- and a y axis. The scales at the axes can be explicitely set (QwtScaleDiv), or are calculated from the plot items, using algorithms (QwtScaleEngine) which can be configured separately for each axis. \image html plot.png \par Example The following example shows (schematically) the most simple way to use QwtPlot. By default, only the left and bottom axes are visible and their scales are computed automatically. \verbatim #include #include QwtPlot *myPlot = new QwtPlot("Two Curves", parent); // add curves QwtPlotCurve *curve1 = new QwtPlotCurve("Curve 1"); QwtPlotCurve *curve2 = new QwtPlotCurve("Curve 2"); // connect or copy the data to the curves curve1->setData(...); curve2->setData(...); curve1->attach(myPlot); curve2->attach(myPlot); // finally, refresh the plot myPlot->replot(); \endverbatim */ class QWT_EXPORT QwtPlot: public QFrame, public QwtPlotDict { Q_OBJECT Q_PROPERTY( QString propertiesDocument READ grabProperties WRITE applyProperties ) public: //! \brief Axis index enum Axis { //! Y axis left of the canvas yLeft, //! Y axis right of the canvas yRight, //! X axis below the canvas xBottom, //! X axis above the canvas xTop, //! Number of axes axisCnt }; /*! Position of the legend, relative to the canvas. \sa insertLegend() \note In case of ExternalLegend, the legend is not handled by QwtPlotRenderer */ enum LegendPosition { //! The legend will be left from the QwtPlot::yLeft axis. LeftLegend, //! The legend will be right from the QwtPlot::yRight axis. RightLegend, //! The legend will be below QwtPlot::xBottom axis. BottomLegend, //! The legend will be between QwtPlot::xTop axis and the title. TopLegend, /*! External means that only the content of the legend will be handled by QwtPlot, but not its geometry. This type can be used to have a legend in an external window ( or on the canvas ). */ ExternalLegend }; explicit QwtPlot( QWidget * = NULL ); explicit QwtPlot( const QwtText &title, QWidget *p = NULL ); virtual ~QwtPlot(); void applyProperties( const QString & ); QString grabProperties() const; void setAutoReplot( bool tf = true ); bool autoReplot() const; // Layout QwtPlotLayout *plotLayout(); const QwtPlotLayout *plotLayout() const; // Title void setTitle( const QString & ); void setTitle( const QwtText &t ); QwtText title() const; QwtTextLabel *titleLabel(); const QwtTextLabel *titleLabel() const; // Canvas QwtPlotCanvas *canvas(); const QwtPlotCanvas *canvas() const; void setCanvasBackground( const QBrush & ); QBrush canvasBackground() const; void setCanvasLineWidth( int w ); int canvasLineWidth() const; virtual QwtScaleMap canvasMap( int axisId ) const; double invTransform( int axisId, int pos ) const; double transform( int axisId, double value ) const; // Axes QwtScaleEngine *axisScaleEngine( int axisId ); const QwtScaleEngine *axisScaleEngine( int axisId ) const; void setAxisScaleEngine( int axisId, QwtScaleEngine * ); void setAxisAutoScale( int axisId, bool on = true ); bool axisAutoScale( int axisId ) const; void enableAxis( int axisId, bool tf = true ); bool axisEnabled( int axisId ) const; void setAxisFont( int axisId, const QFont &f ); QFont axisFont( int axisId ) const; void setAxisScale( int axisId, double min, double max, double step = 0 ); void setAxisScaleDiv( int axisId, const QwtScaleDiv & ); void setAxisScaleDraw( int axisId, QwtScaleDraw * ); double axisStepSize( int axisId ) const; QwtInterval axisInterval( int axisId ) const; const QwtScaleDiv *axisScaleDiv( int axisId ) const; QwtScaleDiv *axisScaleDiv( int axisId ); const QwtScaleDraw *axisScaleDraw( int axisId ) const; QwtScaleDraw *axisScaleDraw( int axisId ); const QwtScaleWidget *axisWidget( int axisId ) const; QwtScaleWidget *axisWidget( int axisId ); void setAxisLabelAlignment( int axisId, Qt::Alignment ); void setAxisLabelRotation( int axisId, double rotation ); void setAxisTitle( int axisId, const QString & ); void setAxisTitle( int axisId, const QwtText & ); QwtText axisTitle( int axisId ) const; void setAxisMaxMinor( int axisId, int maxMinor ); int axisMaxMinor( int axisId ) const; void setAxisMaxMajor( int axisId, int maxMajor ); int axisMaxMajor( int axisId ) const; // Legend void insertLegend( QwtLegend *, LegendPosition = QwtPlot::RightLegend, double ratio = -1.0 ); QwtLegend *legend(); const QwtLegend *legend() const; // Misc virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; virtual void updateLayout(); virtual void drawCanvas( QPainter * ); void updateAxes(); virtual bool event( QEvent * ); virtual void drawItems( QPainter *, const QRectF &, const QwtScaleMap maps[axisCnt] ) const; Q_SIGNALS: /*! A signal which is emitted when the user has clicked on a legend item, which is in QwtLegend::ClickableItem mode. \param plotItem Corresponding plot item of the selected legend item \note clicks are disabled as default \sa QwtLegend::setItemMode(), QwtLegend::itemMode() */ void legendClicked( QwtPlotItem *plotItem ); /*! A signal which is emitted when the user has clicked on a legend item, which is in QwtLegend::CheckableItem mode \param plotItem Corresponding plot item of the selected legend item \param on True when the legen item is checked \note clicks are disabled as default \sa QwtLegend::setItemMode(), QwtLegend::itemMode() */ void legendChecked( QwtPlotItem *plotItem, bool on ); public Q_SLOTS: virtual void replot(); void autoRefresh(); protected Q_SLOTS: virtual void legendItemClicked(); virtual void legendItemChecked( bool ); protected: static bool axisValid( int axisId ); virtual void updateTabOrder(); virtual void resizeEvent( QResizeEvent *e ); private: void initAxesData(); void deleteAxesData(); void updateScaleDiv(); void initPlot( const QwtText &title ); class AxisData; AxisData *d_axisData[axisCnt]; class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_plot_canvas.h0000644000000000000000000001144012176111212015471 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_CANVAS_H #define QWT_PLOT_CANVAS_H #include "qwt_global.h" #include #include #include #include class QwtPlot; class QPixmap; /*! \brief Canvas of a QwtPlot. Canvas is the widget where all plot items are displayed \sa QwtPlot */ class QWT_EXPORT QwtPlotCanvas : public QFrame { Q_OBJECT public: /*! \brief Paint attributes The default setting enables BackingStore and Opaque. \sa setPaintAttribute(), testPaintAttribute() */ enum PaintAttribute { /*! \brief Paint double buffered reusing the content of the pixmap buffer when possible. Using a backing store might improve the performance significantly, when workin with widget overlays ( like rubberbands ). Disabling the cache might improve the performance for incremental paints (using QwtPlotDirectPainter ). \sa backingStore(), invalidateBackingStore() */ BackingStore = 1, /*! \brief Try to fill the complete contents rectangle of the plot canvas When using styled backgrounds Qt assumes, that the canvas doesn't fill its area completely ( f.e because of rounded borders ) and fills the area below the canvas. When this is done with gradients it might result in a serious performance bottleneck - depending on the size. When the Opaque attribute is enabled the canvas tries to identify the gaps with some heuristics and to fill those only. \warning Will not work for semitransparent backgrounds */ Opaque = 2, /*! \brief Try to improve painting of styled backgrounds QwtPlotCanvas supports the box model attributes for customizing the layout with style sheets. Unfortunately the design of Qt style sheets has no concept how to handle backgrounds with rounded corners - beside of padding. When HackStyledBackground is enabled the plot canvas tries to seperate the background from the background border by reverse engeneering to paint the background before and the border after the plot items. In this order the border gets prefectly antialiased and you can avoid some pixel artifacts in the corners. */ HackStyledBackground = 4, /*! When ImmediatePaint is set replot() calls repaint() instead of update(). \sa replot(), QWidget::repaint(), QWidget::update() */ ImmediatePaint = 8 }; //! Paint attributes typedef QFlags PaintAttributes; /*! \brief Focus indicator The default setting is NoFocusIndicator \sa setFocusIndicator(), focusIndicator(), paintFocus() */ enum FocusIndicator { //! Don't paint a focus indicator NoFocusIndicator, /*! The focus is related to the complete canvas. Paint the focus indicator using paintFocus() */ CanvasFocusIndicator, /*! The focus is related to an item (curve, point, ...) on the canvas. It is up to the application to display a focus indication using f.e. highlighting. */ ItemFocusIndicator }; explicit QwtPlotCanvas( QwtPlot * ); virtual ~QwtPlotCanvas(); QwtPlot *plot(); const QwtPlot *plot() const; void setFocusIndicator( FocusIndicator ); FocusIndicator focusIndicator() const; void setBorderRadius( double ); double borderRadius() const; QPainterPath borderPath( const QRect &rect ) const; QBitmap borderMask( const QSize & ) const; void setPaintAttribute( PaintAttribute, bool on = true ); bool testPaintAttribute( PaintAttribute ) const; const QPixmap *backingStore() const; void invalidateBackingStore(); void replot(); virtual bool event( QEvent * ); protected: virtual void paintEvent( QPaintEvent * ); virtual void resizeEvent( QResizeEvent * ); virtual void drawFocusIndicator( QPainter * ); virtual void drawBorder( QPainter * ); void updateStyleSheetInfo(); private: void drawCanvas( QPainter *, bool withBackground ); class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCanvas::PaintAttributes ) #endif pcp-gui-1.5.11/src/libqwt/qwt_plot_curve.h0000644000000000000000000002253012176111212015344 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_CURVE_H #define QWT_PLOT_CURVE_H #include "qwt_global.h" #include "qwt_plot_seriesitem.h" #include "qwt_series_data.h" #include "qwt_text.h" #include #include class QPainter; class QPolygonF; class QwtScaleMap; class QwtSymbol; class QwtCurveFitter; /*! \brief A plot item, that represents a series of points A curve is the representation of a series of points in the x-y plane. It supports different display styles, interpolation ( f.e. spline ) and symbols. \par Usage
a) Assign curve properties
When a curve is created, it is configured to draw black solid lines with in QwtPlotCurve::Lines style and no symbols. You can change this by calling setPen(), setStyle() and setSymbol().
b) Connect/Assign data.
QwtPlotCurve gets its points using a QwtSeriesData object offering a bridge to the real storage of the points ( like QAbstractItemModel ). There are several convenience classes derived from QwtSeriesData, that also store the points inside ( like QStandardItemModel ). QwtPlotCurve also offers a couple of variations of setSamples(), that build QwtSeriesData objects from arrays internally.
c) Attach the curve to a plot
See QwtPlotItem::attach()
\par Example: see examples/bode \sa QwtPointSeriesData, QwtSymbol, QwtScaleMap */ class QWT_EXPORT QwtPlotCurve: public QwtPlotSeriesItem { public: /*! Curve styles. \sa setStyle(), style() */ enum CurveStyle { /*! Don't draw a curve. Note: This doesn't affect the symbols. */ NoCurve = -1, /*! Connect the points with straight lines. The lines might be interpolated depending on the 'Fitted' attribute. Curve fitting can be configured using setCurveFitter(). */ Lines, /*! Draw vertical or horizontal sticks ( depending on the orientation() ) from a baseline which is defined by setBaseline(). */ Sticks, /*! Connect the points with a step function. The step function is drawn from the left to the right or vice versa, depending on the QwtPlotCurve::Inverted attribute. */ Steps, /*! Draw dots at the locations of the data points. Note: This is different from a dotted line (see setPen()), and faster as a curve in QwtPlotCurve::NoStyle style and a symbol painting a point. */ Dots, /*! Styles >= QwtPlotCurve::UserCurve are reserved for derived classes of QwtPlotCurve that overload drawCurve() with additional application specific curve types. */ UserCurve = 100 }; /*! Attribute for drawing the curve \sa setCurveAttribute(), testCurveAttribute(), curveFitter() */ enum CurveAttribute { /*! For QwtPlotCurve::Steps only. Draws a step function from the right to the left. */ Inverted = 0x01, /*! Only in combination with QwtPlotCurve::Lines A QwtCurveFitter tries to interpolate/smooth the curve, before it is painted. \note Curve fitting requires temorary memory for calculating coefficients and additional points. If painting in QwtPlotCurve::Fitted mode is slow it might be better to fit the points, before they are passed to QwtPlotCurve. */ Fitted = 0x02 }; //! Curve attributes typedef QFlags CurveAttributes; /*! Attributes how to represent the curve on the legend \sa setLegendAttribute(), testLegendAttribute(), drawLegendIdentifier() */ enum LegendAttribute { /*! QwtPlotCurve tries to find a color representing the curve and paints a rectangle with it. */ LegendNoAttribute = 0x00, /*! If the style() is not QwtPlotCurve::NoCurve a line is painted with the curve pen(). */ LegendShowLine = 0x01, /*! If the curve has a valid symbol it is painted. */ LegendShowSymbol = 0x02, /*! If the curve has a brush a rectangle filled with the curve brush() is painted. */ LegendShowBrush = 0x04 }; //! Legend attributes typedef QFlags LegendAttributes; /*! Attributes to modify the drawing algorithm. The default setting enables ClipPolygons \sa setPaintAttribute(), testPaintAttribute() */ enum PaintAttribute { /*! Clip polygons before painting them. In situations, where points are far outside the visible area (f.e when zooming deep) this might be a substantial improvement for the painting performance */ ClipPolygons = 0x01, /*! Paint the symbol to a QPixmap and paint the pixmap instead rendering the symbol for each point. The flag has no effect, when the curve is not painted to the canvas ( f.e when exporting the plot to a PDF document ). */ CacheSymbols = 0x02 }; //! Paint attributes typedef QFlags PaintAttributes; explicit QwtPlotCurve( const QString &title = QString::null ); explicit QwtPlotCurve( const QwtText &title ); virtual ~QwtPlotCurve(); virtual int rtti() const; void setPaintAttribute( PaintAttribute, bool on = true ); bool testPaintAttribute( PaintAttribute ) const; void setLegendAttribute( LegendAttribute, bool on = true ); bool testLegendAttribute( LegendAttribute ) const; #ifndef QWT_NO_COMPAT void setRawSamples( const double *xData, const double *yData, int size ); void setSamples( const double *xData, const double *yData, int size ); void setSamples( const QVector &xData, const QVector &yData ); #endif void setSamples( const QVector & ); int closestPoint( const QPoint &pos, double *dist = NULL ) const; double minXValue() const; double maxXValue() const; double minYValue() const; double maxYValue() const; void setCurveAttribute( CurveAttribute, bool on = true ); bool testCurveAttribute( CurveAttribute ) const; void setPen( const QPen & ); const QPen &pen() const; void setBrush( const QBrush & ); const QBrush &brush() const; void setBaseline( double ref ); double baseline() const; void setStyle( CurveStyle style ); CurveStyle style() const; void setSymbol( const QwtSymbol *s ); const QwtSymbol *symbol() const; void setCurveFitter( QwtCurveFitter * ); QwtCurveFitter *curveFitter() const; virtual void drawSeries( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void updateLegend( QwtLegend * ) const; virtual void drawLegendIdentifier( QPainter *, const QRectF & ) const; protected: void init(); virtual void drawCurve( QPainter *, int style, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void drawSymbols( QPainter *, const QwtSymbol &, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; void drawLines( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; void drawSticks( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; void drawDots( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; void drawSteps( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void fillCurve( QPainter *, const QwtScaleMap &, const QwtScaleMap &, const QRectF &canvasRect, QPolygonF & ) const; void closePolyline( QPainter *, const QwtScaleMap &, const QwtScaleMap &, QPolygonF & ) const; private: class PrivateData; PrivateData *d_data; }; //! boundingRect().left() inline double QwtPlotCurve::minXValue() const { return boundingRect().left(); } //! boundingRect().right() inline double QwtPlotCurve::maxXValue() const { return boundingRect().right(); } //! boundingRect().top() inline double QwtPlotCurve::minYValue() const { return boundingRect().top(); } //! boundingRect().bottom() inline double QwtPlotCurve::maxYValue() const { return boundingRect().bottom(); } Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::PaintAttributes ) Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::LegendAttributes ) Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::CurveAttributes ) #endif pcp-gui-1.5.11/src/libqwt/qwt_plot_dict.h0000644000000000000000000000315412176111212015144 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ /*! \file !*/ #ifndef QWT_PLOT_DICT #define QWT_PLOT_DICT #include "qwt_global.h" #include "qwt_plot_item.h" #include /// \var typedef QList< QwtPlotItem *> QwtPlotItemList /// \brief See QT 4.x assistant documentation for QList typedef QList QwtPlotItemList; typedef QList::ConstIterator QwtPlotItemIterator; /*! \brief A dictionary for plot items QwtPlotDict organizes plot items in increasing z-order. If autoDelete() is enabled, all attached items will be deleted in the destructor of the dictionary. QwtPlotDict can be used to get access to all QwtPlotItem items - or all items of a specific type - that are currently on the plot. \sa QwtPlotItem::attach(), QwtPlotItem::detach(), QwtPlotItem::z() */ class QWT_EXPORT QwtPlotDict { public: explicit QwtPlotDict(); virtual ~QwtPlotDict(); void setAutoDelete( bool ); bool autoDelete() const; const QwtPlotItemList& itemList() const; QwtPlotItemList itemList( int rtti ) const; void detachItems( int rtti = QwtPlotItem::Rtti_PlotItem, bool autoDelete = true ); private: friend class QwtPlotItem; void attachItem( QwtPlotItem *, bool ); class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_plot_directpainter.h0000644000000000000000000000614712176111212017063 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_DIRECT_PAINTER_H #define QWT_PLOT_DIRECT_PAINTER_H #include "qwt_global.h" #include class QRegion; class QwtPlotAbstractSeriesItem; /*! \brief Painter object trying to paint incrementally Often applications want to display samples while they are collected. When there are too many samples complete replots will be expensive to be processed in a collection cycle. QwtPlotDirectPainter offers an API to paint subsets ( f.e all additions points ) without erasing/repainting the plot canvas. On certain environments it might be important to calculate a proper clip region before painting. F.e. for Qt Embedded only the clipped part of the backing store will be copied to a ( maybe unaccelerated ) frame buffer. \warning Incremental painting will only help when no replot is triggered by another operation ( like changing scales ) and nothing needs to be erased. */ class QWT_EXPORT QwtPlotDirectPainter: public QObject { public: /*! \brief Paint attributes \sa setAttribute(), testAttribute(), drawSeries() */ enum Attribute { /*! Initializing a QPainter is an expensive operation. When AtomicPainter is set each call of drawSeries() opens/closes a temporary QPainter. Otherwise QwtPlotDirectPainter tries to use the same QPainter as long as possible. */ AtomicPainter = 0x01, /*! When FullRepaint is set the plot canvas is explicitely repainted after the samples have been rendered. */ FullRepaint = 0x02, /*! When QwtPlotCanvas::BackingStore is enabled the painter has to paint to the backing store and the widget. In certain situations/environments it might be faster to paint to the backing store only and then copy the backingstore to the canvas. This flag can also be useful for settings, where Qt fills the the clip region with the widget background. */ CopyBackingStore = 0x04 }; //! Paint attributes typedef QFlags Attributes; QwtPlotDirectPainter( QObject *parent = NULL ); virtual ~QwtPlotDirectPainter(); void setAttribute( Attribute, bool on ); bool testAttribute( Attribute ) const; void setClipping( bool ); bool hasClipping() const; void setClipRegion( const QRegion & ); QRegion clipRegion() const; void drawSeries( QwtPlotAbstractSeriesItem *, int from, int to ); void reset(); virtual bool eventFilter( QObject *, QEvent * ); private: class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotDirectPainter::Attributes ) #endif pcp-gui-1.5.11/src/libqwt/qwt_plot_grid.h0000644000000000000000000000416512176111212015151 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_GRID_H #define QWT_PLOT_GRID_H #include "qwt_global.h" #include "qwt_plot_item.h" #include "qwt_scale_div.h" class QPainter; class QPen; class QwtScaleMap; class QwtScaleDiv; /*! \brief A class which draws a coordinate grid The QwtPlotGrid class can be used to draw a coordinate grid. A coordinate grid consists of major and minor vertical and horizontal gridlines. The locations of the gridlines are determined by the X and Y scale divisions which can be assigned with setXDiv() and setYDiv(). The draw() member draws the grid within a bounding rectangle. */ class QWT_EXPORT QwtPlotGrid: public QwtPlotItem { public: explicit QwtPlotGrid(); virtual ~QwtPlotGrid(); virtual int rtti() const; void enableX( bool tf ); bool xEnabled() const; void enableY( bool tf ); bool yEnabled() const; void enableXMin( bool tf ); bool xMinEnabled() const; void enableYMin( bool tf ); bool yMinEnabled() const; void setXDiv( const QwtScaleDiv &sx ); const QwtScaleDiv &xScaleDiv() const; void setYDiv( const QwtScaleDiv &sy ); const QwtScaleDiv &yScaleDiv() const; void setPen( const QPen &p ); void setMajPen( const QPen &p ); const QPen& majPen() const; void setMinPen( const QPen &p ); const QPen& minPen() const; virtual void draw( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect ) const; virtual void updateScaleDiv( const QwtScaleDiv &xMap, const QwtScaleDiv &yMap ); private: void drawLines( QPainter *painter, const QRectF &, Qt::Orientation orientation, const QwtScaleMap &, const QList & ) const; class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_plot_histogram.h0000644000000000000000000000776412176111212016231 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_HISTOGRAM_H #define QWT_PLOT_HISTOGRAM_H #include "qwt_global.h" #include "qwt_plot_seriesitem.h" #include "qwt_column_symbol.h" #include #include class QwtIntervalData; class QString; class QPolygonF; /*! \brief QwtPlotHistogram represents a series of samples, where an interval is associated with a value ( \f$y = f([x1,x2])\f$ ). The representation depends on the style() and an optional symbol() that is displayed for each interval. \note The term "histogram" is used in a different way in the areas of digital image processing and statistics. Wikipedia introduces the terms "image histogram" and "color histogram" to avoid confusions. While "image histograms" can be displayed by a QwtPlotCurve there is no applicable plot item for a "color histogram" yet. */ class QWT_EXPORT QwtPlotHistogram: public QwtPlotSeriesItem { public: /*! Histogram styles. The default style is QwtPlotHistogram::Columns. \sa setStyle(), style(), setSymbol(), symbol(), setBaseline() */ enum HistogramStyle { /*! Draw an outline around the area, that is build by all intervals using the pen() and fill it with the brush(). The outline style requires, that the intervals are in increasing order and not overlapping. */ Outline, /*! Draw a column for each interval. When a symbol() has been set the symbol is used otherwise the column is displayed as plain rectangle using pen() and brush(). */ Columns, /*! Draw a simple line using the pen() for each interval. */ Lines, /*! Styles >= UserStyle are reserved for derived classes that overload drawSeries() with additional application specific ways to display a histogram. */ UserStyle = 100 }; explicit QwtPlotHistogram( const QString &title = QString::null ); explicit QwtPlotHistogram( const QwtText &title ); virtual ~QwtPlotHistogram(); virtual int rtti() const; void setPen( const QPen & ); const QPen &pen() const; void setBrush( const QBrush & ); const QBrush &brush() const; void setSamples( const QVector & ); void setBaseline( double reference ); double baseline() const; void setStyle( HistogramStyle style ); HistogramStyle style() const; void setSymbol( const QwtColumnSymbol * ); const QwtColumnSymbol *symbol() const; virtual void drawSeries( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual QRectF boundingRect() const; virtual void drawLegendIdentifier( QPainter *, const QRectF & ) const; protected: virtual QwtColumnRect columnRect( const QwtIntervalSample &, const QwtScaleMap &, const QwtScaleMap & ) const; virtual void drawColumn( QPainter *, const QwtColumnRect &, const QwtIntervalSample & ) const; void drawColumns( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const; void drawOutline( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const; void drawLines( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const; private: void init(); void flushPolygon( QPainter *, double baseLine, QPolygonF & ) const; class PrivateData; PrivateData *d_data; }; #endif pcp-gui-1.5.11/src/libqwt/qwt_plot_intervalcurve.h0000644000000000000000000000737212176111212017120 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_INTERVAL_CURVE_H #define QWT_PLOT_INTERVAL_CURVE_H #include "qwt_global.h" #include "qwt_plot_seriesitem.h" #include "qwt_series_data.h" class QwtIntervalSymbol; /*! \brief QwtPlotIntervalCurve represents a series of samples, where each value is associated with an interval ( \f$[y1,y2] = f(x)\f$ ). The representation depends on the style() and an optional symbol() that is displayed for each interval. QwtPlotIntervalCurve might be used to disply error bars or the area between 2 curves. */ class QWT_EXPORT QwtPlotIntervalCurve: public QwtPlotSeriesItem { public: /*! \brief Curve styles. The default setting is QwtPlotIntervalCurve::Tube. \sa setStyle(), style() */ enum CurveStyle { /*! Don't draw a curve. Note: This doesn't affect the symbols. */ NoCurve, /*! Build 2 curves from the upper and lower limits of the intervals and draw them with the pen(). The area between the curves is filled with the brush(). */ Tube, /*! Styles >= QwtPlotIntervalCurve::UserCurve are reserved for derived classes that overload drawSeries() with additional application specific curve types. */ UserCurve = 100 }; /*! Attributes to modify the drawing algorithm. \sa setPaintAttribute(), testPaintAttribute() */ enum PaintAttribute { /*! Clip polygons before painting them. In situations, where points are far outside the visible area (f.e when zooming deep) this might be a substantial improvement for the painting performance. */ ClipPolygons = 0x01, //! Check if a symbol is on the plot canvas before painting it. ClipSymbol = 0x02 }; //! Paint attributes typedef QFlags PaintAttributes; explicit QwtPlotIntervalCurve( const QString &title = QString::null ); explicit QwtPlotIntervalCurve( const QwtText &title ); virtual ~QwtPlotIntervalCurve(); virtual int rtti() const; void setPaintAttribute( PaintAttribute, bool on = true ); bool testPaintAttribute( PaintAttribute ) const; void setSamples( const QVector & ); void setPen( const QPen & ); const QPen &pen() const; void setBrush( const QBrush & ); const QBrush &brush() const; void setStyle( CurveStyle style ); CurveStyle style() const; void setSymbol( const QwtIntervalSymbol * ); const QwtIntervalSymbol *symbol() const; virtual void drawSeries( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual QRectF boundingRect() const; virtual void drawLegendIdentifier( QPainter *, const QRectF & ) const; protected: void init(); virtual void drawTube( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void drawSymbols( QPainter *, const QwtIntervalSymbol &, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; private: class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotIntervalCurve::PaintAttributes ) #endif pcp-gui-1.5.11/src/libqwt/qwt_plot_item.h0000644000000000000000000001276412176111212015166 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_ITEM_H #define QWT_PLOT_ITEM_H #include "qwt_global.h" #include "qwt_legend_itemmanager.h" #include "qwt_text.h" #include class QString; class QPainter; class QWidget; class QwtPlot; class QwtLegend; class QwtScaleMap; class QwtScaleDiv; /*! \brief Base class for items on the plot canvas A plot item is "something", that can be painted on the plot canvas, or only affects the scales of the plot widget. They can be categorized as: - Representator\n A "Representator" is an item that represents some sort of data on the plot canvas. The different representator classes are organized according to the characteristics of the data: - QwtPlotMarker Represents a point or a horizontal/vertical coordinate - QwtPlotCurve Represents a series of points - QwtPlotSpectrogram ( QwtPlotRasterItem ) Represents raster data - ... - Decorators\n A "Decorator" is an item, that displays additional information, that is not related to any data: - QwtPlotGrid - QwtPlotScaleItem - QwtPlotSvgItem - ... Depending on the QwtPlotItem::ItemAttribute flags, an item is included into autoscaling or has an entry on the legnd. Before misusing the existing item classes it might be better to implement a new type of plot item ( don't implement a watermark as spectrogram ). Deriving a new type of QwtPlotItem primarily means to implement the YourPlotItem::draw() method. \sa The cpuplot example shows the implementation of additional plot items. */ class QWT_EXPORT QwtPlotItem: public QwtLegendItemManager { public: /*! \brief Runtime type information RttiValues is used to cast plot items, without having to enable runtime type information of the compiler. */ enum RttiValues { //! Unspecific value, that can be used, when it doesn't matter Rtti_PlotItem = 0, //! For QwtPlotGrid Rtti_PlotGrid, //! For QwtPlotScaleItem Rtti_PlotScale, //! For QwtPlotMarker Rtti_PlotMarker, //! For QwtPlotCurve Rtti_PlotCurve, //! For QwtPlotSpectroCurve Rtti_PlotSpectroCurve, //! For QwtPlotIntervalCurve Rtti_PlotIntervalCurve, //! For QwtPlotHistogram Rtti_PlotHistogram, //! For QwtPlotSpectrogram Rtti_PlotSpectrogram, //! For QwtPlotSvgItem Rtti_PlotSVG, /*! Values >= Rtti_PlotUserItem are reserved for plot items not implemented in the Qwt library. */ Rtti_PlotUserItem = 1000 }; /*! Plot Item Attributes \sa setItemAttribute(), testItemAttribute() */ enum ItemAttribute { //! The item is represented on the legend. Legend = 0x01, /*! The boundingRect() of the item is included in the autoscaling calculation. */ AutoScale = 0x02 }; //! Plot Item Attributes typedef QFlags ItemAttributes; //! Render hints enum RenderHint { //! Enable antialiasing RenderAntialiased = 1 }; //! Render hints typedef QFlags RenderHints; explicit QwtPlotItem( const QwtText &title = QwtText() ); virtual ~QwtPlotItem(); void attach( QwtPlot *plot ); void detach(); QwtPlot *plot() const; void setTitle( const QString &title ); void setTitle( const QwtText &title ); const QwtText &title() const; virtual int rtti() const; void setItemAttribute( ItemAttribute, bool on = true ); bool testItemAttribute( ItemAttribute ) const; void setRenderHint( RenderHint, bool on = true ); bool testRenderHint( RenderHint ) const; double z() const; void setZ( double z ); void show(); void hide(); virtual void setVisible( bool ); bool isVisible () const; void setAxes( int xAxis, int yAxis ); void setXAxis( int axis ); int xAxis() const; void setYAxis( int axis ); int yAxis() const; virtual void itemChanged(); /*! \brief Draw the item \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas in painter coordinates */ virtual void draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const = 0; virtual QRectF boundingRect() const; virtual void updateLegend( QwtLegend * ) const; virtual void updateScaleDiv( const QwtScaleDiv&, const QwtScaleDiv& ); virtual QWidget *legendItem() const; QRectF scaleRect( const QwtScaleMap &, const QwtScaleMap & ) const; QRectF paintRect( const QwtScaleMap &, const QwtScaleMap & ) const; private: // Disabled copy constructor and operator= QwtPlotItem( const QwtPlotItem & ); QwtPlotItem &operator=( const QwtPlotItem & ); class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotItem::ItemAttributes ) Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotItem::RenderHints ) #endif pcp-gui-1.5.11/src/libqwt/qwt_plot_layout.h0000644000000000000000000000545012176111212015537 0ustar /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_LAYOUT_H #define QWT_PLOT_LAYOUT_H #include "qwt_global.h" #include "qwt_plot.h" /*! \brief Layout engine for QwtPlot. It is used by the QwtPlot widget to organize its internal widgets or by QwtPlot::print() to render its content to a QPaintDevice like a QPrinter, QPixmap/QImage or QSvgRenderer. */ class QWT_EXPORT QwtPlotLayout { public: /*! Options to configure the plot layout engine \sa activate(), QwtPlotRenderer */ enum Option { //! Unused AlignScales = 0x01, /*! Ignore the dimension of the scrollbars. There are no scrollbars, when the plot is not rendered to widgets. */ IgnoreScrollbars = 0x02, //! Ignore all frames. IgnoreFrames = 0x04, //! Ignore the legend. IgnoreLegend = 0x08 }; //! Layout options typedef QFlags