diff options
Diffstat (limited to 'kview/kviewcanvas')
-rw-r--r-- | kview/kviewcanvas/ChangeLog | 18 | ||||
-rw-r--r-- | kview/kviewcanvas/Makefile.am | 18 | ||||
-rw-r--r-- | kview/kviewcanvas/config/Makefile.am | 16 | ||||
-rw-r--r-- | kview/kviewcanvas/config/confmodules.cpp | 145 | ||||
-rw-r--r-- | kview/kviewcanvas/config/confmodules.h | 51 | ||||
-rw-r--r-- | kview/kviewcanvas/config/defaults.h | 46 | ||||
-rw-r--r-- | kview/kviewcanvas/config/generalconfigwidget.ui | 300 | ||||
-rw-r--r-- | kview/kviewcanvas/config/kviewcanvasconfig.desktop | 118 | ||||
-rw-r--r-- | kview/kviewcanvas/kimagecanvas.cpp | 953 | ||||
-rw-r--r-- | kview/kviewcanvas/kimagecanvas.h | 366 | ||||
-rw-r--r-- | kview/kviewcanvas/kimageholder.cpp | 371 | ||||
-rw-r--r-- | kview/kviewcanvas/kimageholder.h | 105 | ||||
-rw-r--r-- | kview/kviewcanvas/kviewcanvas.desktop | 63 | ||||
-rw-r--r-- | kview/kviewcanvas/test/Makefile.am | 9 | ||||
-rw-r--r-- | kview/kviewcanvas/test/main.cpp | 51 | ||||
-rw-r--r-- | kview/kviewcanvas/test/test.cpp | 46 | ||||
-rw-r--r-- | kview/kviewcanvas/test/test.h | 25 |
17 files changed, 2701 insertions, 0 deletions
diff --git a/kview/kviewcanvas/ChangeLog b/kview/kviewcanvas/ChangeLog new file mode 100644 index 00000000..1edb3529 --- /dev/null +++ b/kview/kviewcanvas/ChangeLog @@ -0,0 +1,18 @@ +2003-09-27 Matthias Kretz <kretz@kde.org> + + * config/confmodules.cpp: + Call m_config->sync() in save() and use a real KConfig object instead of + a KSimpleConfig. + * kimagecanvas.cpp: + Renamed readSettings to loadSettings and call it in the ctor. + +2003-08-19 Matthias Kretz <kretz@kde.org> + + * kimagecanvas.cpp: + Fix checkBounds() to always keep the aspect ratio. + Create the factory with it's own KInstance. + * kimagecanvas.{h,cpp}: + New method boundImageTo( QSize ). Fits the image into the + requested width and height. + +# vim: sw=4 ts=4 tw=80 noet diff --git a/kview/kviewcanvas/Makefile.am b/kview/kviewcanvas/Makefile.am new file mode 100644 index 00000000..27e45d9f --- /dev/null +++ b/kview/kviewcanvas/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = config test + +kde_module_LTLIBRARIES = libkviewcanvas.la +INCLUDES = -I$(top_srcdir)/kview $(all_includes) + +noinst_HEADERS = kimageholder.h kimagecanvas.h + +libkviewcanvas_la_SOURCES = kimageholder.cpp kimagecanvas.cpp +libkviewcanvas_la_LDFLAGS = $(all_libraries) -module -no-undefined -avoid-version +libkviewcanvas_la_LIBADD = $(LIB_KPARTS) $(LIB_KDEPRINT) $(LIB_KUTILS) \ + $(top_builddir)/kview/kimageviewer/libkimageviewer.la + +METASOURCES = AUTO + +kde_services_DATA = kviewcanvas.desktop + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/kviewcanvas.pot diff --git a/kview/kviewcanvas/config/Makefile.am b/kview/kviewcanvas/config/Makefile.am new file mode 100644 index 00000000..b22a1ad5 --- /dev/null +++ b/kview/kviewcanvas/config/Makefile.am @@ -0,0 +1,16 @@ +kde_module_LTLIBRARIES = kcm_kviewcanvasconfig.la +INCLUDES = $(all_includes) + +noinst_HEADERS = confmodules.h + +kcm_kviewcanvasconfig_la_SOURCES = generalconfigwidget.ui confmodules.cpp +kcm_kviewcanvasconfig_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) -module -avoid-version +kcm_kviewcanvasconfig_la_LIBADD = $(LIB_KDEUI) + +kcm_kviewcanvasconfig_DATA = kviewcanvasconfig.desktop +kcm_kviewcanvasconfigdir = $(kde_servicesdir)/kconfiguredialog + +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/kcm_kviewcanvasconfig.pot diff --git a/kview/kviewcanvas/config/confmodules.cpp b/kview/kviewcanvas/config/confmodules.cpp new file mode 100644 index 00000000..c5e47dac --- /dev/null +++ b/kview/kviewcanvas/config/confmodules.cpp @@ -0,0 +1,145 @@ +/* This file is part of the KDE project + Copyright (C) 2002-2003 Matthias Kretz <kretz@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + 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-1301, USA. + +*/ + +#include "confmodules.h" +#include "generalconfigwidget.h" +#include "defaults.h" + +#include <qlayout.h> +#include <qcheckbox.h> +#include <qframe.h> + +#include <klocale.h> +#include <ksimpleconfig.h> +#include <kcolorbutton.h> +#include <klistview.h> +#include <knuminput.h> +#include <kgenericfactory.h> + +typedef KGenericFactory<KViewCanvasConfig, QWidget> KViewCanvasConfigFactory; +K_EXPORT_COMPONENT_FACTORY( kcm_kviewcanvasconfig, KViewCanvasConfigFactory( "kcm_kviewcanvasconfig" ) ) + +KViewCanvasConfig::KViewCanvasConfig( QWidget * parent, const char *, const QStringList & args ) + : KCModule( KViewCanvasConfigFactory::instance(), parent, args ) + , m_config( new KConfig( "kviewcanvasrc" ) ) +{ + QBoxLayout * layout = new QVBoxLayout( this ); + layout->setAutoAdd( true ); + + m_pWidget = new GeneralConfigWidget( this ); + m_pWidget->m_pMinWidth ->setRange( 1, 200 ); + m_pWidget->m_pMinHeight->setRange( 1, 200 ); + m_pWidget->m_pMaxWidth ->setRange( 1, 10000 ); + m_pWidget->m_pMaxHeight->setRange( 1, 10000 ); + + // clear m_items + m_items.clear(); + + for( unsigned int i = 1; i <= Defaults::numOfBlendEffects; ++i ) + { + QCheckListItem * item = new QCheckListItem( m_pWidget->m_pListView, i18n( Defaults::blendEffectDescription[ i ] ), QCheckListItem::CheckBox ); + m_items.append( item ); + } + + connect( m_pWidget->m_pListView, SIGNAL( clicked( QListViewItem * ) ), this, SLOT( configChanged() ) ); + connect( m_pWidget->m_pListView, SIGNAL( spacePressed( QListViewItem * ) ), this, SLOT( configChanged() ) ); + + connect( m_pWidget->m_pSmoothScaling, SIGNAL( toggled( bool ) ), this, SLOT( configChanged() ) ); + connect( m_pWidget->m_pKeepRatio, SIGNAL( toggled( bool ) ), this, SLOT( configChanged() ) ); + connect( m_pWidget->m_pCenterImage, SIGNAL( toggled( bool ) ), this, SLOT( configChanged() ) ); + connect( m_pWidget->m_bgColor, SIGNAL( changed( const QColor & ) ), this, SLOT( configChanged() ) ); + connect( m_pWidget->m_pMinWidth, SIGNAL( valueChanged( int ) ), this, SLOT( configChanged() ) ); + connect( m_pWidget->m_pMaxWidth, SIGNAL( valueChanged( int ) ), this, SLOT( configChanged() ) ); + connect( m_pWidget->m_pMinHeight, SIGNAL( valueChanged( int ) ), this, SLOT( configChanged() ) ); + connect( m_pWidget->m_pMaxHeight, SIGNAL( valueChanged( int ) ), this, SLOT( configChanged() ) ); + + load(); +} + +KViewCanvasConfig::~KViewCanvasConfig() +{ +} + +void KViewCanvasConfig::save() +{ + KConfigGroup cfgGroup( m_config, "Settings" ); + cfgGroup.writeEntry( "Smooth Scaling", m_pWidget->m_pSmoothScaling->isChecked() ); + cfgGroup.writeEntry( "Keep Aspect Ratio", m_pWidget->m_pKeepRatio->isChecked() ); + cfgGroup.writeEntry( "Center Image", m_pWidget->m_pCenterImage->isChecked() ); + + cfgGroup.writeEntry( "Background Color", m_pWidget->m_bgColor->color() ); + + cfgGroup.writeEntry( "Minimum Width" , m_pWidget->m_pMinWidth->value() ); + cfgGroup.writeEntry( "Minimum Height", m_pWidget->m_pMinHeight->value() ); + cfgGroup.writeEntry( "Maximum Width" , m_pWidget->m_pMaxWidth->value() ); + cfgGroup.writeEntry( "Maximum Height", m_pWidget->m_pMaxHeight->value() ); + + KConfigGroup cfgGroup2( m_config, "Blend Effects" ); + QCheckListItem *item = m_items.first(); + for( int i = 1; item; item = m_items.next(), ++i ) + cfgGroup2.writeEntry( QString::number( i ), item->isOn() ); + m_config->sync(); +} + +void KViewCanvasConfig::load() +{ + KConfigGroup cfgGroup( m_config, "Settings" ); + m_pWidget->m_pSmoothScaling->setChecked( cfgGroup.readBoolEntry( "Smooth Scaling", Defaults::smoothScaling ) ); + m_pWidget->m_pKeepRatio->setChecked( cfgGroup.readBoolEntry( "Keep Aspect Ratio", Defaults::keepAspectRatio ) ); + m_pWidget->m_pCenterImage->setChecked( cfgGroup.readBoolEntry( "Center Image", Defaults::centerImage ) ); + + m_pWidget->m_bgColor->setColor( cfgGroup.readColorEntry( "Background Color", &Defaults::bgColor ) ); + + m_pWidget->m_pMinWidth ->setValue( cfgGroup.readNumEntry( "Minimum Width" , Defaults::minSize.width() ) ); + m_pWidget->m_pMinHeight->setValue( cfgGroup.readNumEntry( "Minimum Height", Defaults::minSize.height() ) ); + m_pWidget->m_pMaxWidth ->setValue( cfgGroup.readNumEntry( "Maximum Width" , Defaults::maxSize.width() ) ); + m_pWidget->m_pMaxHeight->setValue( cfgGroup.readNumEntry( "Maximum Height", Defaults::maxSize.height() ) ); + + KConfigGroup cfgGroup2( m_config, "Blend Effects" ); + QCheckListItem * item = m_items.first(); + for( int i = 1; item; item = m_items.next(), ++i ) + item->setOn( cfgGroup2.readBoolEntry( QString::number( i ), false ) ); +} + +void KViewCanvasConfig::defaults() +{ + m_pWidget->m_pSmoothScaling->setChecked( Defaults::smoothScaling ); + m_pWidget->m_pKeepRatio->setChecked( Defaults::keepAspectRatio ); + m_pWidget->m_pCenterImage->setChecked( Defaults::centerImage ); + + m_pWidget->m_bgColor->setColor( Defaults::bgColor ); + + m_pWidget->m_pMinWidth ->setValue( Defaults::minSize.width() ); + m_pWidget->m_pMinHeight->setValue( Defaults::minSize.height() ); + m_pWidget->m_pMaxWidth ->setValue( Defaults::maxSize.width() ); + m_pWidget->m_pMaxHeight->setValue( Defaults::maxSize.height() ); + + QCheckListItem * item = m_items.first(); + for( int i = 1; item; item = m_items.next(), ++i ) + item->setOn( false ); + emit changed( true ); +} + +void KViewCanvasConfig::configChanged() +{ + emit changed( true ); +} + +// vim:sw=4:ts=4 + +#include "confmodules.moc" diff --git a/kview/kviewcanvas/config/confmodules.h b/kview/kviewcanvas/config/confmodules.h new file mode 100644 index 00000000..f7dfe262 --- /dev/null +++ b/kview/kviewcanvas/config/confmodules.h @@ -0,0 +1,51 @@ +/* This file is part of the KDE project + Copyright (C) 2002-2003 Matthias Kretz <kretz@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + 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-1301, USA. + +*/ + +#ifndef CONFMODULES_H +#define CONFMODULES_H + +#include <kcmodule.h> +#include <qptrlist.h> + +class GeneralConfigWidget; +class QCheckListItem; +class KConfig; + +class KViewCanvasConfig : public KCModule +{ + Q_OBJECT + public: + KViewCanvasConfig( QWidget * parent, const char * name = 0, const QStringList & args = QStringList() ); + ~KViewCanvasConfig(); + + void load(); + void save(); + void defaults(); + + private slots: + void configChanged(); + + private: + KConfig * m_config; + GeneralConfigWidget * m_pWidget; + QPtrList<QCheckListItem> m_items; +}; + +// vim:sw=4:ts=4 + +#endif // CONFMODULES_H diff --git a/kview/kviewcanvas/config/defaults.h b/kview/kviewcanvas/config/defaults.h new file mode 100644 index 00000000..0a92d651 --- /dev/null +++ b/kview/kviewcanvas/config/defaults.h @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Matthias Kretz <kretz@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + 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-1301, USA. + +*/ + +#ifndef DEFAULTS_H +#define DEFAULTS_H + +#include <klocale.h> +#include <qsize.h> +#include <qcolor.h> + +namespace Defaults { + static const bool smoothScaling = false; + static const bool keepAspectRatio = true; + static const bool centerImage = true; + static const QColor bgColor( Qt::black ); + static const QSize minSize( 1, 1 ); + static const QSize maxSize( 10000, 10000 ); + static const unsigned int numOfBlendEffects = 4; + static const char * blendEffectDescription[ 6 ] = { + I18N_NOOP( "No Blending" ), + I18N_NOOP( "Wipe From Left" ), + I18N_NOOP( "Wipe From Right" ), + I18N_NOOP( "Wipe From Top" ), + I18N_NOOP( "Wipe From Bottom" ), + I18N_NOOP( "Alpha Blend" ) + }; +} + +#endif // DEFAULTS_H + +// vim: sw=4 ts=4 diff --git a/kview/kviewcanvas/config/generalconfigwidget.ui b/kview/kviewcanvas/config/generalconfigwidget.ui new file mode 100644 index 00000000..b4646381 --- /dev/null +++ b/kview/kviewcanvas/config/generalconfigwidget.ui @@ -0,0 +1,300 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>GeneralConfigWidget</class> +<author>Matthias Kretz <kretz@kde.org></author> +<widget class="QWidget"> + <property name="name"> + <cstring>GeneralConfigWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>398</width> + <height>327</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLayoutWidget" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>Layout4</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KIntNumInput" row="0" column="1"> + <property name="name"> + <cstring>m_pMinHeight</cstring> + </property> + <property name="label"> + <string>Minimum height:</string> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="maxValue"> + <number>200</number> + </property> + <property name="whatsThis" stdset="0"> + <string>The height of the image shown will not get smaller than the size you enter here. +A value of 10 would cause a 1x1 image to be stretched vertically by a factor of 10.</string> + </property> + </widget> + <widget class="KIntNumInput" row="1" column="1"> + <property name="name"> + <cstring>m_pMaxHeight</cstring> + </property> + <property name="label"> + <string>Maximum height:</string> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="maxValue"> + <number>100000</number> + </property> + <property name="whatsThis" stdset="0"> + <string>The height of the image shown will not get bigger than the size you enter here. +A value of 100 would cause a 1000x1000 image to be compressed vertically by a factor of 0.1.</string> + </property> + </widget> + <widget class="KIntNumInput" row="0" column="0"> + <property name="name"> + <cstring>m_pMinWidth</cstring> + </property> + <property name="label"> + <string>Minimum width:</string> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="maxValue"> + <number>200</number> + </property> + <property name="whatsThis" stdset="0"> + <string>The width of the image shown will not get smaller than the size you enter here. +A value of 10 would cause a 1x1 image to be stretched horizontally by a factor of 10.</string> + </property> + </widget> + <widget class="KIntNumInput" row="1" column="0"> + <property name="name"> + <cstring>m_pMaxWidth</cstring> + </property> + <property name="label"> + <string>Maximum width:</string> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="maxValue"> + <number>100000</number> + </property> + <property name="whatsThis" stdset="0"> + <string>The width of the image shown will not get bigger than the size you enter here. +A value of 100 would cause a 1000x1000 image to be compressed horizontally by a factor of 0.1.</string> + </property> + </widget> + <spacer row="1" column="2"> + <property name="name"> + <cstring>Spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>MinimumExpanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + <spacer row="0" column="2"> + <property name="name"> + <cstring>Spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>MinimumExpanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel3</cstring> + </property> + <property name="text"> + <string>Choose which blend effects should be used:</string> + </property> + </widget> + <widget class="KListView"> + <column> + <property name="text"> + <string>Effect</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>m_pListView</cstring> + </property> + <property name="selectionMode" stdset="0"> + <enum>NoSelection</enum> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + <property name="whatsThis" stdset="0"> + <string>Every effect selected may be used to create a transition effect between the images. If you select multiple effects they will be chosen randomly.</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pSmoothScaling</cstring> + </property> + <property name="text"> + <string>Use smooth scaling (high quality but slower)</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pKeepRatio</cstring> + </property> + <property name="text"> + <string>Keep aspect ratio</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If this is checked KView will always try to keep the aspect ratio. That means if the width is scaled with a factor x, the height is scaled with the same factor.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pCenterImage</cstring> + </property> + <property name="text"> + <string>Center image</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox" row="0" column="1"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string>&Background Color</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_bgColor</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>151</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </grid> +</widget> +<tabstops> + <tabstop>m_pSmoothScaling</tabstop> + <tabstop>m_pKeepRatio</tabstop> + <tabstop>m_pCenterImage</tabstop> + <tabstop>m_pMinWidth</tabstop> + <tabstop>m_pMinHeight</tabstop> + <tabstop>m_pMaxWidth</tabstop> + <tabstop>m_pMaxHeight</tabstop> + <tabstop>m_pListView</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>klistview.h</includehint> + <includehint>kcolorbutton.h</includehint> +</includehints> +</UI> diff --git a/kview/kviewcanvas/config/kviewcanvasconfig.desktop b/kview/kviewcanvas/config/kviewcanvasconfig.desktop new file mode 100644 index 00000000..7ce31c64 --- /dev/null +++ b/kview/kviewcanvas/config/kviewcanvasconfig.desktop @@ -0,0 +1,118 @@ +[Desktop Entry] +Icon=kview +Type=Service +ServiceTypes=KCModule + +X-KDE-ModuleType=Library +X-KDE-Library=kviewcanvasconfig +X-KDE-FactoryName=KViewCanvasConfigFactory +X-KDE-ParentApp=kview +X-KDE-ParentComponents=kviewcanvas +X-KDE-Weight=1 +X-KDE-CfgDlgHierarchy=Viewer + +Name=Viewer +Name[ar]=العارض +Name[bg]=Визуализатор +Name[br]=Gweler +Name[bs]=Preglednik +Name[ca]=Visualitzador +Name[cs]=Prohlížeč +Name[cy]=Gwelydd +Name[da]=Fremviser +Name[de]=Betrachter +Name[el]=Προβολέας +Name[eo]=Rigardilo +Name[es]=Visor +Name[et]=Näitaja +Name[eu]=Ikustailua +Name[fa]=مشاهدهگر +Name[fi]=Näytin +Name[fr]=Afficheur +Name[gl]=Visor +Name[he]=מציג +Name[hi]=प्रदर्शक +Name[hu]=Nézegető +Name[is]=Birtir +Name[it]=Visore +Name[ja]=ビューア +Name[kk]=Кескінді қарау +Name[km]=កម្មវិធីមើល +Name[lt]=Žiūriklis +Name[ms]=Pemapar +Name[nb]=Fremviser +Name[nds]=Kieker +Name[ne]=दर्शक +Name[nl]=Weergaveprogramma +Name[nn]=Framvisar +Name[pa]=ਦਰਸ਼ਕ +Name[pl]=Przeglądarka obrazków +Name[pt]=Visualizador +Name[pt_BR]=Visualizador +Name[ro]=Vizualizor +Name[ru]=Просмотрщик +Name[se]=Čájeheaddji +Name[sk]=Prehliadač +Name[sl]=Pregledovalnik +Name[sr]=Приказивач +Name[sr@Latn]=Prikazivač +Name[sv]=Visning +Name[ta]=காட்சி +Name[tg]=Намоишгар +Name[tr]=Görüntüleyici +Name[uk]=Переглядач +Name[uz]=Koʻruvchi +Name[uz@cyrillic]=Кўрувчи +Name[wa]=Håyneu +Name[zh_CN]=查看器 +Name[zh_HK]=檢視器 +Comment=General KViewCanvas Configuration +Comment[ar]=اعدادات KViewCanvas العامة +Comment[bg]=Общи настройки на визуализатора (KViewCanvas) +Comment[bs]=Opšte KViewCanvas postavke +Comment[ca]=Configuració general de KViewCanvas +Comment[cs]=Obecné nastavení KView +Comment[cy]=Ffurfweddiad Cyffredinol KGweldCynfas +Comment[da]=Generel indstilling af KViewCanvas +Comment[de]=Allgemeine Einstellungen für KViewCanvas +Comment[el]=Γενική ρύθμιση του KViewCanvas +Comment[eo]=Ĝenerala Agordo de KViewCanvas +Comment[es]=Configuración general de KViewCanvas +Comment[et]=KView lõuendite üldine seadistus +Comment[eu]=KViewCanvas konfigurazio orokorra +Comment[fa]=پیکربندی عمومی KViewCanvas +Comment[fi]=Yleiset KViewCanvas -asetukset +Comment[fr]=Configuration générale de KViewCanvas +Comment[gl]=Configuración xeral de KViewCanvas +Comment[he]=הגדרות KViewCanvas כלליות +Comment[hi]=सामान्य के-व्यू-केनवास कॉन्फ़िगरेशन +Comment[hu]=A KViewCanvas általános beállításai +Comment[is]=Almennar stillingar KViewCanvas +Comment[it]=Configurazione generale per KViewCanvas +Comment[ja]=KViewCanvas の一般的な設定 +Comment[kk]=KViewCanvas өрісінің жалпы баптаулары +Comment[km]=ការកំណត់រចនាសម្ព័ន្ធទូទៅសម្រាប់ KViewCanvas +Comment[lt]=Bendrasis KViewCanvas konfigūravimas +Comment[ms]=Konfigurasi KViewCanvas Umum +Comment[nb]=Generelt oppsett av KViewCanvas +Comment[nds]=Allgemeen Instellen för KViewCanvas +Comment[ne]=साधारण केडीई दृश्य क्यानभास कन्फिगरेसन +Comment[nl]=Algemene KViewCanvas instellingen +Comment[nn]=Generelt oppsett av KViewCanvas +Comment[pl]=Ogólna konfiguracja KViewCanvas +Comment[pt]=Configuração Geral do KViewCanvas +Comment[pt_BR]=Configuração Geral do Canvas com o KView +Comment[ro]=Configurare KViewCanvas general +Comment[ru]=Общая настройка KViewCanvas +Comment[sk]=Všeobecné nastavenie KViewCanvas +Comment[sl]=Splošne nastavitve KViewCanvas +Comment[sr]=Општа подешавања за KViewCanvas +Comment[sr@Latn]=Opšta podešavanja za KViewCanvas +Comment[sv]=Allmän inställning av Kviews duk +Comment[ta]=பொதுவான கேகாட்சி சித்திரவடிவ வடிவமைப்பு +Comment[tg]=Танзимоти умумии KViewCanvas +Comment[tr]=Genel KView Ekran Ayarları +Comment[uk]=Загальні параметри KViewCanvas +Comment[zh_CN]=KViewCanvas 常规配置 +Comment[zh_HK]=一般 KViewCanvas 設定 +Comment[zh_TW]=一般 KViewCanvas 設定 diff --git a/kview/kviewcanvas/kimagecanvas.cpp b/kview/kviewcanvas/kimagecanvas.cpp new file mode 100644 index 00000000..6c54850f --- /dev/null +++ b/kview/kviewcanvas/kimagecanvas.cpp @@ -0,0 +1,953 @@ +/* This file is part of the KDE project + Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + 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-1301, USA. + +*/ + +#include "kimagecanvas.h" +#include "kimageholder.h" +#include "version.h" +#include "config/defaults.h" + +#include <qcolor.h> +#include <qimage.h> +#include <qapplication.h> +#include <qwmatrix.h> +#include <qtimer.h> + +#include <kpixmap.h> +#include <kdebug.h> +#include <kgenericfactory.h> +#include <ksettings/dispatcher.h> +#include <kconfig.h> + +#define KIMAGECANVAS_WIPESIZE 5 + +const int MOUSECURSORHIDETIME = 3000; + +//extern bool qt_use_xrender; + +typedef KGenericFactory<KImageCanvas> KImageCanvasFactory; +K_EXPORT_COMPONENT_FACTORY( libkviewcanvas, + KImageCanvasFactory( "kviewcanvas" ) ) + +KImageCanvas::KImageCanvas( QWidget * parent, const char * name, const QStringList & ) + : QScrollView( parent, name, WResizeNoErase | WStaticContents ) + , m_client( 0 ) + , m_oldClient( 0 ) + , m_image( 0 ) + , m_imageTransformed( 0 ) + , m_pixmap( 0 ) + , m_pTimer( new QTimer( this, "KImageCanvas/Timer" ) ) + , m_maxsize( Defaults::maxSize ) + , m_minsize( Defaults::minSize ) + , m_currentsize( 0, 0 ) + , m_zoom( 1.0 ) + , m_fastscale( ! Defaults::smoothScaling ) + , m_keepaspectratio( Defaults::keepAspectRatio ) + , m_bImageChanged( false ) + , m_bSizeChanged( false ) + , m_bNeedNewPixmap( false ) + , m_bCentered( Defaults::centerImage ) + , m_bImageUpdateScheduled( false ) + , m_bNewImage( false ) + , m_iBlendTimerId( 0 ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + setFrameStyle( QFrame::NoFrame ); + setResizePolicy( QScrollView::Manual ); + setMinimumSize( 0, 0 ); + setBgColor( Defaults::bgColor ); + + connect( this, SIGNAL( imageChanged() ), this, SLOT( slotImageChanged() ) ); + connect( m_pTimer, SIGNAL( timeout() ), this, SLOT( hideCursor() ) ); + + KSettings::Dispatcher::self()->registerInstance( + KImageCanvasFactory::instance(), this, + SLOT( loadSettings() ) ); + + viewport()->setFocusProxy( this ); + clear(); + + QWidget::setMouseTracking( true ); + viewport()->setMouseTracking( true ); + m_cursor.setShape( Qt::CrossCursor ); + viewport()->setCursor( m_cursor ); + m_pTimer->start( MOUSECURSORHIDETIME, true ); + + loadSettings(); +} + +KImageCanvas::~KImageCanvas() +{ + kdDebug( 4620 ) << k_funcinfo << endl; + delete m_image; m_image = 0; + delete m_pixmap; m_pixmap = 0; +} + +void KImageCanvas::setBgColor( const QColor & color ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + viewport()->setPaletteBackgroundColor( color ); + if( m_client ) + m_client->setPaletteBackgroundColor( color ); +} + +const QColor & KImageCanvas::bgColor() const +{ + kdDebug( 4620 ) << k_funcinfo << endl; + return viewport()->paletteBackgroundColor(); +} + +int KImageCanvas::imageDepth() const +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( ! m_image ) + return 0; + + return m_image->depth(); +} + +QSize KImageCanvas::imageSize() const +{ + //kdDebug( 4620 ) << k_funcinfo << endl; + if( ! m_image ) + return QSize( 0, 0 ); + + return m_matrix.isIdentity() ? m_image->size() : m_matrix.mapRect( QRect( QPoint(), m_image->size() ) ).size(); +} + +QSize KImageCanvas::currentSize() const +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( ! m_image ) + return QSize( 0, 0 ); + + return m_currentsize; +} + +const QImage * KImageCanvas::image() const +{ + if( m_imageTransformed ) + return m_imageTransformed; + return m_image; +} + +QRect KImageCanvas::selection() const +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( m_client ) + return m_selection; + else + return QRect(); +} + +void KImageCanvas::setCentered( bool centered ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( m_bCentered != centered ) + { + m_bCentered = centered; + center(); + } +} + +void KImageCanvas::setImage( const QImage & newimage ) +{ + bool emitHasImage = m_image ? false : true; + m_matrix.reset(); + matrixChanged(); + delete m_image; + m_image = new QImage( newimage ); + m_bNewImage = true; + // don't emit the signal here - call the slot directly + slotImageChanged(); + + sizeFromZoom( m_zoom ); + updateImage(); + if( emitHasImage && m_image ) + emit hasImage( true ); +} + +void KImageCanvas::setImage( const QImage & newimage, const QSize & size ) +{ + kdDebug( 4620 ) << k_funcinfo << size << endl; + bool emitHasImage = m_image ? false : true; + m_matrix.reset(); + matrixChanged(); + delete m_image; + m_image = new QImage( newimage ); + m_bNewImage = true; + // don't emit the signal here - call the slot directly + slotImageChanged(); + + resizeImage( size ); + updateImage(); + if( emitHasImage && m_image ) + emit hasImage( true ); +} + +void KImageCanvas::setZoom( double zoom ) +{ + kdDebug( 4620 ) << k_funcinfo << zoom << endl; + if( m_image == 0 ) + return; + + if( zoom > 0.0 && m_zoom != zoom ) + { + m_zoom = zoom; + sizeFromZoom( m_zoom ); + emit zoomChanged( m_zoom ); + updateImage(); + } +} + +void KImageCanvas::boundImageTo( const QSize & size ) +{ + bool keepAspectRatio = m_keepaspectratio; + m_keepaspectratio = true; + resizeImage( size ); + m_keepaspectratio = keepAspectRatio; +} + +void KImageCanvas::setMaximumImageSize( const QSize & maxsize ) +{ + kdDebug( 4620 ) << k_funcinfo << maxsize << endl; + if( ( ! m_minsize.isEmpty() ) && + ( maxsize.width() < m_minsize.width() || maxsize.height() < m_minsize.height() ) ) + { + kdWarning( 4620 ) << "the new maximum image size is smaller than the minimum size" << endl; + return; + } + + m_maxsize = maxsize; + + resizeImage( m_currentsize ); +} + +void KImageCanvas::setMinimumImageSize( const QSize & minsize ) +{ + kdDebug( 4620 ) << k_funcinfo << minsize << endl; + if( ( ! m_maxsize.isEmpty() ) && + ( minsize.width() > m_maxsize.width() || minsize.height() > m_maxsize.height() ) ) + { + kdWarning( 4620 ) << "the new minimum image size is greater than the maximum size" << endl; + return; + } + + m_minsize = minsize; + + resizeImage( m_currentsize ); +} + +void KImageCanvas::resizeImage( const QSize & newsize ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( m_image == 0 ) + return; + + QSize size = newsize; + + // check that it fits into min and max sizes + checkBounds( size ); + + // calculate the new zoom factor + zoomFromSize( size ); + + if( size != m_currentsize ) + { + m_currentsize = size; + sizeChanged(); + + updateImage(); + } +} + +void KImageCanvas::hideScrollbars( bool hidden ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( hidden ) + { + setVScrollBarMode( AlwaysOff ); + setHScrollBarMode( AlwaysOff ); + } + else + { + setVScrollBarMode( Auto ); + setHScrollBarMode( Auto ); + } +} + +void KImageCanvas::setKeepAspectRatio( bool aspect ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + m_keepaspectratio = aspect; +} + +unsigned int KImageCanvas::numOfBlendEffects() const +{ + return Defaults::numOfBlendEffects; +} + +QString KImageCanvas::blendEffectDescription( unsigned int idx ) const +{ + kdDebug( 4620 ) << k_funcinfo << endl; + switch( idx ) + { + case NoBlending: + kdWarning( 4620 ) << k_funcinfo << " shouldn't be called with an index of 0 - That's always not really defined\n"; + return i18n( Defaults::blendEffectDescription[ 0 ] ); + case AlphaBlend: + return i18n( Defaults::blendEffectDescription[ 5 ] ); + case WipeFromLeft: + return i18n( Defaults::blendEffectDescription[ 1 ] ); + case WipeFromRight: + return i18n( Defaults::blendEffectDescription[ 2 ] ); + case WipeFromTop: + return i18n( Defaults::blendEffectDescription[ 3 ] ); + case WipeFromBottom: + return i18n( Defaults::blendEffectDescription[ 4 ] ); + } + kdError( 4620 ) << "Effect description for effect with index " << idx << " doesn't exist\n"; + return QString::null; +} + +bool KImageCanvas::eventFilter( QObject * obj, QEvent * ev ) +{ + if( ( obj == m_client || obj == m_oldClient ) && ev->type() == QEvent::MouseMove ) + mouseMoveEvent( static_cast<QMouseEvent*>( ev ) ); + return QScrollView::eventFilter( obj, ev ); +} + +void KImageCanvas::setFastScale( bool fastscale ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + m_fastscale = fastscale; + if( m_fastscale ) + { + // wo do scaling with a matrix now, so the m_imageTransformed isn't needed anymore + delete m_imageTransformed; + m_imageTransformed = 0; + } + else + { + matrixChanged(); // set the flag to dirty so that a new m_imageTransformed will be created + // else we very relyably get a crash + } + updateImage(); +} + +void KImageCanvas::clear() +{ + kdDebug( 4620 ) << k_funcinfo << endl; + bool emitHasImage = m_image ? true : false; + delete m_image; + m_image = 0; + m_currentsize -= m_currentsize; //zero size + if( m_client ) + m_client->clear(); + if( emitHasImage && ! m_image ) + emit hasImage( false ); +} + +void KImageCanvas::flipHorizontal( bool change ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( m_image == 0 ) + return; + + if( change ) + { + QWMatrix matrix( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F ); + *m_image = m_image->xForm( matrix ); + emit imageChanged(); + } + else + { + m_matrix.scale( 1.0, -1.0 ); + matrixChanged(); + } + // size didn't change + updateImage(); +} + +void KImageCanvas::flipVertical( bool change ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( m_image == 0 ) + return; + + if( change ) + { + QWMatrix matrix( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F ); + *m_image = m_image->xForm( matrix ); + emit imageChanged(); + } + else + { + m_matrix.scale( -1.0, 1.0 ); + matrixChanged(); + } + // size didn't change + updateImage(); +} + +void KImageCanvas::rotate( double a, bool change ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( m_image == 0 ) + return; + + if( change ) + { + QWMatrix matrix; + matrix.rotate( a ); + *m_image = m_image->xForm( matrix ); + emit imageChanged(); + } + else + { + m_matrix.rotate( a ); + matrixChanged(); + } + //adjust m_currentsize + sizeFromZoom( m_zoom ); + updateImage(); +} + +void KImageCanvas::checkBounds( QSize & newsize ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( m_keepaspectratio ) + { + // check that the new size has the same aspect ratio the original image had + QSize origsize = imageSize(); + double x1 = double( origsize.height() ) / double( newsize.height() ); + double x2 = double( origsize.width() ) / double( newsize.width() ); + if( ( newsize * x1 != origsize ) || ( newsize * x2 != origsize ) ) + { + // not OK + kdDebug( 4620 ) << "checkBounds: the aspect ratio wasn't kept changing from " << newsize << endl; + // the user want's that the aspect ratio doesn't change. The + // question is: make it larger or smaller? + // we make it smaller (we depend on that in boundImageTo) + newsize = origsize / KMAX( x1, x2 ); + kdDebug( 4620 ) << "checkBounds: to " << newsize << endl; + } + } + if( ( ! m_maxsize.isEmpty() ) && + ( newsize.width() > m_maxsize.width() || newsize.height() > m_maxsize.height() ) ) + { + kdDebug( 4620 ) << "checkBounds: the new size is bigger than the max size" << endl; + if( m_keepaspectratio ) + { + double x1 = double( m_maxsize.height() ) / double( newsize.height() ); + double x2 = double( m_maxsize.width() ) / double( newsize.width() ); + double x = KMIN( x1, x2 );//( x1 > x2 ) ? x2 : x1; + newsize *= x; + } + else + newsize = newsize.boundedTo( m_maxsize ); + } + if( ( ! m_minsize.isEmpty() ) && + ( newsize.width() < m_minsize.width() || newsize.height() < m_minsize.height() ) ) + { + kdDebug( 4620 ) << "checkBounds: the new size is smaller than the min size" << endl; + if( m_keepaspectratio ) + { + double x1 = double( m_minsize.height() ) / double( newsize.height() ); + double x2 = double( m_minsize.width() ) / double( newsize.width() ); + double x = KMAX( x1, x2 );//( x1 > x2 ) ? x1 : x2; + newsize *= x; + } + else + newsize = newsize.expandedTo( m_minsize ); + } + // if it still won't fit we have a problem: we can't keep the aspect ratio or we have + // to violate the min/max settings + if( ( ! m_maxsize.isEmpty() ) && + ( newsize.width() > m_maxsize.width() || newsize.height() > m_maxsize.height() ) ) + { + kdDebug( 4620 ) << "checkBounds: Sorry, I can't keep the aspect ratio." << endl; + newsize = newsize.boundedTo( m_maxsize ); + } +} + +void KImageCanvas::zoomFromSize( const QSize & newsize ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( ! m_image ) + return; + + QSize originalsize = imageSize(); + double widthzoom = double( newsize.width() ) / double( originalsize.width() ); + double heightzoom = double( newsize.height() ) / double( originalsize.height() ); + double zoom = ( widthzoom + heightzoom ) / 2; + if( zoom != m_zoom ) + { + m_zoom = zoom; + emit zoomChanged( m_zoom ); + } +} + +void KImageCanvas::sizeFromZoom( double zoom ) +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( ! m_image ) + return; + + QSize newsize = zoom * imageSize(); + kdDebug( 4620 ) << "change size from " << imageSize() << " to " << newsize << endl; + resizeImage( newsize ); +} + +void KImageCanvas::updateImage() +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( ! m_bImageUpdateScheduled ) + QTimer::singleShot( 0, this, SLOT( slotUpdateImage() ) ); + m_bImageUpdateScheduled = true; +} + +void KImageCanvas::slotUpdateImage() +{ + kdDebug( 4620 ) << k_funcinfo << endl; + m_bImageUpdateScheduled = false; + if( m_image == 0 ) + return; + + //only update if something was changed + if( m_bImageChanged || m_bSizeChanged || m_bMatrixChanged ) + { + kdDebug( 4620 ) << "actually updating the image now" << endl; + QApplication::setOverrideCursor( WaitCursor ); + if( m_bNewImage || ! m_client ) + { + finishNewClient(); + m_oldClient = m_client; + m_client = createNewClient(); + } + m_client->setImage( pixmap() ); + + if( m_bSizeChanged || m_bNewImage ) + { + QSize sh = m_client->sizeHint(); + if( ! sh.isValid() ) + sh = QSize( 0, 0 ); + m_client->resize( sh ); + resizeContents( sh.width(), sh.height() ); + center(); + } + QRect drawRect = m_client->drawRect(); + switch( m_iBlendEffect ) + { + case NoBlending: + break; + case AlphaBlend: + break; + case WipeFromLeft: + drawRect.setRight( KIMAGECANVAS_WIPESIZE + contentsX() ); + m_client->setDrawRect( drawRect ); + break; + case WipeFromRight: + drawRect.rLeft() += KMIN( drawRect.width() - KIMAGECANVAS_WIPESIZE, contentsX() + visibleWidth() ); + m_client->setDrawRect( drawRect ); + break; + case WipeFromTop: + drawRect.setBottom( KIMAGECANVAS_WIPESIZE + contentsY() ); + m_client->setDrawRect( drawRect ); + break; + case WipeFromBottom: + drawRect.setTop( KMIN( drawRect.height() - KIMAGECANVAS_WIPESIZE, contentsY() + visibleHeight() ) ); + m_client->setDrawRect( drawRect ); + break; + } + m_client->update(); + m_iBlendTimerId = startTimer( 5 ); + QApplication::restoreOverrideCursor(); + } + + m_bNewImage = false; + m_bImageChanged = false; + m_bSizeChanged = false; + m_bMatrixChanged = false; +} + +void KImageCanvas::mouseMoveEvent( QMouseEvent * ) +{ + if( m_cursor.shape() == Qt::BlankCursor ) + { + m_cursor.setShape( Qt::CrossCursor ); + viewport()->setCursor( m_cursor ); + if( m_client ) + m_client->setCursor( m_cursor ); + } + m_pTimer->start( MOUSECURSORHIDETIME, true ); +} + + +void KImageCanvas::resizeEvent( QResizeEvent * ev ) +{ + kdDebug( 4620 ) << "KImageCanvas resized to " << ev->size() << endl; + QScrollView::resizeEvent( ev ); + center(); +} + +void KImageCanvas::contentsMousePressEvent( QMouseEvent * ev ) +{ + if ( ev->button() == RightButton ) + emit contextPress( ev->globalPos() ); + QScrollView::contentsMousePressEvent( ev ); +} + +void KImageCanvas::contentsWheelEvent( QWheelEvent * ev ) +{ + //kdDebug( 4620 ) << k_funcinfo << endl; + // Ctrl+Wheelmouse changes the zoom. + // Wheelmouse scrolls around + if ( ev->state() & ControlButton ) + { + int delta = ev->delta() / 120; + double zoom = m_zoom; + // make zoom a value of 1/16, 1/15, 1/14, .. , 1/2, 1, 2, 3, .. , 15, 16 + bool done = false; + for( int i = 15; i > 0; --i ) + { + if( zoom <= ( 1.0 / i ) ) + { + if( zoom < ( 1.0 / ( i + 0.5 ) ) ) + zoom = ( 1.0 / ( i + 1 ) ); + else + zoom = ( 1.0 / i ); + done = true; + // zoom = 1/16, 1/15, .. , 1/2, 1 + double x = 1.0 / zoom - delta; + if( x == 0 ) + zoom = 2.0; + else + zoom = 1.0 / x; + break; + } + } + if( ! done ) + for( int i = 2; i < 17; ++i ) + { + if( zoom < (double)i ) + { + if( zoom < ( i - 0.5 ) ) + zoom = i - 1.0; + else + zoom = (double)i; + done = true; + // zoom = 1, 2, .., 15, 16 + zoom = zoom + delta; + if( zoom < 0.9 ) + zoom = 0.5; + break; + } + } + if( ! done ) + { + zoom = 16.0; + zoom = zoom + delta; + if( zoom > 16.0 ) + zoom = 16.0; + } + kdDebug( 4620 ) << "Mousewheel: oldzoom = " << m_zoom << " newzoom = " << zoom << endl; + ev->accept(); + bool oldscale = fastScale(); + setFastScale( true ); + setZoom( zoom ); + setFastScale( oldscale ); + } + else + QScrollView::contentsWheelEvent( ev ); +} + +void KImageCanvas::keyPressEvent( QKeyEvent * ev ) +{ + //kdDebug( 4620 ) << k_funcinfo << endl; + switch( ev->key() ) + { + case Key_Down: + ev->accept(); + verticalScrollBar()->addLine(); + break; + case Key_Up: + ev->accept(); + verticalScrollBar()->subtractLine(); + break; + case Key_Left: + ev->accept(); + horizontalScrollBar()->subtractLine(); + break; + case Key_Right: + ev->accept(); + horizontalScrollBar()->addLine(); + break; + case Key_PageUp: + ev->accept(); + verticalScrollBar()->subtractPage(); + break; + case Key_PageDown: + ev->accept(); + verticalScrollBar()->addPage(); + break; + default: + ev->ignore(); + break; + } +} + +void KImageCanvas::timerEvent( QTimerEvent * ev ) +{ + if( ev->timerId() == m_iBlendTimerId ) + { + QRect drawRect = m_client->drawRect(); + switch( m_iBlendEffect ) + { + case NoBlending: + finishNewClient(); + break; + case AlphaBlend: + finishNewClient(); + //if( qt_use_xrender ) + //{ + //} + //else + //{ + //kdWarning( 4620 ) << "no XRender" << endl; + //finishNewClient(); + //} + break; + case WipeFromLeft: + drawRect.rRight() += KIMAGECANVAS_WIPESIZE; + m_client->setDrawRect( drawRect ); + m_client->update( drawRect.right() - KIMAGECANVAS_WIPESIZE, 0, KIMAGECANVAS_WIPESIZE, m_client->height() ); + if( drawRect.right() >= contentsX() + visibleWidth() ) + finishNewClient(); + break; + case WipeFromRight: + drawRect.rLeft() -= KIMAGECANVAS_WIPESIZE; + m_client->setDrawRect( drawRect ); + m_client->update( drawRect.left(), 0, KIMAGECANVAS_WIPESIZE, m_client->height() ); + if( drawRect.left() <= contentsX() ) + finishNewClient(); + break; + case WipeFromTop: + drawRect.rBottom() += KIMAGECANVAS_WIPESIZE; + m_client->setDrawRect( drawRect ); + m_client->update( 0, drawRect.bottom() - KIMAGECANVAS_WIPESIZE, m_client->width(), KIMAGECANVAS_WIPESIZE ); + if( drawRect.bottom() >= contentsY() + visibleHeight() ) + finishNewClient(); + break; + case WipeFromBottom: + drawRect.rTop() -= KIMAGECANVAS_WIPESIZE; + m_client->setDrawRect( drawRect ); + m_client->update( 0, drawRect.top(), m_client->width(), KIMAGECANVAS_WIPESIZE ); + if( drawRect.top() <= contentsY() ) + finishNewClient(); + break; + default: + kdFatal( 4620 ) << "unknown Blend Effect" << endl; + break; + } + } + else + killTimer( ev->timerId() ); +} + +void KImageCanvas::hideCursor() +{ + kdDebug( 4620 ) << k_funcinfo << endl; + m_cursor.setShape( Qt::BlankCursor ); + viewport()->setCursor( m_cursor ); + if( m_client ) + m_client->setCursor( m_cursor ); +} + +const KPixmap KImageCanvas::pixmap() +{ + kdDebug( 4620 ) << k_funcinfo << ( m_bNeedNewPixmap ? "convert from Image" : "use old copy" ) << endl; + // create a new Pixmap in m_pixmap if needed + if( m_bNeedNewPixmap ) + { + // only do it again if requested + m_bNeedNewPixmap = false; + // ok, the old one may go now + delete m_pixmap; + + // if smoothscaling is wanted and the transformation matrix or the image + // itself changed... + if( ! m_fastscale && ( m_bMatrixChanged || m_bImageChanged ) ) + { + delete m_imageTransformed; + // we create a new image transformed by the matrix + m_imageTransformed = new QImage( m_matrix.isIdentity() ? *m_image : m_image->xForm( m_matrix ) ); + kdDebug( 4620 ) << "Size of m_image: " << m_image->size() << endl; + kdDebug( 4620 ) << "Size of m_imageTransformed: " << m_imageTransformed->size() << endl; + } + // smoothScale or fast scaling via m_matrix + m_pixmap = new KPixmap(); + m_pixmap->convertFromImage( m_fastscale ? *m_image : m_imageTransformed->smoothScale( m_currentsize ), KPixmap::ColorOnly ); + } + if( m_fastscale ) + { + // fast scaling is needed so we need to scale now + QWMatrix matrix( m_matrix ); + matrix.scale( m_zoom, m_zoom ); + if( ! matrix.isIdentity() ) + return m_pixmap->xForm( matrix ); + } + return *m_pixmap; +} + +void KImageCanvas::slotImageChanged() +{ + kdDebug( 4620 ) << k_funcinfo << endl; + m_bImageChanged = true; + m_bNeedNewPixmap = true; +} + +void KImageCanvas::loadSettings() +{ + KConfigGroup cfgGroup( KImageCanvasFactory::instance()->config(), + "Settings" ); + setFastScale( ! cfgGroup.readBoolEntry( "Smooth Scaling", ! fastScale() ) ); + setKeepAspectRatio( cfgGroup.readBoolEntry( "Keep Aspect Ratio", + keepAspectRatio() ) ); + setCentered( cfgGroup.readBoolEntry( "Center Image", centered() ) ); + + setBgColor( cfgGroup.readColorEntry( "Background Color", &bgColor() ) ); + + setMinimumImageSize( QSize( cfgGroup.readNumEntry( "Minimum Width", + minimumImageSize().width() ), cfgGroup.readNumEntry( + "Minimum Height", minimumImageSize().height() ) ) ); + setMaximumImageSize( QSize( cfgGroup.readNumEntry( "Maximum Width", + maximumImageSize().width() ), cfgGroup.readNumEntry( + "Maximum Height", maximumImageSize().height() ) ) ); + + KConfigGroup blendConfig( KImageCanvasFactory::instance()->config(), + "Blend Effects" ); + /* TODO + m_vEffects.clear(); + for( unsigned int i = 1; i <= numOfBlendEffects(); ++i ) + { + if( blendConfig.readBoolEntry( QString::number( i ), false ) ) + m_vEffects.push_back( i ); + } + // and now tell the canvas what blend effect to use + switchBlendEffect(); + */ +} + +void KImageCanvas::selected( const QRect & rect ) +{ + //kdDebug( 4620 ) << k_funcinfo << rect << endl; + m_selection = rect; + if( ! m_selection.isNull() ) + { + m_selection.setTop( int( ( m_selection.top() + 0.5 ) / m_zoom ) ); + m_selection.setLeft( int( ( m_selection.left() + 0.5 ) / m_zoom ) ); + m_selection.setRight( int( ( m_selection.right() + 0.5 ) / m_zoom ) ); + m_selection.setBottom( int( ( m_selection.bottom() + 0.5 ) / m_zoom ) ); + } + //kdDebug( 4620 ) << "m_selection = " << m_selection << endl; + emit selectionChanged( m_selection ); +} + +void KImageCanvas::mapCursorPos( const QPoint & pos ) +{ + QPoint mapped( static_cast<int>( ( pos.x() + 0.5 ) / m_zoom ), static_cast<int>( ( pos.y() + 0.5 ) / m_zoom ) ); + //kdDebug( 4620 ) << k_funcinfo << pos << " -> " << mapped << endl; + emit cursorPos( mapped ); +} + +void KImageCanvas::sizeChanged() +{ + kdDebug( 4620 ) << k_funcinfo << endl; + m_bSizeChanged = true; + if( ! m_fastscale ) + m_bNeedNewPixmap = true; + emit imageSizeChanged( m_currentsize ); +} + +void KImageCanvas::matrixChanged() +{ + kdDebug( 4620 ) << k_funcinfo << endl; + m_bMatrixChanged = true; + m_bNeedNewPixmap = true; +} + +void KImageCanvas::center() +{ + kdDebug( 4620 ) << k_funcinfo << endl; + if( m_bCentered && m_client ) + { + int x = 0; + int y = 0; + + int scrollbarwidth = ( height() >= m_currentsize.height() ) ? 0 : verticalScrollBar()->width(); + int scrollbarheight = ( width() - scrollbarwidth >= m_currentsize.width() ) ? 0 : horizontalScrollBar()->height(); + scrollbarwidth = ( height() - scrollbarheight >= m_currentsize.height() ) ? 0 : verticalScrollBar()->width(); + + int availheight = height() - scrollbarheight; + int availwidth = width() - scrollbarwidth; + + if( availwidth > m_currentsize.width() ) + x = ( availwidth - m_currentsize.width() ) / 2; + if( availheight > m_currentsize.height() ) + y = ( availheight - m_currentsize.height() ) / 2; + + kdDebug( 4620 ) << "center with left top at " << x << ", " << y << endl; + moveChild( m_client, x, y ); + } +} + +void KImageCanvas::finishNewClient() +{ + kdDebug( 4620 ) << k_funcinfo << endl; + killTimer( m_iBlendTimerId ); + if( m_client ) + m_client->setDrawRect( m_client->rect() ); + delete m_oldClient; + m_oldClient = 0; + emit showingImageDone(); +} + +KImageHolder * KImageCanvas::createNewClient() +{ + kdDebug( 4620 ) << k_funcinfo << endl; + KImageHolder * client = new KImageHolder( viewport() ); + client->setMinimumSize( 0, 0 ); + client->setMouseTracking( true ); + client->installEventFilter( this ); + setFocusProxy( client ); + client->setFocusPolicy( QWidget::StrongFocus ); + client->setFocus(); + + addChild( client, 0, 0 ); + + connect( client, SIGNAL( contextPress( const QPoint& ) ), SIGNAL( contextPress( const QPoint& ) ) ); + connect( client, SIGNAL( cursorPos( const QPoint & ) ), SLOT( mapCursorPos( const QPoint & ) ) ); + connect( client, SIGNAL( selected( const QRect & ) ), SLOT( selected( const QRect & ) ) ); + connect( client, SIGNAL( wannaScroll( int, int ) ), SLOT( scrollBy( int, int ) ) ); + + return client; +} + +#include "kimagecanvas.moc" + +// vim:sw=4:ts=4 diff --git a/kview/kviewcanvas/kimagecanvas.h b/kview/kviewcanvas/kimagecanvas.h new file mode 100644 index 00000000..8a0bffda --- /dev/null +++ b/kview/kviewcanvas/kimagecanvas.h @@ -0,0 +1,366 @@ +/* This file is part of the KDE project + Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + 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-1301, USA. + +*/ +// $Id$ + +#ifndef _KIMAGECANVAS_H +#define _KIMAGECANVAS_H + +#include "kimageviewer/canvas.h" + +#include <qscrollview.h> +#include <qwmatrix.h> +#include <qcursor.h> +#include <qrect.h> + +#include <kdemacros.h> + +class KImageHolder; +class QColor; +class QImage; +class KPixmap; + +/** + * @short KViewCanvas + * @author Matthias Kretz <kretz@kde.org> + * @version $Id$ + */ +class KDE_EXPORT KImageCanvas : public QScrollView, public KImageViewer::Canvas +{ + Q_OBJECT + public: + /** + * KImageCanvas Constructor + */ + KImageCanvas( QWidget * parent, const char * name, const QStringList & args ); + + /** + * KImageCanvas Destructor + */ + virtual ~KImageCanvas(); + + /** + * set the background color of the canvas + */ + void setBgColor( const QColor & ); + + /** + * returns the current background color + */ + const QColor & bgColor() const; + + /** + * the depth of the contained image + */ + int imageDepth() const; + + /** + * the size of the unzoomed image + */ + QSize imageSize() const; + + /** + * the size of the zoomed (current) image + */ + QSize currentSize() const; + + /** + * returns the zoom factor + */ + double zoom() const { return m_zoom; } + + /** + * returns the current (unzoomed) image + */ + const QImage * image() const; + + /** + * Scrolls the content so that the point (x, y) is in the top-left corner. + */ + void setXYOffset( int x, int y ) { setContentsPos( x, y ); } + + /** + * Returns the leftmost visible X coordinate of the image. + */ + int xOffset() const { return contentsX(); } + + /** + * Returns the topmost visible Y coordinate of the image. + */ + int yOffset() const { return contentsY(); } + + /** + * Returns whether to use fast or smooth scaling + */ + bool fastScale() const { return m_fastscale; } + + /** + * Return whether the image should always be centered. + */ + bool centered() const { return m_bCentered; } + + /** + * Return the selected rectangle + */ + QRect selection() const; + + /** + * Returns whether the aspect ratio of the image is kept + */ + bool keepAspectRatio() const { return m_keepaspectratio; } + + /** + * @return the number of available blend effects + */ + unsigned int numOfBlendEffects() const; + + /** + * @return the description of the blend effect + */ + QString blendEffectDescription( unsigned int ) const; + + /** + * @return the current maximum image size + */ + const QSize & maximumImageSize() const { return m_maxsize; } + + /** + * @return the current minimum image size + */ + const QSize & minimumImageSize() const { return m_minsize; } + + /** + * @return a pointer to the QWidget interface of this object + */ + QWidget * widget() { return static_cast<QWidget *>( this ); } + + bool eventFilter( QObject *, QEvent * ); + + signals: + /** + * a mouse button was pressed and a context menu should be openend + */ + void contextPress( const QPoint& ); + + /** + * the size of the image has changed (a new image was loaded, or the + * image was zoomed or cropped) + * + * it passes the new size of the image + */ + void imageSizeChanged( const QSize & ); + + /** + * The zoom of the image has changed. + */ + void zoomChanged( double zoom ); + + /** + * The selection has changed. Connect to this signal if you want to + * do something with a selection of the image (e.g. crop). + */ + void selectionChanged( const QRect & ); + + /** + * Emitted when an image is finished being shown. If a blend effect is being used + * the signal is emitted when the effect is finished. + */ + void showingImageDone(); + + /** + * This signal is emitted whenever the canvas changes between image/no-image. For + * example, if someone calls @ref clear() hasImage( false ) is emitted if an image + * was shown before. + */ + void hasImage( bool ); + + /** + * Some methods of the canvas not only change the way the image is shown (e.g. zoom) + * but also change the image itself (e.g. rotation) - @ref image() returns something + * different. If such a change happens this signal is emitted. + * It is not emitted when a new image is set with the @ref setImage() methods. + */ + void imageChanged(); + + /** + * The current mouse cursor position on the image. + */ + void cursorPos( const QPoint & ); + + public slots: + /** + * Set if the image should always be centered if the canvas is + * bigger than the image. + */ + void setCentered( bool ); + + /** + * give the canvas a new image to show. The zoom level is kept. + */ + void setImage( const QImage & ); + + /** + * Give the canvas a new image to show. + * + * You have to pass the size the image should have when it appears + * on screen. + */ + void setImage( const QImage &, const QSize & ); + + /** + * set the zoom to be used when showing the image + */ + void setZoom( double ); + + /** + * Fit the image into the requested width and height. + */ + void boundImageTo( const QSize & size ); + + /** + * Set the maximum size of the image. If this is set the image will + * never exceed this size. + * + * If you set this to 0x0 the image size may be as big as possible + */ + void setMaximumImageSize( const QSize & ); + + /** + * Set the minimum size of the image. If this is set the image will + * never be smaller than this size. + * + * If you set this to 0x0 the image size can be as small as possible + */ + void setMinimumImageSize( const QSize & ); + + /** + * Resize the image to the given size. It will keep the aspect ratio + * as long as keepAspectRatio is true (default). The image will be as + * large as possible within the given constraints. + */ + void resizeImage( const QSize & ); + + /** + * Hides the scrollbars of the canvas. It's still possible to scroll + * by moving the image with the mouse. + */ + void hideScrollbars( bool ); + + /** + * Changes the zoom behaviour: Normally the aspect ratio of the image + * won't change, but if you want to allow it you may do. + */ + void setKeepAspectRatio( bool ); + + /** + * If the canvas supports different methods for scaling you may + * switch between fast and smooth scaling. + * + * It defaults to smooth scaling. + */ + void setFastScale( bool ); + + /** + * clears the canvas (no image loaded) + */ + void clear(); + + /** + * flip the image horizontally + */ + void flipHorizontal( bool change = false ); + + /** + * flip the image vertically + */ + void flipVertical( bool change = false ); + + /** + * rotate the image a degrees counterclockwise + */ + void rotate( double a, bool change = false ); + + protected: + void checkBounds( QSize & newsize ); + void zoomFromSize( const QSize & ); + void sizeFromZoom( double ); + void updateImage(); + + void mouseMoveEvent( QMouseEvent * ); + void resizeEvent( QResizeEvent * ); + void contentsMousePressEvent( QMouseEvent * ); + void contentsWheelEvent( QWheelEvent * ); + void keyPressEvent( QKeyEvent * ); + void timerEvent( QTimerEvent * ); + + protected slots: + void slotUpdateImage(); + void hideCursor(); + void slotImageChanged(); + void loadSettings(); + + private slots: + void selected( const QRect & ); // map rect to unzoomed rect + void mapCursorPos( const QPoint & ); + + private: + enum BlendEffect { + NoBlending = 0, + WipeFromLeft = 1, + WipeFromRight = 2, + WipeFromTop = 3, + WipeFromBottom = 4, + AlphaBlend = 5 + }; + const KPixmap pixmap(); + void sizeChanged(); + void matrixChanged(); + void center(); + void finishNewClient(); + KImageHolder * createNewClient(); + + KImageHolder * m_client; + KImageHolder * m_oldClient; + QImage * m_image; //unzoomed copy of the current image + QImage * m_imageTransformed; //xForm( m_matrix ) copy of the current image + KPixmap * m_pixmap; //copy of the current pixmap (if ( m_fastscale ) it's unzoomed else it's m_imageTransformed.smoothScale()d) + + QTimer * m_pTimer; // timer for single shot to hide the cursor + QCursor m_cursor; // the cursor show in the canvas (for auto-hiding) + + QWMatrix m_matrix; // the current transformation matrix + QSize m_maxsize, m_minsize; + QSize m_currentsize; + + double m_zoom; + bool m_fastscale; + bool m_keepaspectratio; + bool m_bImageChanged; + bool m_bSizeChanged; + bool m_bMatrixChanged; + bool m_bNeedNewPixmap; + bool m_bCentered; + bool m_bImageUpdateScheduled; + bool m_bNewImage; + int m_iBlendTimerId; + + QRect m_selection; //unzoomed selection rect +}; + +// vim:sw=4:ts=4 + +#endif // _KIMAGECANVAS_H diff --git a/kview/kviewcanvas/kimageholder.cpp b/kview/kviewcanvas/kimageholder.cpp new file mode 100644 index 00000000..9009c7fc --- /dev/null +++ b/kview/kviewcanvas/kimageholder.cpp @@ -0,0 +1,371 @@ +/* This file is part of the KDE project + Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + 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-1301, USA. + +*/ + +//$Id$ + +#include <assert.h> + +#include <qcolor.h> +#include <qwidget.h> +#include <qimage.h> +#include <qpainter.h> +#include <qpen.h> +#include <qmovie.h> +#include <qpixmap.h> + +#include <kpixmap.h> +#include <kdebug.h> + +#include "kimageholder.h" + +KImageHolder::KImageHolder( QWidget * parent, const char * name ) + : QWidget( parent, name, Qt::WResizeNoErase | Qt::WRepaintNoErase ) + , m_selected( false ) + , m_bSelecting( false ) + , m_scrollTimerId( 0 ) + , m_xOffset( 0 ) + , m_yOffset( 0 ) + , m_pen( new QPen( QColor( 255, 255, 255 ), 0, DashLine ) ) + , m_pPixmap( 0 ) + , m_pDoubleBuffer( 0 ) + , m_pCheckboardPixmap( 0 ) +{ + setBackgroundMode( QWidget::NoBackground ); +} + +KImageHolder::~KImageHolder() +{ + delete m_pen; + delete m_pPixmap; + delete m_pDoubleBuffer; + delete m_pCheckboardPixmap; + m_pen = 0; + m_pPixmap = 0; + m_pDoubleBuffer = 0; + m_pCheckboardPixmap = 0; +} + +void KImageHolder::mousePressEvent( QMouseEvent *ev ) +{ + //kdDebug( 4620 ) << k_funcinfo << " ev->state() = " << ev->state() << endl; + // if the right mouse button is pressed emit the contextPress signal + if ( ev->button() == RightButton ) + { + emit contextPress( mapToGlobal( ev->pos() ) ); + return; + } + + if( m_pPixmap == 0 ) + return; + + if( ev->button() == LeftButton || ev->button() == MidButton ) + { + m_scrollpos = ev->globalPos(); + m_selectionStartPoint = ev->pos(); + } +} + +void KImageHolder::mouseMoveEvent( QMouseEvent *ev ) +{ + //FIXME: when scrolling the cursorpos shouldn't change + if( this->rect().contains( ev->pos(), false ) ) + emit cursorPos( ev->pos() ); + //kdDebug( 4620 ) << k_funcinfo << " ev->state() = " << ev->state() << endl; + if( ev->state() & LeftButton || ev->state() & MidButton ) + { + // scroll when a modifier and left button or the middle button is pressed + if( ev->state() & AltButton || ev->state() & ControlButton || ev->state() & ShiftButton || ev->state() & MidButton ) + { + QPoint difference = m_scrollpos - ev->globalPos(); + emit wannaScroll( difference.x(), difference.y() ); + } + else // create a selection + { + QWidget * parentwidget = ( QWidget* )parent(); + if( ! m_bSelecting ) + { + m_bSelecting = true; + if( m_selected ) { + // remove old rubberband + eraseSelect(); + m_selected = false; + } + + m_selection.setLeft( m_selectionStartPoint.x() ); + m_selection.setRight( m_selectionStartPoint.x() ); + m_selection.setTop( m_selectionStartPoint.y() ); + m_selection.setBottom( m_selectionStartPoint.y() ); + } + // currently called only on drag, + // so assume a selection has been started + bool erase = m_selected; + + if( !m_selected ) + m_selected = true; + + // Autoscrolling: + // For every pixel the mouse leaves the image canvas the canvas + // should scroll faster. The scrolling should be independent from + // the mouse movement. Therefor I need a timer to do the scroll + // movement: + // e.g.: m_xOffset=-1 => scroll to the left 1 px per 50ms + // -2 => scroll to the left 2 px per 50ms + // 2 => scroll to the right 2 px per 50ms + // ... + m_xOffset = mapTo( parentwidget, ev->pos() ).x(); + m_yOffset = mapTo( parentwidget, ev->pos() ).y(); + if( m_xOffset > 0 ) + { + m_xOffset -= parentwidget->width(); + if( m_xOffset < 0 ) + m_xOffset = 0; + } + if( m_yOffset > 0 ) + { + m_yOffset -= parentwidget->height(); + if( m_yOffset < 0 ) + m_yOffset = 0; + } + if( m_scrollTimerId != 0 && m_xOffset == 0 && m_yOffset == 0 ) + { + killTimer( m_scrollTimerId ); + m_scrollTimerId = 0; + } + else if( m_scrollTimerId == 0 && ( m_xOffset != 0 || m_yOffset != 0 ) ) + m_scrollTimerId = startTimer( 50 ); + + int r = ev->x() < width() ? ( ev->x() < 0 ? 0 : ev->x() ) : width() - 1; + int b = ev->y() < height() ? ( ev->y() < 0 ? 0 : ev->y() ) : height() - 1; + + if( r != m_selection.right() || b != m_selection.bottom() ) + { + if( erase ) + eraseSelect(); + + m_selection.setRight( r ); + m_selection.setBottom( b ); + emit selected( m_selection.normalize() ); + + QPainter painter( this ); + drawSelect( painter ); + } + } + m_scrollpos = ev->globalPos(); + m_selectionStartPoint = ev->pos(); + } +} + +void KImageHolder::mouseReleaseEvent( QMouseEvent * ev ) +{ + if( m_bSelecting ) + { + m_xOffset = m_yOffset = 0; + if( m_scrollTimerId != 0 ) + { + killTimer( m_scrollTimerId ); + m_scrollTimerId = 0; + } + } + if( ev->state() & LeftButton || ev->state() & MidButton ) + if( m_bSelecting ) + m_bSelecting = false; + else + clearSelection(); +} + +void KImageHolder::drawSelect( QPainter & painter ) +{ + painter.save(); + painter.setRasterOp( XorROP ); + painter.setPen( *m_pen ); + painter.drawRect( m_selection.normalize() ); + painter.restore(); +} + +void KImageHolder::eraseSelect() +{ + QRegion r( m_selection.normalize() ); + QRect inner = m_selection.normalize(); + inner.rLeft() += 1; + inner.rTop() += 1; + inner.rRight() -= 1; + inner.rBottom() -= 1; + r -= inner; + + QMemArray<QRect> rects = r.rects(); + + if( m_pDoubleBuffer ) + for( unsigned int i = 0; i < rects.size(); ++i ) + bitBlt( this, rects[ i ].topLeft(), m_pDoubleBuffer, rects[ i ], CopyROP ); + else + for( unsigned int i = 0; i < rects.size(); ++i ) + bitBlt( this, rects[ i ].topLeft(), m_pPixmap, rects[ i ], CopyROP ); +} + +void KImageHolder::clearSelection() +{ + if( m_selected ) + { + eraseSelect(); + m_selected = false; + } + m_selection.setSize( QSize( 0, 0 ) ); + emit selected( m_selection ); +} + +void KImageHolder::setImage( const KPixmap & pix ) +{ + clearSelection(); + + setPixmap( pix ); +} + +void KImageHolder::setImage( const QImage & image ) +{ + clearSelection(); + kdDebug( 4620 ) << "converting Image to Pixmap" << endl; + KPixmap pix( image ); + + setPixmap( pix ); +} + +void KImageHolder::setImage( const QMovie & /*movie*/ ) +{ + clearSelection(); + //setMovie( movie ); + kdWarning( 4620 ) << "setImage( QMovie ) not implemented" << endl; +} + +void KImageHolder::clear() +{ + delete m_pPixmap; + m_pPixmap = 0; + delete m_pDoubleBuffer; + m_pDoubleBuffer = 0; + hide(); + clearSelection(); +} + +QRect KImageHolder::selection() const +{ + if( m_selected ) + return m_selection.normalize(); + else + return QRect(); +} + +QSize KImageHolder::sizeHint() const +{ + if( m_pPixmap ) + return m_pPixmap->size(); + return QSize( 0, 0 ); +} + +void KImageHolder::paintEvent( QPaintEvent *ev ) +{ + QPainter painter( this ); + painter.setClipRegion( ev->region().intersect( m_drawRect ) ); + if( m_pPixmap ) + { + if( m_pPixmap->mask() ) + { + if( ! m_pDoubleBuffer ) + { + m_pDoubleBuffer = new KPixmap( m_pPixmap->size() ); + QPainter p( m_pDoubleBuffer ); + p.drawTiledPixmap( m_pDoubleBuffer->rect(), checkboardPixmap() ); + p.end(); + bitBlt( m_pDoubleBuffer, QPoint( 0, 0 ), m_pPixmap, m_pPixmap->rect() ); + } + painter.drawPixmap( 0, 0, *m_pDoubleBuffer ); + } + else + painter.drawPixmap( 0, 0, *m_pPixmap ); + } + if( m_selected ) + drawSelect( painter ); +} + +void KImageHolder::timerEvent( QTimerEvent * ev ) +{ + if( ev->timerId() != m_scrollTimerId ) + return; + + emit wannaScroll( m_xOffset, m_yOffset ); +} + +void KImageHolder::setPixmap( const KPixmap & pixmap ) +{ + kdDebug( 4620 ) << k_funcinfo << " " << pixmap.width() << 'x' << pixmap.height() << endl; + delete m_pPixmap; + delete m_pDoubleBuffer; + m_pDoubleBuffer = 0; + m_pPixmap = new KPixmap( pixmap ); + m_drawRect = m_pPixmap->rect(); + show(); +} + +const KPixmap & KImageHolder::checkboardPixmap() +{ + if( ! m_pCheckboardPixmap ) + { + const char * xpm[] = { + "32 32 2 1", + " c #666666", + "X c #999999", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + " XXXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + "XXXXXXXXXXXXXXXX ", + }; + m_pCheckboardPixmap = new KPixmap( xpm ); + } + return *m_pCheckboardPixmap; +} + +#include "kimageholder.moc" + +// vim:sw=4:ts=4 diff --git a/kview/kviewcanvas/kimageholder.h b/kview/kviewcanvas/kimageholder.h new file mode 100644 index 00000000..780ce372 --- /dev/null +++ b/kview/kviewcanvas/kimageholder.h @@ -0,0 +1,105 @@ +/* This file is part of the KDE project + Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + 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-1301, USA. + +*/ +// $Id$ + +#ifndef _KIMAGEHOLDER_H +#define _KIMAGEHOLDER_H + +#include <qwidget.h> +class QRect; +class QPainter; +class QPen; +class QPixmap; +class KPixmap; +class QPoint; + +/** + * @short Image widget + * @version $Id$ + */ +class KImageHolder : public QWidget +{ + Q_OBJECT + public: + KImageHolder( QWidget *parent = 0, const char * name = 0 ); + + virtual ~KImageHolder(); + + void clearSelection(); + + void setImage( const KPixmap & ); + void setImage( const QImage & ); + void setImage( const QMovie & ); + + /** + * clears the ImageHolder + */ + void clear(); + + /** + * the selected rect + */ + QRect selection() const; + + QSize sizeHint() const; + + void setDrawRect( const QRect & rect ) { m_drawRect = rect; } + const QRect & drawRect() const { return m_drawRect; } + + signals: + void contextPress( const QPoint& ); + void selected( const QRect & ); + void wannaScroll( int dx, int dy ); + void cursorPos( const QPoint & ); + + protected: + void mousePressEvent( QMouseEvent * ); + void mouseMoveEvent( QMouseEvent * ); + void mouseReleaseEvent( QMouseEvent * ); + void paintEvent( QPaintEvent * ); + virtual void timerEvent( QTimerEvent * ); + + private: + void drawSelect( QPainter & ); + void eraseSelect(); + + void setPixmap( const KPixmap & ); + + private: + QRect m_selection; + QRect m_drawRect; + QPoint m_scrollpos; + QPoint m_selectionStartPoint; + + const KPixmap & checkboardPixmap(); + + bool m_selected; + bool m_bSelecting; + int m_scrollTimerId; + int m_xOffset, m_yOffset; + + QPen *m_pen; + + KPixmap * m_pPixmap; + KPixmap * m_pDoubleBuffer; + KPixmap * m_pCheckboardPixmap; +}; + +// vim:sw=4:ts=4 + +#endif // _KIMAGEHOLDER_H diff --git a/kview/kviewcanvas/kviewcanvas.desktop b/kview/kviewcanvas/kviewcanvas.desktop new file mode 100644 index 00000000..ecc7ddfd --- /dev/null +++ b/kview/kviewcanvas/kviewcanvas.desktop @@ -0,0 +1,63 @@ +[Desktop Entry] +Type=Service +Name=KView Image Viewer Widget +Name[af]=K-bekyk Beeld Aansig Gui-element +Name[ar]=كائن عارض الصور KView +Name[br]=Widget gweler skeudennoù KView +Name[bs]=KView predglednik slika - grafički element +Name[ca]=Estri visualitzador d'imatges KView +Name[cs]=Komponenta prohlížeče obrázků KView +Name[cy]=Celfigyn Gwelydd Delweddau KGweld +Name[da]=KView-billedviserkontrol +Name[de]=KView Bildanzeige-Bildschirmausschnitt +Name[el]=Γραφικό συστατικό προβολέα εικόνων του KView +Name[eo]=Bildrigardilo fenestro +Name[es]=Widget visor de imágenes de KView +Name[et]=KView pildifailide näitaja element +Name[eu]=KView irudi ikustailu botoia +Name[fa]=عنصر مشاهدهگر تصویر KView +Name[fi]=KView-kuviennäyttökomponentti +Name[fr]=Widget visualisateur d'images KView +Name[gl]=Complemento do visor de Imaxes KView +Name[he]=פריט מציג תמונות ל־KView +Name[hi]=के-व्यू छवि प्रदर्शक विजेट +Name[hr]=KView widget za pregled slika +Name[hu]=KView képnézegető grafikus elem +Name[is]=KView myndbirtigræja +Name[it]=Widget visore immagini KView +Name[ja]=KView 画像ビューアウィジェット +Name[kk]=KView кескінді көрсететін бөлшегі +Name[km]=ធាតុក្រាហ្វិកកម្មវិធីមើលរូបភាព KView +Name[lt]=KView paveikslėlių žiūriklio valdiklis +Name[ms]=Widget Pemapar Imej KView +Name[nb]=KView bilde-fremviserelement +Name[nds]=KView-Bildkiekrahmen +Name[ne]=केडीई दृश्य छवि दर्शक विजेट +Name[nl]=KView afbeeldingwidget +Name[nn]=KView biletvisarelement +Name[nso]=KView Widget ya Molebeledi wa Ponagalo +Name[pl]=Okienko przeglądarki obrazków KView +Name[pt]=Elemento de Visualização de Imagens do KView +Name[pt_BR]=Componente de Visualização de Imagens do KVisualização +Name[ro]=Widget vizualizare imagini KView +Name[ru]=Виджет с просмотром изображения KView +Name[se]=KView govvačájehanáhta +Name[sk]=Prvok prehliadača obrázkov KView +Name[sl]=Gradnik pregledovalnika slik KView +Name[sr]=KView, контрола за приказ слика +Name[sr@Latn]=KView, kontrola za prikaz slika +Name[sv]=Kview bildvisande komponent +Name[ta]=கேகாட்சி பிம்பக் காட்சி சாளரம் +Name[tg]=Виджет бо намоиши тасвироти KView +Name[tr]=KView Resim Görüntüleme Parçacığı +Name[uk]=Віджет переглядача зображень KView +Name[ven]=Tshishumiswa tsha vhuthogwa tsha muvhoni wa tshifanyiso tsha mbonalelo ya K +Name[wa]=Ahesse håyneu d' imådjes KView +Name[xh]=Widget Yombonisi Womfanekiso we KView +Name[zh_CN]=KView 图像查看器部件 +Name[zh_HK]=KView 圖像檢視器器件 +Name[zh_TW]=KView 影像檢視器界面工具 +Name[zu]=I-widget Yombukisi Wesithombe se-KView +X-KDE-Library=libkviewcanvas +InitialPreference=2 +ServiceTypes=KImageViewer/Canvas diff --git a/kview/kviewcanvas/test/Makefile.am b/kview/kviewcanvas/test/Makefile.am new file mode 100644 index 00000000..1fc3e92c --- /dev/null +++ b/kview/kviewcanvas/test/Makefile.am @@ -0,0 +1,9 @@ +INCLUDES = -I$(top_srcdir)/kview $(all_includes) + +METASOURCES = AUTO + +check_PROGRAMS = test + +test_SOURCES = main.cpp test.cpp +test_LDFLAGS = $(KDE_RPATH) $(all_libraries) +test_LDADD = $(LIB_KPARTS) $(top_builddir)/kview/kimageviewer/libkimageviewer.la diff --git a/kview/kviewcanvas/test/main.cpp b/kview/kviewcanvas/test/main.cpp new file mode 100644 index 00000000..360fdefd --- /dev/null +++ b/kview/kviewcanvas/test/main.cpp @@ -0,0 +1,51 @@ +#include "test.h" +#include <kapplication.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <klocale.h> + +static const char description[] = + I18N_NOOP("A KDE KPart Application"); + +static const char version[] = "v0.1"; + +static KCmdLineOptions options[] = +{ + { "+[URL]", I18N_NOOP( "Image to open" ), 0 }, + KCmdLineLastOption +}; + +int main(int argc, char **argv) +{ + KAboutData about("kimageviewertest", I18N_NOOP("KImageViewerTest"), version, description, KAboutData::License_GPL, "(C) 2001 Matthias Kretz", 0, 0, "kretz@kde.org"); + about.addAuthor( "Matthias Kretz", 0, "kretz@kde.org" ); + KCmdLineArgs::init(argc, argv, &about); + KCmdLineArgs::addCmdLineOptions( options ); + KApplication app; + + if (app.isRestored()) + RESTORE(KImageViewerTest) + else + { + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if ( args->count() == 0 ) + { + KImageViewerTest *widget = new KImageViewerTest; + widget->show(); + } + else + { + int i = 0; + for (; i < args->count(); i++ ) + { + KImageViewerTest *widget = new KImageViewerTest; + widget->show(); + widget->load( args->url( i ) ); + } + } + args->clear(); + } + + return app.exec(); +} diff --git a/kview/kviewcanvas/test/test.cpp b/kview/kviewcanvas/test/test.cpp new file mode 100644 index 00000000..8422f944 --- /dev/null +++ b/kview/kviewcanvas/test/test.cpp @@ -0,0 +1,46 @@ +/* + * kimageviewertest.cpp + * + * Copyright (c) 2001 Matthias Kretz <kretz@kde.org> + */ +#include "test.h" +#include <kimageviewer/canvas.h> + +#include <kurl.h> +#include <klibloader.h> +#include <kmessagebox.h> +#include <kparts/componentfactory.h> + +#include <qimage.h> + +KImageViewerTest::KImageViewerTest() + : KParts::MainWindow( 0L, "KImageViewerTest" ) +{ + QWidget * widget = KParts::ComponentFactory::createInstanceFromQuery<QWidget>( + "KImageViewer/Canvas", QString::null, this ); + if( widget ) + { + m_part = dynamic_cast<KImageViewer::Canvas *>( widget ); + setCentralWidget( widget ); + } + else + { + KMessageBox::error(this, "Could not find our Part!"); + kapp->quit(); + } +} + +KImageViewerTest::~KImageViewerTest() +{ +} + +void KImageViewerTest::load(const KURL& url) +{ + QImage image( url.fileName() ); + if( m_part ) + m_part->setImage( image ); + else + KMessageBox::error(this, "can't load the file"); +} + +#include "test.moc" diff --git a/kview/kviewcanvas/test/test.h b/kview/kviewcanvas/test/test.h new file mode 100644 index 00000000..b6a85188 --- /dev/null +++ b/kview/kviewcanvas/test/test.h @@ -0,0 +1,25 @@ +#ifndef KIMAGEVIEWERTEST_H +#define KIMAGEVIEWERTEST_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <kapplication.h> +#include <kparts/mainwindow.h> + +namespace KImageViewer { class Canvas; }; + +class KImageViewerTest : public KParts::MainWindow +{ + Q_OBJECT +public: + KImageViewerTest(); + virtual ~KImageViewerTest(); + void load(const KURL& url); + +private: + KImageViewer::Canvas *m_part; +}; + +#endif // KIMAGEVIEWERTEST_H |