kwin Library API Documentation

buttons.cpp

00001 /*
00002     $Id: buttons.cpp,v 1.8 2003/09/19 11:14:41 lunakl Exp $
00003 
00004     This is the new kwindecoration kcontrol module
00005 
00006     Copyright (c) 2001
00007         Karol Szwed <gallium@kde.org>
00008         http://gallium.n3.net/
00009 
00010     Supports new kwin configuration plugins, and titlebar button position
00011     modification via dnd interface.
00012 
00013     Based on original "kwintheme" (Window Borders)
00014     Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
00015 
00016     This program is free software; you can redistribute it and/or modify
00017     it under the terms of the GNU General Public License as published by
00018     the Free Software Foundation; either version 2 of the License, or
00019     (at your option) any later version.
00020   
00021     This program is distributed in the hope that it will be useful,
00022     but WITHOUT ANY WARRANTY; without even the implied warranty of
00023     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024     GNU General Public License for more details.
00025   
00026     You should have received a copy of the GNU General Public License
00027     along with this program; if not, write to the Free Software
00028     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00029 
00030 */
00031 
00032 #include <qpainter.h>
00033 #include <klocale.h>
00034 #include <kglobalsettings.h>
00035 #include "buttons.h"
00036 #include "pixmaps.h"
00037 
00038 
00039 // General purpose button globals (I know I shouldn't use them :)
00040 //===============================================================
00041 
00042 enum Buttons{ BtnMenu=0, BtnOnAllDesktops, BtnSpacer, BtnHelp,
00043               BtnMinimize, BtnMaximize, BtnClose, BtnCount };
00044 QListBoxPixmap* buttons[ BtnCount ];
00045 QPixmap*        pixmaps[ BtnCount ];
00046 QPixmap*        miniSpacer;
00047 
00048 
00049 //==============================================================
00050 
00051 ButtonDrag::ButtonDrag( char btn, QWidget* parent, const char* name)
00052     : QStoredDrag( "kcontrol/kwindecoration_buttons", parent, name)
00053 {
00054     QByteArray payload(1);
00055     payload[0] = btn;
00056     setEncodedData( payload );
00057 }
00058 
00059 
00060 bool ButtonDrag::canDecode( QDragMoveEvent* e )
00061 {
00062     return e->provides( "kcontrol/kwindecoration_buttons" );
00063 }
00064 
00065 
00066 bool ButtonDrag::decode( QDropEvent* e, char& btn )
00067 {
00068     QByteArray payload = e->data( "kcontrol/kwindecoration_buttons" );
00069     if ( payload.size() )
00070     {
00071         e->accept();
00072         btn = payload[0];
00073         return TRUE;
00074     }
00075     return FALSE;
00076 }
00077 
00078 
00079 
00081 // Implements the button drag source list box
00083 
00084 // Converts the button character value to its index
00085 static int btnIndex( char btn )
00086 {
00087     switch (btn)
00088     {
00089         case 'M':
00090             return BtnMenu;
00091             break;
00092         case 'S':
00093             return BtnOnAllDesktops;
00094             break;
00095         case '_':
00096             return BtnSpacer;
00097             break;
00098         case 'H':
00099             return BtnHelp;
00100             break;
00101         case 'I':
00102             return BtnMinimize;
00103             break;
00104         case 'A':
00105             return BtnMaximize;
00106             break;
00107         case 'X':
00108             return BtnClose;
00109             break;
00110         default:
00111             return -1;  // Not found...
00112     }
00113 }
00114 
00115 
00116 // Returns the pixmap of a button item
00117 const QPixmap* btnPixmap( char btn )
00118 {
00119     if (btn == '_')
00120         return miniSpacer;
00121 
00122     int btnindex = btnIndex( btn );
00123     if (btnindex == -1)
00124         return NULL;
00125 
00126     return buttons[btnindex]->pixmap();
00127 }
00128 
00129 
00130 
00131 ButtonSource::ButtonSource( QWidget* parent, const char* name )
00132   : QListBox( parent, name)
00133 {
00134     // Create the listbox pixmaps
00135     pixmaps[ BtnMenu ]      = new QPixmap( button_menu_xpm );
00136     pixmaps[ BtnOnAllDesktops ] = new QPixmap( button_on_all_desktops_xpm );
00137     pixmaps[ BtnSpacer ]    = new QPixmap( button_spacer_xpm );
00138     pixmaps[ BtnHelp ]      = new QPixmap( button_help_xpm );
00139     pixmaps[ BtnMinimize ]  = new QPixmap( button_minimize_xpm );
00140     pixmaps[ BtnMaximize ]  = new QPixmap( button_maximize_xpm );
00141     pixmaps[ BtnClose ]     = new QPixmap( button_close_xpm );
00142     miniSpacer              = new QPixmap( titlebarspacer_xpm );
00143 
00144     // Add all possible button/spacer types to the list box.
00145     buttons[ BtnMenu ]      = new QListBoxPixmap( this, *pixmaps[BtnMenu], i18n("Menu") );
00146     buttons[ BtnOnAllDesktops]  = new QListBoxPixmap( this, *pixmaps[BtnOnAllDesktops], i18n("On All Desktops") );
00147     buttons[ BtnSpacer ]    = new QListBoxPixmap( this, *pixmaps[BtnSpacer], i18n("Spacer") );
00148     buttons[ BtnHelp ]      = new QListBoxPixmap( this, *pixmaps[BtnHelp], i18n("Help") );
00149     buttons[ BtnMinimize ]  = new QListBoxPixmap( this, *pixmaps[BtnMinimize], i18n("Minimize") );
00150     buttons[ BtnMaximize ]  = new QListBoxPixmap( this, *pixmaps[BtnMaximize], i18n("Maximize") );
00151     buttons[ BtnClose ]     = new QListBoxPixmap( this, *pixmaps[BtnClose], i18n("Close") );
00152 
00153     spacerCount = 0;    // No spacers inserted yet
00154     setAcceptDrops( TRUE );
00155 }
00156 
00157 
00158 ButtonSource::~ButtonSource()
00159 {
00160     for( int i = 0; i < BtnCount; i++)
00161         if (pixmaps[i])
00162             delete pixmaps[i];
00163 
00164     if (miniSpacer)
00165         delete miniSpacer;
00166 }
00167 
00168 
00169 void ButtonSource::hideAllButtons()
00170 {
00171     // Hide all listbox items which are visible
00172     if (index( buttons[BtnMenu] ) != -1)
00173         takeItem( buttons[BtnMenu] );
00174     if (index( buttons[BtnOnAllDesktops] )!= -1)
00175         takeItem( buttons[BtnOnAllDesktops] );
00176     if (index( buttons[BtnHelp] ) != -1)
00177         takeItem( buttons[BtnHelp] );
00178     if (index( buttons[BtnMinimize] ) != -1)
00179         takeItem( buttons[BtnMinimize] );
00180     if (index( buttons[BtnMaximize] ) != -1)
00181         takeItem( buttons[BtnMaximize] );
00182     if (index( buttons[BtnClose] ) != -1)
00183         takeItem( buttons[BtnClose] );
00184     if (index( buttons[BtnSpacer] ) != -1)
00185         takeItem( buttons[BtnSpacer] );
00186 
00187     spacerCount = 10;   // 10 inserted spacers (max)
00188 }
00189 
00190 void ButtonSource::showAllButtons()
00191 {
00192     // Hide all listbox items which are visible
00193     if (index( buttons[BtnMenu] ) == -1)
00194         insertItem( buttons[BtnMenu] );
00195     if (index( buttons[BtnOnAllDesktops] )== -1)
00196         insertItem( buttons[BtnOnAllDesktops] );
00197     if (index( buttons[BtnHelp] ) == -1)
00198         insertItem( buttons[BtnHelp] );
00199     if (index( buttons[BtnMinimize] ) == -1)
00200         insertItem( buttons[BtnMinimize] );
00201     if (index( buttons[BtnMaximize] ) == -1)
00202         insertItem( buttons[BtnMaximize] );
00203     if (index( buttons[BtnClose] ) == -1)
00204         insertItem( buttons[BtnClose] );
00205     if (index( buttons[BtnSpacer] ) == -1)
00206         insertItem( buttons[BtnSpacer] );
00207 
00208     spacerCount = 0;    // No inserted spacers
00209 }
00210 
00211 
00212 void ButtonSource::showButton( char btn )
00213 {
00214     // Ignore spacers (max 10)
00215     if (btn == '_')
00216         spacerCount--;
00217 
00218     int btnindex = btnIndex(btn);
00219 
00220     // Check if the item is already inserted...
00221     if ( (btnindex != -1) && (index( buttons[btnindex] ) == -1) )
00222     {
00223         setUpdatesEnabled( FALSE );
00224         insertItem( buttons[ btnindex ] );
00225         setUpdatesEnabled( TRUE );
00226         sort();
00227     }
00228 }
00229 
00230 
00231 void ButtonSource::hideButton( char btn )
00232 {
00233     // Ignore spacers (max 10)
00234     if (btn == '_')
00235     {
00236         spacerCount++;
00237         if (spacerCount != 10)
00238         return;
00239     }
00240 
00241     int btnindex = btnIndex(btn);
00242 
00243     // Check if the item is already removed...
00244     if ( (btnindex != -1) && (index( buttons[btnindex] ) != -1) )
00245     {
00246         setUpdatesEnabled( FALSE );
00247         // De-select before removal
00248         setSelected( buttons[ btnindex ], false );
00249         takeItem( buttons[ btnindex ] );
00250         setUpdatesEnabled( TRUE );
00251         sort();
00252     }
00253 }
00254 
00255 
00256 char ButtonSource::convertToChar( QString s )
00257 {
00258     // Convert the item to its character representation
00259     if (s == i18n("Menu"))
00260         return 'M';
00261     else if (s == i18n("On All Desktops"))
00262         return 'S';
00263     else if (s == i18n("Spacer"))
00264         return '_';
00265     else if (s == i18n("Help"))
00266         return 'H';
00267     else if (s == i18n("Minimize"))
00268         return 'I';
00269     else if (s == i18n("Maximize"))
00270         return 'A';
00271     else if (s == i18n("Close"))
00272         return 'X';
00273     else
00274         return '?';
00275 }
00276 
00277 
00278 void ButtonSource::mousePressEvent( QMouseEvent* e )
00279 {
00280     // Make a selection before moving the mouse
00281     QListBox::mousePressEvent( e );
00282 
00283     // Make sure we have at laest 1 item in the listbox
00284     if ( count() > 0 )
00285     {
00286         // Obtain currently selected item
00287         char btn = convertToChar( currentText() );
00288         ButtonDrag* bd = new ButtonDrag( btn, this );
00289         bd->dragCopy();
00290     }
00291 }
00292 
00293 
00294 void ButtonSource::dragMoveEvent( QDragMoveEvent* /* e */ )
00295 {
00296     // Do nothing...
00297 }
00298 
00299 
00300 void ButtonSource::dragEnterEvent( QDragEnterEvent* e )
00301 {
00302     if ( ButtonDrag::canDecode( e ) )
00303         e->accept();
00304 }
00305 
00306 
00307 void ButtonSource::dragLeaveEvent( QDragLeaveEvent* /* e */ )
00308 {
00309     // Do nothing...
00310 }
00311 
00312 
00313 void ButtonSource::dropEvent( QDropEvent* /* e */ )
00314 {
00315     // Allow the button to be removed from the ButtonDropSite
00316     emit buttonDropped();
00317 }
00318 
00319 
00321 // This class renders and handles the demo titlebar dropsite
00323 
00324 ButtonDropSite::ButtonDropSite( QWidget* parent, const char* name )
00325     : QFrame( parent, name )
00326 {
00327     setAcceptDrops( TRUE );
00328     setFrameShape( WinPanel );
00329     setFrameShadow( Raised );
00330     setMinimumHeight( 26 );
00331     setMaximumHeight( 26 );
00332     setMinimumWidth( 250 );     // Ensure buttons will fit
00333 
00334     mouseClickPoint.setX(0);
00335     mouseClickPoint.setY(0);
00336 }
00337 
00338 
00339 ButtonDropSite::~ButtonDropSite()
00340 {
00341     // Do nothing...
00342 }
00343 
00344 
00345 void ButtonDropSite::dragMoveEvent( QDragMoveEvent* /* e */ )
00346 {
00347     // Do nothing...
00348 }
00349 
00350 
00351 void ButtonDropSite::dragEnterEvent( QDragEnterEvent* e )
00352 {
00353     if ( ButtonDrag::canDecode( e ) )
00354         e->accept();
00355 }
00356 
00357 
00358 void ButtonDropSite::dragLeaveEvent( QDragLeaveEvent* /* e */ )
00359 {
00360     // Do nothing...
00361 }
00362 
00363 
00364 void ButtonDropSite::dropEvent( QDropEvent* e )
00365 {
00366     char btn;
00367     if ( ButtonDrag::decode(e, btn) )
00368     {
00369         bool isleft;
00370         int strPos;
00371 
00372         // If we are moving buttons around, remove the old item first.
00373         if (btn == '*')
00374         {
00375             btn = removeButtonAtPoint( mouseClickPoint );
00376             if (btn != '?')
00377                 emit buttonRemoved( btn );
00378         }
00379 
00380         if (btn != '?')
00381         {
00382             // Add the button to our button strings
00383             buttonInsertedAtPoint( e->pos(), isleft, strPos );
00384 
00385             if (isleft)
00386                 buttonsLeft.insert( strPos, btn );
00387             else
00388                 buttonsRight.insert( strPos, btn );
00389 
00390             repaint(false);
00391 
00392             // Allow listbox to update itself
00393             emit buttonAdded( btn );
00394             emit changed();
00395         }
00396     }
00397 }
00398 
00399 
00400 // Starts dragging a button...
00401 void ButtonDropSite::mousePressEvent( QMouseEvent* e )
00402 {
00403     mouseClickPoint = e->pos();
00404 
00405     ButtonDrag* bd = new ButtonDrag( '*', this );
00406     bd->dragCopy();
00407 }
00408 
00409 
00410 int ButtonDropSite::buttonWidth( char btn )
00411 {
00412     if (btn == '_')
00413         return 6;       // ensure this matches with the pixmap widths
00414     else
00415         return 20;      // Assume characters given are all valid
00416 }
00417 
00418 
00419 // Computes the total space the buttons will take in the titlebar
00420 int ButtonDropSite::calcButtonStringWidth( const QString& s )
00421 {
00422     QChar ch;
00423     unsigned int offset = 0;
00424 
00425     for(unsigned int i = 0; i < s.length(); i++)
00426     {
00427         ch = s[i];
00428         offset += buttonWidth( ch.latin1() );
00429     }
00430     return (int)offset;
00431 }
00432 
00433 
00434 // This slot is called after we drop on the item listbox...
00435 void ButtonDropSite::removeClickedButton()
00436 {
00437     if ( !mouseClickPoint.isNull() )
00438     {
00439         char btn = removeButtonAtPoint( mouseClickPoint );
00440         mouseClickPoint.setX(0);
00441         mouseClickPoint.setY(0);
00442         repaint(false);
00443 
00444         emit buttonRemoved( btn );
00445         emit changed();
00446     }
00447 }
00448 
00449 
00450 // Find the string and position at which to insert the new button...
00451 void ButtonDropSite::buttonInsertedAtPoint( QPoint p, bool& isleft, int& strPos )
00452 {
00453     int leftoffset = calcButtonStringWidth( buttonsLeft );
00454     int rightoffset = calcButtonStringWidth( buttonsRight );
00455     int posx = p.x() - 3;
00456 
00457     // The centre of the titlebar text tells us whether to add to the left or right
00458     if ( posx < ( leftoffset - rightoffset + ((geometry().width() - 6) / 2)))
00459         isleft = true;
00460     else
00461         isleft = false;
00462 
00463     QString s = isleft ? buttonsLeft : buttonsRight;
00464     int offset = isleft ? 0 : geometry().width() - 6 - rightoffset;
00465     QChar ch;
00466 
00467     strPos = s.length();
00468 
00469     for (unsigned int i = 0; i < s.length(); i++)
00470     {
00471         if ( posx < (offset + 5 ))
00472         {
00473             strPos = i;
00474             break;
00475         }
00476         ch = s[i];
00477         offset += buttonWidth( ch.latin1() );
00478     }
00479 }
00480 
00481 
00482 char ButtonDropSite::removeButtonAtPoint( QPoint p )
00483 {
00484     int offset = -1;
00485     bool isleft = false;
00486 
00487     // Shrink contents rect by 1 to fit in the titlebar border
00488     QRect r = contentsRect();
00489     r.moveBy(1 , 1);
00490     r.setWidth( r.width() - 2 );
00491     r.setHeight( r.height() - 2 );
00492 
00493     // Bail out if the borders were clicked
00494     if ( !r.contains(p) )
00495         return '?';
00496 
00497     int posx = p.x();
00498 
00499     // Is the point in the LHS/RHS button area?
00500     if ( (!buttonsLeft.isEmpty()) && (posx <= (calcButtonStringWidth( buttonsLeft )+3)) )
00501     {
00502         offset = 3;
00503         isleft = true;
00504     }
00505     else if ( (!buttonsRight.isEmpty()) && (posx >= geometry().width() - calcButtonStringWidth(buttonsRight) - 3))
00506         {
00507             offset = geometry().width() - calcButtonStringWidth(buttonsRight) - 3;
00508             isleft = false;
00509         }
00510 
00511     // Step through the button strings and remove the appropriate button
00512     if (offset != -1)
00513     {
00514         QChar ch;
00515         QString s = isleft ? buttonsLeft : buttonsRight;
00516 
00517         // Step through the items, to find the appropriate one to remove.
00518         for (unsigned int i = 0; i < s.length(); i++)
00519         {
00520             ch = s[i];
00521             offset += buttonWidth( ch.latin1() );
00522             if (posx <= offset)
00523             {
00524                 s.remove( i, 1 );       // Remove the current button item
00525                 if (isleft)
00526                     buttonsLeft = s;
00527                 else
00528                     buttonsRight = s;
00529                 return ch.latin1();
00530             }
00531         }
00532     }
00533 
00534     return '?';
00535 }
00536 
00537 
00538 void ButtonDropSite::drawButtonString( QPainter* p, QString& s, int offset )
00539 {
00540     QChar ch;
00541 
00542     for(unsigned int i = 0; i < s.length(); i++)
00543     {
00544         ch = s[i];
00545         p->drawPixmap( offset, 3, *btnPixmap(ch.latin1()) );
00546         offset += buttonWidth(ch.latin1());
00547     }
00548 }
00549 
00550 
00551 void ButtonDropSite::drawContents( QPainter* p )
00552 {
00553     int leftoffset = calcButtonStringWidth( buttonsLeft );
00554     int rightoffset = calcButtonStringWidth( buttonsRight );
00555     int offset = 3;
00556 
00557     QRect r = contentsRect();
00558 
00559     // Shrink by 1
00560     r.moveBy(1 + leftoffset, 1);
00561     r.setWidth( r.width() - 2 - leftoffset - rightoffset );
00562     r.setHeight( r.height() - 2 );
00563 
00564     drawButtonString( p, buttonsLeft, offset );
00565 
00566     QColor c1( 0x0A, 0x5F, 0x89 );      // KDE 2 titlebar default colour
00567     p->fillRect( r, c1 );
00568     p->setPen( Qt::white );
00569     p->setFont( QFont( KGlobalSettings::generalFont().family(), 12, QFont::Bold) );
00570     p->drawText( r, AlignLeft | AlignVCenter, i18n("KDE") );
00571 
00572     offset = geometry().width() - 3 - rightoffset;
00573     drawButtonString( p, buttonsRight, offset );
00574 }
00575 
00576 #include "buttons.moc"
00577 // vim: ts=4
KDE Logo
This file is part of the documentation for kwin Library Version 3.2.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Mar 5 04:41:13 2004 by doxygen 1.3.6-20040222 written by Dimitri van Heesch, © 1997-2003