kwin Library API Documentation

buttons.cpp

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