diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2012-01-22 01:02:36 -0600 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2012-01-22 01:02:36 -0600 |
commit | b81e43465b14836b17e4fe2dea91c78a2bdd29b3 (patch) | |
tree | 7815d61ce59a6ccb6e655ed44f5fea786f520985 /tdm/kfrontend/themer | |
parent | 7021f40c13f949b7cb5ded32d0241d648a43bf6c (diff) | |
download | tdebase-b81e43465b14836b17e4fe2dea91c78a2bdd29b3.tar.gz tdebase-b81e43465b14836b17e4fe2dea91c78a2bdd29b3.zip |
Part 2 of prior commit
Diffstat (limited to 'tdm/kfrontend/themer')
-rw-r--r-- | tdm/kfrontend/themer/CMakeLists.txt | 41 | ||||
-rw-r--r-- | tdm/kfrontend/themer/Makefile.am | 16 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmitem.cpp | 657 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmitem.h | 272 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmlabel.cpp | 276 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmlabel.h | 87 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmlayout.cpp | 168 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmlayout.h | 98 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmpixmap.cpp | 340 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmpixmap.h | 73 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmrect.cpp | 181 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmrect.h | 67 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmthemer.cpp | 404 | ||||
-rw-r--r-- | tdm/kfrontend/themer/tdmthemer.h | 128 |
14 files changed, 2808 insertions, 0 deletions
diff --git a/tdm/kfrontend/themer/CMakeLists.txt b/tdm/kfrontend/themer/CMakeLists.txt new file mode 100644 index 000000000..fc0b80fc3 --- /dev/null +++ b/tdm/kfrontend/themer/CMakeLists.txt @@ -0,0 +1,41 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/tdm/kfrontend + ${CMAKE_SOURCE_DIR}/tdmlib + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +# FIXME this must be optimized +##### config.ci (generated) ##################### + +add_custom_command( OUTPUT config.ci + COMMAND perl -w ${CMAKE_SOURCE_DIR}/tdm/confproc.pl ${CMAKE_SOURCE_DIR}/tdm/config.def config.ci + DEPENDS ${CMAKE_SOURCE_DIR}/tdm/confproc.pl ${CMAKE_SOURCE_DIR}/tdm/config.def ) +set_property( SOURCE tdmthemer.cpp APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/config.ci ) + + +##### tdmthemer (static) ######################## + +tde_add_library( tdmthemer STATIC_PIC AUTOMOC + SOURCES + tdmthemer.cpp tdmitem.cpp tdmpixmap.cpp + tdmrect.cpp tdmlabel.cpp tdmlayout.cpp +) diff --git a/tdm/kfrontend/themer/Makefile.am b/tdm/kfrontend/themer/Makefile.am new file mode 100644 index 000000000..f736795d6 --- /dev/null +++ b/tdm/kfrontend/themer/Makefile.am @@ -0,0 +1,16 @@ +AM_CPPFLAGS = -I$(srcdir)/../../backend -I$(srcdir)/.. -I../.. \ + -I$(top_srcdir)/tdmlib \ + $(all_includes) + +noinst_LIBRARIES = libtdmthemer.a +libtdmthemer_a_SOURCES = \ + tdmthemer.cpp \ + tdmitem.cpp \ + tdmpixmap.cpp \ + tdmrect.cpp \ + tdmlabel.cpp \ + tdmlayout.cpp + +METASOURCES = AUTO + +libtdmthemer_a_COMPILE_FIRST = ../../config.ci diff --git a/tdm/kfrontend/themer/tdmitem.cpp b/tdm/kfrontend/themer/tdmitem.cpp new file mode 100644 index 000000000..8cf126b66 --- /dev/null +++ b/tdm/kfrontend/themer/tdmitem.cpp @@ -0,0 +1,657 @@ +/* + * 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 "tdmitem.h" +#include "tdmlayout.h" +#include "tdmconfig.h" + +#include <kglobal.h> +#include <kdebug.h> + +#include <tqframe.h> +#include <tqwidget.h> +#include <tqlayout.h> +#include <tqimage.h> +#include <tqpainter.h> + +extern bool argb_visual_available; + +KdmItem::KdmItem( KdmItem *parent, const TQDomNode &node, const char *name ) + : TQObject( parent, name ) + , boxManager( 0 ) + , fixedManager( 0 ) + , image( 0 ) + , myWidget( 0 ) + , myLayoutItem( 0 ) + , buttonParent( 0 ) +{ + init(node, name); +} + + +KdmItem::KdmItem( TQWidget *parent, const TQDomNode &node, const char *name ) + : TQObject( parent, name ) + , boxManager( 0 ) + , fixedManager( 0 ) + , image( 0 ) + , myWidget( 0 ) + , myLayoutItem( 0 ) + , buttonParent( 0 ) +{ + init(node, name); +} + +void +KdmItem::init( const TQDomNode &node, const char * ) +{ + // 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"; + m_backgroundModifier = 255; + + 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. + TQDomNodeList childList = node.childNodes(); + for (uint nod = 0; nod < childList.count(); nod++) { + TQDomNode child = childList.item( nod ); + TQDomElement el = child.toElement(); + TQString tagName = el.tagName(), attr; + + if (tagName == "pos") { + parseAttribute( el.attribute( "x", TQString::null ), pos.x, pos.xType ); + parseAttribute( el.attribute( "y", TQString::null ), pos.y, pos.yType ); + parseAttribute( el.attribute( "width", TQString::null ), pos.width, pos.wType ); + parseAttribute( el.attribute( "height", TQString::null ), pos.height, pos.hType ); + pos.anchor = el.attribute( "anchor", "nw" ); + } + + if (tagName == "bgmodifier") { + m_backgroundModifier = TQString(el.attribute( "value", "255" )).toInt(); + } + } + + TQDomNode tnode = node; + id = tnode.toElement().attribute( "id", TQString::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; + + TQValueList<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 + } + + TQValueList<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; + + TQValueList<KdmItem *>::Iterator it; + for (it = m_children.begin(); it != m_children.end(); ++it) + (*it)->inheritFromButton( button ); +} + +KdmItem * +KdmItem::findNode( const TQString &_id ) const +{ + if (id == _id) + return const_cast<KdmItem *>( this ); + + TQValueList<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( TQWidget *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 + TQFrame* frame = ::tqqt_cast<TQFrame *>( widget ); + if (frame) + frame->setFrameStyle( TQFrame::NoFrame ); + + setGeometry(area, true); + + connect( myWidget, TQT_SIGNAL(destroyed()), TQT_SLOT(widgetGone()) ); +} + +void +KdmItem::widgetGone() +{ + myWidget = 0; +} + +void +KdmItem::setLayoutItem( TQLayoutItem *item ) +{ + myLayoutItem = item; + // XXX hiding not supported - it think it's pointless here + if (myLayoutItem->widget()) + connect( myLayoutItem->widget(), TQT_SIGNAL(destroyed()), + TQT_SLOT(layoutItemGone()) ); + else if (myLayoutItem->layout()) + connect( myLayoutItem->layout(), TQT_SIGNAL(destroyed()), + TQT_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 TQRect &newGeometry, bool force ) +{ + kdDebug() << " KdmItem::setGeometry " << id << newGeometry << endl; + // check if already 'in place' + if (!force && area == newGeometry) + return; + + area = newGeometry; + + if (myWidget) { + TQRect widGeo = newGeometry; + if ( widGeo.height() > myWidget->maximumHeight() ) { + widGeo.moveTop( widGeo.top() + ( widGeo.height() - myWidget->maximumHeight() ) / 2 ); + widGeo.setHeight( myWidget->maximumHeight() ); + } + myWidget->setGeometry( widGeo ); + } + 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( TQPainter *p, const TQRect &rect ) +{ + if (isHidden()) + return; + + if (myWidget || (myLayoutItem && myLayoutItem->widget())) { + // KListView because it's missing a Q_OBJECT' + // FIXME: This is a nice idea in theory, but in practice it is + // very confusing for the user not to see the empty list box + // delineated from the rest of the greeter. + // Maybe set a darker version of the background instead of an exact copy? + if ( myWidget && myWidget->isA( "KListView" ) ) { + if ((_compositor.isEmpty()) || (!argb_visual_available)) { + // Software blend only (no compositing support) + TQPixmap copy( myWidget->size() ); + kdDebug() << myWidget->geometry() << " " << area << " " << myWidget->size() << endl; + bitBlt( ©, TQPoint( 0, 0), p->device(), myWidget->geometry(), TQt::CopyROP ); + // Lighten it slightly + TQImage lightVersion; + lightVersion = copy.convertToImage(); + + register uchar * r = lightVersion.bits(); + register uchar * g = lightVersion.bits() + 1; + register uchar * b = lightVersion.bits() + 2; + uchar * end = lightVersion.bits() + lightVersion.numBytes(); + + while ( r != end ) { + if ((*r) < (255-m_backgroundModifier)) + *r = (uchar) (*r) + m_backgroundModifier; + else + *r = 255; + if ((*g) < (255-m_backgroundModifier)) + *g = (uchar) (*g) + m_backgroundModifier; + else + *g = 255; + if ((*b) < (255-m_backgroundModifier)) + *b = (uchar) (*b) + m_backgroundModifier; + else + *b = 255; + r += 4; + g += 4; + b += 4; + } + + copy = lightVersion; + // Set it + myWidget->setPaletteBackgroundPixmap( copy ); + } + else { + // We have compositing support! + TQRgb blend_color = tqRgba(m_backgroundModifier, m_backgroundModifier, m_backgroundModifier, 0); // RGBA overlay + float alpha = tqAlpha(blend_color) / 255.; + int pixel = tqAlpha(blend_color) << 24 | + int(tqRed(blend_color) * alpha) << 16 | + int(tqGreen(blend_color) * alpha) << 8 | + int(tqBlue(blend_color) * alpha); + + TQImage img( myWidget->size(), 32 ); + img = img.convertDepth(32); + img.setAlphaBuffer(true); + register uchar * rd = img.bits(); + for( int y = 0; y < img.height(); ++y ) + { + for( short int x = 0; x < img.width(); ++x ) + { + *reinterpret_cast<TQRgb*>(rd) = blend_color; + rd += 4; + } + } + myWidget->setPaletteBackgroundPixmap( img ); + } + } + return; + } + + if (area.intersects( rect )) { + TQRect 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 + TQValueList<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 (isShown == ExplicitlyHidden) + return; + + 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) { + TQValueList<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) { + TQValueList<KdmItem *>::Iterator it; + for (it = m_children.begin(); it != m_children.end(); ++it) { + (*it)->state = state; + (*it)->statusChanged(); + } + } +} + +// BEGIN protected inheritable + +TQSize +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 TQSize( w, h ); +} + +TQRect +KdmItem::placementHint( const TQRect &parentRect ) +{ + TQSize hintedSize = sizeHint(); + TQSize boxHint; + + int x = parentRect.left(), + y = parentRect.top(), + w = parentRect.width(), + h = parentRect.height(); + + kdDebug() << timestamp() << " KdmItem::placementHint parentRect=" << 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() << timestamp() << " 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 += tqRound( 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 += tqRound( 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 = tqRound( 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 = tqRound( parentRect.height() / 100.0 * pos.height ); + else if (pos.hType == DTbox) + h = boxHint.height(); + else if (hintedSize.height() > 0) { + if (w && pos.wType != DTnone) + h = (hintedSize.height() * w) / hintedSize.width(); + else + h = hintedSize.height(); + } else + h = 0; + + // we choose to take the hinted size, but it's better to listen to the aspect ratio + if (pos.wType == DTnone && pos.hType != DTnone && h && w) { + w = tqRound(float(hintedSize.width() * h) / hintedSize.height()); + } + + // 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() << timestamp() << " placementHint " << this << " 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 TQRect( 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, TQT_SIGNAL(needUpdate( int, int, int, int )), TQT_SIGNAL(needUpdate( int, int, int, int )) ); + connect( item, TQT_SIGNAL(activated( const TQString & )), TQT_SIGNAL(activated( const TQString & )) ); +} + +void +KdmItem::parseAttribute( const TQString &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; + TQString sCopy = s; + sCopy.remove( p, 1 ); + sCopy.replace( ',', '.' ); + val = (int)sCopy.toDouble(); + } else { // int value + dType = DTpixel; + TQString sCopy = s; + if (sCopy.at( 0 ) == '-') { + sCopy.remove( 0, 1 ); + dType = DTnpixel; + } + sCopy.replace( ',', '.' ); + val = (int)sCopy.toDouble(); + } +} + +void +KdmItem::parseFont( const TQString &s, TQFont &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 TQString &s, TQColor &color ) +{ + if (s.at( 0 ) != '#') + return; + bool ok; + TQString sCopy = s; + int hexColor = sCopy.remove( 0, 1 ).toInt( &ok, 16 ); + if (ok) + color.setRgb( hexColor ); +} + +void +KdmItem::setBoxLayout( const TQDomNode &node ) +{ + if (!boxManager) + boxManager = new KdmLayoutBox( node ); + currentManager = MBox; +} + +void +KdmItem::setFixedLayout( const TQDomNode &node ) +{ + if (!fixedManager) + fixedManager = new KdmLayoutFixed( node ); + currentManager = MFixed; +} + +TQWidget * +KdmItem::parentWidget() const +{ + if (myWidget) + return myWidget; + if (!this->parent()) + return 0; + + if (parent()->qt_cast(TQWIDGET_OBJECT_NAME_STRING)) + return (TQWidget*)parent(); + return ((KdmItem*)parent())->parentWidget(); +} + +#include "tdmitem.moc" diff --git a/tdm/kfrontend/themer/tdmitem.h b/tdm/kfrontend/themer/tdmitem.h new file mode 100644 index 000000000..27158a7fd --- /dev/null +++ b/tdm/kfrontend/themer/tdmitem.h @@ -0,0 +1,272 @@ +/* + * 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 TDMITEM_H +#define TDMITEM_H + +#include <tqobject.h> +#include <tqvaluelist.h> +#include <tqrect.h> +#include <tqdom.h> + +class KdmItem; +class KdmLayoutBox; +class KdmLayoutFixed; + +class TQPainter; +class TQLayoutItem; + +/** class KdmItem + * @short Base class for every tdmthemes' 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 TQObject { + Q_OBJECT + + friend class KdmThemer; + +public: + /** + * Item constructor and destructor + */ + KdmItem( KdmItem *parent, const TQDomNode &node = TQDomNode(), const char *name = 0 ); + KdmItem( TQWidget *parent, const TQDomNode &node = TQDomNode(), const char *name = 0 ); // for the root + + 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 TQRect &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( TQPainter *painter, const TQRect &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 TQRect placementHint( const TQRect &parentGeometry ); + + /** + * Create the box layout manager; next children will be + * managed by the box layouter + */ + void setBoxLayout( const TQDomNode &node = TQDomNode() ); + + /** + * Create the fixed layout manager; next children will be + * in fixed position relative to this item + */ + void setFixedLayout( const TQDomNode &node = TQDomNode() ); + + TQString type() const { return itemType; } + void setType( const TQString &t ) { itemType = t; } + void setBaseDir( const TQString &bd ) { basedir = bd; } + + TQString baseDir() const + { + if (basedir.isEmpty() && parent()) + return static_cast<KdmItem *>( parent()->qt_cast( "KdmItem" ) )->baseDir(); + return basedir; + } + + KdmItem *findNode( const TQString &id ) const; + virtual void setWidget( TQWidget *widget ); + TQWidget *widget() const { return myWidget; } + virtual void setLayoutItem( TQLayoutItem *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; } + TQRect rect() const { return area; } + + TQWidget *parentWidget() const; + TQString getId() const { return id; } + +signals: + void needUpdate( int x, int y, int w, int h ); + void activated( const TQString &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 TQSize 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( TQPainter *painter, const TQRect ®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 + TQRect 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; + TQString 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 TQString &, int &, enum DataType & ); + void parseFont( const TQString &, TQFont & ); + void parseColor( const TQString &, TQColor & ); + + void inheritFromButton( KdmItem *button ); + void init( const TQDomNode &node = TQDomNode(), const char *name = 0 ); + + TQString itemType, id; + TQValueList<KdmItem *> m_children; + + int m_backgroundModifier; + + // Layouting related variables + enum { MNone = 0, MFixed = 1, MBox = 2 } currentManager; + KdmLayoutBox *boxManager; + KdmLayoutFixed *fixedManager; + + // Compositing related variables + TQImage *image; + + // defines the directory the theme is in (may be present in the parent) + TQString basedir; + + TQWidget *myWidget; + TQLayoutItem *myLayoutItem; + + enum { InitialHidden, ExplicitlyHidden, Shown } isShown; + + KdmItem *buttonParent; +}; + +#endif diff --git a/tdm/kfrontend/themer/tdmlabel.cpp b/tdm/kfrontend/themer/tdmlabel.cpp new file mode 100644 index 000000000..5239d48dc --- /dev/null +++ b/tdm/kfrontend/themer/tdmlabel.cpp @@ -0,0 +1,276 @@ +/* + * 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 "tdmlabel.h" +#include "tdmconfig.h" +#include "../kgreeter.h" + +#include <kglobal.h> +#include <klocale.h> +#include <kmacroexpander.h> +#include <kdebug.h> + +#include <tqdatetime.h> +#include <tqpainter.h> +#include <tqfontmetrics.h> +#include <tqtimer.h> +#include <tqaccel.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 TQDomNode &node, const char *name ) + : KdmItem( parent, node, name ), myAccel(0) +{ + 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 TQString locale = KGlobal::locale()->language(); + + // Read LABEL ID + TQDomNode n = node; + TQDomElement 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 + TQDomNodeList childList = node.childNodes(); + bool stockUsed = false; + for (uint nod = 0; nod < childList.count(); nod++) { + TQDomNode child = childList.item( nod ); + TQDomElement el = child.toElement(); + TQString 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) { + TQString 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 TQTimer( this ); + timer->start( 1000 ); + connect( timer, TQT_SIGNAL(timeout()), TQT_SLOT(update()) ); + } + setTextInt( lookupText( label.text ) ); +} + +void +KdmLabel::setTextInt( const TQString &txt) +{ + // TODO: catch && + cText = txt; + cAccel = txt.find('&'); + delete myAccel; + myAccel = 0; + if (cAccel != -1) { + cText.remove('&'); + myAccel = new TQAccel(parentWidget()); + myAccel->insertItem(ALT + UNICODE_ACCEL + cText.at(cAccel).lower().unicode()); + connect(myAccel, TQT_SIGNAL(activated(int)), TQT_SLOT(slotAccel())); + } +} + +void +KdmLabel::slotAccel() +{ + if (buttonParent) + emit activated(buttonParent->getId()); + else + emit activated(id); +} + +void +KdmLabel::setText( const TQString &txt ) +{ + label.text = txt; + setTextInt( lookupText( label.text ) ); +} + +TQSize +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 + TQSize hint = TQFontMetrics( 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( TQPainter *p, const TQRect &/*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..) + if (cAccel != -1 && (!id.isEmpty() || buttonParent) ) { + TQString left = cText.left(cAccel); + TQString right = cText.mid(cAccel + 1); + p->drawText( area, AlignLeft | SingleLine, left ); + TQRect tarea = area; + TQFontMetrics fm(l->font); + tarea.rLeft() += fm.width(left); + TQFont f(l->font); + f.setUnderline(true); + p->setFont ( f ); + p->drawText( tarea, AlignLeft | SingleLine, TQString(cText.at(cAccel))); + tarea.rLeft() += fm.width(cText.at(cAccel)); + p->setFont( l->font ); + p->drawText( tarea, AlignLeft | SingleLine, right); + } else { + 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() +{ + TQString text = lookupText( label.text ); + if (text != cText) { + setTextInt(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"); + { "admin", I18N_NOOP("&Administration") }, + { "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("Caps Lock is enabled.") }, + { "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:") }, + { "domain-label", I18N_NOOP("Domain:") }, + { "login", I18N_NOOP("Login") } +}; + +TQString +KdmLabel::lookupStock( const TQString &stock ) +{ + //FIXME add key accels! + TQString 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() << timestamp() << " Invalid <stock> element. Check your theme!" << endl; + return stock; +} + +TQString +KdmLabel::lookupText( const TQString &t ) +{ + TQString text = t; + + text.replace( '_', '&' ); + + TQMap<TQChar,TQString> m; + struct utsname uts; + uname( &uts ); + m['n'] = TQString::fromLocal8Bit( uts.nodename ); + char buf[256]; + buf[sizeof(buf) - 1] = '\0'; + m['h'] = gethostname( buf, sizeof(buf) - 1 ) ? "localhost" : TQString::fromLocal8Bit( buf ); +#ifdef HAVE_GETDOMAINNAME + m['o'] = getdomainname( buf, sizeof(buf) - 1 ) ? "localdomain" : TQString::fromLocal8Bit( buf ); +#elif defined(HAVE_SYSINFO) + m['o'] = (unsigned)sysinfo( SI_SRPC_DOMAIN, buf, sizeof(buf) ) > sizeof(buf) ? "localdomain" : TQString::fromLocal8Bit( buf ); +#endif + m['d'] = TQString::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( TQDateTime::currentDateTime(), false, false ); + + return KMacroExpander::expandMacros( text, m ); +} + +#include "tdmlabel.moc" diff --git a/tdm/kfrontend/themer/tdmlabel.h b/tdm/kfrontend/themer/tdmlabel.h new file mode 100644 index 000000000..8b955fca5 --- /dev/null +++ b/tdm/kfrontend/themer/tdmlabel.h @@ -0,0 +1,87 @@ +/* + * 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 "tdmitem.h" + +#include <tqcolor.h> +#include <tqfont.h> + +class TQTimer; + +/* + * KdmLabel. A label element + */ + +class KdmLabel : public KdmItem { + Q_OBJECT + +public: + KdmLabel( KdmItem *parent, const TQDomNode &node, const char *name = 0 ); + void setText( const TQString &txt ); + +protected: + // reimplemented; returns the minimum size of rendered text + virtual TQSize sizeHint(); + + // draw the label + virtual void drawContents( TQPainter *p, const TQRect &r ); + + // handle switching between normal / active / prelight configurations + virtual void statusChanged(); + +public: + struct LabelStruct { + TQString text; + bool isTimer; + bool hasId; + TQString id; + struct LabelClass { + TQColor color; + TQFont font; + bool present; + } normal, active, prelight; + int maximumWidth; + } label; + + TQTimer *timer; + +public slots: + void update(); + void slotAccel(); + +private: + /* Method to lookup the caption associated with an item */ + TQString lookupStock( const TQString &stock ); + + /* Lookup variables in the text */ + TQString lookupText( const TQString &t ); + + TQString cText; + int cAccel; + TQAccel *myAccel; + + void setTextInt(const TQString &); +}; + +#endif diff --git a/tdm/kfrontend/themer/tdmlayout.cpp b/tdm/kfrontend/themer/tdmlayout.cpp new file mode 100644 index 000000000..9a277a7a3 --- /dev/null +++ b/tdm/kfrontend/themer/tdmlayout.cpp @@ -0,0 +1,168 @@ +/* + * 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 "tdmlayout.h" +#include "tdmconfig.h" +#include "tdmitem.h" + +#include <kdebug.h> + +#include <tqdom.h> +#include <tqrect.h> + +KdmLayoutFixed::KdmLayoutFixed( const TQDomNode &/*node*/ ) +{ + //Parsing FIXED parameters on 'node' [NONE!] +} + +void +KdmLayoutFixed::update( const TQRect &parentGeometry, bool force ) +{ + kdDebug() << timestamp() << " KdmLayoutFixed::update " << parentGeometry << endl; + + // I can't layout children if the parent rectangle is not valid + if (parentGeometry.width() < 0 || parentGeometry.height() < 0) { + kdDebug() << timestamp() << " invalid\n"; + return; + } + // For each child in list I ask their hinted size and set it! + for (TQValueList<KdmItem *>::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) + (*it)->setGeometry( (*it)->placementHint( parentGeometry ), force ); +} + +KdmLayoutBox::KdmLayoutBox( const TQDomNode &node ) +{ + //Parsing BOX parameters + TQDomNode n = node; + TQDomElement 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 TQRect &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. + TQRect childrenRect = /*box.isVertical ? TQRect( 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 (TQValueList<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 (TQValueList<KdmItem *>::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) { + if ((*it)->isExplicitlyHidden()) + continue; + if (box.isVertical) { + TQRect temp( childrenRect.left(), childrenRect.top(), childrenRect.width(), height ); + (*it)->setGeometry( temp, force ); + childrenRect.setTop( childrenRect.top() + height + box.spacing ); + } else { + TQRect temp( childrenRect.left(), childrenRect.top(), width, childrenRect.height() ); + kdDebug() << timestamp() << " placement " << *it << " " << temp << " " << (*it)->placementHint( temp ) << endl; + temp = (*it)->placementHint( temp ); + (*it)->setGeometry( temp, force ); + childrenRect.setLeft( childrenRect.left() + width + box.spacing ); + } + } + } else { + for (TQValueList<KdmItem *>::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) { + if ((*it)->isExplicitlyHidden()) + continue; + + TQRect 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() << timestamp() << " 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) +TQSize +KdmLayoutBox::sizeHint() +{ + // Sum up area taken by children + int w = 0, h = 0; + for (TQValueList<KdmItem *>::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) { + TQSize s = (*it)->placementHint( TQRect() ).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 TQSize( w < box.minwidth ? box.minwidth : w, + h < box.minheight ? box.minheight : h ); +} diff --git a/tdm/kfrontend/themer/tdmlayout.h b/tdm/kfrontend/themer/tdmlayout.h new file mode 100644 index 000000000..c147fd329 --- /dev/null +++ b/tdm/kfrontend/themer/tdmlayout.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 TDMLAYOUT_H +#define TDMLAYOUT_H + +/** + * this is a container for a lot of other stuff + * but can be treated like a usual widget + */ + +#include <tqvaluelist.h> +#include <tqsize.h> + +class KdmItem; + +class TQDomNode; +class TQRect; + +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 TQRect &parentGeometry ) = 0; + +protected: + TQValueList<KdmItem *> m_children; +}; + +class KdmLayoutFixed : public KdmLayout { + +public: + KdmLayoutFixed( const TQDomNode &node ); + + // Updates the layout of all boxed items knowing that the parent + // has the @p parentGeometry geometry + void update( const TQRect &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 TQDomNode &node ); + + // Updates the layout of all boxed items knowing that they + // should fit into @p parentGeometry container + void update( const TQRect &parentGeometry, bool force ); + + // Computes the size hint of the box, telling which is the + // smallest size inside which boxed items will fit + TQSize sizeHint(); + +private: + struct { + bool isVertical; + int spacing; + int xpadding; + int ypadding; + int minwidth; + int minheight; + bool homogeneous; + } box; +// TQSize hintedSize; +}; + +#endif diff --git a/tdm/kfrontend/themer/tdmpixmap.cpp b/tdm/kfrontend/themer/tdmpixmap.cpp new file mode 100644 index 000000000..7a8d1a3d2 --- /dev/null +++ b/tdm/kfrontend/themer/tdmpixmap.cpp @@ -0,0 +1,340 @@ +/* + * 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 "tdmpixmap.h" +#include <tdmconfig.h> + +#include <kimageeffect.h> +#ifdef HAVE_LIBART +#include <ksvgiconengine.h> +#endif + +#include <kdebug.h> +#include <kstandarddirs.h> + +#include <tqfile.h> +#include <tqpainter.h> +#include <tqpixmap.h> +#include <tqimage.h> + +extern bool argb_visual_available; + +KdmPixmap::KdmPixmap( KdmItem *parent, const TQDomNode &node, const char *name ) + : KdmItem( parent, node, name ) +{ + itemType = "pixmap"; + + // Set default values for pixmap (note: strings are already Null) + pixmap.normal.tint.setRgb( 0x800000 ); + pixmap.normal.alpha = 0.0; + pixmap.active.present = false; + pixmap.prelight.present = false; + bool true_transparency = false; + + // Read PIXMAP ID + // it rarely happens that a pixmap can be a button too! + TQDomNode n = node; + TQDomElement elPix = n.toElement(); + + // Read PIXMAP TAGS + TQDomNodeList childList = node.childNodes(); + for (uint nod = 0; nod < childList.count(); nod++) { + TQDomNode child = childList.item( nod ); + TQDomElement el = child.toElement(); + TQString tagName = el.tagName(); + + if (tagName == "normal") { + pixmap.normal.fullpath = fullPath( el.attribute( "file", "" ) ); + parseColor( el.attribute( "tint", "#ffffff" ), pixmap.normal.tint ); + pixmap.normal.alpha = el.attribute( "alpha", "1.0" ).toFloat(); + + if (el.attribute( "file", "" ) == "@@@TDMBACKGROUND@@@") { + if ((_compositor.isEmpty()) || (!argb_visual_available)) { + // Software blend only (no compositing support) + // Use the preset TDM background... + KStandardDirs *m_pDirs = KGlobal::dirs(); + KSimpleConfig *config = new KSimpleConfig( TQFile::decodeName( _backgroundCfg ) ); + config->setGroup("Desktop0"); + pixmap.normal.fullpath = m_pDirs->findResource("wallpaper", config->readPathEntry("Wallpaper")); + // TODO: Detect when there is no wallpaper and use the background settings instead + delete config; + } + else { + true_transparency = true; + pixmap.normal.alpha = 0.0; + } + } + + } else if (tagName == "active") { + pixmap.active.present = true; + pixmap.active.fullpath = fullPath( el.attribute( "file", "" ) ); + 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; + pixmap.prelight.fullpath = fullPath(el.attribute( "file", "" ) ); + parseColor( el.attribute( "tint", "#ffffff" ), pixmap.prelight.tint ); + pixmap.prelight.alpha = el.attribute( "alpha", "1.0" ).toFloat(); + } + } + + // look if we have to have the aspect ratio ready + if (((pos.wType == DTnone && pos.hType != DTnone) || + (pos.wType != DTnone && pos.hType == DTnone) || + (pos.wType == DTnone && pos.hType == DTnone)) && + !pixmap.normal.fullpath.endsWith( ".svg" )) + loadPixmap( &pixmap.normal ); +} + +TQSize +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 TQRect &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 ); +} + + +TQString +KdmPixmap::fullPath( const TQString &fileName) +{ + if (fileName.isEmpty()) + return TQString::null; + + TQString fullName = fileName; + if (fullName.at( 0 ) != '/') + fullName = baseDir() + "/" + fileName; + return fullName; +} + +void +KdmPixmap::renderSvg( PixmapStruct::PixmapClass *pClass, const TQRect &area ) +{ +#ifdef HAVE_LIBART + // Special stuff for SVG icons + KSVGIconEngine *svgEngine = new KSVGIconEngine(); + + if (svgEngine->load( area.width(), area.height(), pClass->fullpath )) { + TQImage *t = svgEngine->image(); + pClass->pixmap = *t; + pClass->readyPixmap.resize( 0, 0 ); + delete t; + } else { + kdWarning() << "failed to load " << pClass->fullpath << endl; + pClass->fullpath = TQString::null; + } + + delete svgEngine; +#else + Q_UNUSED(pClass); + Q_UNUSED(area); +#endif +} + +void +KdmPixmap::loadPixmap( PixmapStruct::PixmapClass *pClass ) +{ + TQString fullpath = pClass->fullpath; + + kdDebug() << timestamp() << " load " << fullpath << endl; + int index = fullpath.findRev('.'); + TQString ext = fullpath.right(fullpath.length() - index); + fullpath = fullpath.left(index); + kdDebug() << timestamp() << " ext " << ext << " " << fullpath << endl; + TQString testpath = TQString("-%1x%2").arg(area.width()).arg(area.height()) + ext; + kdDebug() << timestamp() << " testing for " << fullpath + testpath << endl; + if (KStandardDirs::exists(fullpath + testpath)) + pClass->pixmap.load(fullpath + testpath); + else + pClass->pixmap.load( fullpath + ext ); + kdDebug() << timestamp() << " done\n"; +} + +void +KdmPixmap::drawContents( TQPainter *p, const TQRect &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; + + kdDebug() << "draw " << id << " " << pClass->pixmap.isNull() << endl; + + if (pClass->pixmap.isNull()) { + if (pClass->fullpath.isEmpty()) // if neither is set, we're empty + return; + + if (!pClass->fullpath.endsWith( ".svg" ) ) { + loadPixmap(pClass); + } else { + kdDebug() << timestamp() << " renderSVG\n"; + renderSvg( pClass, area ); + kdDebug() << timestamp() << " done\n"; + } + } + + 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()) { + + bool haveTint = pClass->tint.rgb() != 0xFFFFFF; + bool haveAlpha = pClass->alpha < 1.0; + + TQImage scaledImage; + + // use the loaded pixmap or a scaled version if needed + + kdDebug() << timestamp() << " prepare readyPixmap " << pClass->fullpath << " " << area.size() << " " << pClass->pixmap.size() << endl; + if (area.size() != pClass->pixmap.size()) { + if (pClass->fullpath.endsWith( ".svg" )) { + kdDebug() << timestamp() << " renderSVG\n"; + renderSvg( pClass, area ); + scaledImage = pClass->pixmap.convertToImage(); + } else { + kdDebug() << timestamp() << " convertFromImage smoothscale\n"; + if (pClass->pixmap.isNull()) { + scaledImage = TQImage(); + } + else { + TQImage tempImage = pClass->pixmap.convertToImage(); + kdDebug() << timestamp() << " convertToImage done\n"; + scaledImage = tempImage.smoothScale( area.width(), area.height() ); + } + kdDebug() << timestamp() << " done\n"; + } + } else { + if (haveTint || haveAlpha) + { + scaledImage = pClass->pixmap.convertToImage(); + // enforce rgba values for the latter + if (!scaledImage.isNull()) scaledImage = scaledImage.convertDepth( 32 ); + } + else + pClass->readyPixmap = pClass->pixmap; + } + + if (haveTint || haveAlpha) { + // blend image(pix) with the given tint + + if (!scaledImage.isNull()) 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( tqRed( l ) * tint_red ); + int g = int( tqGreen( l ) * tint_green ); + int b = int( tqBlue( l ) * tint_blue ); + int a = int( tqAlpha( l ) * tint_alpha ); + ls[x] = tqRgba( r, g, b, a ); + } + } + } + if ((_compositor.isEmpty()) || (!argb_visual_available)) { + // Software blend only (no compositing support) + } + else { + // We have a compositor! + // Apply the alpha in the same manner as above, exept we are now + // using the hardware blending engine for all painting + scaledImage = pClass->readyPixmap; + if (!scaledImage.isNull()) scaledImage = scaledImage.convertDepth( 32 ); + int w = scaledImage.width(); + int h = scaledImage.height(); + + for (int y = 0; y < h; ++y) { + QRgb *ls = (QRgb *)scaledImage.scanLine( y ); + for (int x = 0; x < w; ++x) { + QRgb l = ls[x]; + float alpha_adjust = (tqAlpha( l )/256.0); + int r = int( tqRed( l ) * alpha_adjust ); + int g = int( tqGreen( l ) * alpha_adjust ); + int b = int( tqBlue( l ) * alpha_adjust ); + int a = int( tqAlpha( l ) * 1 ); + ls[x] = tqRgba( r, g, b, a ); + } + } + } + + if (!scaledImage.isNull()) { + kdDebug() << timestamp() << " convertFromImage " << id << " " << area << endl; + pClass->readyPixmap.convertFromImage( scaledImage ); + } + } + kdDebug() << timestamp() << " 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 "tdmpixmap.moc" diff --git a/tdm/kfrontend/themer/tdmpixmap.h b/tdm/kfrontend/themer/tdmpixmap.h new file mode 100644 index 000000000..faa71a034 --- /dev/null +++ b/tdm/kfrontend/themer/tdmpixmap.h @@ -0,0 +1,73 @@ +/* + * 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 TDMPIXMAP_H +#define TDMPIXMAP_H + +#include "tdmitem.h" + +//#include <tqrect.h> +#include <tqpixmap.h> + +#include <ksimpleconfig.h> +#include <kstandarddirs.h> + +/* + * KdmPixmap. A pixmap element + */ + +class KdmPixmap : public KdmItem { + Q_OBJECT + +public: + KdmPixmap( KdmItem *parent, const TQDomNode &node, const char *name = 0 ); + +protected: + // reimplemented; returns the size of loaded pixmap + virtual TQSize sizeHint(); + + // draw the pixmap + virtual void drawContents( TQPainter *p, const TQRect &r ); + + // handle switching between normal / active / prelight configurations + virtual void statusChanged(); + + virtual void setGeometry( const TQRect &newGeometry, bool force ); + + struct PixmapStruct { + struct PixmapClass { + TQString fullpath; + TQPixmap pixmap; + TQPixmap readyPixmap; + TQColor tint; + float alpha; //TODO added: not in greeter.dtd + bool present; + } normal, active, prelight; + } pixmap; + +private: + // Method to load the pixmap path given by the theme + TQString fullPath( const TQString &fileName ); + void renderSvg( PixmapStruct::PixmapClass *pClass, const TQRect &area ); + void loadPixmap( PixmapStruct::PixmapClass *pClass ); +}; + +#endif diff --git a/tdm/kfrontend/themer/tdmrect.cpp b/tdm/kfrontend/themer/tdmrect.cpp new file mode 100644 index 000000000..9056a513c --- /dev/null +++ b/tdm/kfrontend/themer/tdmrect.cpp @@ -0,0 +1,181 @@ +/* + * 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 "tdmrect.h" +#include "tdmthemer.h" +#include "tdmconfig.h" + +#include <kimageeffect.h> +#include <kdebug.h> + +#include <tqimage.h> +#include <tqpainter.h> +#include <tqwidget.h> +#include <tqlayout.h> + +extern bool argb_visual_available; + +KdmRect::KdmRect( KdmItem *parent, const TQDomNode &node, const char *name ) + : KdmItem( parent, node, name ) +{ + init( node, name ); +} + +KdmRect::KdmRect( TQWidget *parent, const TQDomNode &node, const char *name ) + : KdmItem( parent, node, name ) +{ + init( node, name ); +} + +void +KdmRect::init( const TQDomNode &node, const char * ) +{ + 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 + TQDomNode n = node; + TQDomElement elRect = n.toElement(); + + // Read RECT TAGS + TQDomNodeList childList = node.childNodes(); + for (uint nod = 0; nod < childList.count(); nod++) { + TQDomNode child = childList.item( nod ); + TQDomElement el = child.toElement(); + TQString tagName = el.tagName(); + + if (tagName == "normal") { + parseColor( el.attribute( "color", TQString::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", TQString::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", TQString::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( TQPainter *p, const TQRect &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, TQBrush( rClass->color ) ); + else { +// if ((_compositor.isEmpty()) || (!argb_visual_available)) { + // Software blend only (no compositing support) + TQRect backRect = r; + backRect.moveBy( area.x(), area.y() ); + TQPixmap backPixmap( backRect.size() ); + bitBlt( &backPixmap, TQPoint( 0, 0 ), p->device(), backRect ); + TQImage backImage = backPixmap.convertToImage(); + KImageEffect::blend( rClass->color, backImage, rClass->alpha ); + p->drawImage( backRect.x(), backRect.y(), backImage ); + // area.moveBy(1,1); +// } +// else { +// // We have compositing support! +// } + } +} + +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( TQWidget *widget ) +{ + widget->setFont( rect.normal.font ); +} + +void +KdmRect::recursiveSetAttribs( TQLayoutItem *li ) +{ + TQWidget *w; + TQLayout *l; + + if ((w = li->widget())) + setAttribs( w ); + else if ((l = li->layout())) { + TQLayoutIterator it = l->iterator(); + for (TQLayoutItem *itm = it.current(); itm; itm = ++it) + recursiveSetAttribs( itm ); + } +} + +void +KdmRect::setLayoutItem( TQLayoutItem *item ) +{ + KdmItem::setLayoutItem( item ); + recursiveSetAttribs( item ); +} +*/ + +void +KdmRect::setWidget( TQWidget *widget ) +{ + if ( rect.normal.color.isValid() && widget ) + { + TQPalette p = widget->palette(); + p.setColor( TQPalette::Normal, TQColorGroup::Text, rect.normal.color ); + widget->setPalette(p); + } + KdmItem::setWidget( widget ); + //setAttribs( widget ); +} + +#include "tdmrect.moc" diff --git a/tdm/kfrontend/themer/tdmrect.h b/tdm/kfrontend/themer/tdmrect.h new file mode 100644 index 000000000..6dfdc126a --- /dev/null +++ b/tdm/kfrontend/themer/tdmrect.h @@ -0,0 +1,67 @@ +/* + * 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 TDMRECT_H +#define TDMRECT_H + +#include "tdmitem.h" + +#include <tqcolor.h> +#include <tqfont.h> + +/* + * KdmRect: A themed rectangular element + */ + +class KdmRect : public KdmItem { + Q_OBJECT + +public: + KdmRect( KdmItem *parent, const TQDomNode &node, const char *name = 0 ); + KdmRect( TQWidget *parent, const TQDomNode &node, const char *name = 0 ); + +protected: + // draw the rect + virtual void drawContents( TQPainter *p, const TQRect &r ); + + // handle switching between normal / active / prelight configurations + virtual void statusChanged(); + + struct RectStruct { + struct RectClass { + float alpha; + TQColor color; + bool present; + TQFont font; + } normal, active, prelight; + bool hasBorder; + } rect; + + virtual void setWidget( TQWidget *widget ); +// virtual void setLayoutItem( TQLayoutItem *item ); + void init( const TQDomNode &node, const char *name ); + +private: + void setAttribs( TQWidget *widget ); + void recursiveSetAttribs( TQLayoutItem *item ); +}; + +#endif diff --git a/tdm/kfrontend/themer/tdmthemer.cpp b/tdm/kfrontend/themer/tdmthemer.cpp new file mode 100644 index 000000000..d2dc77935 --- /dev/null +++ b/tdm/kfrontend/themer/tdmthemer.cpp @@ -0,0 +1,404 @@ +/* + * 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 "tdmthemer.h" +#include "tdmitem.h" +#include "tdmpixmap.h" +#include "tdmrect.h" +#include "tdmlabel.h" + +#include <tdmconfig.h> +#include <kfdialog.h> + +#include <kiconloader.h> +#include <kimageeffect.h> +#include <klocale.h> +#include <ksimpleconfig.h> +#include <kdebug.h> + +#include <tqfile.h> +#include <tqfileinfo.h> +#include <tqtimer.h> // animation timer - TODO +#include <tqobjectlist.h> +#include <tqpainter.h> +#include <tqwidget.h> +#include <tqregion.h> +#include <tqlineedit.h> +#include <tqapplication.h> + +#include <unistd.h> + +extern bool argb_visual_available; + +/* + * KdmThemer. The main theming interface + */ +KdmThemer::KdmThemer( const TQString &_filename, const TQString &mode, TQWidget *parent ) + : TQObject( parent ) + , rootItem( 0 ) + , backBuffer( 0 ) +{ + // Set the mode we're working in + m_currentMode = mode; + + // read the XML file and create DOM tree + TQString filename = _filename; + if (!::access( TQFile::encodeName( filename + "/GdmGreeterTheme.desktop" ), R_OK )) { + KSimpleConfig cfg( filename + "/GdmGreeterTheme.desktop" ); + cfg.setGroup( "GdmGreeterTheme" ); + filename += '/' + cfg.readEntry( "Greeter" ); + } + TQFile 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( parent, TQDomNode(), "tdm root" ); + + connect( rootItem, TQT_SIGNAL(needUpdate( int, int, int, int )), + widget(), TQT_SLOT(update( int, int, int, int )) ); + + rootItem->setBaseDir( TQFileInfo( filename ).dirPath( true ) ); + + // generate all the items defined in the theme + generateItems( rootItem ); + + connect( rootItem, TQT_SIGNAL(activated( const TQString & )), TQT_SIGNAL(activated( const TQString & )) ); + connect( rootItem, TQT_SIGNAL(activated( const TQString & )), TQT_SLOT(slotActivated( const TQString & )) ); + + TQTimer::singleShot(800, this, TQT_SLOT(slotPaintRoot())); + +/* *TODO* + // Animation timer + TQTimer *time = new TQTimer( this ); + time->start( 500 ); + connect( time, TQT_SIGNAL(timeout()), TQT_SLOT(update()) ) +*/ +} + +KdmThemer::~KdmThemer() +{ + delete rootItem; + delete backBuffer; +} + +inline TQWidget * +KdmThemer::widget() +{ + return static_cast<TQWidget *>(parent()); +} + +KdmItem * +KdmThemer::findNode( const TQString &item ) const +{ + return rootItem->findNode( item ); +} + +void +KdmThemer::updateGeometry( bool force ) +{ + rootItem->setGeometry( TQRect( TQPoint(), widget()->size() ), force ); +} + +// BEGIN other functions + +void +KdmThemer::widgetEvent( TQEvent *e ) +{ + if (!rootItem) + return; + switch (e->type()) { + case TQEvent::MouseMove: + { + TQMouseEvent *me = TQT_TQMOUSEEVENT(e); + rootItem->mouseEvent( me->x(), me->y() ); + } + break; + case TQEvent::MouseButtonPress: + { + TQMouseEvent *me = TQT_TQMOUSEEVENT(e); + rootItem->mouseEvent( me->x(), me->y(), true ); + } + break; + case TQEvent::MouseButtonRelease: + { + TQMouseEvent *me = TQT_TQMOUSEEVENT(e); + rootItem->mouseEvent( me->x(), me->y(), false, true ); + } + break; + case TQEvent::Show: + rootItem->show(); + break; + case TQEvent::Resize: + updateGeometry( false ); + showStructure( rootItem ); + break; + case TQEvent::Paint: + { + TQRect paintRect = TQT_TQPAINTEVENT(e)->rect(); + kdDebug() << timestamp() << " paint on: " << paintRect << endl; + + if ((_compositor.isEmpty()) || (!argb_visual_available)) { + // Software blend only (no compositing support) + if (!backBuffer) + backBuffer = new TQPixmap( widget()->size() ); + if (backBuffer->size() != widget()->size()) + backBuffer->resize( widget()->size() ); + + TQPainter p; + p.begin( backBuffer ); + rootItem->paint( &p, paintRect ); + p.end(); + + bitBlt( widget(), paintRect.topLeft(), backBuffer, paintRect ); + } + else { + // We have compositing support! + TQRgb blend_color = tqRgba(0, 0, 0, 0); // RGBA + float alpha = tqAlpha(blend_color) / 255.; + int pixel = tqAlpha(blend_color) << 24 | + int(tqRed(blend_color) * alpha) << 16 | + int(tqGreen(blend_color) * alpha) << 8 | + int(tqBlue(blend_color) * alpha); + TQPainter p1; + p1.begin( widget() ); + p1.fillRect( paintRect, TQColor(blend_color, pixel) ); + rootItem->paint( &p1, paintRect ); + p1.end(); + } + + } + break; + default: + break; + } +} + +/* +void +KdmThemer::pixmap( const TQRect &r, TQPixmap *px ) +{ + bitBlt( px, TQPoint( 0, 0 ), widget(), r ); +} +*/ + +void +KdmThemer::generateItems( KdmItem *parent, const TQDomNode &node ) +{ + if (!parent) + return; + + TQDomNodeList subnodeList; //List of subnodes of this node + + /* + * Get the child nodes + */ + if (node.isNull()) { // It's the first node, get its child nodes + TQDomElement theme = domTree.documentElement(); + + // Get its tag, and check it's correct ("greeter") + if (theme.tagName() != "greeter") { + kdDebug() << timestamp() << " 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++) { + TQDomNode subnode = subnodeList.item( nod ); + TQDomElement el = subnode.toElement(); + TQString tagName = el.tagName(); + + if (tagName == "item") { + if (!willDisplay( subnode )) + continue; + TQString id = el.attribute("id"); + if (id.startsWith("plugin-specific-")) { + id = id.mid(strlen("plugin-specific-")); + if (!_pluginsLogin.contains(id)) + continue; + } + + // It's a new item. Draw it + TQString 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" || type == "list") { + newItem = new KdmRect( parent, subnode ); + newItem->setType( type ); + } + // newItem = new KdmEntry( 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 TQDomNode &node ) +{ + TQDomNode showNode = node.namedItem( "show" ); + + // No "show" node means this item can be displayed at all times + if (showNode.isNull()) + return true; + + TQDomElement el = showNode.toElement(); + + TQString modes = el.attribute( "modes" ); + if (!modes.isNull()) { + TQStringList modeList = TQStringList::split( ",", modes ); + + // If current mode isn't in this list, do not display item + if (modeList.find( m_currentMode ) == modeList.end()) + return false; + } + + TQString 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; + else if (type == "userlist") + return _userList; + else if ( type == "!userlist" ) + return !_userList; + +// if (type == "system") +// return true; + + // All tests passed, item will be displayed + return true; +} + +void +KdmThemer::showStructure( TQObject *obj ) +{ + + const TQObjectList wlist = obj->childrenListObject(); + static int counter = 0; + if (counter == 0) + kdDebug() << timestamp() << " \n\n<======= Widget tree =================" << endl; + if (!wlist.isEmpty()) { + counter++; + TQObjectListIterator it( wlist ); + TQObject *object; + + while ((object = it.current()) != 0) { + ++it; + TQString 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() << timestamp() << " \n\n<======= Widget tree =================\n\n" << endl; +} + +void +KdmThemer::slotActivated( const TQString &id ) +{ + TQString toactivate; + if (id == "username-label") + toactivate = "user-entry"; + else if (id == "password-label") + toactivate = "pw-entry"; + else + return; + + KdmItem *item = findNode(toactivate); + if (!item || !item->widget()) + return; + + item->widget()->setFocus(); + TQLineEdit *le = (TQLineEdit*)item->widget()->qt_cast(TQLINEEDIT_OBJECT_NAME_STRING); + if (le) + le->selectAll(); +} + +void +KdmThemer::slotPaintRoot() +{ + KdmItem *back_item = findNode("background"); + if (!back_item) + return; + + TQRect screen = TQApplication::desktop()->screenGeometry(0); + TQPixmap pm(screen.size()); + + TQPainter painter( &pm, true ); + back_item->paint( &painter, back_item->rect()); + painter.end(); + + TQT_TQWIDGET(TQApplication::desktop()->screen())->setErasePixmap(pm); + TQT_TQWIDGET(TQApplication::desktop()->screen())->erase(); +} + +#include "tdmthemer.moc" diff --git a/tdm/kfrontend/themer/tdmthemer.h b/tdm/kfrontend/themer/tdmthemer.h new file mode 100644 index 000000000..2b8865b4d --- /dev/null +++ b/tdm/kfrontend/themer/tdmthemer.h @@ -0,0 +1,128 @@ +/* + * 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 TDMTHEMER_H +#define TDMTHEMER_H + +#include <tqobject.h> +#include <tqdom.h> +#include <tqimage.h> + +class KdmThemer; +class KdmItem; +class KdmPixmap; +class KdmRect; +class KdmBox; + +class TQRect; +class TQWidget; +class TQEvent; + +/** +* @author Unai Garro +*/ + + + +/* +* The themer widget. Whatever drawn here is just themed +* according to a XML file set by the user. +*/ + + +class KdmThemer : public TQObject { + Q_OBJECT + +public: + /* + * Construct and destruct the interface + */ + + KdmThemer( const TQString &path, const TQString &mode, TQWidget *parent ); + ~KdmThemer(); + + bool isOK() { return rootItem != 0; } + /* + * Gives a sizeHint to the widget (parent size) + */ + //TQSize sizeHint() const{ return parentWidget()->size(); } + + /* + * Takes a shot of the current widget + */ +// void pixmap( const TQRect &r, TQPixmap *px ); + + virtual // just to put the reference in the vmt + KdmItem *findNode( const TQString & ) const; + + void updateGeometry( bool force ); // force = true for external calls + + // must be called by parent widget + void widgetEvent( TQEvent *e ); + +signals: + void activated( const TQString &id ); + +protected slots: + void slotActivated( const TQString &id ); + void slotPaintRoot(); + +private: + /* + * Our display mode (e.g. console, remote, ...) + */ + TQString m_currentMode; + + /* + * The config file being used + */ + TQDomDocument domTree; + + /* + * Stores the root of the theme + */ + KdmItem *rootItem; + + /* + * The backbuffer + */ + TQPixmap *backBuffer; + + // methods + + /* + * Test whether item needs to be displayed + */ + bool willDisplay( const TQDomNode &node ); + + /* + * Parses the XML file looking for the + * item list and adds those to the themer + */ + void generateItems( KdmItem *parent = 0, const TQDomNode &node = TQDomNode() ); + + void showStructure( TQObject *obj ); + + TQWidget *widget(); +}; + + +#endif |