summaryrefslogtreecommitdiffstats
path: root/kdm/kfrontend/themer
diff options
context:
space:
mode:
Diffstat (limited to 'kdm/kfrontend/themer')
-rw-r--r--kdm/kfrontend/themer/Makefile.am16
-rw-r--r--kdm/kfrontend/themer/kdmitem.cpp532
-rw-r--r--kdm/kfrontend/themer/kdmitem.h263
-rw-r--r--kdm/kfrontend/themer/kdmlabel.cpp231
-rw-r--r--kdm/kfrontend/themer/kdmlabel.h81
-rw-r--r--kdm/kfrontend/themer/kdmlayout.cpp167
-rw-r--r--kdm/kfrontend/themer/kdmlayout.h98
-rw-r--r--kdm/kfrontend/themer/kdmpixmap.cpp242
-rw-r--r--kdm/kfrontend/themer/kdmpixmap.h69
-rw-r--r--kdm/kfrontend/themer/kdmrect.cpp154
-rw-r--r--kdm/kfrontend/themer/kdmrect.h65
-rw-r--r--kdm/kfrontend/themer/kdmthemer.cpp329
-rw-r--r--kdm/kfrontend/themer/kdmthemer.h123
13 files changed, 2370 insertions, 0 deletions
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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <kglobal.h>
+#include <kdebug.h>
+
+#include <qframe.h>
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qimage.h>
+#ifdef DRAW_OUTLINE
+# include <qpainter.h>
+#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<KdmItem *>( 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<KdmItem *>::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<KdmItem *>::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<KdmItem *>::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<KdmItem *>( this );
+
+ QValueList<KdmItem *>::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<QFrame *>( 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<KdmItem *>::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<KdmItem *>::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<KdmItem *>::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<KdmItem*>( 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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <qobject.h>
+#include <qvaluelist.h>
+#include <qrect.h>
+#include <qdom.h>
+
+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<KdmItem *>( 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 &region ) = 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<KdmItem *> 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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <kgreeter.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmacroexpander.h>
+#include <kdebug.h>
+
+#include <qdatetime.h>
+#include <qpainter.h>
+#include <qfontmetrics.h>
+#include <qtimer.h>
+
+#include <unistd.h>
+#include <sys/utsname.h>
+#if !defined(HAVE_GETDOMAINNAME) && defined(HAVE_SYSINFO)
+# include <sys/systeminfo.h>
+#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 <stock> 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<QChar,QString> 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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <qcolor.h>
+#include <qfont.h>
+
+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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <kdebug.h>
+
+#include <qdom.h>
+#include <qrect.h>
+
+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<KdmItem *>::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<KdmItem *>::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<KdmItem *>::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<KdmItem *>::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<KdmItem *>::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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <qvaluelist.h>
+#include <qsize.h>
+
+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<KdmItem *> 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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <config.h>
+
+#include "kdmpixmap.h"
+
+#include <kimageeffect.h>
+#ifdef HAVE_LIBART
+#include <ksvgiconengine.h>
+#endif
+
+#include <kdebug.h>
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qimage.h>
+
+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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <qrect.h>
+#include <qpixmap.h>
+
+/*
+ * 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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <kimageeffect.h>
+#include <kdebug.h>
+
+#include <qimage.h>
+#include <qpainter.h>
+#include <qwidget.h>
+#include <qlayout.h>
+
+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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <qcolor.h>
+#include <qfont.h>
+
+/*
+ * 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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <kdmconfig.h>
+#include <kfdialog.h>
+
+#include <kiconloader.h>
+#include <kimageeffect.h>
+#include <klocale.h>
+#include <ksimpleconfig.h>
+#include <kdebug.h>
+
+#include <qfile.h>
+#include <qfileinfo.h>
+//#include <qtimer.h> // animation timer - TODO
+#include <qobjectlist.h>
+#include <qpainter.h>
+#include <qwidget.h>
+#include <qregion.h>
+
+#include <unistd.h>
+
+/*
+ * 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<QWidget *>(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<QMouseEvent *>(e);
+ rootItem->mouseEvent( me->x(), me->y() );
+ }
+ break;
+ case QEvent::MouseButtonPress:
+ {
+ QMouseEvent *me = static_cast<QMouseEvent *>(e);
+ rootItem->mouseEvent( me->x(), me->y(), true );
+ }
+ break;
+ case QEvent::MouseButtonRelease:
+ {
+ QMouseEvent *me = static_cast<QMouseEvent *>(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<QPaintEvent *>(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 <ugarro@users.sourceforge.net>
+ * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
+ * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
+ *
+ * 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 <qobject.h>
+#include <qdom.h>
+
+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