From 4aed2c8219774f5d797760606b8489a92ddc5163 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kicker/libkicker/Makefile.am | 19 + kicker/libkicker/appletinfo.cpp | 112 ++++ kicker/libkicker/appletinfo.h | 92 ++++ kicker/libkicker/global.cpp | 477 ++++++++++++++++ kicker/libkicker/global.h | 112 ++++ kicker/libkicker/kickerSettings.kcfg | 342 ++++++++++++ kicker/libkicker/kickerSettings.kcfgc | 8 + kicker/libkicker/kickertip.cpp | 557 +++++++++++++++++++ kicker/libkicker/kickertip.h | 121 +++++ kicker/libkicker/kshadowengine.cpp | 251 +++++++++ kicker/libkicker/kshadowengine.h | 123 +++++ kicker/libkicker/kshadowsettings.cpp | 182 +++++++ kicker/libkicker/kshadowsettings.h | 236 ++++++++ kicker/libkicker/menuinfo.cpp | 68 +++ kicker/libkicker/menuinfo.h | 52 ++ kicker/libkicker/panelbutton.cpp | 985 ++++++++++++++++++++++++++++++++++ kicker/libkicker/panelbutton.h | 471 ++++++++++++++++ kicker/libkicker/paneldrag.cpp | 180 +++++++ kicker/libkicker/paneldrag.h | 68 +++ kicker/libkicker/panner.cpp | 396 ++++++++++++++ kicker/libkicker/panner.h | 115 ++++ kicker/libkicker/simplebutton.cpp | 258 +++++++++ kicker/libkicker/simplebutton.h | 89 +++ 23 files changed, 5314 insertions(+) create mode 100644 kicker/libkicker/Makefile.am create mode 100644 kicker/libkicker/appletinfo.cpp create mode 100644 kicker/libkicker/appletinfo.h create mode 100644 kicker/libkicker/global.cpp create mode 100644 kicker/libkicker/global.h create mode 100644 kicker/libkicker/kickerSettings.kcfg create mode 100644 kicker/libkicker/kickerSettings.kcfgc create mode 100644 kicker/libkicker/kickertip.cpp create mode 100644 kicker/libkicker/kickertip.h create mode 100644 kicker/libkicker/kshadowengine.cpp create mode 100644 kicker/libkicker/kshadowengine.h create mode 100644 kicker/libkicker/kshadowsettings.cpp create mode 100644 kicker/libkicker/kshadowsettings.h create mode 100644 kicker/libkicker/menuinfo.cpp create mode 100644 kicker/libkicker/menuinfo.h create mode 100644 kicker/libkicker/panelbutton.cpp create mode 100644 kicker/libkicker/panelbutton.h create mode 100644 kicker/libkicker/paneldrag.cpp create mode 100644 kicker/libkicker/paneldrag.h create mode 100644 kicker/libkicker/panner.cpp create mode 100644 kicker/libkicker/panner.h create mode 100644 kicker/libkicker/simplebutton.cpp create mode 100644 kicker/libkicker/simplebutton.h (limited to 'kicker/libkicker') diff --git a/kicker/libkicker/Makefile.am b/kicker/libkicker/Makefile.am new file mode 100644 index 000000000..5ec65be46 --- /dev/null +++ b/kicker/libkicker/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = $(all_includes) + +lib_LTLIBRARIES = libkickermain.la + +libkickermain_la_SOURCES = appletinfo.cpp global.cpp kickertip.cpp \ + menuinfo.cpp panelbutton.cpp panner.cpp \ + kickerSettings.kcfgc kshadowsettings.cpp \ + kshadowengine.cpp paneldrag.cpp \ + simplebutton.cpp + +libkickermain_la_METASOURCES = AUTO + +libkickermain_la_LDFLAGS = $(all_libraries) -version-info 1:0:0 -no-undefined +libkickermain_la_LIBADD = $(LIB_KIO) + +kde_kcfg_DATA = kickerSettings.kcfg + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/libkicker.pot diff --git a/kicker/libkicker/appletinfo.cpp b/kicker/libkicker/appletinfo.cpp new file mode 100644 index 000000000..cfb626fac --- /dev/null +++ b/kicker/libkicker/appletinfo.cpp @@ -0,0 +1,112 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include +#include +#include + +#include "appletinfo.h" + +AppletInfo::AppletInfo( const QString& deskFile, const QString& configFile, const AppletInfo::AppletType type) + : m_type (type), + m_unique(true), + m_hidden(false) +{ + QFileInfo fi(deskFile); + m_desktopFile = fi.fileName(); + + const char* resource = "applets"; + switch (type) + { + case Extension: + resource = "extensions"; + break; + case BuiltinButton: + resource = "builtinbuttons"; + break; + case SpecialButton: + resource = "specialbuttons"; + break; + case Undefined: + case Applet: + default: + break; + } + + KDesktopFile df(m_desktopFile, true, resource); + + // set the appletssimple attributes + setName(df.readName()); + setComment(df.readComment()); + setIcon(df.readIcon()); + + // library + setLibrary(df.readEntry("X-KDE-Library")); + + // is it a unique applet? + setIsUnique(df.readBoolEntry("X-KDE-UniqueApplet", false)); + + // should it be shown in the gui? + m_hidden = df.readBoolEntry("Hidden", false); + + if (configFile.isEmpty()) + { + // generate a config file base name from the library name + m_configFile = m_lib.lower(); + + if (m_unique) + { + m_configFile.append("rc"); + } + else + { + m_configFile.append("_") + .append(kapp->randomString(20).lower()) + .append("_rc"); + } + } + else + { + m_configFile = configFile; + } +} + +bool AppletInfo::operator!=( const AppletInfo& rhs) const +{ + return configFile() != rhs.configFile(); +} + +bool AppletInfo::operator<( const AppletInfo& rhs ) const +{ + return ( QString::localeAwareCompare( name(), rhs.name() ) < 0 ); +} + +bool AppletInfo::operator> ( const AppletInfo& rhs ) const +{ + return ( QString::localeAwareCompare( name(), rhs.name() ) > 0 ); +} + +bool AppletInfo::operator<= ( const AppletInfo& rhs ) const +{ + return ( QString::localeAwareCompare( name(), rhs.name() ) <= 0 ); +} diff --git a/kicker/libkicker/appletinfo.h b/kicker/libkicker/appletinfo.h new file mode 100644 index 000000000..b9ab187ba --- /dev/null +++ b/kicker/libkicker/appletinfo.h @@ -0,0 +1,92 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __appletinfo_h__ +#define __appletinfo_h__ + +#include +#include +#include +#include + +#include + +class KDE_EXPORT AppletInfo +{ + public: + typedef QValueVector List; + typedef QMap Dict; + + enum AppletType { Undefined = 0, + Applet = 1, + BuiltinButton = 2, + SpecialButton = 4, + Extension = 8, + Button = BuiltinButton | SpecialButton }; + + AppletInfo(const QString& desktopFile = QString::null, + const QString& configFile = QString::null, + const AppletType type = Undefined); + + QString name() const { return m_name; } + QString comment() const { return m_comment; } + QString icon() const { return m_icon; } + + AppletType type() const { return m_type; } + + QString library() const { return m_lib; } + QString desktopFile() const { return m_desktopFile; } + QString configFile() const { return m_configFile; } + + bool isUniqueApplet() const { return m_unique; } + bool isHidden() const { return m_hidden; } + + void setConfigFile(QString cf) { m_configFile = cf; } + + bool operator<(const AppletInfo& rhs) const; + bool operator>(const AppletInfo& rhs) const; + bool operator<=(const AppletInfo& rhs) const; + bool operator!=(const AppletInfo& rhs) const; + + void setType(AppletType type) { m_type = type; } + + protected: + void setName(QString name) { m_name = name; } + void setComment(QString comment) { m_comment = comment; } + void setIcon(QString icon) { m_icon = icon; } + void setLibrary(QString lib) { m_lib = lib; } + void setIsUnique(bool u) { m_unique = u; } + + private: + QString m_name; + QString m_comment; + QString m_icon; + QString m_lib; + QString m_desktopFile; + QString m_configFile; + AppletType m_type; + bool m_unique; + bool m_hidden; +}; + +#endif diff --git a/kicker/libkicker/global.cpp b/kicker/libkicker/global.cpp new file mode 100644 index 000000000..1f393616d --- /dev/null +++ b/kicker/libkicker/global.cpp @@ -0,0 +1,477 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "global.h" +#include "kickerSettings.h" + +namespace KickerLib +{ + +KPanelExtension::Position directionToPosition(KPanelApplet::Direction d ) +{ + switch (d) + { + case KPanelApplet::Down: + return KPanelExtension::Top; + break; + + case KPanelApplet::Left: + return KPanelExtension::Right; + break; + + case KPanelApplet::Right: + return KPanelExtension::Left; + break; + + case KPanelApplet::Up: + default: + return KPanelExtension::Bottom; + break; + } +} + +KPanelExtension::Position directionToPopupPosition(KPanelApplet::Direction d) +{ + switch (d) + { + case KPanelApplet::Up: + return KPanelExtension::Top; + break; + + case KPanelApplet::Down: + return KPanelExtension::Bottom; + break; + + case KPanelApplet::Left: + return KPanelExtension::Left; + break; + + case KPanelApplet::Right: + default: + return KPanelExtension::Right; + break; + } +} + +KPanelApplet::Direction positionToDirection(KPanelExtension::Position p) +{ + switch (p) + { + case KPanelExtension::Top: + return KPanelApplet::Down; + break; + + case KPanelExtension::Right: + return KPanelApplet::Left; + break; + + case KPanelExtension::Left: + return KPanelApplet::Right; + break; + + case KPanelExtension::Bottom: + default: + return KPanelApplet::Up; + break; + } +} + +KPanelApplet::Direction arrowToDirection(Qt::ArrowType p) +{ + switch (p) + { + case Qt::DownArrow: + return KPanelApplet::Down; + break; + + case Qt::LeftArrow: + return KPanelApplet::Left; + break; + + case Qt::RightArrow: + return KPanelApplet::Right; + break; + + case Qt::UpArrow: + default: + return KPanelApplet::Up; + break; + } +} + +int sizeValue(KPanelExtension::Size s) +{ + switch (s) + { + case KPanelExtension::SizeTiny: + return 24; + break; + + case KPanelExtension::SizeSmall: + return 30; + break; + + case KPanelExtension::SizeNormal: + return 46; + break; + + case KPanelExtension::SizeLarge: + default: + return 58; + break; + } +} + +int maxButtonDim() +{ + return (2 * KickerSettings::iconMargin()) + KIcon::SizeLarge; +} + +QString newDesktopFile(const KURL& url) +{ + QString base = url.fileName(); + if (base.endsWith(".desktop")) + base.truncate(base.length()-8); + QRegExp r("(.*)(?=-\\d+)"); + if (r.search(base) > -1) + base = r.cap(1); + + QString file = base + ".desktop"; + + for(int n = 1; ++n; ) + { + QString path = locate("appdata", file); + if (path.isEmpty()) + break; + + file = QString("%2-%1.desktop").arg(n).arg(base); + } + file = locateLocal("appdata", file); + return file; +} + +QString copyDesktopFile(const KURL& url) +{ + QString file = newDesktopFile(url); + KURL dest; + dest.setPath(file); + KIO::NetAccess::upload(url.path(), dest, 0); + return file; +} + +QPopupMenu* reduceMenu(QPopupMenu *menu) +{ + if (menu->count() != 1) + { + return menu; + } + + QMenuItem *item = menu->findItem(menu->idAt(0)); + + if (item->popup()) + { + return reduceMenu(item->popup()); + } + + return menu; +} + +QPoint popupPosition(KPanelApplet::Direction d, + const QWidget* popup, + const QWidget* source, + const QPoint& offset) +{ + QRect r; + if (source->isTopLevel()) + { + r = source->geometry(); + } + else + { + r = QRect(source->mapToGlobal(QPoint(0, 0)), + source->mapToGlobal(QPoint(source->width(), source->height()))); + + switch (d) + { + case KPanelApplet::Left: + case KPanelApplet::Right: + r.setLeft( source->topLevelWidget()->x() ); + r.setWidth( source->topLevelWidget()->width() ); + break; + case KPanelApplet::Up: + case KPanelApplet::Down: + r.setTop( source->topLevelWidget()->y() ); + r.setHeight( source->topLevelWidget()->height() ); + break; + } + } + + switch (d) + { + case KPanelApplet::Left: + case KPanelApplet::Right: + { + QDesktopWidget* desktop = QApplication::desktop(); + QRect screen = desktop->screenGeometry(desktop->screenNumber(const_cast(source))); + int x = (d == KPanelApplet::Left) ? r.left() - popup->width() : + r.right() + 1; + int y = r.top() + offset.y(); + + // try to keep this on screen + if (y + popup->height() > screen.bottom()) + { + y = r.bottom() - popup->height() + offset.y(); + + if (y < screen.top()) + { + y = screen.bottom() - popup->height(); + + if (y < screen.top()) + { + y = screen.top(); + } + } + } + + return QPoint(x, y); + } + case KPanelApplet::Up: + case KPanelApplet::Down: + default: + { + int x = 0; + int y = (d == KPanelApplet::Up) ? r.top() - popup->height() : + r.bottom() + 1; + + if (QApplication::reverseLayout()) + { + x = r.right() - popup->width() + 1; + + if (offset.x() > 0) + { + x -= r.width() - offset.x(); + } + + // try to keep this on the screen + if (x - popup->width() < 0) + { + x = r.left(); + } + + return QPoint(x, y); + } + else + { + QDesktopWidget* desktop = QApplication::desktop(); + QRect screen = desktop->screenGeometry(desktop->screenNumber(const_cast(source))); + x = r.left() + offset.x(); + + // try to keep this on the screen + if (x + popup->width() > screen.right()) + { + x = r.right() - popup->width() + 1 + offset.x(); + + if (x < screen.left()) + { + x = screen.left(); + } + } + } + + return QPoint(x, y); + } + } +} + +void colorize(QImage& image) +{ + KConfig *config = KGlobal::config(); + config->setGroup("WM"); + QColor color = QApplication::palette().active().highlight(); + QColor activeTitle = config->readColorEntry("activeBackground", &color); + QColor inactiveTitle = config->readColorEntry("inactiveBackground", &color); + + // figure out which color is most suitable for recoloring to + int h1, s1, v1, h2, s2, v2, h3, s3, v3; + activeTitle.hsv(&h1, &s1, &v1); + inactiveTitle.hsv(&h2, &s2, &v2); + QApplication::palette().active().background().hsv(&h3, &s3, &v3); + + if ( (kAbs(h1-h3)+kAbs(s1-s3)+kAbs(v1-v3) < kAbs(h2-h3)+kAbs(s2-s3)+kAbs(v2-v3)) && + ((kAbs(h1-h3)+kAbs(s1-s3)+kAbs(v1-v3) < 32) || (s1 < 32)) && (s2 > s1)) + color = inactiveTitle; + else + color = activeTitle; + + // limit max/min brightness + int r, g, b; + color.rgb(&r, &g, &b); + int gray = qGray(r, g, b); + if (gray > 180) { + r = (r - (gray - 180) < 0 ? 0 : r - (gray - 180)); + g = (g - (gray - 180) < 0 ? 0 : g - (gray - 180)); + b = (b - (gray - 180) < 0 ? 0 : b - (gray - 180)); + } else if (gray < 76) { + r = (r + (76 - gray) > 255 ? 255 : r + (76 - gray)); + g = (g + (76 - gray) > 255 ? 255 : g + (76 - gray)); + b = (b + (76 - gray) > 255 ? 255 : b + (76 - gray)); + } + color.setRgb(r, g, b); + KIconEffect::colorize(image, color, 1.0); +} + +QColor blendColors(const QColor& c1, const QColor& c2) +{ + int r1, g1, b1; + int r2, g2, b2; + + c1.rgb(&r1, &g1, &b1); + c2.rgb(&r2, &g2, &b2); + + r1 += (int) (.5 * (r2 - r1)); + g1 += (int) (.5 * (g2 - g1)); + b1 += (int) (.5 * (b2 - b1)); + + return QColor(r1, g1, b1); +} + +QColor shadowColor(const QColor& c) +{ + int r = c.red(); + int g = c.green(); + int b = c.blue(); + + if ( r < 128 ) + r = 255; + else + r = 0; + + if ( g < 128 ) + g = 255; + else + g = 0; + + if ( b < 128 ) + b = 255; + else + b = 0; + + return QColor( r, g, b ); +} + +QIconSet menuIconSet(const QString& icon) +{ + QIconSet iconset; + int iconSize = KickerSettings::menuEntryHeight(); + + if (iconSize < 0) + { + return iconset; + } + + if (icon != "unknown") + { + if (iconSize > 0) + { + iconset = KGlobal::iconLoader()->loadIconSet(icon, + KIcon::NoGroup, + iconSize, true); + } + else if (iconSize == 0) + { + QPixmap normal = KGlobal::iconLoader()->loadIcon(icon, + KIcon::Small, + 0, + KIcon::DefaultState, + 0, + true); + + QPixmap active = KGlobal::iconLoader()->loadIcon(icon, + KIcon::Small, + 0, + KIcon::ActiveState, + 0, + true); + + // make sure they are not larger than 20x20 + if (normal.width() > 20 || normal.height() > 20) + { + normal.convertFromImage(normal.convertToImage().smoothScale(20,20)); + } + + if (active.width() > 20 || active.height() > 20) + { + active.convertFromImage(active.convertToImage().smoothScale(20,20)); + } + + iconset.setPixmap(normal, QIconSet::Small, QIconSet::Normal); + iconset.setPixmap(active, QIconSet::Small, QIconSet::Active); + } + } + + if (iconset.isNull()) + { + QPixmap pix(iconSize, iconSize); + QBitmap map(iconSize, iconSize, true); + pix.setMask(map); + iconset = QIconSet(pix, pix); + } + + return iconset; +} + +void drawBlendedRect(QPainter *p, const QRect &r, const QColor &color, int alpha) +{ + static QPixmap pix; + static QColor last_color = Qt::black; + static int last_alpha = 0; + + if (pix.isNull() || last_color != color || last_alpha != alpha) + { + QImage img(16, 16, 32); + img.setAlphaBuffer(false); + img.fill(((uint)(alpha & 0xFF) << 24) | (color.rgb() & 0xFFFFFF)); + img.setAlphaBuffer(true); + pix.convertFromImage(img); + last_color = color; + last_alpha = alpha; + } + + p->drawTiledPixmap(r, pix); +} + +} // namespace + diff --git a/kicker/libkicker/global.h b/kicker/libkicker/global.h new file mode 100644 index 000000000..2b9449584 --- /dev/null +++ b/kicker/libkicker/global.h @@ -0,0 +1,112 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __pglobal_h__ +#define __pglobal_h__ + +#include +#include + +#include +#include +#include + +namespace KickerLib +{ + +/* + * Functions to convert between various enums + */ +KDE_EXPORT KPanelExtension::Position directionToPosition(KPanelApplet::Direction d); +KDE_EXPORT KPanelExtension::Position directionToPopupPosition(KPanelApplet::Direction d); +KDE_EXPORT KPanelApplet::Direction positionToDirection(KPanelExtension::Position p); +KDE_EXPORT KPanelApplet::Direction arrowToDirection(Qt::ArrowType p); +KDE_EXPORT int sizeValue(KPanelExtension::Size s); + +/** + * Pixel sizes for but sizes and margins + */ +KDE_EXPORT int maxButtonDim(); + +/** + * Tint the image to reflect the current color scheme + * Used, for instance, by KMenu side bar + */ +KDE_EXPORT void colorize(QImage& image); + +/** + * Blend a color rectangle on a painter + */ +KDE_EXPORT void drawBlendedRect(QPainter *p, const QRect &r, const QColor &color = Qt::black, int alpha = 0x40); + +/** + * Blend two colours together to get a colour halfway in between + */ +KDE_EXPORT QColor blendColors(const QColor& c1, const QColor& c2); + +/** + * Create or copy .desktop files for use in kicker safely and easily + */ +KDE_EXPORT QString copyDesktopFile(const KURL&url); +KDE_EXPORT QString newDesktopFile(const KURL&url); + + +/** + * Reduces a popup menu + * + * When a popup menu contains only 1 sub-menu, it makes no sense to + * show this popup-menu but we better show the sub-menu directly. + * + * This function checks whether that is the case and returns either the + * original menu or the sub-menu when appropriate. + */ +KDE_EXPORT QPopupMenu *reduceMenu(QPopupMenu *); + + +/** + * Calculate the appropriate position for a popup menu based on the + * direction, the size of the menu, the widget geometry, and a optional + * point in the local coordinates of the widget. + */ +KDE_EXPORT QPoint popupPosition(KPanelApplet::Direction d, + const QWidget* popup, + const QWidget* source, + const QPoint& offset = QPoint(0, 0)); + +/** + * Calculate an acceptable inverse of the given color wich will be used + * as the shadow color. + */ +KDE_EXPORT QColor shadowColor(const QColor& c); + +/** + * Get an appropriate for a menu in Plasma. As the user may set this size + * globally, it is important to always use this method. + * @param icon the name of icon requested + * @return the icon set for the requested icon + */ +KDE_EXPORT QIconSet menuIconSet(const QString& icon); + +} + +#endif // __pglobal_h__ diff --git a/kicker/libkicker/kickerSettings.kcfg b/kicker/libkicker/kickerSettings.kcfg new file mode 100644 index 000000000..42f02bcad --- /dev/null +++ b/kicker/libkicker/kickerSettings.kcfg @@ -0,0 +1,342 @@ + + + +kapplication.h +klocale.h + + + + + + + false + + + + + true + + + + + When this option is enabled, the panel will become pseudo-transparent + false + + + + + When this option is enabled, the panel containing the menubar will become pseudo-transparent as well + false + + + + + When this option is enabled, the panel will display a tiled image as its background + true + + + + + false + + + + + When this option is enabled, when the panel is placed on the side or top edges of the screen, the background image will be rotated to match the panel's orientation + true + + + + + Here you can choose an image to be displayed on the panel. Press the 'browse' button to choose a theme using the file dialog. This option is only effective if 'Enable background image' is selected + wallpapers/default.png + + + + + 33 + 0 + 100 + + + + + (QApplication::palette().active().mid()) + This option sets the color to use when tinting transparent panels + + + + + 0 + + + + + true + Select this option to make applet handles only visible on mouse hover. Applet handles let you move, remove and configure applets. + + + + + false + Select this option to always hide the applet handles. Beware this could disable moving, removing or configuring some applets. + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DescriptionAndName + + + + + + true + + + + + 0 + + + + + false + + + + + 30 + 1 + + + + + false + + + + + false + + + + + prefmenu.desktop,systemmenu.desktop + + + + + + + + + 5 + 100 + + + + + false + + + + + + + + + false + + + + + false + + + + + false + + + + + false + + + + + false + + + + + + + + + QColor() + + + + + + + + + QColor() + + + + + + + + + QColor() + + + + + + + + + QColor() + + + + + + + + + QColor() + + + + + + + + + true + + + + + kside.png + + + + + kside_tile.png + + + + + false + + + + + i18n("Applications") + + + + + + + + + true + + + + + true + + + + + true + + + + + 500 + 0 + + + + + 500 + + + + + 200 + + + + + false + + + + + 3 + + + + + true + + + + + KGlobalSettings::generalFont() + + + + + KGlobalSettings::textColor() + + + + + + + diff --git a/kicker/libkicker/kickerSettings.kcfgc b/kicker/libkicker/kickerSettings.kcfgc new file mode 100644 index 000000000..59c271928 --- /dev/null +++ b/kicker/libkicker/kickerSettings.kcfgc @@ -0,0 +1,8 @@ +File=kickerSettings.kcfg +Singleton=true +ClassName=KickerSettings +Mutators=true +Visibility=KDE_EXPORT +IncludeFiles=qapplication.h +GlobalEnums=true +MemberVariables=dpointer diff --git a/kicker/libkicker/kickertip.cpp b/kicker/libkicker/kickertip.cpp new file mode 100644 index 000000000..403641443 --- /dev/null +++ b/kicker/libkicker/kickertip.cpp @@ -0,0 +1,557 @@ +/***************************************************************** + +Copyright (c) 2004 Zack Rusin + Sami Kyostil + Aaron J. Seigo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include +#include +#include +#include +#include + +#include + +#include "global.h" + +#include "kickertip.h" +#include "kickerSettings.h" + +// putting this #include higher results in compile errors +#include + +static const int DEFAULT_FRAMES_PER_SECOND = 30; + +KickerTip* KickerTip::m_self = 0; +int KickerTip::m_tippingEnabled = 1; + +void KickerTip::Client::updateKickerTip() const +{ + if (KickerTip::the()->isTippingFor(dynamic_cast(this)) && + KickerTip::the()->isVisible()) + { + KickerTip::the()->display(); + } +} + +KickerTip* KickerTip::the() +{ + if (!m_self) + { + m_self = new KickerTip(0); + } + + return m_self; +} + +KickerTip::KickerTip(QWidget * parent) + : QWidget(parent, "animtt",WX11BypassWM), + m_richText(0), + m_mimeFactory(0), + m_dissolveSize(0), + m_dissolveDelta(-1), + m_direction(KPanelApplet::Up), + m_dirty(false), + m_toolTipsEnabled(KickerSettings::showToolTips()), + m_tippingFor(0) +{ + setFocusPolicy(NoFocus); + setBackgroundMode(NoBackground); + resize(0, 0); + hide(); + connect(&m_frameTimer, SIGNAL(timeout()), SLOT(internalUpdate())); +} + +KickerTip::~KickerTip() +{ + delete m_richText; + delete m_mimeFactory; +} + +void KickerTip::display() +{ + if (!tippingEnabled()) + { + return; + } + + { + // prevent tips from showing when the active window is fullscreened + NETRootInfo ri(qt_xdisplay(), NET::ActiveWindow); + NETWinInfo wi(qt_xdisplay(), ri.activeWindow(), ri.rootWindow(), NET::WMState); + if (wi.state() & NET::FullScreen) + { + return; + } + } + + QWidget *widget = const_cast(m_tippingFor); + KickerTip::Client *client = dynamic_cast(widget); + + if (!client) + { + return; + } + + // delete the mimefactory and create a new one so any old pixmaps used in the + // richtext area are freed but the mimefactory is ready to be added to in + // the call to updateKickerTip + delete m_mimeFactory; + m_mimeFactory = new QMimeSourceFactory(); + + // Declare interchange object and define defaults. + Data data; + data.maskEffect = Dissolve; + data.duration = 2000; + data.direction = KPanelApplet::Up; + data.mimeFactory = m_mimeFactory; + + // Tickle the information out of the bastard. + client->updateKickerTip(data); + + // Hide the tip if there is nothing to show + if (data.message.isEmpty() && data.subtext.isEmpty() && data.icon.isNull()) + { + hide(); + return; + } + + delete m_richText; + m_richText = new QSimpleRichText("

" + data.message + "

" + + data.subtext + "

", font(), QString::null, 0, + m_mimeFactory); + m_richText->setWidth(640); + m_direction = data.direction; + + if (KickerSettings::mouseOversShowIcon()) + { + m_icon = data.icon; + } + else if (KickerSettings::mouseOversShowText()) + { + m_icon = QPixmap(); + } + else + { + // don't bother since we have NOTHING to show + return; + } + + m_maskEffect = isVisible() ? Plain : data.maskEffect; + m_dissolveSize = 24; + m_dissolveDelta = -1; + + displayInternal(); + + m_frameTimer.start(1000 / DEFAULT_FRAMES_PER_SECOND); + + // close the message window after given mS + if (data.duration > 0) + { + disconnect(&m_timer, SIGNAL(timeout()), 0, 0); + connect(&m_timer, SIGNAL(timeout()), SLOT(hide())); + m_timer.start(data.duration, true); + } + else + { + m_timer.stop(); + } + + move(KickerLib::popupPosition(m_direction, this, m_tippingFor)); + show(); +} + +void KickerTip::paintEvent(QPaintEvent * e) +{ + if (m_dirty) + { + displayInternal(); + m_dirty = false; + } + + QPainter p(this); + p.drawPixmap(e->rect().topLeft(), m_pixmap, e->rect()); +} + +void KickerTip::mousePressEvent(QMouseEvent * /*e*/) +{ + QToolTip::setGloballyEnabled(m_toolTipsEnabled); + hide(); +} + +static void drawRoundRect(QPainter &p, const QRect &r) +{ + static int line[8] = { 1, 3, 4, 5, 6, 7, 7, 8 }; + static int border[8] = { 1, 2, 1, 1, 1, 1, 1, 1 }; + int xl, xr, y1, y2; + QPen pen = p.pen(); + bool drawBorder = pen.style() != QPen::NoPen; + + if (r.width() < 16 || r.height() < 16) + { + p.drawRect(r); + return; + } + + p.fillRect(r.x(), r.y() + 8, r.width(), r.height() - 16, p.brush()); + p.fillRect(r.x() + 8, r.y(), r.width() - 16, r.height(), p.brush()); + + p.setPen(p.brush().color()); + + for (int i = 0; i < 8; i++) + { + xl = i; + xr = r.width() - i - 1; + y1 = 7; + y2 = 7 - (line[i] - 1); + + p.drawLine(xl, y1, xl, y2); + p.drawLine(xr, y1, xr, y2); + + y1 = r.height() - y1 - 1; + y2 = r.height() - y2 - 1; + + p.drawLine(xl, y1, xl, y2); + p.drawLine(xr, y1, xr, y2); + + } + + if (drawBorder) + { + p.setPen(pen); + + if (r.height() > 16) + { + p.drawLine(r.x(), r.y() + 8, r.x(), r.y() + r.height() - 9); + p.drawLine(r.x() + r.width() - 1, r.y() + 8, r.x() + r.width() - 1, r.y() + r.height() - 9); + } + if (r.width() > 16) + { + p.drawLine(r.x() + 8, r.y(), r.x() + r.width() - 9, r.y()); + p.drawLine(r.x() + 8, r.y() + r.height() - 1, r.x() + r.width() - 9, r.y() + r.height() - 1); + } + + for (int i = 0; i < 8; i++) + { + xl = i; + xr = r.width() - i - 1; + y2 = 7 - (line[i] - 1); + y1 = y2 + (border[i] - 1); + + p.drawLine(xl, y1, xl, y2); + p.drawLine(xr, y1, xr, y2); + + y1 = r.height() - y1 - 1; + y2 = r.height() - y2 - 1; + + p.drawLine(xl, y1, xl, y2); + p.drawLine(xr, y1, xr, y2); + + } + } +} + +void KickerTip::plainMask() +{ + QPainter maskPainter(&m_mask); + + m_mask.fill(Qt::black); + + maskPainter.setBrush(Qt::white); + maskPainter.setPen(Qt::NoPen); + //maskPainter.drawRoundRect(m_mask.rect(), 1600 / m_mask.rect().width(), 1600 / m_mask.rect().height()); + drawRoundRect(maskPainter, m_mask.rect()); + setMask(m_mask); + m_frameTimer.stop(); +} + +void KickerTip::dissolveMask() +{ + QPainter maskPainter(&m_mask); + + m_mask.fill(Qt::black); + + maskPainter.setBrush(Qt::white); + maskPainter.setPen(Qt::NoPen); + //maskPainter.drawRoundRect(m_mask.rect(), 1600 / m_mask.rect().width(), 1600 / m_mask.rect().height()); + drawRoundRect(maskPainter, m_mask.rect()); + + m_dissolveSize += m_dissolveDelta; + + if (m_dissolveSize > 0) + { + maskPainter.setRasterOp(Qt::EraseROP); + + int x, y, s; + const int size = 16; + + for (y = 0; y < height() + size; y += size) + { + x = width(); + s = 4 * m_dissolveSize * x / 128; + for (; x > -size; x -= size, s -= 2) + { + if (s < 0) + { + break; + } + maskPainter.drawEllipse(x - s / 2, y - s / 2, s, s); + } + } + } + else if (m_dissolveSize < 0) + { + m_frameTimer.stop(); + m_dissolveDelta = 1; + } + + setMask(m_mask); +} + +void KickerTip::displayInternal() +{ + // we need to check for m_tippingFor here as well as m_richText + // since if one is really persistant and moves the mouse around very fast + // you can trigger a situation where m_tippingFor gets reset to 0 but + // before display() is called! + if (!m_tippingFor || !m_richText) + { + return; + } + + // determine text rectangle + QRect textRect(0, 0, 0, 0); + if (KickerSettings::mouseOversShowText()) + { + textRect.setWidth(m_richText->widthUsed()); + textRect.setHeight(m_richText->height()); + } + + int margin = KDialog::marginHint(); + int height = QMAX(m_icon.height(), textRect.height()) + 2 * margin; + int textX = m_icon.isNull() ? margin : 2 + m_icon.width() + 2 * margin; + int width = textX + textRect.width() + margin; + int textY = (height - textRect.height()) / 2; + + // resize pixmap, mask and widget + bool firstTime = m_dissolveSize == 24; + if (firstTime) + { + m_mask.resize(width, height); + m_pixmap.resize(width, height); + resize(width, height); + if (isVisible()) + { + // we've already been shown before, but we may grow larger. + // in the case of Up or Right displaying tips, this growth can + // result in the tip occluding the panel and causing it to redraw + // once we return back to display() causing horrid flicker + move(KickerLib::popupPosition(m_direction, this, m_tippingFor)); + } + } + + // create and set transparency mask + switch(m_maskEffect) + { + case Plain: + plainMask(); + break; + + case Dissolve: + dissolveMask(); + break; + } + + // draw background + QPainter bufferPainter(&m_pixmap); + bufferPainter.setPen(colorGroup().foreground()); + bufferPainter.setBrush(colorGroup().background()); + //bufferPainter.drawRoundRect(0, 0, width, height, 1600 / width, 1600 / height); + drawRoundRect(bufferPainter, QRect(0, 0, width, height)); + + // draw icon if present + if (!m_icon.isNull()) + { + bufferPainter.drawPixmap(margin, + margin, + m_icon, 0, 0, + m_icon.width(), m_icon.height()); + } + + if (KickerSettings::mouseOversShowText()) + { + // draw text shadow + QColorGroup cg = colorGroup(); + cg.setColor(QColorGroup::Text, cg.background().dark(115)); + int shadowOffset = QApplication::reverseLayout() ? -1 : 1; + m_richText->draw(&bufferPainter, textX + shadowOffset, textY + 1, QRect(), cg); + + // draw text + cg = colorGroup(); + m_richText->draw(&bufferPainter, textX, textY, rect(), cg); + } +} + +void KickerTip::tipFor(const QWidget* w) +{ + if (m_tippingFor) + { + disconnect(m_tippingFor, SIGNAL(destroyed(QObject*)), + this, SLOT(tipperDestroyed(QObject*))); + } + + m_tippingFor = w; + + if (m_tippingFor) + { + connect(m_tippingFor, SIGNAL(destroyed(QObject*)), + this, SLOT(tipperDestroyed(QObject*))); + } +} + +void KickerTip::untipFor(const QWidget* w) +{ + if (isTippingFor(w)) + hide(); +} + +bool KickerTip::isTippingFor(const QWidget* w) const +{ + return m_tippingFor == w; +} + +void KickerTip::tipperDestroyed(QObject* o) +{ + // we can't do a dynamic cast because we are in the process of dieing + // so static it is. + untipFor(static_cast(o)); +} + +void KickerTip::internalUpdate() +{ + m_dirty = true; + repaint(false); +} + +void KickerTip::enableTipping(bool tip) +{ + if (tip) + { + m_tippingEnabled++; + } + else + { + m_tippingEnabled--; + } + + if (m_tippingEnabled < 1 && m_self) + { + m_self->hide(); + } +} + +bool KickerTip::tippingEnabled() +{ + return m_tippingEnabled > 0; +} + +void KickerTip::hide() +{ + tipFor(0); + m_timer.stop(); + m_frameTimer.stop(); + QWidget::hide(); +} + +bool KickerTip::eventFilter(QObject *object, QEvent *event) +{ + if (!tippingEnabled()) + { + return false; + } + + if (!object->isWidgetType()) + { + return false; + } + + QWidget *widget = static_cast(object); + + switch (event->type()) + { + case QEvent::Enter: + if (!KickerSettings::showMouseOverEffects()) + { + return false; + } + + if (!mouseGrabber() && + !qApp->activePopupWidget() && + !isTippingFor(widget)) + { + m_toolTipsEnabled = QToolTip::isGloballyEnabled(); + QToolTip::setGloballyEnabled(false); + + tipFor(widget); + m_timer.stop(); + disconnect(&m_timer, SIGNAL(timeout()), 0, 0); + connect(&m_timer, SIGNAL(timeout()), SLOT(display())); + + // delay to avoid false starts + // e.g. when the user quickly zooms their mouse over + // a button then out of kicker + if (isVisible()) + { + m_timer.start(150, true); + } + else + { + m_timer.start(KickerSettings::mouseOversShowDelay(), true); + } + } + break; + case QEvent::Leave: + QToolTip::setGloballyEnabled(m_toolTipsEnabled); + + m_timer.stop(); + + if (isTippingFor(widget) && isVisible()) + { + disconnect(&m_timer, SIGNAL(timeout()), 0, 0); + connect(&m_timer, SIGNAL(timeout()), SLOT(hide())); + m_timer.start(KickerSettings::mouseOversHideDelay(), true); + } + + tipFor(0); + break; + case QEvent::MouseButtonPress: + QToolTip::setGloballyEnabled(m_toolTipsEnabled); + hide(); + default: + break; + } + + return false; +} + +#include + diff --git a/kicker/libkicker/kickertip.h b/kicker/libkicker/kickertip.h new file mode 100644 index 000000000..7211012fb --- /dev/null +++ b/kicker/libkicker/kickertip.h @@ -0,0 +1,121 @@ +/***************************************************************** + +Copyright (c) 2004 Zack Rusin + Sami Kyostil + Aaron J. Seigo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef KICKER_TIP_H +#define KICKER_TIP_H + +#include +#include +#include +#include + +#include + +class QMimeSourceFactory; +class QPaintEvent; +class QSimpleRichText; +class QTimer; + +class KDE_EXPORT KickerTip : public QWidget +{ + Q_OBJECT + +public: + enum MaskEffect { Plain, Dissolve }; + + struct Data + { + QString message; + QString subtext; + QPixmap icon; + KickerTip::MaskEffect maskEffect; + int duration; + KPanelApplet::Direction direction; + + // do NOT delete this in the client! + QMimeSourceFactory* mimeFactory; + }; + + class KDE_EXPORT Client + { + public: + virtual void updateKickerTip(KickerTip::Data&) = 0; + void updateKickerTip() const; + }; + + static KickerTip* the(); + static void enableTipping(bool tip); + static bool tippingEnabled(); + + void untipFor(const QWidget* w); + bool eventFilter(QObject *o, QEvent *e); + +protected: + KickerTip(QWidget * parent); + ~KickerTip(); + + void paintEvent(QPaintEvent * e); + void mousePressEvent(QMouseEvent * e); + + void plainMask(); + void dissolveMask(); + + void displayInternal(); + void hide(); + + void tipFor(const QWidget* w); + bool isTippingFor(const QWidget* w) const; + +protected slots: + void tipperDestroyed(QObject* o); + void internalUpdate(); + void display(); + +private: + QBitmap m_mask; + QPixmap m_pixmap; + QPixmap m_icon; + MaskEffect m_maskEffect; + QSimpleRichText* m_richText; + QMimeSourceFactory* m_mimeFactory; + + int m_dissolveSize; + int m_dissolveDelta; + KPanelApplet::Direction m_direction; + + QTimer m_timer; + QTimer m_frameTimer; + bool m_dirty; + bool m_toolTipsEnabled; + + const QWidget* m_tippingFor; + + static KickerTip* m_self; + static int m_tippingEnabled; + + friend class KickerTip::Client; +}; + +#endif diff --git a/kicker/libkicker/kshadowengine.cpp b/kicker/libkicker/kshadowengine.cpp new file mode 100644 index 000000000..32008883e --- /dev/null +++ b/kicker/libkicker/kshadowengine.cpp @@ -0,0 +1,251 @@ +/* This file is proposed to be part of the KDE libraries. + * Copyright (C) 2003 Laur Ivan + * + * Many thanks to: + * - Bernardo Hung for the enhanced shadow + * algorithm (currently used) + * - Tim Jansen for the API updates and fixes. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include "kshadowsettings.h" +#include "kshadowengine.h" + +KShadowEngine::KShadowEngine() : + m_shadowSettings( new KShadowSettings ) +{ +} + +KShadowEngine::~KShadowEngine() +{ + delete m_shadowSettings; +} + +KShadowEngine::KShadowEngine(KShadowSettings *fx) : + m_shadowSettings(0L) +{ + setShadowSettings(fx); +} + + +void KShadowEngine::setShadowSettings(KShadowSettings *fx) +{ + delete m_shadowSettings; + + m_shadowSettings = fx; +} + +KShadowSettings *KShadowEngine::shadowSettings() +{ + return m_shadowSettings; +} + +QImage KShadowEngine::makeShadow(const QPixmap& textPixmap, const QColor &bgColor) +{ + QImage result; + + // create a new image for for the shaddow + int w = textPixmap.width(); + int h = textPixmap.height(); + + // avoid calling these methods for every pixel + int bgRed = bgColor.red(); + int bgGreen = bgColor.green(); + int bgBlue = bgColor.blue(); + + int thick = m_shadowSettings->thickness() >> 1; + + double alphaShadow; + + /* + * This is the source pixmap + */ + QImage img = textPixmap.convertToImage().convertDepth(32); + + /* + * Resize the image if necessary + */ + if ((result.width() != w) || (result.height() != h)) + { + result.create(w, h, 32); + } + + result.fill(0); // all black + result.setAlphaBuffer(true); + + for (int i = thick; i < w - thick; i++) + { + for (int j = thick; j < h - thick; j++) + { + switch (m_shadowSettings->algorithm()) + { + case KShadowSettings::DoubleLinearDecay: + alphaShadow = doubleLinearDecay(img, i, j); + break; + case KShadowSettings::RadialDecay: + alphaShadow = radialDecay(img, i, j); + break; + case KShadowSettings::NoDecay: + alphaShadow = noDecay(img, i, j); + break; + case KShadowSettings::DefaultDecay: + default: + alphaShadow = defaultDecay(img, i, j); + } + + alphaShadow = (alphaShadow > m_shadowSettings->maxOpacity()) ? m_shadowSettings->maxOpacity() : alphaShadow; + + // update the shadow's i,j pixel. + result.setPixel(i,j, qRgba(bgRed, bgGreen , bgBlue, (int) alphaShadow)); + } + } + return result; +} + +// Multiplication factor for pixels directly above, under, or next to the text +#define AXIS_FACTOR 2.0 +// Multiplication factor for pixels diagonal to the text +#define DIAGONAL_FACTOR 1.0 + +double KShadowEngine::defaultDecay(QImage& source, int i, int j) +{ + if ((i < 1) || (j < 1) || (i > source.width() - 2) || (j > source.height() - 2)) + return 0; + + double alphaShadow; + alphaShadow =(qGray(source.pixel(i-1,j-1)) * DIAGONAL_FACTOR + + qGray(source.pixel(i-1,j )) * AXIS_FACTOR + + qGray(source.pixel(i-1,j+1)) * DIAGONAL_FACTOR + + qGray(source.pixel(i ,j-1)) * AXIS_FACTOR + + 0 + + qGray(source.pixel(i ,j+1)) * AXIS_FACTOR + + qGray(source.pixel(i+1,j-1)) * DIAGONAL_FACTOR + + qGray(source.pixel(i+1,j )) * AXIS_FACTOR + + qGray(source.pixel(i+1,j+1)) * DIAGONAL_FACTOR) / m_shadowSettings->multiplicationFactor(); + + return alphaShadow; +} + +double KShadowEngine::doubleLinearDecay(QImage& source, int i, int j) +{ + //printf("img: %p, %d %d\n", (char *) &source, i, j); + return defaultDecay( source, i, j ); // for now +} + +double KShadowEngine::radialDecay(QImage& source, int i, int j) +{ + //printf("img: %p, %d %d\n", (char *) &source, i, j); + return defaultDecay( source, i, j ); // for now +} + +double KShadowEngine::noDecay(QImage& source, int i, int j) +{ + // create a new image for for the shaddow + int w = source.width(); + int h = source.height(); + int sx, sy; + //int thick = m_shadowSettings->thickness() >> 1; + + double alphaShadow = 0; + double opacity = 0; + for (int k = 1; k <= m_shadowSettings->thickness(); k++) { + /* Generate a shadow THICKNESS pixels thicker + * on either side than the text image. Ensure + * that i +/- k and j +/- k are within the + * bounds of the text pixmap. + */ + opacity = 0; + for (int l = -k; l <= k; l++) { + if (i < k) + sx = 0; + else if (i >= w - k) + sx = w - 1; + else + sx = i + l; + + for (int m = -k; m <= k; m++) { + if (j < k) + sy = 0; + else if (j >= h - k) + sy = h - 1; + else + sy = j + m; + + opacity += qGray(source.pixel(sx, sy)); + } + } + alphaShadow += opacity / m_shadowSettings->multiplicationFactor(); + } + return alphaShadow; +} + +KTextShadowEngine::KTextShadowEngine() : KShadowEngine() +{ + KShadowSettings *shadset = new KShadowSettings(); + + shadset->setOffsetX(0); + shadset->setOffsetY(0); + shadset->setThickness(1); + shadset->setMaxOpacity(96); + + setShadowSettings(shadset); +} + +// taken from mtaskbar, by Sebastian Wolff +void KTextShadowEngine::drawText(QPainter &p, const QRect &tr, int tf, const QString &str, const QSize &size) +{ + // get the color of the shadow: white for dark text, black for bright text + QPen textPen = p.pen(); + QColor shadCol = textPen.color(); + + if (shadCol.red() + + shadCol.green() + + shadCol.blue() <= 3*256/2-1) + { + shadCol = QColor(255,255,255); + } + else + { + shadCol = QColor(0,0,0); + } + + // get a transparent pixmap + QPainter pixPainter; + QPixmap textPixmap(size); + + textPixmap.fill(QColor(0,0,0)); + textPixmap.setMask(textPixmap.createHeuristicMask(true)); + + // draw text + pixPainter.begin(&textPixmap); + pixPainter.setPen(Qt::white); + pixPainter.setFont(p.font()); // get the font from the root painter + pixPainter.drawText(tr, tf, str); + pixPainter.end(); + + // draw shadow + QImage img = makeShadow(textPixmap, shadCol); + + // return + p.drawImage(0, 0, img); + p.drawText(tr, tf, str); +} + diff --git a/kicker/libkicker/kshadowengine.h b/kicker/libkicker/kshadowengine.h new file mode 100644 index 000000000..0fc4877fa --- /dev/null +++ b/kicker/libkicker/kshadowengine.h @@ -0,0 +1,123 @@ +/* This file is proposed to be part of the KDE libraries. + * Copyright (C) 2003 Laur Ivan + * + * Many thanks to: + * - Bernardo Hung for the enhanced shadow + * algorithm (currently used) + * - Tim Jansen for the API updates and fixes. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __FX_SHADOW +#define __FX_SHADOW + +#include +#include +#include + +#include + +class KShadowSettings; + +/** + * This class implements the shadow algorithm(s). It uses a FxData + * object for its parameters. Note that the shadow algorithm is using the + * luminosity of the original pixmap for the shadow one. + * @see KShadowSettings + * @author laur.ivan@corvil.com + * @since 3.2 + */ +class KDE_EXPORT KShadowEngine +{ +public: + /// Creates a new shadow engine. + KShadowEngine(); + + ~KShadowEngine(); + + /** + * Creates a new shadow engine. + * @param fx the shadow settings object with the configuration. The Shadow + * Engine will own this object and also delete it. Must + * be heap-allocated + */ + KShadowEngine(KShadowSettings *fx); + + /** + * Set the KShadowSettings object. + * @param fx the shadow settings object with the configuration. The Shadow + * Engine will own this object and also delete it. Must + * be heap-allocated. + */ + void setShadowSettings(KShadowSettings *fx); + + /** + * Get the current KShadowSettings. + * @param the current shadow settings + */ + KShadowSettings *shadowSettings(); + + /** + * Make shadow! + * + * textPixmap is the original pixmap where a (white) text is drawn. + * bgColor is the color used for the shadow. + * @param textPixmap the pixmap of the text + * @param bgColor the background color + * @return the resulting image + */ + QImage makeShadow(const QPixmap& textPixmap, const QColor &bgColor); + +private: + // No static objects in libs, and no static deleters in kdefx... + //static KShadowSettings s_defaultShadowSettings; + + KShadowSettings *m_shadowSettings; + + /* + * a simple algorithm with 3 pixels thickness + */ + double defaultDecay(QImage& source, int x, int y); + + /* + * a slower algorithm where the influence of a pixel + * is qGray(px)/(abs(dx) + abs(dy) +1). + */ + double doubleLinearDecay(QImage& source, int x, int y); + + /* + * a very slow algorithm where the influence of a pixel + * is qGray(px)/(sqrt(sqr(dx) + sqr(dy)) +1). + */ + double radialDecay(QImage& source, int x, int y); + + /* + * a nice/fast algorithm proposed by Bernardo Hung + */ + double noDecay(QImage& source, int x, int y); + + void *d; +}; + +class KDE_EXPORT KTextShadowEngine : public KShadowEngine +{ +public: + KTextShadowEngine(); + + void drawText(QPainter &p, const QRect &tr, int tf, const QString &str, const QSize &size); +}; + +#endif diff --git a/kicker/libkicker/kshadowsettings.cpp b/kicker/libkicker/kshadowsettings.cpp new file mode 100644 index 000000000..9c935d30f --- /dev/null +++ b/kicker/libkicker/kshadowsettings.cpp @@ -0,0 +1,182 @@ +/* This file is proposed to be part of the KDE libraries. + * Copyright (C) 2003 Laur Ivan + * + * Many thanks to: + * - Tim Jansen for the API updates and fixes. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "kshadowsettings.h" + +KShadowSettings::KShadowSettings() +{ + // init the components with some default values + setDefaults(); +} + +// load/save methods +void KShadowSettings::fromString(const QString &val) +{ + setOffsetX(val.section(',', OFFSET_X, OFFSET_X).toInt()); + setOffsetY(val.section(',', OFFSET_Y, OFFSET_Y).toInt()); + setMultiplicationFactor(val.section(',', MULTIPLICATION_FACTOR, MULTIPLICATION_FACTOR).toDouble()); + setMaxOpacity(val.section(',', MAX_OPACITY, MAX_OPACITY).toDouble()); + setThickness(val.section(',', THICKNESS, THICKNESS).toInt()); + setAlgorithm((Algorithm) val.section(',', ALGORITHM, ALGORITHM).toInt()); + setSelectionType((SelectionType)val.section(',', SELECTION_TYPE, SELECTION_TYPE).toInt()); +} + +QString KShadowSettings::toString() const +{ + QString result; + result.sprintf("%d,%d,%f,%f,%d,%d,%d", + offsetX(), + offsetY(), + multiplicationFactor(), + maxOpacity(), + thickness(), + (int)algorithm(), + (int)selectionType()); + return result; +} + +//*********************************** +// get methods +//*********************************** + +/** + * Returns the decay algorithm to be used (see the alg. enumeration in the .h) + */ +KShadowSettings::Algorithm KShadowSettings::algorithm() const +{ + return _algorithm; +} + +/** + * Returns a multiplication facor used to average the resulted data + */ +double KShadowSettings::multiplicationFactor() const +{ + return _multiplicationFactor; +} + +/** + * Returns the max opacity allowed (0 = transparent, 255 = opaque) + */ +double KShadowSettings::maxOpacity() const +{ + return _maxOpacity; +} + +/** + * Returns the Y offset (0 is centered on text) + */ +int KShadowSettings::offsetX() const +{ + return _offsetX; +} + +/** + * Returns the Y offset (0 is centered on text) + */ +int KShadowSettings::offsetY() const +{ + return _offsetY; +} + +/** + * Returns the thickness. Used by the KShadow algorithm + */ +int KShadowSettings::thickness() const +{ + return _thickness; +} + +/** + * Returns the selection type + */ +KShadowSettings::SelectionType KShadowSettings::selectionType() const +{ + return _selectionType; +} + +// set methods +/** + * set the default parameters + */ +void KShadowSettings::setDefaults() +{ + fromString(DEFAULT_SHADOW_CONFIGURATION); +} + + +/** + * Set the algorithm + */ +void KShadowSettings::setAlgorithm(Algorithm val) +{ + _algorithm = val; +} + +/** + * Set the multiplication factor + */ +void KShadowSettings::setMultiplicationFactor(double val) +{ + _multiplicationFactor = val; +} + +/** + * Set the max. opacity + */ +void KShadowSettings::setMaxOpacity(double val) +{ + _maxOpacity = val; +} + +/** + * Set the X offset of the shadow + */ +void KShadowSettings::setOffsetX(int val) +{ + _offsetX = val; +} + +/** + * Set the Y offset of the shadow + */ +void KShadowSettings::setOffsetY(int val) +{ + _offsetY = val; +} + +/** + * Set the shadow thickness + */ +void KShadowSettings::setThickness(int val) +{ + _thickness = val; +} + +/** + * Set the selection type + */ +void KShadowSettings::setSelectionType(SelectionType val) +{ + _selectionType = val; +} diff --git a/kicker/libkicker/kshadowsettings.h b/kicker/libkicker/kshadowsettings.h new file mode 100644 index 000000000..9a91f1c15 --- /dev/null +++ b/kicker/libkicker/kshadowsettings.h @@ -0,0 +1,236 @@ +/* This file is proposed to be part of the KDE libraries. + * Copyright (C) 2003 Laur Ivan + * + * Many thanks to: + * - Tim Jansen for the API updates and fixes. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __FX_DATA +#define __FX_DATA + +#include + +#define SHADOW_CONFIG_ENTRY QString("ShadowParameters") +#define SHADOW_TEXT_COLOR QString("ShadowTextColor") +#define SHADOW_TEXT_BACKGROUND QString("ShadowTextBackground") + +// fallback configuration string +#define DEFAULT_SHADOW_CONFIGURATION QString("0,0,4.0,120.0,2,1,1,0,0,0") + +/** + * This class is the implementation of a structure for the + * various parameters required by the shadow class. + * + * One may afford this implementation since the shadow class is + * designed to be used as singleton for an application. + * @see KShadowEngine + * @author laur.ivan@corvil.com + * @since 3.2 + */ +class KDE_EXPORT KShadowSettings +{ + public: + /** + * Specifies the order of the options. + * @see fromString + */ + enum ConfigurationOrder + { + OFFSET_X = 0, + OFFSET_Y = OFFSET_X + 1, + MULTIPLICATION_FACTOR = OFFSET_Y + 1, + MAX_OPACITY = MULTIPLICATION_FACTOR + 1, + THICKNESS = MAX_OPACITY + 1, + ALGORITHM = THICKNESS + 1, + SELECTION_TYPE = ALGORITHM + 1 + }; + + public: + /** + * The algorithm used. + */ + enum Algorithm + { + DefaultDecay = 1, ///< the default AXIS/DIAGONAL_FACTOR based alg + DoubleLinearDecay, ///< decay factor is 1/dx+dy + RadialDecay, ///< decay factor is 1/sqrt(dx*dx + dy*dy) + NoDecay ///< decay factor is 1 always + }; + + /** + * The selected method used. + */ + enum SelectionType + { + InverseVideoOnSelection = 0, ///< when selected, the halo is on I/Video + SelectionColorsOnSelection ///< the halo is made w/ selected colors + }; + + /** + * The default constructor. + * Creates an object with default settings for all the variabless. + */ + KShadowSettings(); + + // load/save methods + /** + * Loads the configuration from a string. + * @param the string to load from (comma-separated values) + * @see ConfigurationOrder + */ + virtual void fromString(const QString &s); + /** + * Saves the configuration to a string. + * @return the configuration (comma-separated values) + * @see ConfigurationOrder + */ + virtual QString toString() const; + + // get methods + /** + * Returns the x offset of the shadow. + * @return the x offset + */ + int offsetX() const; + + /** + * Returns the y offset of the shadow. + * @return the y offset + */ + int offsetY() const; + + /** + * Returns the multiplication factor. + * @return the multiplication factor + */ + double multiplicationFactor() const; + + /** + * Returns the maximum opacity of the shadow. + * @return the maximum opacity + */ + double maxOpacity() const; + + /** + * Returns the thickness. + * @return the thickness + */ + int thickness() const; + + /** + * Returns the used algorithm. + * @return the algorithm used + */ + Algorithm algorithm() const; + + /** + * Returns the selection type used. + * @return the selection type + */ + SelectionType selectionType() const; + + // set methods + /** + * Sets default values. + */ + virtual void setDefaults(); + + /** + * Sets the used algorithm. + * @param a the algorithm used + */ + virtual void setAlgorithm(Algorithm a); + + /** + * Sets the multiplication factor. + * @param mf the multiplication factor + */ + virtual void setMultiplicationFactor(double mf); + + /** + * Sets the maximum opacity of the shadow. + * @param mo the maximum opacity + */ + virtual void setMaxOpacity(double mo); + + /** + * Sets the x offset of the shadow. + * @param x the x offset + */ + virtual void setOffsetX(int x); + + /** + * Sets the y offset of the shadow. + * @param y the y offset + */ + virtual void setOffsetY(int y); + + /** + * Sets the thickness. + * @param t the thickness + */ + virtual void setThickness(int t); + + /** + * Sets the selection type used. + * @param s the selection type + */ + virtual void setSelectionType(SelectionType s); + + private: + + /* + * The employed algorithm (see fxshadow.h) + */ + Algorithm _algorithm; + + /** + * This is the multiplication factor for the resulted shadow + */ + double _multiplicationFactor; + + /** + * The maximum permitted opacity for the shadow + */ + double _maxOpacity; + + /* + * offsetX and offsetY are the x/y offsets of the shadow with + * the mention that 0,0 is a centered shadow. + */ + int _offsetX; + int _offsetY; + + /* + * The shadow thickness: + * shadow is this many pixels thicker than the text. + */ + int _thickness; + + /* + * If the value is InverseVideoOnSelection, then the fg/bg + * colours are swapped when the element is selected. + * Otherwise, the selected fg/bg colors are used for text + * as well + */ + SelectionType _selectionType; + + void *d; +}; + + +#endif diff --git a/kicker/libkicker/menuinfo.cpp b/kicker/libkicker/menuinfo.cpp new file mode 100644 index 000000000..740d44d95 --- /dev/null +++ b/kicker/libkicker/menuinfo.cpp @@ -0,0 +1,68 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "menuinfo.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +MenuInfo::MenuInfo(const QString& desktopFile) +{ + KSimpleConfig df(locate("data", QString::fromLatin1("kicker/menuext/%1").arg(desktopFile))); + df.setGroup("Desktop Entry"); + + QStringList list = df.readListEntry("X-KDE-AuthorizeAction"); + if (kapp && !list.isEmpty()) + { + for(QStringList::ConstIterator it = list.begin(); + it != list.end(); + ++it) + { + if (!kapp->authorize((*it).stripWhiteSpace())) + return; + } + } + + name_ = df.readEntry("Name"); + comment_ = df.readEntry("Comment"); + icon_ = df.readEntry("Icon"); + library_ = df.readEntry("X-KDE-Library"); + desktopfile_ = desktopFile; +} + +KPanelMenu* MenuInfo::load(QWidget *parent, const char *name) +{ + if (library_.isEmpty()) + return 0; + + return KParts::ComponentFactory::createInstanceFromLibrary( + QFile::encodeName( library_ ), + parent, name ); +} diff --git a/kicker/libkicker/menuinfo.h b/kicker/libkicker/menuinfo.h new file mode 100644 index 000000000..0d324538e --- /dev/null +++ b/kicker/libkicker/menuinfo.h @@ -0,0 +1,52 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _menuinfo_h_ +#define _menuinfo_h_ + +#include + +#include + +class KPanelMenu; +class QWidget; + +class KDE_EXPORT MenuInfo +{ +public: + MenuInfo(const QString& desktopFile); + + QString name() const { return name_; } + QString comment() const { return comment_; } + QString icon() const { return icon_; } + QString library() const { return library_; } + QString desktopFile() const { return desktopfile_; } + bool isValid() const { return !name_.isEmpty(); } + + KPanelMenu* load(QWidget *parent = 0, const char *name = 0); + +private: + QString name_, comment_, icon_, library_, desktopfile_; +}; + +#endif diff --git a/kicker/libkicker/panelbutton.cpp b/kicker/libkicker/panelbutton.cpp new file mode 100644 index 000000000..f53d4b38f --- /dev/null +++ b/kicker/libkicker/panelbutton.cpp @@ -0,0 +1,985 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "global.h" + +#include "kshadowengine.h" +#include "kshadowsettings.h" + +#include "kickerSettings.h" +#include "panelbutton.h" +#include "panelbutton.moc" + +// init static variable +KShadowEngine* PanelButton::s_textShadowEngine = 0L; + +PanelButton::PanelButton( QWidget* parent, const char* name ) + : QButton(parent, name), + m_valid(true), + m_isLeftMouseButtonDown(false), + m_drawArrow(false), + m_highlight(false), + m_changeCursorOverItem(true), + m_hasAcceptedDrag(false), + m_arrowDirection(KPanelExtension::Bottom), + m_popupDirection(KPanelApplet::Up), + m_orientation(Horizontal), + m_size((KIcon::StdSizes)-1), + m_fontPercent(0.40) +{ + setBackgroundOrigin(AncestorOrigin); + setWFlags(WNoAutoErase); + KGlobal::locale()->insertCatalogue("libkicker"); + calculateIconSize(); + setAcceptDrops(true); + + m_textColor = KGlobalSettings::textColor(); + + updateSettings(KApplication::SETTINGS_MOUSE); + + kapp->addKipcEventMask(KIPC::SettingsChanged | KIPC::IconChanged); + + installEventFilter(KickerTip::the()); + + connect(kapp, SIGNAL(settingsChanged(int)), SLOT(updateSettings(int))); + connect(kapp, SIGNAL(iconChanged(int)), SLOT(updateIcon(int))); +} + +void PanelButton::configure() +{ + QString name = tileName(); + if( name.isEmpty() ) + return; + + if (!KickerSettings::enableTileBackground()) + { + setTile(QString::null); + return; + } + + KConfigGroup tilesGroup( KGlobal::config(), "button_tiles" ); + if( !tilesGroup.readBoolEntry( "Enable" + name + "Tiles", true ) ) { + setTile( QString::null ); + return; + } + + QString tile = tilesGroup.readEntry( name + "Tile" ); + QColor color = QColor(); + + if (tile == "Colorize") + { + color = tilesGroup.readColorEntry( name + "TileColor" ); + tile = QString::null; + } + + setTile( tile, color ); +} + +void PanelButton::setTile(const QString& tile, const QColor& color) +{ + if (tile == m_tile && m_tileColor == color) + { + return; + } + + m_tile = tile; + m_tileColor = color; + loadTiles(); + update(); +} + +void PanelButton::setDrawArrow(bool drawArrow) +{ + if (m_drawArrow == drawArrow) + { + return; + } + + m_drawArrow = drawArrow; + update(); +} + +QImage PanelButton::loadTile(const QString& tile, + const QSize& size, + const QString& state) +{ + QString name = tile; + + if (size.height() < 42) + { + name += "_tiny_"; + } + else if (size.height() < 54) + { + name += "_normal_"; + } + else + { + name += "_large_"; + } + + name += state + ".png"; + + QImage tileImg(KGlobal::dirs()->findResource("tiles", name)); + + // scale if size does not match exactly + if (!tileImg.isNull() && tileImg.size() != size) + { + tileImg = tileImg.smoothScale(size); + } + + return tileImg; +} + +void PanelButton::setEnabled(bool enable) +{ + QButton::setEnabled(enable); + loadIcons(); + update(); +} + +void PanelButton::setPopupDirection(KPanelApplet::Direction d) +{ + m_popupDirection = d; + setArrowDirection(KickerLib::directionToPopupPosition(d)); +} + +void PanelButton::setOrientation(Orientation o) +{ + m_orientation = o; +} + +void PanelButton::updateIcon(int group) +{ + if (group != KIcon::Panel) + { + return; + } + + loadIcons(); + update(); +} + +void PanelButton::updateSettings(int category) +{ + if (category != KApplication::SETTINGS_MOUSE) + { + return; + } + + m_changeCursorOverItem = KGlobalSettings::changeCursorOverIcon(); + + if (m_changeCursorOverItem) + { + setCursor(KCursor::handCursor()); + } + else + { + unsetCursor(); + } +} + +void PanelButton::checkForDeletion(const QString& path) +{ + if (path == m_backingFile) + { + setEnabled(false); + QTimer::singleShot(1000, this, SLOT(scheduleForRemoval())); + } +} + +bool PanelButton::checkForBackingFile() +{ + return QFile::exists(m_backingFile); +} + +void PanelButton::scheduleForRemoval() +{ + static int timelapse = 1000; + if (checkForBackingFile()) + { + setEnabled(true); + timelapse = 1000; + emit hideme(false); + return; + } + else if (KickerSettings::removeButtonsWhenBroken()) + { + if (timelapse > 255*1000) // we'v given it ~8.5 minutes by this point + { + emit removeme(); + return; + } + + if (timelapse > 3000 && isVisible()) + { + emit hideme(true); + } + + timelapse *= 2; + QTimer::singleShot(timelapse, this, SLOT(scheduleForRemoval())); + } +} + +// return the dimension that the button wants to be for a given panel dimension (panelDim) +int PanelButton::preferredDimension(int panelDim) const +{ + // determine the upper limit on the size. Normally, this is panelDim, + // but if conserveSpace() is true, we restrict size to comfortably fit the icon + if (KickerSettings::conserveSpace()) + { + int newSize = preferredIconSize(panelDim); + if (newSize > 0) + { + return QMIN(panelDim, newSize + (KDialog::spacingHint() * 2)); + } + } + + return panelDim; +} + +int PanelButton::widthForHeight(int height) const +{ + int rc = preferredDimension(height); + + // we only paint the text when horizontal, so make sure we're horizontal + // before adding the text in here + if (orientation() == Horizontal && !m_buttonText.isEmpty()) + { + QFont f(font()); + f.setPixelSize(KMIN(height, KMAX(int(float(height) * m_fontPercent), 16))); + QFontMetrics fm(f); + + rc += fm.width(m_buttonText) + KMIN(25, KMAX(5, fm.width('m') / 2)); + } + + return rc; +} + +int PanelButton::heightForWidth(int width) const +{ + return preferredDimension(width); +} + +const QPixmap& PanelButton::labelIcon() const +{ + return m_highlight ? m_iconh : m_icon; +} + +const QPixmap& PanelButton::zoomIcon() const +{ + return m_iconz; +} + +bool PanelButton::isValid() const +{ + return m_valid; +} + +void PanelButton::setTitle(const QString& t) +{ + m_title = t; +} + +void PanelButton::setIcon(const QString& icon) +{ + if (icon == m_iconName) + { + return; + } + + m_iconName = icon; + loadIcons(); + update(); + emit iconChanged(); +} + +QString PanelButton::icon() const +{ + return m_iconName; +} + +bool PanelButton::hasText() const +{ + return !m_buttonText.isEmpty(); +} + +void PanelButton::setButtonText(const QString& text) +{ + m_buttonText = text; + update(); +} + +QString PanelButton::buttonText() const +{ + return m_buttonText; +} + +void PanelButton::setTextColor(const QColor& c) +{ + m_textColor = c; +} + +QColor PanelButton::textColor() const +{ + return m_textColor; +} + +void PanelButton::setFontPercent(double p) +{ + m_fontPercent = p; +} + +double PanelButton::fontPercent() const +{ + return m_fontPercent; +} + +KPanelExtension::Orientation PanelButton::orientation() const +{ + return m_orientation; +} + +KPanelApplet::Direction PanelButton::popupDirection() const +{ + return m_popupDirection; +} + +QPoint PanelButton::center() const +{ + return mapToGlobal(rect().center()); +} + +QString PanelButton::title() const +{ + return m_title; +} + +void PanelButton::triggerDrag() +{ + setDown(false); + + startDrag(); +} + +void PanelButton::startDrag() +{ + emit dragme(m_icon); +} + +void PanelButton::enterEvent(QEvent* e) +{ + if (!m_highlight) + { + m_highlight = true; + repaint(false); + } + + QButton::enterEvent(e); +} + +void PanelButton::leaveEvent(QEvent* e) +{ + if (m_highlight) + { + m_highlight = false; + repaint(false); + } + + QButton::leaveEvent(e); +} + +void PanelButton::dragEnterEvent(QDragEnterEvent* e) +{ + if (e->isAccepted()) + { + m_hasAcceptedDrag = true; + } + + update(); + QButton::dragEnterEvent( e ); +} + +void PanelButton::dragLeaveEvent(QDragLeaveEvent* e) +{ + m_hasAcceptedDrag = false; + update(); + QButton::dragLeaveEvent( e ); +} + +void PanelButton::dropEvent(QDropEvent* e) +{ + m_hasAcceptedDrag = false; + update(); + QButton::dropEvent( e ); +} + +void PanelButton::mouseMoveEvent(QMouseEvent *e) +{ + if (!m_isLeftMouseButtonDown || (e->state() & LeftButton) == 0) + { + return; + } + + QPoint p(e->pos() - m_lastLeftMouseButtonPress); + if (p.manhattanLength() <= 16) + { + // KGlobalSettings::dndEventDelay() is not enough! + return; + } + + m_isLeftMouseButtonDown = false; + triggerDrag(); +} + +void PanelButton::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == LeftButton) + { + m_lastLeftMouseButtonPress = e->pos(); + m_isLeftMouseButtonDown = true; + } + QButton::mousePressEvent(e); +} + +void PanelButton::mouseReleaseEvent(QMouseEvent *e) +{ + if (e->button() == LeftButton) + { + m_isLeftMouseButtonDown = false; + } + QButton::mouseReleaseEvent(e); +} + +void PanelButton::resizeEvent(QResizeEvent*) +{ + loadTiles(); + + if (calculateIconSize()) + { + loadIcons(); + } +} + +void PanelButton::drawButton(QPainter *p) +{ + const QPixmap& tile = (isDown() || isOn()) ? m_down : m_up; + + if (m_tileColor.isValid()) + { + p->fillRect(rect(), m_tileColor); + style().drawPrimitive(QStyle::PE_Panel, p, rect(), colorGroup()); + } + else if (paletteBackgroundPixmap()) + { + // Draw the background. This is always needed, even when using tiles, + // because they don't have to cover the entire button. + QPoint offset = backgroundOffset(); + int ox = offset.x(); + int oy = offset.y(); + p->drawTiledPixmap( 0, 0, width(), height(),*paletteBackgroundPixmap(), ox, oy); + } + + if (!tile.isNull()) + { + // Draw the tile. + p->drawPixmap(0, 0, tile); + } + else if (isDown() || isOn()) + { + // Draw shapes to indicate the down state. + style().drawPrimitive(QStyle::PE_Panel, p, rect(), colorGroup(), QStyle::Style_Sunken); + } + + drawButtonLabel(p); + + if (hasFocus() || m_hasAcceptedDrag) + { + int x1, y1, x2, y2; + rect().coords(&x1, &y1, &x2, &y2); + QRect r(x1+2, y1+2, x2-x1-3, y2-y1-3); + style().drawPrimitive(QStyle::PE_FocusRect, p, r, colorGroup(), + QStyle::Style_Default, colorGroup().button()); + } +} + +void PanelButton::drawButtonLabel(QPainter *p) +{ + QPixmap icon = labelIcon(); + bool active = isDown() || isOn(); + + if (active) + { + icon = icon.convertToImage().smoothScale(icon.width() - 2, + icon.height() - 2); + } + + if (!m_buttonText.isEmpty() && orientation() == Horizontal) + { + int h = height(); + int w = width(); + int y = (h - icon.height())/2; + p->save(); + QFont f = font(); + + double fontPercent = m_fontPercent; + if (active) + { + fontPercent *= .8; + } + f.setPixelSize(KMIN(h, KMAX(int(float(h) * m_fontPercent), 16))); + QFontMetrics fm(f); + p->setFont(f); + + /* Draw shadowed text */ + bool reverse = QApplication::reverseLayout(); + QPainter::TextDirection rtl = reverse ? QPainter::RTL : QPainter::LTR; + + if (!reverse && !icon.isNull()) + { + /* Draw icon */ + p->drawPixmap(3, y, icon); + } + + int tX = reverse ? 3 : icon.width() + KMIN(25, KMAX(5, fm.width('m') / 2)); + int tY = fm.ascent() + ((h - fm.height()) / 2); + + QColor shadCol = KickerLib::shadowColor(m_textColor); + + // get a transparent pixmap + QPainter pixPainter; + QPixmap textPixmap(w, h); + + textPixmap.fill(QColor(0,0,0)); + textPixmap.setMask(textPixmap.createHeuristicMask(true)); + + // draw text + pixPainter.begin(&textPixmap); + pixPainter.setPen(m_textColor); + pixPainter.setFont(p->font()); // get the font from the root painter + pixPainter.drawText(tX, tY, m_buttonText, -1, rtl); + pixPainter.end(); + + if (!s_textShadowEngine) + { + KShadowSettings* shadset = new KShadowSettings(); + shadset->setOffsetX(0); + shadset->setOffsetY(0); + shadset->setThickness(1); + shadset->setMaxOpacity(96); + s_textShadowEngine = new KShadowEngine(shadset); + } + + // draw shadow + QImage img = s_textShadowEngine->makeShadow(textPixmap, shadCol); + p->drawImage(0, 0, img); + p->save(); + p->setPen(m_textColor); + p->drawText(tX, tY, m_buttonText, -1, rtl); + p->restore(); + + if (reverse && !icon.isNull()) + { + p->drawPixmap(w - icon.width() - 3, y, icon); + } + + p->restore(); + } + else if (!icon.isNull()) + { + int y = (height() - icon.height()) / 2; + int x = (width() - icon.width()) / 2; + p->drawPixmap(x, y, icon); + } + + if (m_drawArrow && (m_highlight || active)) + { + QStyle::PrimitiveElement e = QStyle::PE_ArrowUp; + int arrowSize = style().pixelMetric(QStyle::PM_MenuButtonIndicator); + QRect r((width() - arrowSize)/2, 0, arrowSize, arrowSize); + + switch (m_arrowDirection) + { + case KPanelExtension::Top: + e = QStyle::PE_ArrowUp; + break; + case KPanelExtension::Bottom: + e = QStyle::PE_ArrowDown; + r.moveBy(0, height() - arrowSize); + break; + case KPanelExtension::Right: + e = QStyle::PE_ArrowRight; + r = QRect(width() - arrowSize, (height() - arrowSize)/2, arrowSize, arrowSize); + break; + case KPanelExtension::Left: + e = QStyle::PE_ArrowLeft; + r = QRect(0, (height() - arrowSize)/2, arrowSize, arrowSize); + break; + case KPanelExtension::Floating: + if (orientation() == Horizontal) + { + e = QStyle::PE_ArrowDown; + r.moveBy(0, height() - arrowSize); + } + else if (QApplication::reverseLayout()) + { + e = QStyle::PE_ArrowLeft; + r = QRect(0, (height() - arrowSize)/2, arrowSize, arrowSize); + } + else + { + e = QStyle::PE_ArrowRight; + r = QRect(width() - arrowSize, (height() - arrowSize)/2, arrowSize, arrowSize); + } + break; + } + + int flags = QStyle::Style_Enabled; + if (active) + { + flags |= QStyle::Style_Down; + } + style().drawPrimitive(e, p, r, colorGroup(), flags); + } +} + +// return the icon size that would be used if the panel were proposed_size +// if proposed_size==-1, use the current panel size instead +int PanelButton::preferredIconSize(int proposed_size) const +{ + // (re)calculates the icon sizes and report true if they have changed. + // Get sizes from icontheme. We assume they are sorted. + KIconTheme *ith = KGlobal::iconLoader()->theme(); + + if (!ith) + { + return -1; // unknown icon size + } + + QValueList sizes = ith->querySizes(KIcon::Panel); + + int sz = ith->defaultSize(KIcon::Panel); + + if (proposed_size < 0) + { + proposed_size = (orientation() == Horizontal) ? height() : width(); + } + + // determine the upper limit on the size. Normally, this is panelSize, + // but if conserve space is requested, the max button size is used instead. + int upperLimit = proposed_size; + if (proposed_size > KickerLib::maxButtonDim() && + KickerSettings::conserveSpace()) + { + upperLimit = KickerLib::maxButtonDim(); + } + + //kdDebug()< i = sizes.constBegin(); + while (i != sizes.constEnd()) + { + if ((*i) + (2 * KickerSettings::iconMargin()) > upperLimit) + { + break; + } + sz = *i; // get the largest size under the limit + ++i; + } + + //kdDebug()<<"Using icon sizes: "<contains(m_backingFile)) + { + KDirWatch::self()->addFile(m_backingFile); + } + + connect(KDirWatch::self(), SIGNAL(deleted(const QString&)), + this, SLOT(checkForDeletion(const QString&))); + +} + +void PanelButton::setArrowDirection(KPanelExtension::Position dir) +{ + if (m_arrowDirection != dir) + { + m_arrowDirection = dir; + update(); + } +} + +void PanelButton::loadTiles() +{ + if (m_tileColor.isValid()) + { + setBackgroundOrigin(WidgetOrigin); + m_up = m_down = QPixmap(); + } + else if (m_tile.isNull()) + { + setBackgroundOrigin(AncestorOrigin); + m_up = m_down = QPixmap(); + } + else + { + setBackgroundOrigin(WidgetOrigin); + // If only the tiles were named a bit smarter we wouldn't have + // to pass the up or down argument. + m_up = QPixmap(loadTile(m_tile, size(), "up")); + m_down = QPixmap(loadTile(m_tile, size(), "down")); + } +} + +void PanelButton::loadIcons() +{ + KIconLoader * ldr = KGlobal::iconLoader(); + QString nm = m_iconName; + KIcon::States defaultState = isEnabled() ? KIcon::DefaultState : + KIcon::DisabledState; + m_icon = ldr->loadIcon(nm, KIcon::Panel, m_size, defaultState, 0L, true); + + if (m_icon.isNull()) + { + nm = defaultIcon(); + m_icon = ldr->loadIcon(nm, KIcon::Panel, m_size, defaultState); + } + + if (!isEnabled()) + { + m_iconh = m_icon; + } + else + { + m_iconh = ldr->loadIcon(nm, KIcon::Panel, m_size, + KIcon::ActiveState, 0L, true); + } + + m_iconz = ldr->loadIcon(nm, KIcon::Panel, KIcon::SizeHuge, + defaultState, 0L, true ); +} + +// (re)calculates the icon sizes and report true if they have changed. +// (false if we don't know, because theme couldn't be loaded?) +bool PanelButton::calculateIconSize() +{ + int size = preferredIconSize(); + + if (size < 0) + { + // size unknown + return false; + } + + if (m_size != size) + { + // Size has changed, update + m_size = size; + return true; + } + + return false; +} + +void PanelButton::updateKickerTip(KickerTip::Data& data) +{ + data.message = QStyleSheet::escape(title()); + data.subtext = QStyleSheet::escape(QToolTip::textFor(this)); + data.icon = zoomIcon(); + data.direction = popupDirection(); +} + +// +// PanelPopupButton class +// + +PanelPopupButton::PanelPopupButton(QWidget *parent, const char *name) + : PanelButton(parent, name), + m_popup(0), + m_pressedDuringPopup(false), + m_initialized(false) +{ + connect(this, SIGNAL(pressed()), SLOT(slotExecMenu())); +} + +void PanelPopupButton::setPopup(QPopupMenu *popup) +{ + if (m_popup) + { + m_popup->removeEventFilter(this); + disconnect(m_popup, SIGNAL(aboutToHide()), this, SLOT(menuAboutToHide())); + } + + m_popup = popup; + setDrawArrow(m_popup != 0); + + if (m_popup) + { + m_popup->installEventFilter(this); + connect(m_popup, SIGNAL(aboutToHide()), this, SLOT(menuAboutToHide())); + } +} + +QPopupMenu *PanelPopupButton::popup() const +{ + return m_popup; +} + +bool PanelPopupButton::eventFilter(QObject *, QEvent *e) +{ + if (e->type() == QEvent::MouseMove) + { + QMouseEvent *me = static_cast(e); + if (rect().contains(mapFromGlobal(me->globalPos())) && + ((me->state() & ControlButton) != 0 || + (me->state() & ShiftButton) != 0)) + { + PanelButton::mouseMoveEvent(me); + return true; + } + } + else if (e->type() == QEvent::MouseButtonPress || + e->type() == QEvent::MouseButtonDblClick) + { + QMouseEvent *me = static_cast(e); + if (rect().contains(mapFromGlobal(me->globalPos()))) + { + m_pressedDuringPopup = true; + return true; + } + } + else if (e->type() == QEvent::MouseButtonRelease) + { + QMouseEvent *me = static_cast(e); + if (rect().contains(mapFromGlobal(me->globalPos()))) + { + if (m_pressedDuringPopup && m_popup) + { + m_popup->hide(); + } + return true; + } + } + return false; +} + +void PanelPopupButton::showMenu() +{ + if (isDown()) + { + if (m_popup) + { + m_popup->hide(); + } + + setDown(false); + return; + } + + setDown(true); + update(); + slotExecMenu(); +} + +void PanelPopupButton::slotExecMenu() +{ + if (!m_popup) + { + return; + } + + m_pressedDuringPopup = false; + KickerTip::enableTipping(false); + kapp->syncX(); + kapp->processEvents(); + + if (!m_initialized) + { + initPopup(); + } + + m_popup->adjustSize(); + m_popup->exec(KickerLib::popupPosition(popupDirection(), m_popup, this)); +} + +void PanelPopupButton::menuAboutToHide() +{ + if (!m_popup) + { + return; + } + + setDown(false); + KickerTip::enableTipping(true); +} + +void PanelPopupButton::triggerDrag() +{ + if (m_popup) + { + m_popup->hide(); + } + + PanelButton::triggerDrag(); +} + +void PanelPopupButton::setInitialized(bool initialized) +{ + m_initialized = initialized; +} + diff --git a/kicker/libkicker/panelbutton.h b/kicker/libkicker/panelbutton.h new file mode 100644 index 000000000..f71865c77 --- /dev/null +++ b/kicker/libkicker/panelbutton.h @@ -0,0 +1,471 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __panelbutton_h__ +#define __panelbutton_h__ + +#include + +#include + +#include +#include +#include + +#include "kickertip.h" + +class QPopupMenu; +class KConfigGroup; +class KShadowEngine; + +/** + * PanelButton is the base class for all buttons to be + * placed in Kicker's panels. It inherits QButton, and + * KickerTip::Client. + */ +class KDE_EXPORT PanelButton: public QButton, public KickerTip::Client +{ + Q_OBJECT + +public: + /** + * Create a panel button + * @param parent the parent widget + * @param name the widget's name + */ + PanelButton( QWidget* parent, const char* name ); + + /** + * Configures this button according to the user's preferences for + * button tiles/colors/etc. This must be called by the container + * embedding the button after consturction and thereafter whenever + * the configuration changes to ensure it remains properly styled. + * Note that it is not used for configuration specific to the subclass. + */ + void configure(); + + /** + * Prompts the button to save it's configuration. Subclass specific + * settings should be saved in this method to the KConfigGroup passed in. + */ + virtual void saveConfig(KConfigGroup&) const {} + + /** + * Reimplement this to display a properties dialog for your button. + */ + virtual void properties() {} + + /** + * Reimplement this to give Kicker a hint for the width of the button + * given a certain height. + */ + virtual int widthForHeight(int height) const; + + /** + * Reimplement this to give Kicker a hint for the height of the button + * given a certain width. + */ + virtual int heightForWidth(int width) const; + + /** + * @return the button's current icon + */ + virtual const QPixmap& labelIcon() const; + + /** + * @return the button's zoom icon + */ + virtual const QPixmap& zoomIcon() const; + + /** + * @return true if this button is valid. + */ + bool isValid() const; + + /** + * Changes the title for the panel button. + * @param t the button's title + */ + void setTitle(const QString& t); + + /** + * @return the title of the button. + */ + QString title() const; + + /** + * Changes the name of the panel button's tile, with + * optional color. + * @param tile the button's tile name + * @param color the button's tile color + */ + void setTile(const QString& tile, const QColor& color = QColor()); + + /** + * Set to true to draw an arrow on the button. + */ + void setDrawArrow(bool drawArrow); + + /** + * Used to set the icon for this panel button. + * @param icon the path to the button's icon + */ + void setIcon(const QString& icon); + + /** + * @return the button's icon + */ + QString icon() const; + + /** + * @return whether this button has a text label or not + */ + bool hasText() const; + + /** + * Change the button's text label + * @param text text for button's label + */ + void setButtonText(const QString& text); + + /** + * @return button's text label + */ + QString buttonText() const; + + /** + * Change the button's text label color + * @param c the new text label color + */ + void setTextColor(const QColor& c); + + /** + * @return the button's text label color + */ + QColor textColor() const; + + /** + * Change the button's text scale + * @param p font scale (in percent) + */ + void setFontPercent(double p); + + /** + * @return the button's text scale (in percent) + */ + double fontPercent() const; + + /** + * @return the orientation of the button + */ + Orientation orientation() const; + + /** + * @return the button's popup direction (read from parent KPanelApplet) + */ + KPanelApplet::Direction popupDirection() const; + + /** + * @return global position of the center of the button + */ + QPoint center() const; + + /** + * Used to load the graphical tile of the button + * @param name path/name of button's tile + * @param size size of the tile + * @param state used if button has multiple states (null by default) + */ + static QImage loadTile(const QString& name, const QSize&, + const QString& state = QString::null); + + /** + * Update the contents of the button's KickerTip + * @param data new KickerTip data + */ + void updateKickerTip(KickerTip::Data& data); + +signals: + /** + * Emitted when the button's icon is changed. + */ + void iconChanged(); + + /** + * Emitted to notify parent containers to save config + */ + void requestSave(); + + /** + * Emitted when the button needs to be removed from it's container + * @see KickerSettings::removeButtonsWhenBroken() + */ + void removeme(); + + /** + * Emitted when the button may need to be removed, but that removal depends + * on as-yet-uncertain future events and therefore ought to be hidden from + * view, though not deleted quite yet. + * @see KickerSettings::removeButtonsWhenBroken() + */ + void hideme(bool hide); + + /** + * Emitted when button initiates a drag + */ + void dragme(const QPixmap); + + /** + * Overloads dragme to support panel button's with a list of KURL's ([url/servicemenu/browser]button) + */ + void dragme(const KURL::List, const QPixmap); + +public slots: + /** + * Set to true to enable the button. + */ + void setEnabled(bool enable); + + /** + * Sets the orientation of the button (ie. which direction the icon will rotate). + */ + void setOrientation(Orientation o); + + /** + * Sets the direction to pop up the contents of the button. + */ + void setPopupDirection(KPanelApplet::Direction d); + +protected: + /** + * Subclasses must implement this to define the name of the button which is + * used to identify this button for saving and loading. It must be unique + * to the subclass, should not be i18n'd and is never made user visible. + * KDE4: remove this and use the classname directly instead. + */ + virtual QString tileName() = 0; + + /** + * @return the default icon for the button + */ + virtual QString defaultIcon() const { return "unknown"; }; + + /** + * Called right before drag occurs. + */ + virtual void triggerDrag(); + + /** + * Emits a signal to drag the button. Reimplement this if, for example, + * if you need the button to call dragme(KURL::List, const QPixmap) + * instead of dragme(const QPixmap) + */ + virtual void startDrag(); + + virtual void enterEvent(QEvent *); + virtual void leaveEvent(QEvent *); + virtual void dragEnterEvent(QDragEnterEvent *); + virtual void dragLeaveEvent(QDragLeaveEvent *); + virtual void dropEvent(QDropEvent *); + virtual void mouseMoveEvent(QMouseEvent *); + virtual void mousePressEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + virtual void resizeEvent(QResizeEvent*); + virtual void drawButton(QPainter *); + virtual void drawButtonLabel(QPainter *); + + /** + * @return the preferred icon size. + */ + virtual int preferredIconSize(int proposed_size = -1) const; + + /** + * @return the preferred dimensions for the button + */ + virtual int preferredDimension(int panelDim) const; + + /** + * if the button represents a local file, it tells PanelButton + * what file that is and it starts to watch it. if the file is + * deleted, it is disabled and then checked for one second later + * to see if has returned (e.g. a reinstall occurred) by calling + * checkForBackingFile(). if that returns false, then the button + * is removed from kicker. + * TODO: implement a heuristic that checks back in intervals for + * the reappearance of the file and returns the button to the panel + */ + virtual bool checkForBackingFile(); + + /** + * Set the file backing this button (See @ref checkForBackingFile()), + * you shouldn't need to use this, currently it's only used in [url/service]button + */ + void backedByFile(const QString& localFilePath); + + /** + * Sets the button's arrow direction. + * @param dir the arrow direction + */ + void setArrowDirection(KPanelExtension::Position dir); + + /** + * Loads the tiles for the button + */ + void loadTiles(); + + /** + * Loads the icons for the button + */ + void loadIcons(); + + /** + * (Re)Calculate icon sizes and return true if they have changed. + */ + bool calculateIconSize(); + + bool m_valid; + QPixmap m_icon; + +protected slots: + /** + * Called from KApplication when global icon settings have changed. + * @param group the new group + */ + void updateIcon(int group); + + /** + * Called from KApplication when global settings have changed. + * @param category the settings category, see KApplication::SettingsCategory + */ + void updateSettings(int category); + + /** + * Used for backedByFile, to check if the file backing this button + * has been deleted. + * @param path path to backing file + */ + void checkForDeletion(const QString& path); + + /** + * Called to prepare the button for removal from the Kicker + */ + void scheduleForRemoval(); + +private: + QPoint m_lastLeftMouseButtonPress; + bool m_isLeftMouseButtonDown; + bool m_drawArrow; + bool m_highlight; + bool m_changeCursorOverItem; + bool m_hasAcceptedDrag; + QColor m_textColor; + QColor m_tileColor; + QString m_buttonText; + QString m_tile; + QString m_title; + QString m_iconName; + QString m_backingFile; + QPixmap m_up; + QPixmap m_down; + QPixmap m_iconh; // hover + QPixmap m_iconz; // mouse over + KPanelExtension::Position m_arrowDirection; + KPanelApplet::Direction m_popupDirection; + Orientation m_orientation; + int m_size; + double m_fontPercent; + static KShadowEngine* s_textShadowEngine; + + class PanelPopupPrivate; + PanelPopupPrivate* d; +}; + +/** + * Base class for panelbuttons which popup a menu + */ +class KDE_EXPORT PanelPopupButton : public PanelButton +{ + Q_OBJECT + +public: + /** + * Create a panel button that pops up a menu. + * @param parent the parent widget + * @param name the widget's name + */ + PanelPopupButton(QWidget *parent=0, const char *name=0); + + /** + * Sets the button's popup menu. + * @param popup the menu to pop up + */ + void setPopup(QPopupMenu *popup); + + /** + * @return the button's popup menu + */ + QPopupMenu *popup() const; + + bool eventFilter(QObject *, QEvent *); + virtual void showMenu(); + +protected: + /** + * Called each time the button is clicked and the popup + * is displayed. Reimplement for dynamic popup menus. + */ + virtual void initPopup() {}; + + /** + * Called before drag occurs. Reimplement to do any + * necessary setup before the button is dragged. + */ + virtual void triggerDrag(); + + /** + * Marks the menu as initialized. + */ + void setInitialized(bool initialized); + +protected slots: + /** + * Connected to the button's pressed() signal, this is + * the code that actually displays the menu. Reimplement if + * you need to take care of any tasks before the popup is + * displayed (eg. KickerTip) + */ + virtual void slotExecMenu(); + +private slots: + void menuAboutToHide(); + +private: + QPopupMenu *m_popup; + bool m_pressedDuringPopup; + bool m_initialized; + + class PanelPopupButtonPrivate; + PanelPopupButtonPrivate* d; +}; + +#endif // __panelbutton_h__ diff --git a/kicker/libkicker/paneldrag.cpp b/kicker/libkicker/paneldrag.cpp new file mode 100644 index 000000000..871ac1d96 --- /dev/null +++ b/kicker/libkicker/paneldrag.cpp @@ -0,0 +1,180 @@ +/***************************************************************** +Copyright (c) 2004 Aaron J. Seigo + 2004 Stephen Depooter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include +#include + +#include + +#include "paneldrag.h" + +#define PANELDRAG_BUFSIZE sizeof(BaseContainer*) + sizeof(pid_t) + +PanelDrag::PanelDrag(BaseContainer* container, QWidget* dragSource) + : QDragObject(dragSource, 0) +{ + pid_t source_pid = getpid(); + + a.resize(PANELDRAG_BUFSIZE); + memcpy(a.data(), &container, sizeof(BaseContainer*)); + memcpy(a.data() + sizeof(BaseContainer*), &source_pid, sizeof(pid_t)); +} + +PanelDrag::~PanelDrag() +{ +} + +bool PanelDrag::decode(const QMimeSource* e, BaseContainer** container) +{ + QByteArray a = e->encodedData("application/basecontainerptr"); + + if (a.size() != PANELDRAG_BUFSIZE) + { + return false; + } + + pid_t target_pid = getpid(); + pid_t source_pid; + memcpy(&source_pid, a.data() + sizeof(QObject*), sizeof(pid_t)); + + if (source_pid == target_pid) + { + memcpy(container, a.data(), sizeof(QObject*)); + return true; + } + + return false; +} + +bool PanelDrag::canDecode(const QMimeSource *e) +{ + if (!e->provides("application/basecontainerptr")) + { + return false; + } + + QByteArray a = e->encodedData("application/basecontainerptr"); + if (a.size() != PANELDRAG_BUFSIZE) + { + return false; + } + +/* pid_t target_pid = getpid(); + pid_t source_pid; + memcpy(&source_pid, a.data() + sizeof(void*), sizeof(pid_t)); + + if (source_pid != target_pid) + { + return true; + } */ + + return true; +} + +QByteArray PanelDrag::encodedData(const char * mimeType) const +{ + if (QString("application/basecontainerptr") == mimeType && + a.size() == PANELDRAG_BUFSIZE) + { + return a; + } + + return QByteArray(); +} + +const char * PanelDrag::format(int i) const +{ + if (i == 0) + { + return "application/basecontainerptr"; + } + + return 0; +} + + +AppletInfoDrag::AppletInfoDrag(const AppletInfo& info, QWidget *dragSource) + : QDragObject(dragSource, 0) +{ + QBuffer buff(a); + buff.open(IO_WriteOnly); + QDataStream s(&buff); + s << info.desktopFile() << info.configFile() << info.type(); +} + +AppletInfoDrag::~AppletInfoDrag() +{ +} + +const char * AppletInfoDrag::format(int i) const +{ + if (i == 0) + { + return "application/appletinfo"; + } + + return 0; +} + +QByteArray AppletInfoDrag::encodedData(const char* mimeType) const +{ + if (QString("application/appletinfo") == mimeType) + { + return a; + } + + return QByteArray(); +} + +bool AppletInfoDrag::canDecode(const QMimeSource * e) +{ + if (!e->provides("application/appletinfo")) + { + return false; + } + + return true; +} + +bool AppletInfoDrag::decode(const QMimeSource* e, AppletInfo& container) +{ + QByteArray a = e->encodedData("application/appletinfo"); + + if (a.isEmpty()) + { + return false; + } + + QBuffer buff(a); + buff.open(IO_ReadOnly); + QDataStream s(&buff); + + QString desktopFile; + QString configFile; + int type; + s >> desktopFile >> configFile >> type; + AppletInfo info(desktopFile, configFile, (AppletInfo::AppletType)type); + container = info; + return true; +} + diff --git a/kicker/libkicker/paneldrag.h b/kicker/libkicker/paneldrag.h new file mode 100644 index 000000000..ba85ad375 --- /dev/null +++ b/kicker/libkicker/paneldrag.h @@ -0,0 +1,68 @@ +/***************************************************************** +Copyright (c) 2004 Aaron J. Seigo + 2004 Stephen Depooter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _paneldrag_h_ +#define _paneldrag_h_ + +#include + +#include + +#include "appletinfo.h" + +class BaseContainer; + +class KDE_EXPORT PanelDrag : public QDragObject +{ + public: + PanelDrag(BaseContainer* container, QWidget *dragSource); + ~PanelDrag(); + + virtual const char * format(int i = 0) const; + virtual QByteArray encodedData(const char *) const; + + static bool canDecode(const QMimeSource * e); + static bool decode(const QMimeSource* e, BaseContainer** container); + + private: + QByteArray a; +}; + +class KDE_EXPORT AppletInfoDrag : public QDragObject +{ + public: + AppletInfoDrag(const AppletInfo& container, QWidget *dragSource); + ~AppletInfoDrag(); + + virtual const char * format(int i = 0) const; + virtual QByteArray encodedData(const char *) const; + + static bool canDecode(const QMimeSource * e); + static bool decode(const QMimeSource* e, AppletInfo& container); + + private: + QByteArray a; +}; + +#endif + diff --git a/kicker/libkicker/panner.cpp b/kicker/libkicker/panner.cpp new file mode 100644 index 000000000..43dd67a41 --- /dev/null +++ b/kicker/libkicker/panner.cpp @@ -0,0 +1,396 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "simplebutton.h" +#include "panner.h" +#include "panner.moc" + +Panner::Panner( QWidget* parent, const char* name ) + : QWidget( parent, name ), + _luSB(0), + _rdSB(0), + _cwidth(0), _cheight(0), + _cx(0), _cy(0) +{ + KGlobal::locale()->insertCatalogue("libkicker"); + setBackgroundOrigin( AncestorOrigin ); + + _updateScrollButtonsTimer = new QTimer(this); + connect(_updateScrollButtonsTimer, SIGNAL(timeout()), this, SLOT(reallyUpdateScrollButtons())); + + _clipper = new QWidget(this); + _clipper->setBackgroundOrigin(AncestorOrigin); + _clipper->installEventFilter( this ); + _viewport = new QWidget(_clipper); + _viewport->setBackgroundOrigin(AncestorOrigin); + + // layout + _layout = new QBoxLayout(this, QBoxLayout::LeftToRight); + _layout->addWidget(_clipper, 1); + setOrientation(Horizontal); +} + +Panner::~Panner() +{ +} + +void Panner::createScrollButtons() +{ + if (_luSB) + { + return; + } + + // left/up scroll button + _luSB = new SimpleArrowButton(this); + _luSB->installEventFilter(this); + //_luSB->setAutoRepeat(true); + _luSB->setMinimumSize(12, 12); + _luSB->hide(); + _layout->addWidget(_luSB); + connect(_luSB, SIGNAL(pressed()), SLOT(startScrollLeftUp())); + connect(_luSB, SIGNAL(released()), SLOT(stopScroll())); + + // right/down scroll button + _rdSB = new SimpleArrowButton(this); + _rdSB->installEventFilter(this); + //_rdSB->setAutoRepeat(true); + _rdSB->setMinimumSize(12, 12); + _rdSB->hide(); + _layout->addWidget(_rdSB); + connect(_rdSB, SIGNAL(pressed()), SLOT(startScrollRightDown())); + connect(_rdSB, SIGNAL(released()), SLOT(stopScroll())); + + // set up the buttons + setupButtons(); +} + +void Panner::setupButtons() +{ + if (orientation() == Horizontal) + { + if (_luSB) + { + _luSB->setArrowType(Qt::LeftArrow); + _rdSB->setArrowType(Qt::RightArrow); + _luSB->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding)); + _rdSB->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding)); + QToolTip::add(_luSB, i18n("Scroll left")); + QToolTip::add(_rdSB, i18n("Scroll right")); + setMinimumSize(24, 0); + } + _layout->setDirection(QBoxLayout::LeftToRight); + } + else + { + if (_luSB) + { + _luSB->setArrowType(Qt::UpArrow); + _rdSB->setArrowType(Qt::DownArrow); + _luSB->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); + _rdSB->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); + QToolTip::add(_luSB, i18n("Scroll up")); + QToolTip::add(_rdSB, i18n("Scroll down")); + setMinimumSize(0, 24); + } + _layout->setDirection(QBoxLayout::TopToBottom); + } + + if (isVisible()) + { + // we need to manually redo the layout if we are visible + // otherwise let the toolkit decide when to do this + _layout->activate(); + } +} + +void Panner::setOrientation(Orientation o) +{ + _orient = o; + setupButtons(); + reallyUpdateScrollButtons(); +} + +void Panner::resizeEvent( QResizeEvent* ) +{ + //QScrollView::resizeEvent( e ); + //updateScrollButtons(); +} + +void Panner::scrollRightDown() +{ + if(orientation() == Horizontal) // scroll right + scrollBy( _step, 0 ); + else // scroll down + scrollBy( 0, _step ); + if (_step < 64) + _step++; +} + +void Panner::scrollLeftUp() +{ + if(orientation() == Horizontal) // scroll left + scrollBy( -_step, 0 ); + else // scroll up + scrollBy( 0, -_step ); + if (_step < 64) + _step++; +} + +void Panner::startScrollRightDown() +{ + _scrollTimer = new QTimer(this); + connect(_scrollTimer, SIGNAL(timeout()), SLOT(scrollRightDown())); + _scrollTimer->start(50); + _step = 8; + scrollRightDown(); +} + +void Panner::startScrollLeftUp() +{ + _scrollTimer = new QTimer(this); + connect(_scrollTimer, SIGNAL(timeout()), SLOT(scrollLeftUp())); + _scrollTimer->start(50); + _step = 8; + scrollLeftUp(); +} + +void Panner::stopScroll() +{ + delete _scrollTimer; + _scrollTimer = 0; +} + +void Panner::reallyUpdateScrollButtons() +{ + int delta = 0; + + _updateScrollButtonsTimer->stop(); + + if (orientation() == Horizontal) + { + delta = contentsWidth() - width(); + } + else + { + delta = contentsHeight() - height(); + } + + if (delta >= 1) + { + createScrollButtons(); + + // since the buttons may be visible but of the wrong size + // we need to do this every single time + _luSB->show(); + _rdSB->show(); + } + else if (_luSB && _luSB->isVisibleTo(this)) + { + _luSB->hide(); + _rdSB->hide(); + } +} + +void Panner::updateScrollButtons() +{ + _updateScrollButtonsTimer->start(200, true); +} + +void Panner::setContentsPos(int x, int y) +{ + if (x < 0) + x = 0; + else if (x > (contentsWidth() - visibleWidth())) + x = contentsWidth() - visibleWidth(); + + if (y < 0) + y = 0; + else if (y > (contentsHeight() - visibleHeight())) + y = contentsHeight() - visibleHeight(); + + if (x == contentsX() && y == contentsY()) + return; + + _viewport->move(-x, -y); + emit contentsMoving(x, y); +} + +void Panner::scrollBy(int dx, int dy) +{ + setContentsPos(contentsX() + dx, contentsY() + dy); +} + +void Panner::resizeContents( int w, int h ) +{ + _viewport->resize(w, h); + setContentsPos(contentsX(), contentsY()); + updateScrollButtons(); +} + +QPoint Panner::contentsToViewport( const QPoint& p ) const +{ + return QPoint(p.x() - contentsX() - _clipper->x(), p.y() - contentsY() - _clipper->y()); +} + +QPoint Panner::viewportToContents( const QPoint& vp ) const +{ + return QPoint(vp.x() + contentsX() + _clipper->x(), vp.y() + contentsY() + _clipper->y()); +} + +void Panner::contentsToViewport( int x, int y, int& vx, int& vy ) const +{ + const QPoint v = contentsToViewport(QPoint(x,y)); + vx = v.x(); + vy = v.y(); +} + +void Panner::viewportToContents( int vx, int vy, int& x, int& y ) const +{ + const QPoint c = viewportToContents(QPoint(vx,vy)); + x = c.x(); + y = c.y(); +} + +void Panner::ensureVisible( int x, int y ) +{ + ensureVisible(x, y, 50, 50); +} + +void Panner::ensureVisible( int x, int y, int xmargin, int ymargin ) +{ + int pw=visibleWidth(); + int ph=visibleHeight(); + + int cx=-contentsX(); + int cy=-contentsY(); + int cw=contentsWidth(); + int ch=contentsHeight(); + + if ( pw < xmargin*2 ) + xmargin=pw/2; + if ( ph < ymargin*2 ) + ymargin=ph/2; + + if ( cw <= pw ) { + xmargin=0; + cx=0; + } + if ( ch <= ph ) { + ymargin=0; + cy=0; + } + + if ( x < -cx+xmargin ) + cx = -x+xmargin; + else if ( x >= -cx+pw-xmargin ) + cx = -x+pw-xmargin; + + if ( y < -cy+ymargin ) + cy = -y+ymargin; + else if ( y >= -cy+ph-ymargin ) + cy = -y+ph-ymargin; + + if ( cx > 0 ) + cx=0; + else if ( cx < pw-cw && cw>pw ) + cx=pw-cw; + + if ( cy > 0 ) + cy=0; + else if ( cy < ph-ch && ch>ph ) + cy=ph-ch; + + setContentsPos( -cx, -cy ); +} + +bool Panner::eventFilter( QObject *obj, QEvent *e ) +{ + if ( obj == _viewport || obj == _clipper ) + { + switch ( e->type() ) + { + case QEvent::Resize: + viewportResizeEvent((QResizeEvent *)e); + break; + case QEvent::MouseButtonPress: + viewportMousePressEvent( (QMouseEvent*)e ); + if ( ((QMouseEvent*)e)->isAccepted() ) + return true; + break; + case QEvent::MouseButtonRelease: + viewportMouseReleaseEvent( (QMouseEvent*)e ); + if ( ((QMouseEvent*)e)->isAccepted() ) + return true; + break; + case QEvent::MouseButtonDblClick: + viewportMouseDoubleClickEvent( (QMouseEvent*)e ); + if ( ((QMouseEvent*)e)->isAccepted() ) + return true; + break; + case QEvent::MouseMove: + viewportMouseMoveEvent( (QMouseEvent*)e ); + if ( ((QMouseEvent*)e)->isAccepted() ) + return true; + break; + default: + break; + } + } + + return QWidget::eventFilter( obj, e ); // always continue with standard event processing +} + +void Panner::viewportResizeEvent( QResizeEvent* ) +{ +} + +void Panner::viewportMousePressEvent( QMouseEvent* e) +{ + e->ignore(); +} + +void Panner::viewportMouseReleaseEvent( QMouseEvent* e ) +{ + e->ignore(); +} + +void Panner::viewportMouseDoubleClickEvent( QMouseEvent* e ) +{ + e->ignore(); +} + +void Panner::viewportMouseMoveEvent( QMouseEvent* e ) +{ + e->ignore(); +} diff --git a/kicker/libkicker/panner.h b/kicker/libkicker/panner.h new file mode 100644 index 000000000..6657c9a76 --- /dev/null +++ b/kicker/libkicker/panner.h @@ -0,0 +1,115 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __panner_h__ +#define __panner_h__ + +#include + +#include "simplebutton.h" + +class QBoxLayout; +class QTimer; + +class KDE_EXPORT Panner : public QWidget +{ + Q_OBJECT + +public: + Panner( QWidget* parent, const char* name = 0 ); + ~Panner(); + + QSize minimumSizeHint() const { return QWidget::minimumSizeHint(); } + + Qt::Orientation orientation() const { return _orient; } + virtual void setOrientation(Orientation orientation); + + QWidget *viewport() const { return _viewport; } + + QRect contentsRect() const { return QRect(0, 0, width(), height()); } + + int contentsX() const { return _viewport ? -_viewport->x() : 0; } + int contentsY() const { return _viewport ? -_viewport->y() : 0; } + int contentsWidth() const { return _viewport ? _viewport->width() : 0; } + int contentsHeight() const { return _viewport ? _viewport->height() : 0; } + void setContentsPos(int x, int y); + + int visibleWidth() const { return _clipper->width(); } + int visibleHeight() const { return _clipper->height(); } + + void contentsToViewport( int x, int y, int& vx, int& vy ) const; + void viewportToContents( int vx, int vy, int& x, int& y ) const; + QPoint contentsToViewport( const QPoint& ) const; + QPoint viewportToContents( const QPoint& ) const; + + void addChild(QWidget *child) { child->show(); } + void removeChild(QWidget *child) { child->hide(); } + int childX(QWidget *child) const { return child->x(); } + int childY(QWidget *child) const { return child->y(); } + void moveChild(QWidget *child, int x, int y) { child->move(x, y); } + + void ensureVisible( int x, int y ); + void ensureVisible( int x, int y, int xmargin, int ymargin ); + +public slots: + virtual void resizeContents( int w, int h ); + void startScrollRightDown(); + void startScrollLeftUp(); + void stopScroll(); + void scrollRightDown(); + void scrollLeftUp(); + void reallyUpdateScrollButtons(); + void scrollBy(int dx, int dy); + +signals: + void contentsMoving(int x, int y); + +protected: + virtual bool eventFilter( QObject *obj, QEvent *e ); + virtual void resizeEvent(QResizeEvent *ev); + virtual void viewportResizeEvent( QResizeEvent* ); + virtual void viewportMousePressEvent( QMouseEvent* ); + virtual void viewportMouseReleaseEvent( QMouseEvent* ); + virtual void viewportMouseDoubleClickEvent( QMouseEvent* ); + virtual void viewportMouseMoveEvent( QMouseEvent* ); + +private: + void setupButtons(); + void createScrollButtons(); + void updateScrollButtons(); + + Orientation _orient; + QBoxLayout *_layout; + SimpleArrowButton *_luSB; // Left Scroll Button + SimpleArrowButton *_rdSB; // Right Scroll Button + QTimer *_updateScrollButtonsTimer; + QTimer *_scrollTimer; + + QWidget *_clipper; + QWidget *_viewport; + int _cwidth, _cheight; + int _cx, _cy; + int _step; +}; + +#endif diff --git a/kicker/libkicker/simplebutton.cpp b/kicker/libkicker/simplebutton.cpp new file mode 100644 index 000000000..223e71982 --- /dev/null +++ b/kicker/libkicker/simplebutton.cpp @@ -0,0 +1,258 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2004 Nadeem Hasan + Copyright (C) 2004-2005 Aaron J. Seigo + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "simplebutton.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUTTON_MARGIN KDialog::spacingHint() + +SimpleButton::SimpleButton(QWidget *parent, const char *name) + : QButton(parent, name), + m_highlight(false), + m_orientation(Qt::Horizontal) +{ + setBackgroundOrigin( AncestorOrigin ); + + connect( kapp, SIGNAL( settingsChanged( int ) ), + SLOT( slotSettingsChanged( int ) ) ); + connect( kapp, SIGNAL( iconChanged( int ) ), + SLOT( slotIconChanged( int ) ) ); + + kapp->addKipcEventMask( KIPC::SettingsChanged ); + kapp->addKipcEventMask( KIPC::IconChanged ); + + slotSettingsChanged( KApplication::SETTINGS_MOUSE ); +} + +void SimpleButton::setPixmap(const QPixmap &pix) +{ + QButton::setPixmap(pix); + generateIcons(); + update(); +} + +void SimpleButton::setOrientation(Qt::Orientation orientation) +{ + m_orientation = orientation; + update(); +} + +QSize SimpleButton::sizeHint() const +{ + const QPixmap* pm = pixmap(); + + if (!pm) + return QButton::sizeHint(); + else + return QSize(pm->width() + BUTTON_MARGIN, pm->height() + BUTTON_MARGIN); +} + +QSize SimpleButton::minimumSizeHint() const +{ + const QPixmap* pm = pixmap(); + + if (!pm) + return QButton::minimumSizeHint(); + else + return QSize(pm->width(), pm->height()); +} + +void SimpleButton::drawButton( QPainter *p ) +{ + drawButtonLabel(p); +} + +void SimpleButton::drawButtonLabel( QPainter *p ) +{ + if (!pixmap()) + { + return; + } + + QPixmap pix = isEnabled() ? (m_highlight? m_activeIcon : m_normalIcon) : m_disabledIcon; + + if (isOn() || isDown()) + { + pix = pix.convertToImage().smoothScale(pix.width() - 2, + pix.height() - 2); + } + + int h = height(); + int w = width(); + int ph = pix.height(); + int pw = pix.width(); + int margin = BUTTON_MARGIN; + QPoint origin(margin / 2, margin / 2); + + if (ph < (h - margin)) + { + origin.setY((h - ph) / 2); + } + + if (pw < (w - margin)) + { + origin.setX((w - pw) / 2); + } + + p->drawPixmap(origin, pix); +} + +void SimpleButton::generateIcons() +{ + if (!pixmap()) + { + return; + } + + QImage image = pixmap()->convertToImage(); + KIconEffect effect; + + m_normalIcon = effect.apply(image, KIcon::Panel, KIcon::DefaultState); + m_activeIcon = effect.apply(image, KIcon::Panel, KIcon::ActiveState); + m_disabledIcon = effect.apply(image, KIcon::Panel, KIcon::DisabledState); + + updateGeometry(); +} + +void SimpleButton::slotSettingsChanged(int category) +{ + if (category != KApplication::SETTINGS_MOUSE) + { + return; + } + + bool changeCursor = KGlobalSettings::changeCursorOverIcon(); + + if (changeCursor) + { + setCursor(KCursor::handCursor()); + } + else + { + unsetCursor(); + } +} + +void SimpleButton::slotIconChanged( int group ) +{ + if (group != KIcon::Panel) + { + return; + } + + generateIcons(); + update(); +} + +void SimpleButton::enterEvent( QEvent *e ) +{ + m_highlight = true; + + repaint( false ); + QButton::enterEvent( e ); +} + +void SimpleButton::leaveEvent( QEvent *e ) +{ + m_highlight = false; + + repaint( false ); + QButton::enterEvent( e ); +} + +void SimpleButton::resizeEvent( QResizeEvent * ) +{ + generateIcons(); +} + + +SimpleArrowButton::SimpleArrowButton(QWidget *parent, Qt::ArrowType arrow, const char *name) + : SimpleButton(parent, name) +{ + setBackgroundOrigin(AncestorOrigin); + _arrow = arrow; + _inside = false; +} + +QSize SimpleArrowButton::sizeHint() const +{ + return QSize( 12, 12 ); +} + +void SimpleArrowButton::setArrowType(Qt::ArrowType a) +{ + if (_arrow != a) + { + _arrow = a; + update(); + } +} + +Qt::ArrowType SimpleArrowButton::arrowType() const +{ + return _arrow; +} + +void SimpleArrowButton::drawButton( QPainter *p ) +{ + QRect r(1, 1, width() - 2, height() - 2); + + QStyle::PrimitiveElement pe = QStyle::PE_ArrowLeft; + switch (_arrow) + { + case Qt::LeftArrow: pe = QStyle::PE_ArrowLeft; break; + case Qt::RightArrow: pe = QStyle::PE_ArrowRight; break; + case Qt::UpArrow: pe = QStyle::PE_ArrowUp; break; + case Qt::DownArrow: pe = QStyle::PE_ArrowDown; break; + } + + int flags = QStyle::Style_Default | QStyle::Style_Enabled; + if (isDown() || isOn()) flags |= QStyle::Style_Down; + style().drawPrimitive(pe, p, r, colorGroup(), flags); +} + +void SimpleArrowButton::enterEvent( QEvent *e ) +{ + _inside = true; + SimpleButton::enterEvent( e ); + update(); +} + +void SimpleArrowButton::leaveEvent( QEvent *e ) +{ + _inside = false; + SimpleButton::enterEvent( e ); + update(); +} + +#include "simplebutton.moc" + +// vim:ts=4:sw=4:et diff --git a/kicker/libkicker/simplebutton.h b/kicker/libkicker/simplebutton.h new file mode 100644 index 000000000..5423dff6b --- /dev/null +++ b/kicker/libkicker/simplebutton.h @@ -0,0 +1,89 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2004 Nadeem Hasan + Copyright (C) 2004-2005 Aaron J. Seigo + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SIMPLEBUTTON_H +#define SIMPLEBUTTON_H + +#include +#include + +#include + +class KDE_EXPORT SimpleButton : public QButton +{ + Q_OBJECT + + public: + SimpleButton(QWidget *parent, const char *name = 0); + void setPixmap(const QPixmap &pix); + void setOrientation(Qt::Orientation orientaton); + QSize sizeHint() const; + QSize minimumSizeHint() const; + + protected: + void drawButton( QPainter *p ); + void drawButtonLabel( QPainter *p ); + void generateIcons(); + + void enterEvent( QEvent *e ); + void leaveEvent( QEvent *e ); + void resizeEvent( QResizeEvent *e ); + + protected slots: + virtual void slotSettingsChanged( int category ); + virtual void slotIconChanged( int group ); + + private: + bool m_highlight; + QPixmap m_normalIcon; + QPixmap m_activeIcon; + QPixmap m_disabledIcon; + Qt::Orientation m_orientation; + class SimpleButtonPrivate; + SimpleButtonPrivate* d; +}; + +class KDE_EXPORT SimpleArrowButton: public SimpleButton +{ + Q_OBJECT + + public: + SimpleArrowButton(QWidget *parent = 0, Qt::ArrowType arrow = Qt::UpArrow, const char *name = 0); + virtual ~SimpleArrowButton() {}; + QSize sizeHint() const; + + protected: + virtual void enterEvent( QEvent *e ); + virtual void leaveEvent( QEvent *e ); + virtual void drawButton(QPainter *p); + Qt::ArrowType arrowType() const; + + public slots: + void setArrowType(Qt::ArrowType a); + + private: + Qt::ArrowType _arrow; + bool _inside; +}; + + +#endif // HIDEBUTTON_H + +// vim:ts=4:sw=4:et -- cgit v1.2.1