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 --- kdm/kfrontend/themer/Makefile.am | 16 ++ kdm/kfrontend/themer/kdmitem.cpp | 532 +++++++++++++++++++++++++++++++++++++ kdm/kfrontend/themer/kdmitem.h | 263 ++++++++++++++++++ kdm/kfrontend/themer/kdmlabel.cpp | 231 ++++++++++++++++ kdm/kfrontend/themer/kdmlabel.h | 81 ++++++ kdm/kfrontend/themer/kdmlayout.cpp | 167 ++++++++++++ kdm/kfrontend/themer/kdmlayout.h | 98 +++++++ kdm/kfrontend/themer/kdmpixmap.cpp | 242 +++++++++++++++++ kdm/kfrontend/themer/kdmpixmap.h | 69 +++++ kdm/kfrontend/themer/kdmrect.cpp | 154 +++++++++++ kdm/kfrontend/themer/kdmrect.h | 65 +++++ kdm/kfrontend/themer/kdmthemer.cpp | 329 +++++++++++++++++++++++ kdm/kfrontend/themer/kdmthemer.h | 123 +++++++++ 13 files changed, 2370 insertions(+) create mode 100644 kdm/kfrontend/themer/Makefile.am create mode 100644 kdm/kfrontend/themer/kdmitem.cpp create mode 100644 kdm/kfrontend/themer/kdmitem.h create mode 100644 kdm/kfrontend/themer/kdmlabel.cpp create mode 100644 kdm/kfrontend/themer/kdmlabel.h create mode 100644 kdm/kfrontend/themer/kdmlayout.cpp create mode 100644 kdm/kfrontend/themer/kdmlayout.h create mode 100644 kdm/kfrontend/themer/kdmpixmap.cpp create mode 100644 kdm/kfrontend/themer/kdmpixmap.h create mode 100644 kdm/kfrontend/themer/kdmrect.cpp create mode 100644 kdm/kfrontend/themer/kdmrect.h create mode 100644 kdm/kfrontend/themer/kdmthemer.cpp create mode 100644 kdm/kfrontend/themer/kdmthemer.h (limited to 'kdm/kfrontend/themer') diff --git a/kdm/kfrontend/themer/Makefile.am b/kdm/kfrontend/themer/Makefile.am new file mode 100644 index 000000000..7f6eb5701 --- /dev/null +++ b/kdm/kfrontend/themer/Makefile.am @@ -0,0 +1,16 @@ +AM_CPPFLAGS = -I$(srcdir)/../../backend -I$(srcdir)/.. -I../.. \ + -I$(top_srcdir)/kdmlib \ + $(all_includes) + +noinst_LIBRARIES = libkdmthemer.a +libkdmthemer_a_SOURCES = \ + kdmthemer.cpp \ + kdmitem.cpp \ + kdmpixmap.cpp \ + kdmrect.cpp \ + kdmlabel.cpp \ + kdmlayout.cpp + +METASOURCES = AUTO + +libkdmthemer_a_COMPILE_FIRST = ../../config.ci diff --git a/kdm/kfrontend/themer/kdmitem.cpp b/kdm/kfrontend/themer/kdmitem.cpp new file mode 100644 index 000000000..48c0d1faf --- /dev/null +++ b/kdm/kfrontend/themer/kdmitem.cpp @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Generic Kdm Item + */ + +//#define DRAW_OUTLINE 1 // for debugging only + +#include "kdmitem.h" +#include "kdmlayout.h" + +#include +#include + +#include +#include +#include +#include +#ifdef DRAW_OUTLINE +# include +#endif + +KdmItem::KdmItem( KdmItem *parent, const QDomNode &node, const char *name ) + : QObject( parent, name ) + , boxManager( 0 ) + , fixedManager( 0 ) + , image( 0 ) + , myWidget( 0 ) + , myLayoutItem( 0 ) + , buttonParent( 0 ) +{ + // Set default layout for every item + currentManager = MNone; + pos.x = pos.y = 0; + pos.width = pos.height = 1; + pos.xType = pos.yType = pos.wType = pos.hType = DTnone; + pos.anchor = "nw"; + + isShown = InitialHidden; + + // Set defaults for derived item's properties + properties.incrementalPaint = false; + state = Snormal; + + // The "toplevel" node (the screen) is really just like a fixed node + if (!parent || !parent->inherits( "KdmItem" )) { + setFixedLayout(); + return; + } + // Read the mandatory Pos tag. Other tags such as normal, prelighted, + // etc.. are read under specific implementations. + QDomNodeList childList = node.childNodes(); + for (uint nod = 0; nod < childList.count(); nod++) { + QDomNode child = childList.item( nod ); + QDomElement el = child.toElement(); + QString tagName = el.tagName(), attr; + + if (tagName == "pos") { + parseAttribute( el.attribute( "x", QString::null ), pos.x, pos.xType ); + parseAttribute( el.attribute( "y", QString::null ), pos.y, pos.yType ); + parseAttribute( el.attribute( "width", QString::null ), pos.width, pos.wType ); + parseAttribute( el.attribute( "height", QString::null ), pos.height, pos.hType ); + pos.anchor = el.attribute( "anchor", "nw" ); + } + } + + QDomNode tnode = node; + id = tnode.toElement().attribute( "id", QString::number( (ulong)this, 16 ) ); + + // Tell 'parent' to add 'me' to its children + KdmItem *parentItem = static_cast( parent ); + parentItem->addChildItem( this ); +} + +KdmItem::~KdmItem() +{ + delete boxManager; + delete fixedManager; + delete image; +} + +void +KdmItem::update() +{ +} + +void +KdmItem::needUpdate() +{ + emit needUpdate( area.x(), area.y(), area.width(), area.height() ); +} + +void +KdmItem::show( bool force ) +{ + if (isShown != InitialHidden && !force) + return; + + QValueList::Iterator it; + for (it = m_children.begin(); it != m_children.end(); ++it) + (*it)->show(); + + isShown = Shown; + + if (myWidget) + myWidget->show(); + // XXX showing of layouts not implemented, prolly pointless anyway + + needUpdate(); +} + +void +KdmItem::hide( bool force ) +{ + if (isShown == ExplicitlyHidden) + return; + + if (isShown == InitialHidden && force) { + isShown = ExplicitlyHidden; + return; // no need for further action + } + + QValueList::Iterator it; + for (it = m_children.begin(); it != m_children.end(); ++it) + (*it)->hide(); + + isShown = force ? ExplicitlyHidden : InitialHidden; + + if (myWidget) + myWidget->hide(); + // XXX hiding of layouts not implemented, prolly pointless anyway + + needUpdate(); +} + +void +KdmItem::inheritFromButton( KdmItem *button ) +{ + if (button) + buttonParent = button; + + QValueList::Iterator it; + for (it = m_children.begin(); it != m_children.end(); ++it) + (*it)->inheritFromButton( button ); +} + +KdmItem * +KdmItem::findNode( const QString &_id ) const +{ + if (id == _id) + return const_cast( this ); + + QValueList::ConstIterator it; + for (it = m_children.begin(); it != m_children.end(); ++it) { + KdmItem *t = (*it)->findNode( _id ); + if (t) + return t; + } + + return 0; +} + +void +KdmItem::setWidget( QWidget *widget ) +{ +// delete myWidget; -- themer->widget() owns the widgets + + myWidget = widget; + if (isHidden()) + myWidget->hide(); + else + myWidget->show(); + + // Remove borders so that it blends nicely with the theme background + QFrame* frame = ::qt_cast( widget ); + if (frame) + frame->setFrameStyle( QFrame::NoFrame ); + + myWidget->setGeometry(area); + + connect( myWidget, SIGNAL(destroyed()), SLOT(widgetGone()) ); +} + +void +KdmItem::widgetGone() +{ + myWidget = 0; +} + +void +KdmItem::setLayoutItem( QLayoutItem *item ) +{ + myLayoutItem = item; + // XXX hiding not supported - it think it's pointless here + if (myLayoutItem->widget()) + connect( myLayoutItem->widget(), SIGNAL(destroyed()), + SLOT(layoutItemGone()) ); + else if (myLayoutItem->layout()) + connect( myLayoutItem->layout(), SIGNAL(destroyed()), + SLOT(layoutItemGone()) ); +} + +void +KdmItem::layoutItemGone() +{ + myLayoutItem = 0; +} + +/* This is called as a result of KdmLayout::update, and directly on the root */ +void +KdmItem::setGeometry( const QRect &newGeometry, bool force ) +{ + kdDebug() << " KdmItem::setGeometry " << id << newGeometry << endl; + // check if already 'in place' + if (!force && area == newGeometry) + return; + + area = newGeometry; + + if (myWidget) + myWidget->setGeometry( newGeometry ); + if (myLayoutItem) + myLayoutItem->setGeometry( newGeometry ); + + // recurr to all boxed children + if (boxManager && !boxManager->isEmpty()) + boxManager->update( newGeometry, force ); + + // recurr to all fixed children + if (fixedManager && !fixedManager->isEmpty()) + fixedManager->update( newGeometry, force ); + + // TODO send *selective* repaint signal +} + +void +KdmItem::paint( QPainter *p, const QRect &rect ) +{ + if (isHidden()) + return; + + if (myWidget || (myLayoutItem && myLayoutItem->widget())) + return; + + if (area.intersects( rect )) { + QRect contentsRect = area.intersect( rect ); + contentsRect.moveBy( QMIN( 0, -area.x() ), QMIN( 0, -area.y() ) ); + drawContents( p, contentsRect ); + } + +#ifdef DRAW_OUTLINE + // Draw bounding rect for this item + p->setPen( Qt::white ); + p->drawRect( area ); +#endif + + if (myLayoutItem) + return; + + // Dispatch paint events to children + QValueList::Iterator it; + for (it = m_children.begin(); it != m_children.end(); ++it) + (*it)->paint( p, rect ); +} + +KdmItem *KdmItem::currentActive = 0; + +void +KdmItem::mouseEvent( int x, int y, bool pressed, bool released ) +{ + if (buttonParent && buttonParent != this) { + buttonParent->mouseEvent( x, y, pressed, released ); + return; + } + + ItemState oldState = state; + if (area.contains( x, y )) { + if (released && oldState == Sactive) { + if (buttonParent) + emit activated( id ); + state = Sprelight; + currentActive = 0; + } else if (pressed || currentActive == this) { + state = Sactive; + currentActive = this; + } else if (!currentActive) + state = Sprelight; + else + state = Snormal; + } else { + if (released) + currentActive = 0; + if (currentActive == this) + state = Sprelight; + else + state = Snormal; + } + + if (!buttonParent) { + QValueList::Iterator it; + for (it = m_children.begin(); it != m_children.end(); ++it) + (*it)->mouseEvent( x, y, pressed, released ); + } + + if (oldState != state) + statusChanged(); +} + +void +KdmItem::statusChanged() +{ + if (buttonParent == this) { + QValueList::Iterator it; + for (it = m_children.begin(); it != m_children.end(); ++it) { + (*it)->state = state; + (*it)->statusChanged(); + } + } +} + +// BEGIN protected inheritable + +QSize +KdmItem::sizeHint() +{ + if (myWidget) + return myWidget->size(); + if (myLayoutItem) + return myLayoutItem->sizeHint(); + int w = pos.wType == DTpixel ? kAbs( pos.width ) : -1, + h = pos.hType == DTpixel ? kAbs( pos.height ) : -1; + return QSize( w, h ); +} + +QRect +KdmItem::placementHint( const QRect &parentRect ) +{ + QSize hintedSize = sizeHint(); + QSize boxHint; + + int x = parentRect.left(), + y = parentRect.top(), + w = parentRect.width(), + h = parentRect.height(); + + kdDebug() << "KdmItem::placementHint parentRect=" << id << parentRect << " hintedSize=" << hintedSize << endl; + // check if width or height are set to "box" + if (pos.wType == DTbox || pos.hType == DTbox) { + if (myLayoutItem || myWidget) + boxHint = hintedSize; + else { + if (!boxManager) + return parentRect; + boxHint = boxManager->sizeHint(); + } + kdDebug() << " => boxHint " << boxHint << endl; + } + + if (pos.xType == DTpixel) + x += pos.x; + else if (pos.xType == DTnpixel) + x = parentRect.right() - pos.x; + else if (pos.xType == DTpercent) + x += int( parentRect.width() / 100.0 * pos.x ); + + if (pos.yType == DTpixel) + y += pos.y; + else if (pos.yType == DTnpixel) + y = parentRect.bottom() - pos.y; + else if (pos.yType == DTpercent) + y += int( parentRect.height() / 100.0 * pos.y ); + + if (pos.wType == DTpixel) + w = pos.width; + else if (pos.wType == DTnpixel) + w -= pos.width; + else if (pos.wType == DTpercent) + w = int( parentRect.width() / 100.0 * pos.width ); + else if (pos.wType == DTbox) + w = boxHint.width(); + else if (hintedSize.width() > 0) + w = hintedSize.width(); + else + w = 0; + + if (pos.hType == DTpixel) + h = pos.height; + else if (pos.hType == DTnpixel) + h -= pos.height; + else if (pos.hType == DTpercent) + h = int( parentRect.height() / 100.0 * pos.height ); + else if (pos.hType == DTbox) + h = boxHint.height(); + else if (hintedSize.height() > 0) + h = hintedSize.height(); + else + h = 0; + + // defaults to center + int dx = -w / 2, dy = -h / 2; + + // anchor the rect to an edge / corner + if (pos.anchor.length() > 0 && pos.anchor.length() < 3) { + if (pos.anchor.find( 'n' ) >= 0) + dy = 0; + if (pos.anchor.find( 's' ) >= 0) + dy = -h; + if (pos.anchor.find( 'w' ) >= 0) + dx = 0; + if (pos.anchor.find( 'e' ) >= 0) + dx = -w; + } + // KdmItem *p = static_cast( parent() ); + kdDebug() << "KdmItem::placementHint " << id << " x=" << x << " dx=" << dx << " w=" << w << " y=" << y << " dy=" << dy << " h=" << h << " " << parentRect << endl; + y += dy; + x += dx; + + // Note: no clipping to parent because this broke many themes! + return QRect( x, y, w, h ); +} + +// END protected inheritable + + +void +KdmItem::addChildItem( KdmItem *item ) +{ + m_children.append( item ); + switch (currentManager) { + case MNone: // fallback to the 'fixed' case + setFixedLayout(); + case MFixed: + fixedManager->addItem( item ); + break; + case MBox: + boxManager->addItem( item ); + break; + } + + // signal bounce from child to parent + connect( item, SIGNAL(needUpdate( int, int, int, int )), SIGNAL(needUpdate( int, int, int, int )) ); + connect( item, SIGNAL(activated( const QString & )), SIGNAL(activated( const QString & )) ); +} + +void +KdmItem::parseAttribute( const QString &s, int &val, enum DataType &dType ) +{ + if (s.isEmpty()) + return; + + int p; + if (s == "box") { // box value + dType = DTbox; + val = 0; + } else if ((p = s.find( '%' )) >= 0) { // percent value + dType = DTpercent; + QString sCopy = s; + sCopy.remove( p, 1 ); + sCopy.replace( ',', '.' ); + val = (int)sCopy.toDouble(); + } else { // int value + dType = DTpixel; + QString sCopy = s; + if (sCopy.at( 0 ) == '-') { + sCopy.remove( 0, 1 ); + dType = DTnpixel; + } + sCopy.replace( ',', '.' ); + val = (int)sCopy.toDouble(); + } +} + +void +KdmItem::parseFont( const QString &s, QFont &font ) +{ + int splitAt = s.findRev( ' ' ); + if (splitAt < 1) + return; + font.setFamily( s.left( splitAt ) ); + int fontSize = s.mid( splitAt + 1 ).toInt(); + if (fontSize > 1) + font.setPointSize( fontSize ); +} + +void +KdmItem::parseColor( const QString &s, QColor &color ) +{ + if (s.at( 0 ) != '#') + return; + bool ok; + QString sCopy = s; + int hexColor = sCopy.remove( 0, 1 ).toInt( &ok, 16 ); + if (ok) + color.setRgb( hexColor ); +} + +void +KdmItem::setBoxLayout( const QDomNode &node ) +{ + if (!boxManager) + boxManager = new KdmLayoutBox( node ); + currentManager = MBox; +} + +void +KdmItem::setFixedLayout( const QDomNode &node ) +{ + if (!fixedManager) + fixedManager = new KdmLayoutFixed( node ); + currentManager = MFixed; +} + +#include "kdmitem.moc" diff --git a/kdm/kfrontend/themer/kdmitem.h b/kdm/kfrontend/themer/kdmitem.h new file mode 100644 index 000000000..66feedd02 --- /dev/null +++ b/kdm/kfrontend/themer/kdmitem.h @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KDMITEM_H +#define KDMITEM_H + +#include +#include +#include +#include + +class KdmItem; +class KdmLayoutBox; +class KdmLayoutFixed; + +class QPainter; +class QLayoutItem; + +/** class KdmItem + * @short Base class for every kdmthemes' element. + * + * This class provides methods for arranging it and its children to the + * screen (see note below), painting the whole area or a sub-region using + * an opened painter, handling mouse events or events in general dispatching + * them to children and sending some signals to the root (for example on + * mouse click). + * + * KdmItem sits in a hierarchical top to bottom tree with signals that + * traverse the tree back from leafs (or inner nodes) to the root. + * + * To implement a KdmItem only a few virtual protected methods must be + * reimplemented, other virtual functions are there for convenience only - + * the default implementation should satisfy your needs. + */ + +/** + * A note on layouting - how does it work? + * - setgeometry is called by parent (passing the new geometry) + * - item changes its geometry + * - if item embeds a widget, reposition it too + * - call children's box manager. box->update( my geom ) + * - sum up the whole space taken by children (via *hint calls) if + * needed for box width / height computation. note that the computed + * geometry should be equal or similar to parent's geometry. + * - pad the rectangle bounding box' contents + * - for every child + * - if vertical + * ( use a top-to-bottom insertion, spacing insertion lines by + * children's individual height ) + * - set up a zero height Parent (placed at the insertion line's + * position) and get Geom = child->placementHint( p ) + * - set up child's Size using Parent's width and Geom's height. + * - call to child->setGeometry( Parent.topLeft, Size ) + * - if horizontal + * - flows like the vertical one but uses a left-to-right insertion + * and insertion entry points are vertical lines + * - call to children's fix manager. fixed->update( my geom ) + * - for every child + * - S = get child's geometry hint (and we'll give item the whole + * space it needs, without constraints) + * - call to child->setGeometry( S ) + * - TODO: send a selective redraw signal also merging children's areas + */ + +class KdmItem : public QObject { + Q_OBJECT + + friend class KdmThemer; + +public: + /** + * Item constructor and destructor + */ + KdmItem( KdmItem *parent, const QDomNode &node = QDomNode(), const char *name = 0 ); + virtual ~KdmItem(); + + /** + * Fixup the geometry of an item and its children (even if fixed + * or boxed ones). Note that this will generate repaint signals + * when needed. The default implementation should fit all needs. + */ + virtual void setGeometry( const QRect &newGeometry, bool force ); + + /** + * Paint the item and its children using the given painter. + * This is the compositing core function. It buffers paint operations + * to speed up rendering of dynamic objects. + */ + void paint( QPainter *painter, const QRect &boundaries ); + + /** + * Update representation of contents and repaint. + */ + virtual void update(); + + /** + * Handle mouse motion and dispatch events to children. This + * leads to items prelighting, activation() on click and more.. + */ + void mouseEvent( int x, int y, bool pressed = false, bool released = false ); + + /** + * Similar to sizeHint(..), this returns the area of the item + * given the @p parentGeometry. The default implementation + * takes into account geometric constraints and layoutings. + * @param parentGeometry the geometry of the caller item or a + * null rect if the geometry of the parent is not yet defined. + */ + virtual QRect placementHint( const QRect &parentGeometry ); + + /** + * Create the box layout manager; next children will be + * managed by the box layouter + */ + void setBoxLayout( const QDomNode &node = QDomNode() ); + + /** + * Create the fixed layout manager; next children will be + * in fixed position relative to this item + */ + void setFixedLayout( const QDomNode &node = QDomNode() ); + + QString type() const { return itemType; } + void setType( const QString &t ) { itemType = t; } + void setBaseDir( const QString &bd ) { basedir = bd; } + + QString baseDir() const + { + if (basedir.isEmpty() && parent()) + return static_cast( parent()->qt_cast( "KdmItem" ) )->baseDir(); + return basedir; + } + + KdmItem *findNode( const QString &id ) const; + virtual void setWidget( QWidget *widget ); + virtual void setLayoutItem( QLayoutItem *item ); + + virtual void hide( bool force = false ); + virtual void show( bool force = false ); + + bool isHidden() const { return isShown != Shown; } + bool isExplicitlyHidden() const { return isShown == ExplicitlyHidden; } + QRect rect() const { return area; } + +signals: + void needUpdate( int x, int y, int w, int h ); + void activated( const QString &id ); + +protected slots: + void widgetGone(); + void layoutItemGone(); + +protected: + /** + * Returns the optimal/minimal size for this item. + * This should be reimplemented in items like label and pixmap. + * @return (-1,-1) if no size can be determined (so it should + * default to parent's size). + */ + virtual QSize sizeHint(); + + /** + * Low level graphical function to paint the item. + * All items must reimplement this function to draw themeselves + * (or a part of) into the @p image keeping inside the @p rect . + * Try to do this as fast as possible. + * @param painter the painter to draw the item with + * @param region the part of the the image to render + */ + virtual void drawContents( QPainter *painter, const QRect ®ion ) = 0; + + /** + * Called when item changes its 'state' variable. This must + * handle item's repaint. + */ + virtual void statusChanged(); + + /** + * emits needUpdate( int, int, int, int ) with the full widget area. + */ + void needUpdate(); + + // This enum identifies in which state the item is + enum ItemState { Snormal, Sactive, Sprelight } state; + + static KdmItem *currentActive; + + // This struct can be filled in by derived items + struct { + bool incrementalPaint; + } properties; + + // This is the placement of the item + QRect area; + + // This struct is filled in by KdmItem base class + enum DataType { DTnone, DTpixel, DTnpixel, DTpercent, DTbox }; + struct { + enum DataType xType, yType, wType, hType; + int x; + int y; + int width; + int height; + QString anchor; + } pos; + + /* For internal use ONLY + * Add a child item. This function is called automatically + * when constructing an @p item with this as the parent. + */ + void addChildItem( KdmItem *item ); + + /* For internal use ONLY + * Parse type and value of an attribute (pos tag), a font or a + * color. + */ + void parseAttribute( const QString &, int &, enum DataType & ); + void parseFont( const QString &, QFont & ); + void parseColor( const QString &, QColor & ); + + void inheritFromButton( KdmItem *button ); + + QString itemType, id; + QValueList m_children; + + // Layouting related variables + enum { MNone = 0, MFixed = 1, MBox = 2 } currentManager; + KdmLayoutBox *boxManager; + KdmLayoutFixed *fixedManager; + + // Compositing related variables + QImage *image; + + // defines the directory the theme is in (may be present in the parent) + QString basedir; + + QWidget *myWidget; + QLayoutItem *myLayoutItem; + + enum { InitialHidden, ExplicitlyHidden, Shown } isShown; + + KdmItem *buttonParent; +}; + +#endif diff --git a/kdm/kfrontend/themer/kdmlabel.cpp b/kdm/kfrontend/themer/kdmlabel.cpp new file mode 100644 index 000000000..41d7e4254 --- /dev/null +++ b/kdm/kfrontend/themer/kdmlabel.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kdmlabel.h" +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#if !defined(HAVE_GETDOMAINNAME) && defined(HAVE_SYSINFO) +# include +#endif + +KdmLabel::KdmLabel( KdmItem *parent, const QDomNode &node, const char *name ) + : KdmItem( parent, node, name ) +{ + itemType = "label"; + + // Set default values for label (note: strings are already Null) + label.active.color.setRgb( 0xFFFFFF ); + label.active.present = false; + label.prelight.present = false; + label.maximumWidth = -1; + + const QString locale = KGlobal::locale()->language(); + + // Read LABEL ID + QDomNode n = node; + QDomElement elLab = n.toElement(); + // ID types: clock, pam-error, pam-message, pam-prompt, + // pam-warning, timed-label + label.id = elLab.attribute( "id", "" ); + label.hasId = !(label.id).isEmpty(); + + // Read LABEL TAGS + QDomNodeList childList = node.childNodes(); + bool stockUsed = false; + for (uint nod = 0; nod < childList.count(); nod++) { + QDomNode child = childList.item( nod ); + QDomElement el = child.toElement(); + QString tagName = el.tagName(); + + if (tagName == "pos") + label.maximumWidth = el.attribute( "max-width", "-1" ).toInt(); + else if (tagName == "normal") { + parseColor( el.attribute( "color", "#ffffff" ), label.normal.color ); + parseFont( el.attribute( "font", "Sans 14" ), label.normal.font ); + } else if (tagName == "active") { + label.active.present = true; + parseColor( el.attribute( "color", "#ffffff" ), label.active.color ); + parseFont( el.attribute( "font", "Sans 14" ), label.active.font ); + } else if (tagName == "prelight") { + label.prelight.present = true; + parseColor( el.attribute( "color", "#ffffff" ), label.prelight.color ); + parseFont( el.attribute( "font", "Sans 14" ), label.prelight.font ); + } else if (tagName == "text" && el.attributes().count() == 0 && !stockUsed) { + label.text = el.text(); + } else if (tagName == "text" && !stockUsed) { + QString lang = el.attribute( "xml:lang", "" ); + if (lang == locale) + label.text = el.text(); + } else if (tagName == "stock") { + label.text = lookupStock( el.attribute( "type", "" ) ); + stockUsed = true; + } + } + + // Check if this is a timer label + label.isTimer = label.text.find( "%c" ) >= 0; + if (label.isTimer) { + timer = new QTimer( this ); + timer->start( 1000 ); + connect( timer, SIGNAL(timeout()), SLOT(update()) ); + } + cText = lookupText( label.text ); +} + +void +KdmLabel::setText( const QString &txt ) +{ + label.text = txt; + update(); +} + +QSize +KdmLabel::sizeHint() +{ + // choose the correct label class + struct LabelStruct::LabelClass *l = &label.normal; + if (state == Sactive && label.active.present) + l = &label.active; + else if (state == Sprelight && label.prelight.present) + l = &label.prelight; + // get the hint from font metrics + QSize hint = QFontMetrics( l->font ).size( AlignLeft | SingleLine, cText ); + // clip the result using the max-width label(pos) parameter + if (label.maximumWidth > 0 && hint.width() > label.maximumWidth) + hint.setWidth( label.maximumWidth ); + return hint; +} + +void +KdmLabel::drawContents( QPainter *p, const QRect &/*r*/ ) +{ + // choose the correct label class + struct LabelStruct::LabelClass *l = &label.normal; + if (state == Sactive && label.active.present) + l = &label.active; + else if (state == Sprelight && label.prelight.present) + l = &label.prelight; + // draw the label + p->setFont( l->font ); + p->setPen( l->color ); + //TODO paint clipped (tested but not working..) + p->drawText( area, AlignLeft | SingleLine, cText ); +} + +void +KdmLabel::statusChanged() +{ + KdmItem::statusChanged(); + if (!label.active.present && !label.prelight.present) + return; + if ((state == Sprelight && !label.prelight.present) || + (state == Sactive && !label.active.present)) + return; + needUpdate(); +} + +void +KdmLabel::update() +{ + QString text = lookupText( label.text ); + if (text != cText) { + cText = text; + needUpdate(); + } +} + +static const struct { + const char *type, *text; +} stocks[] = { + { "language", I18N_NOOP("Language") }, + { "session", I18N_NOOP("Session Type") }, + { "system", I18N_NOOP("Menu") }, // i18n("Actions"); + { "disconnect", I18N_NOOP("Disconnect") }, + { "quit", I18N_NOOP("Quit") }, + { "halt", I18N_NOOP("Power off") }, + { "suspend", I18N_NOOP("Suspend") }, + { "reboot", I18N_NOOP("Reboot") }, + { "chooser", I18N_NOOP("XDMCP Chooser") }, + { "config", I18N_NOOP("Configure") }, + { "caps-lock-warning", I18N_NOOP("You have got caps lock on.") }, + { "timed-label", I18N_NOOP("User %s will login in %d seconds") }, + { "welcome-label", I18N_NOOP("Welcome to %h") }, // _greetString + { "username-label", I18N_NOOP("Username:") }, + { "password-label", I18N_NOOP("Password:") }, + { "login", I18N_NOOP("Login") } +}; + +QString +KdmLabel::lookupStock( const QString &stock ) +{ + //FIXME add key accels! + QString type( stock.lower() ); + + for (uint i = 0; i < sizeof(stocks)/sizeof(stocks[0]); i++) + if (type == stocks[i].type) + return i18n(stocks[i].text); + + kdDebug() << "Invalid element. Check your theme!" << endl; + return stock; +} + +QString +KdmLabel::lookupText( const QString &t ) +{ + QString text = t; + + text.replace( '_', '&' ); +// text.remove( '_' ); // FIXME add key accels, remove underscores for now + + QMap m; + struct utsname uts; + uname( &uts ); + m['n'] = QString::fromLocal8Bit( uts.nodename ); + char buf[256]; + buf[sizeof(buf) - 1] = '\0'; + m['h'] = gethostname( buf, sizeof(buf) - 1 ) ? "localhost" : QString::fromLocal8Bit( buf ); +#ifdef HAVE_GETDOMAINNAME + m['o'] = getdomainname( buf, sizeof(buf) - 1 ) ? "localdomain" : QString::fromLocal8Bit( buf ); +#elif defined(HAVE_SYSINFO) + m['o'] = (unsigned)sysinfo( SI_SRPC_DOMAIN, buf, sizeof(buf) ) > sizeof(buf) ? "localdomain" : QString::fromLocal8Bit( buf ); +#endif + m['d'] = QString::number( KThemedGreeter::timedDelay ); + m['s'] = KThemedGreeter::timedUser; + // xgettext:no-c-format + KGlobal::locale()->setDateFormat( i18n("date format", "%a %d %B") ); + m['c'] = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(), false, false ); + + return KMacroExpander::expandMacros( text, m ); +} + +#include "kdmlabel.moc" diff --git a/kdm/kfrontend/themer/kdmlabel.h b/kdm/kfrontend/themer/kdmlabel.h new file mode 100644 index 000000000..b80d0189a --- /dev/null +++ b/kdm/kfrontend/themer/kdmlabel.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KDELABEL_H +#define KDELABEL_H + +#include "kdmitem.h" + +#include +#include + +class QTimer; + +/* + * KdmLabel. A label element + */ + +class KdmLabel : public KdmItem { + Q_OBJECT + +public: + KdmLabel( KdmItem *parent, const QDomNode &node, const char *name = 0 ); + void setText( const QString &txt ); + +protected: + // reimplemented; returns the minimum size of rendered text + virtual QSize sizeHint(); + + // draw the label + virtual void drawContents( QPainter *p, const QRect &r ); + + // handle switching between normal / active / prelight configurations + virtual void statusChanged(); + + struct LabelStruct { + QString text; + bool isTimer; + bool hasId; + QString id; + struct LabelClass { + QColor color; + QFont font; + bool present; + } normal, active, prelight; + int maximumWidth; + } label; + + QTimer *timer; + +public slots: + void update(); + +private: + /* Method to lookup the caption associated with an item */ + QString lookupStock( const QString &stock ); + + /* Lookup variables in the text */ + QString lookupText( const QString &t ); + + QString cText; +}; + +#endif diff --git a/kdm/kfrontend/themer/kdmlayout.cpp b/kdm/kfrontend/themer/kdmlayout.cpp new file mode 100644 index 000000000..ed93be264 --- /dev/null +++ b/kdm/kfrontend/themer/kdmlayout.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kdmlayout.h" +#include "kdmitem.h" + +#include + +#include +#include + +KdmLayoutFixed::KdmLayoutFixed( const QDomNode &/*node*/ ) +{ + //Parsing FIXED parameters on 'node' [NONE!] +} + +void +KdmLayoutFixed::update( const QRect &parentGeometry, bool force ) +{ + kdDebug() << "KdmLayoutFixed::update " << parentGeometry << endl; + + // I can't layout children if the parent rectangle is not valid + if (parentGeometry.width() < 0 || parentGeometry.height() < 0) { + kdDebug() << "invalid\n"; + return; + } + // For each child in list I ask their hinted size and set it! + for (QValueList::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) + (*it)->setGeometry( (*it)->placementHint( parentGeometry ), force ); +} + +KdmLayoutBox::KdmLayoutBox( const QDomNode &node ) +{ + //Parsing BOX parameters + QDomNode n = node; + QDomElement el = n.toElement(); + box.isVertical = el.attribute( "orientation", "vertical" ) != "horizontal"; + box.xpadding = el.attribute( "xpadding", "0" ).toInt(); + box.ypadding = el.attribute( "ypadding", "0" ).toInt(); + box.spacing = el.attribute( "spacing", "0" ).toInt(); + box.minwidth = el.attribute( "min-width", "0" ).toInt(); + box.minheight = el.attribute( "min-height", "0" ).toInt(); + box.homogeneous = el.attribute( "homogeneous", "false" ) == "true"; +} + +void +KdmLayoutBox::update( const QRect &parentGeometry, bool force ) +{ + kdDebug() << this << " update " << parentGeometry << endl; + + // I can't layout children if the parent rectangle is not valid + if (!parentGeometry.isValid() || parentGeometry.isEmpty()) + return; + + // Check if box size was computed. If not compute it + // TODO check if this prevents updating changing items +// if (!hintedSize.isValid()) +// sizeHint(); + +// kdDebug() << this << " hintedSize " << hintedSize << endl; + + //XXX why was this asymmetric? it broke things big time. + QRect childrenRect = /*box.isVertical ? QRect( parentGeometry.topLeft(), hintedSize ) :*/ parentGeometry; + // Begin cutting the parent rectangle to attach children on the right place + childrenRect.addCoords( box.xpadding, box.ypadding, -box.xpadding, -box.ypadding ); + + kdDebug() << this << " childrenRect " << childrenRect << endl; + + // For each child in list ... + if (box.homogeneous) { + int ccnt = 0; + for (QValueList::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) + if (!(*it)->isExplicitlyHidden()) + ccnt++; + int height = (childrenRect.height() - (ccnt - 1) * box.spacing) / ccnt; + int width = (childrenRect.width() - (ccnt - 1) * box.spacing) / ccnt; + + for (QValueList::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) { + if ((*it)->isExplicitlyHidden()) + continue; + if (box.isVertical) { + QRect temp( childrenRect.left(), childrenRect.top(), childrenRect.width(), height ); + (*it)->setGeometry( temp, force ); + childrenRect.setTop( childrenRect.top() + height + box.spacing ); + } else { + QRect temp( childrenRect.left(), childrenRect.top(), width, childrenRect.height() ); + kdDebug() << "placement " << *it << " " << temp << " " << (*it)->placementHint( temp ) << endl; + temp = (*it)->placementHint( temp ); + (*it)->setGeometry( temp, force ); + childrenRect.setLeft( childrenRect.left() + width + box.spacing ); + } + } + } else { + for (QValueList::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) { + if ((*it)->isExplicitlyHidden()) + continue; + + QRect temp = childrenRect, itemRect; + if (box.isVertical) { + temp.setHeight( 0 ); + itemRect = (*it)->placementHint( temp ); + temp.setHeight( itemRect.height() ); + childrenRect.setTop( childrenRect.top() + itemRect.size().height() + box.spacing ); + } else { + temp.setWidth( 0 ); + itemRect = (*it)->placementHint( temp ); + kdDebug() << this << " placementHint " << *it << " " << temp << " " << itemRect << endl; + temp.setWidth( itemRect.width() ); + childrenRect.setLeft( childrenRect.left() + itemRect.size().width() + box.spacing ); + kdDebug() << "childrenRect after " << *it << " " << childrenRect << endl; + } + itemRect = (*it)->placementHint( temp ); + kdDebug() << this << " placementHint2 " << *it << " " << temp << " " << itemRect << endl; + (*it)->setGeometry( itemRect, force ); + } + } +} + +//FIXME truly experimental (is so close to greeter_geometry.c) +QSize +KdmLayoutBox::sizeHint() +{ + // Sum up area taken by children + int w = 0, h = 0; + for (QValueList::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) { + QSize s = (*it)->placementHint( QRect() ).size(); + if (box.isVertical) { + if (s.width() > w) + w = s.width(); + h += s.height(); + } else { + if (s.height() > h) + h = s.height(); + w += s.width(); + } + } + + // Add padding and items spacing + w += 2 * box.xpadding; + h += 2 * box.ypadding; + if (box.isVertical) + h += box.spacing * (m_children.count() - 1); + else + w += box.spacing * (m_children.count() - 1); + + // Make hint at least equal to minimum size (if set) + return QSize( w < box.minwidth ? box.minwidth : w, + h < box.minheight ? box.minheight : h ); +} diff --git a/kdm/kfrontend/themer/kdmlayout.h b/kdm/kfrontend/themer/kdmlayout.h new file mode 100644 index 000000000..2e00675fb --- /dev/null +++ b/kdm/kfrontend/themer/kdmlayout.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KDMLAYOUT_H +#define KDMLAYOUT_H + +/** + * this is a container for a lot of other stuff + * but can be treated like a usual widget + */ + +#include +#include + +class KdmItem; + +class QDomNode; +class QRect; + +class KdmLayout { + +public: +// virtual ~KdmLayout() {}; + + // Adds an item that will be managed + void addItem( KdmItem *item ) { m_children.append( item ); } + + // Return false if any item are managed by this layouter + bool isEmpty() { return m_children.isEmpty(); } + + // Updates the layout of all items knowing that the parent + // has the @p parentGeometry geometry +// virtual void update( const QRect &parentGeometry ) = 0; + +protected: + QValueList m_children; +}; + +class KdmLayoutFixed : public KdmLayout { + +public: + KdmLayoutFixed( const QDomNode &node ); + + // Updates the layout of all boxed items knowing that the parent + // has the @p parentGeometry geometry + void update( const QRect &parentGeometry, bool force ); +}; + +/** + * this is a container for a lot of other stuff + * but can be treated like a usual widget + */ + +class KdmLayoutBox : public KdmLayout { + +public: + KdmLayoutBox( const QDomNode &node ); + + // Updates the layout of all boxed items knowing that they + // should fit into @p parentGeometry container + void update( const QRect &parentGeometry, bool force ); + + // Computes the size hint of the box, telling which is the + // smallest size inside which boxed items will fit + QSize sizeHint(); + +private: + struct { + bool isVertical; + int spacing; + int xpadding; + int ypadding; + int minwidth; + int minheight; + bool homogeneous; + } box; +// QSize hintedSize; +}; + +#endif diff --git a/kdm/kfrontend/themer/kdmpixmap.cpp b/kdm/kfrontend/themer/kdmpixmap.cpp new file mode 100644 index 000000000..337c19ced --- /dev/null +++ b/kdm/kfrontend/themer/kdmpixmap.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "kdmpixmap.h" + +#include +#ifdef HAVE_LIBART +#include +#endif + +#include + +#include +#include +#include + +KdmPixmap::KdmPixmap( KdmItem *parent, const QDomNode &node, const char *name ) + : KdmItem( parent, node, name ) +{ + itemType = "pixmap"; + + // Set default values for pixmap (note: strings are already Null) + pixmap.normal.tint.setRgb( 0xFFFFFF ); + pixmap.normal.alpha = 1.0; + pixmap.active.present = false; + pixmap.prelight.present = false; + + // Read PIXMAP ID + // it rarely happens that a pixmap can be a button too! + QDomNode n = node; + QDomElement elPix = n.toElement(); + + // Read PIXMAP TAGS + QDomNodeList childList = node.childNodes(); + for (uint nod = 0; nod < childList.count(); nod++) { + QDomNode child = childList.item( nod ); + QDomElement el = child.toElement(); + QString tagName = el.tagName(); + + if (tagName == "normal") { + loadPixmap( el.attribute( "file", "" ), pixmap.normal.pixmap, pixmap.normal.fullpath ); + parseColor( el.attribute( "tint", "#ffffff" ), pixmap.normal.tint ); + pixmap.normal.alpha = el.attribute( "alpha", "1.0" ).toFloat(); + } else if (tagName == "active") { + pixmap.active.present = true; + loadPixmap( el.attribute( "file", "" ), pixmap.active.pixmap, pixmap.active.fullpath ); + parseColor( el.attribute( "tint", "#ffffff" ), pixmap.active.tint ); + pixmap.active.alpha = el.attribute( "alpha", "1.0" ).toFloat(); + } else if (tagName == "prelight") { + pixmap.prelight.present = true; + loadPixmap( el.attribute( "file", "" ), pixmap.prelight.pixmap, pixmap.prelight.fullpath ); + parseColor( el.attribute( "tint", "#ffffff" ), pixmap.prelight.tint ); + pixmap.prelight.alpha = el.attribute( "alpha", "1.0" ).toFloat(); + } + } +} + +QSize +KdmPixmap::sizeHint() +{ + // choose the correct pixmap class + PixmapStruct::PixmapClass * pClass = &pixmap.normal; + if (state == Sactive && pixmap.active.present) + pClass = &pixmap.active; + if (state == Sprelight && pixmap.prelight.present) + pClass = &pixmap.prelight; + // use the pixmap size as the size hint + if (!pClass->pixmap.isNull()) + return pClass->pixmap.size(); + return KdmItem::sizeHint(); +} + +void +KdmPixmap::setGeometry( const QRect &newGeometry, bool force ) +{ + KdmItem::setGeometry( newGeometry, force ); + pixmap.active.readyPixmap.resize( 0, 0 ); + pixmap.prelight.readyPixmap.resize( 0, 0 ); + pixmap.normal.readyPixmap.resize( 0, 0 ); +} + + +void +KdmPixmap::loadPixmap( const QString &fileName, QPixmap &map, QString &fullName ) +{ + if (fileName.isEmpty()) + return; + + fullName = fileName; + if (fullName.at( 0 ) != '/') + fullName = baseDir() + "/" + fileName; + + if (!fullName.endsWith( ".svg" )) // we delay it for svgs + if (!map.load( fullName )) + fullName = QString::null; +} + +void +KdmPixmap::renderSvg( PixmapStruct::PixmapClass *pClass, const QRect &area ) +{ +#ifdef HAVE_LIBART + // Special stuff for SVG icons + KSVGIconEngine *svgEngine = new KSVGIconEngine(); + + if (svgEngine->load( area.width(), area.height(), pClass->fullpath )) { + QImage *t = svgEngine->image(); + pClass->pixmap = *t; + pClass->readyPixmap.resize( 0, 0 ); + delete t; + } else { + kdWarning() << "failed to load " << pClass->fullpath << endl; + pClass->fullpath = QString::null; + } + + delete svgEngine; +#else + Q_UNUSED(pClass); + Q_UNUSED(area); +#endif +} + +void +KdmPixmap::drawContents( QPainter *p, const QRect &r ) +{ + // choose the correct pixmap class + PixmapStruct::PixmapClass *pClass = &pixmap.normal; + if (state == Sactive && pixmap.active.present) + pClass = &pixmap.active; + if (state == Sprelight && pixmap.prelight.present) + pClass = &pixmap.prelight; + + if (pClass->pixmap.isNull()) { + if (pClass->fullpath.isEmpty()) // if neither is set, we're empty + return; + + kdDebug() << "renderSVG\n"; + renderSvg( pClass, area ); + } + + int px = area.left() + r.left(); + int py = area.top() + r.top(); + int sx = r.x(); + int sy = r.y(); + int sw = r.width(); + int sh = r.height(); + if (px < 0) { + px *= -1; + sx += px; + px = 0; + } + if (py < 0) { + py *= -1; + sy += py; + py = 0; + } + + + if (pClass->readyPixmap.isNull()) { + QImage scaledImage; + + // use the loaded pixmap or a scaled version if needed + + if (area.size() != pClass->pixmap.size()) { + if (pClass->fullpath.endsWith( ".svg" )) { + kdDebug() << "renderSVG\n"; + renderSvg( pClass, area ); + scaledImage = pClass->pixmap.convertToImage(); + } else { + kdDebug() << "convertFromImage\n"; + QImage tempImage = pClass->pixmap.convertToImage(); + scaledImage = tempImage.smoothScale( area.width(), area.height() ); + } + } else + scaledImage = pClass->pixmap.convertToImage(); + + bool haveTint = pClass->tint.rgb() != 0xFFFFFF; + bool haveAlpha = pClass->alpha < 1.0; + + if (haveTint || haveAlpha) { + // blend image(pix) with the given tint + + scaledImage = scaledImage.convertDepth( 32 ); + int w = scaledImage.width(); + int h = scaledImage.height(); + float tint_red = float( pClass->tint.red() ) / 255; + float tint_green = float( pClass->tint.green() ) / 255; + float tint_blue = float( pClass->tint.blue() ) / 255; + float tint_alpha = pClass->alpha; + + for (int y = 0; y < h; ++y) { + QRgb *ls = (QRgb *)scaledImage.scanLine( y ); + for (int x = 0; x < w; ++x) { + QRgb l = ls[x]; + int r = int( qRed( l ) * tint_red ); + int g = int( qGreen( l ) * tint_green ); + int b = int( qBlue( l ) * tint_blue ); + int a = int( qAlpha( l ) * tint_alpha ); + ls[x] = qRgba( r, g, b, a ); + } + } + + } + + pClass->readyPixmap.convertFromImage( scaledImage ); + } + // kdDebug() << "Pixmap::drawContents " << pClass->readyPixmap.size() << " " << px << " " << py << " " << sx << " " << sy << " " << sw << " " << sh << endl; + p->drawPixmap( px, py, pClass->readyPixmap, sx, sy, sw, sh ); +} + +void +KdmPixmap::statusChanged() +{ + KdmItem::statusChanged(); + if (!pixmap.active.present && !pixmap.prelight.present) + return; + if ((state == Sprelight && !pixmap.prelight.present) || + (state == Sactive && !pixmap.active.present)) + return; + needUpdate(); +} + +#include "kdmpixmap.moc" diff --git a/kdm/kfrontend/themer/kdmpixmap.h b/kdm/kfrontend/themer/kdmpixmap.h new file mode 100644 index 000000000..eb621a0a5 --- /dev/null +++ b/kdm/kfrontend/themer/kdmpixmap.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KDMPIXMAP_H +#define KDMPIXMAP_H + +#include "kdmitem.h" + +//#include +#include + +/* + * KdmPixmap. A pixmap element + */ + +class KdmPixmap : public KdmItem { + Q_OBJECT + +public: + KdmPixmap( KdmItem *parent, const QDomNode &node, const char *name = 0 ); + +protected: + // reimplemented; returns the size of loaded pixmap + virtual QSize sizeHint(); + + // draw the pixmap + virtual void drawContents( QPainter *p, const QRect &r ); + + // handle switching between normal / active / prelight configurations + virtual void statusChanged(); + + virtual void setGeometry( const QRect &newGeometry, bool force ); + + struct PixmapStruct { + struct PixmapClass { + QString fullpath; + QPixmap pixmap; + QPixmap readyPixmap; + QColor tint; + float alpha; //TODO added: not in greeter.dtd + bool present; + } normal, active, prelight; + } pixmap; + +private: + // Method to load the pixmap given by the theme + void loadPixmap( const QString &fileName, QPixmap &p, QString &path ); + void renderSvg( PixmapStruct::PixmapClass *pClass, const QRect &area ); +}; + +#endif diff --git a/kdm/kfrontend/themer/kdmrect.cpp b/kdm/kfrontend/themer/kdmrect.cpp new file mode 100644 index 000000000..478c5c8b3 --- /dev/null +++ b/kdm/kfrontend/themer/kdmrect.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kdmrect.h" +#include "kdmthemer.h" + +#include +#include + +#include +#include +#include +#include + +KdmRect::KdmRect( KdmItem *parent, const QDomNode &node, const char *name ) + : KdmItem( parent, node, name ) +{ + itemType = "rect"; + + // Set default values for rect (note: strings are already Null) + rect.normal.alpha = 1; + rect.active.present = false; + rect.prelight.present = false; + rect.hasBorder = false; + + // A rect can have no properties (defaults to parent ones) + if (node.isNull()) + return; + + // Read RECT ID + QDomNode n = node; + QDomElement elRect = n.toElement(); + + // Read RECT TAGS + QDomNodeList childList = node.childNodes(); + for (uint nod = 0; nod < childList.count(); nod++) { + QDomNode child = childList.item( nod ); + QDomElement el = child.toElement(); + QString tagName = el.tagName(); + + if (tagName == "normal") { + parseColor( el.attribute( "color", QString::null ), rect.normal.color ); + rect.normal.alpha = el.attribute( "alpha", "1.0" ).toFloat(); + parseFont( el.attribute( "font", "Sans 14" ), rect.normal.font ); + } else if (tagName == "active") { + rect.active.present = true; + parseColor( el.attribute( "color", QString::null ), rect.active.color ); + rect.active.alpha = el.attribute( "alpha", "1.0" ).toFloat(); + parseFont( el.attribute( "font", "Sans 14" ), rect.active.font ); + } else if (tagName == "prelight") { + rect.prelight.present = true; + parseColor( el.attribute( "color", QString::null ), rect.prelight.color ); + rect.prelight.alpha = el.attribute( "alpha", "1.0" ).toFloat(); + parseFont( el.attribute( "font", "Sans 14" ), rect.prelight.font ); + } else if (tagName == "border") + rect.hasBorder = true; + } +} + +void +KdmRect::drawContents( QPainter *p, const QRect &r ) +{ + // choose the correct rect class + RectStruct::RectClass *rClass = &rect.normal; + if (state == Sactive && rect.active.present) + rClass = &rect.active; + if (state == Sprelight && rect.prelight.present) + rClass = &rect.prelight; + + if (rClass->alpha <= 0 || !rClass->color.isValid()) + return; + + if (rClass->alpha == 1) + p->fillRect( area, QBrush( rClass->color ) ); + else { + QRect backRect = r; + backRect.moveBy( area.x(), area.y() ); + QPixmap backPixmap( backRect.size() ); + bitBlt( &backPixmap, QPoint( 0, 0 ), p->device(), backRect ); + QImage backImage = backPixmap.convertToImage(); + KImageEffect::blend( rClass->color, backImage, rClass->alpha ); + p->drawImage( backRect.x(), backRect.y(), backImage ); + // area.moveBy(1,1); + } +} + +void +KdmRect::statusChanged() +{ + KdmItem::statusChanged(); + if (!rect.active.present && !rect.prelight.present) + return; + if ((state == Sprelight && !rect.prelight.present) || + (state == Sactive && !rect.active.present)) + return; + needUpdate(); +} + +/* +void +KdmRect::setAttribs( QWidget *widget ) +{ + widget->setFont( rect.normal.font ); +} + +void +KdmRect::recursiveSetAttribs( QLayoutItem *li ) +{ + QWidget *w; + QLayout *l; + + if ((w = li->widget())) + setAttribs( w ); + else if ((l = li->layout())) { + QLayoutIterator it = l->iterator(); + for (QLayoutItem *itm = it.current(); itm; itm = ++it) + recursiveSetAttribs( itm ); + } +} + +void +KdmRect::setWidget( QWidget *widget ) +{ + KdmItem::setWidget( widget ); + setAttribs( widget ); +} + +void +KdmRect::setLayoutItem( QLayoutItem *item ) +{ + KdmItem::setLayoutItem( item ); + recursiveSetAttribs( item ); +} +*/ + +#include "kdmrect.moc" diff --git a/kdm/kfrontend/themer/kdmrect.h b/kdm/kfrontend/themer/kdmrect.h new file mode 100644 index 000000000..2e89a6a52 --- /dev/null +++ b/kdm/kfrontend/themer/kdmrect.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KDMRECT_H +#define KDMRECT_H + +#include "kdmitem.h" + +#include +#include + +/* + * KdmRect: A themed rectangular element + */ + +class KdmRect : public KdmItem { + Q_OBJECT + +public: + KdmRect( KdmItem *parent, const QDomNode &node, const char *name = 0 ); + +protected: + // draw the rect + virtual void drawContents( QPainter *p, const QRect &r ); + + // handle switching between normal / active / prelight configurations + virtual void statusChanged(); + + struct RectStruct { + struct RectClass { + float alpha; + QColor color; + bool present; + QFont font; + } normal, active, prelight; + bool hasBorder; + } rect; + +// virtual void setWidget( QWidget *widget ); +// virtual void setLayoutItem( QLayoutItem *item ); + +private: + void setAttribs( QWidget *widget ); + void recursiveSetAttribs( QLayoutItem *item ); +}; + +#endif diff --git a/kdm/kfrontend/themer/kdmthemer.cpp b/kdm/kfrontend/themer/kdmthemer.cpp new file mode 100644 index 000000000..65eebabf4 --- /dev/null +++ b/kdm/kfrontend/themer/kdmthemer.cpp @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kdmthemer.h" +#include "kdmitem.h" +#include "kdmpixmap.h" +#include "kdmrect.h" +#include "kdmlabel.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +//#include // animation timer - TODO +#include +#include +#include +#include + +#include + +/* + * KdmThemer. The main theming interface + */ +KdmThemer::KdmThemer( const QString &_filename, const QString &mode, QWidget *parent ) + : QObject( parent ) + , rootItem( 0 ) + , backBuffer( 0 ) +{ + // Set the mode we're working in + m_currentMode = mode; + + // read the XML file and create DOM tree + QString filename = _filename; + if (!::access( QFile::encodeName( filename + "/GdmGreeterTheme.desktop" ), R_OK )) { + KSimpleConfig cfg( filename + "/GdmGreeterTheme.desktop" ); + cfg.setGroup( "GdmGreeterTheme" ); + filename += '/' + cfg.readEntry( "Greeter" ); + } + QFile opmlFile( filename ); + if (!opmlFile.open( IO_ReadOnly )) { + FDialog::box( widget(), errorbox, i18n( "Cannot open theme file %1" ).arg(filename) ); + return; + } + if (!domTree.setContent( &opmlFile )) { + FDialog::box( widget(), errorbox, i18n( "Cannot parse theme file %1" ).arg(filename) ); + return; + } + // Set the root (screen) item + rootItem = new KdmRect( 0, QDomNode(), "kdm root" ); + connect( rootItem, SIGNAL(needUpdate( int, int, int, int )), + widget(), SLOT(update( int, int, int, int )) ); + + rootItem->setBaseDir( QFileInfo( filename ).dirPath( true ) ); + + // generate all the items defined in the theme + generateItems( rootItem ); + + connect( rootItem, SIGNAL(activated( const QString & )), SIGNAL(activated( const QString & )) ); + +/* *TODO* + // Animation timer + QTimer *time = new QTimer( this ); + time->start( 500 ); + connect( time, SIGNAL(timeout()), SLOT(update()) ) +*/ +} + +KdmThemer::~KdmThemer() +{ + delete rootItem; + delete backBuffer; +} + +inline QWidget * +KdmThemer::widget() +{ + return static_cast(parent()); +} + +KdmItem * +KdmThemer::findNode( const QString &item ) const +{ + return rootItem->findNode( item ); +} + +void +KdmThemer::updateGeometry( bool force ) +{ + rootItem->setGeometry( QRect( QPoint(), widget()->size() ), force ); +} + +// BEGIN other functions + +void +KdmThemer::widgetEvent( QEvent *e ) +{ + if (!rootItem) + return; + switch (e->type()) { + case QEvent::MouseMove: + { + QMouseEvent *me = static_cast(e); + rootItem->mouseEvent( me->x(), me->y() ); + } + break; + case QEvent::MouseButtonPress: + { + QMouseEvent *me = static_cast(e); + rootItem->mouseEvent( me->x(), me->y(), true ); + } + break; + case QEvent::MouseButtonRelease: + { + QMouseEvent *me = static_cast(e); + rootItem->mouseEvent( me->x(), me->y(), false, true ); + } + break; + case QEvent::Show: + rootItem->show(); + break; + case QEvent::Resize: + updateGeometry( false ); + showStructure( rootItem ); + break; + case QEvent::Paint: + { + QRect paintRect = static_cast(e)->rect(); + kdDebug() << "paint on: " << paintRect << endl; + + if (!backBuffer) + backBuffer = new QPixmap( widget()->size() ); + if (backBuffer->size() != widget()->size()) + backBuffer->resize( widget()->size() ); + + QPainter p; + p.begin( backBuffer ); + rootItem->paint( &p, paintRect ); + p.end(); + + bitBlt( widget(), paintRect.topLeft(), backBuffer, paintRect ); + } + break; + default: + break; + } +} + +/* +void +KdmThemer::pixmap( const QRect &r, QPixmap *px ) +{ + bitBlt( px, QPoint( 0, 0 ), widget(), r ); +} +*/ + +void +KdmThemer::generateItems( KdmItem *parent, const QDomNode &node ) +{ + if (!parent) + return; + + QDomNodeList subnodeList; //List of subnodes of this node + + /* + * Get the child nodes + */ + if (node.isNull()) { // It's the first node, get its child nodes + QDomElement theme = domTree.documentElement(); + + // Get its tag, and check it's correct ("greeter") + if (theme.tagName() != "greeter") { + kdDebug() << "This does not seem to be a correct theme file." << endl; + return; + } + // Get the list of child nodes + subnodeList = theme.childNodes(); + } else + subnodeList = node.childNodes(); + + /* + * Go through each of the child nodes + */ + for (uint nod = 0; nod < subnodeList.count(); nod++) { + QDomNode subnode = subnodeList.item( nod ); + QDomElement el = subnode.toElement(); + QString tagName = el.tagName(); + + if (tagName == "item") { + if (!willDisplay( subnode )) + continue; + // It's a new item. Draw it + QString type = el.attribute( "type" ); + + KdmItem *newItem = 0; + + if (type == "label") + newItem = new KdmLabel( parent, subnode ); + else if (type == "pixmap") + newItem = new KdmPixmap( parent, subnode ); + else if (type == "rect") + newItem = new KdmRect( parent, subnode ); + else if (type == "entry") { + newItem = new KdmRect( parent, subnode ); + newItem->setType( type ); + } + // newItem = new KdmEntry( parent, subnode ); + //else if (type=="list") + // newItem = new KdmList( parent, subnode ); + else if (type == "svg") + newItem = new KdmPixmap( parent, subnode ); + if (newItem) { + generateItems( newItem, subnode ); + if (el.attribute( "button", "false" ) == "true") + newItem->inheritFromButton( newItem ); + } + } else if (tagName == "box") { + if (!willDisplay( subnode )) + continue; + // It's a new box. Draw it + parent->setBoxLayout( subnode ); + generateItems( parent, subnode ); + } else if (tagName == "fixed") { + if (!willDisplay( subnode )) + continue; + // It's a new box. Draw it + parent->setFixedLayout( subnode ); + generateItems( parent, subnode ); + } + } +} + +bool KdmThemer::willDisplay( const QDomNode &node ) +{ + QDomNode showNode = node.namedItem( "show" ); + + // No "show" node means this item can be displayed at all times + if (showNode.isNull()) + return true; + + QDomElement el = showNode.toElement(); + + QString modes = el.attribute( "modes" ); + if (!modes.isNull()) { + QStringList modeList = QStringList::split( ",", modes ); + + // If current mode isn't in this list, do not display item + if (modeList.find( m_currentMode ) == modeList.end()) + return false; + } + + QString type = el.attribute( "type" ); + if (type == "config" || type == "suspend") + return false; // not implemented (yet) + if (type == "timed") + return _autoLoginDelay != 0; + if (type == "chooser") +#ifdef XDMCP + return _loginMode != LOGIN_LOCAL_ONLY; +#else + return false; +#endif + if (type == "halt" || type == "reboot") + return _allowShutdown != SHUT_NONE; +// if (type == "system") +// return true; + + // All tests passed, item will be displayed + return true; +} + +void +KdmThemer::showStructure( QObject *obj ) +{ + + const QObjectList *wlist = obj->children(); + static int counter = 0; + if (counter == 0) + kdDebug() << "\n\n<======= Widget tree =================" << endl; + if (wlist) { + counter++; + QObjectListIterator it( *wlist ); + QObject *object; + + while ((object = it.current()) != 0) { + ++it; + QString node; + for (int i = 1; i < counter; i++) + node += "-"; + + if (object->inherits( "KdmItem" )) { + KdmItem *widget = (KdmItem *)object; + kdDebug() << node << "|" << widget->type() << " me=" << widget->id << " " << widget->area << endl; + } + + showStructure( object ); + } + counter--; + } + if (counter == 0) + kdDebug() << "\n\n<======= Widget tree =================\n\n" << endl; +} + +#include "kdmthemer.moc" diff --git a/kdm/kfrontend/themer/kdmthemer.h b/kdm/kfrontend/themer/kdmthemer.h new file mode 100644 index 000000000..34baffbb7 --- /dev/null +++ b/kdm/kfrontend/themer/kdmthemer.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2003 by Unai Garro + * Copyright (C) 2004 by Enrico Ros + * Copyright (C) 2004 by Stephan Kulow + * Copyright (C) 2004 by Oswald Buddenhagen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KDMTHEMER_H +#define KDMTHEMER_H + +#include +#include + +class KdmThemer; +class KdmItem; +class KdmPixmap; +class KdmRect; +class KdmBox; + +class QRect; +class QWidget; +class QEvent; + +/** +* @author Unai Garro +*/ + + + +/* +* The themer widget. Whatever drawn here is just themed +* according to a XML file set by the user. +*/ + + +class KdmThemer : public QObject { + Q_OBJECT + +public: + /* + * Construct and destruct the interface + */ + + KdmThemer( const QString &path, const QString &mode, QWidget *parent ); + ~KdmThemer(); + + bool isOK() { return rootItem != 0; } + /* + * Gives a sizeHint to the widget (parent size) + */ + //QSize sizeHint() const{ return parentWidget()->size(); } + + /* + * Takes a shot of the current widget + */ +// void pixmap( const QRect &r, QPixmap *px ); + + virtual // just to put the reference in the vmt + KdmItem *findNode( const QString & ) const; + + void updateGeometry( bool force ); // force = true for external calls + + // must be called by parent widget + void widgetEvent( QEvent *e ); + +signals: + void activated( const QString &id ); + +private: + /* + * Our display mode (e.g. console, remote, ...) + */ + QString m_currentMode; + + /* + * The config file being used + */ + QDomDocument domTree; + + /* + * Stores the root of the theme + */ + KdmItem *rootItem; + + /* + * The backbuffer + */ + QPixmap *backBuffer; + + // methods + + /* + * Test whether item needs to be displayed + */ + bool willDisplay( const QDomNode &node ); + + /* + * Parses the XML file looking for the + * item list and adds those to the themer + */ + void generateItems( KdmItem *parent = 0, const QDomNode &node = QDomNode() ); + + void showStructure( QObject *obj ); + + QWidget *widget(); +}; + + +#endif -- cgit v1.2.1