KDevelop API Documentation

lib/util/splitter.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 Copyright (C) 2001 Bernd Gehrmann <bernd@kdevelop.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #include <qframe.h> 00021 #include <qpainter.h> 00022 #include <qtimer.h> 00023 #include <qstyle.h> 00024 #include <kdebug.h> 00025 00026 #include "splitter.h" 00027 00028 00029 Splitter::Splitter(QWidget *parent, const char *name) 00030 : QWidget(parent, name) 00031 { 00032 _or = Horizontal; 00033 00034 handlelist.setAutoDelete(true); 00035 } 00036 00037 00038 Splitter::~Splitter() 00039 {} 00040 00041 00042 void Splitter::setOrientation(Orientation orient) 00043 { 00044 if (orient != _or) { 00045 if (!childlist.isEmpty()) { 00046 if (hasMultipleChildren()) { 00047 kdDebug(9000) << "Cannot change the orientation of a splitter with several widgets." << endl; 00048 return; 00049 } 00050 if (orient == Horizontal) { 00051 SplitterHandle *handle = new SplitterHandle(childlist.first(), this, "handle"); 00052 // handle->show(); 00053 handlelist.append(handle); 00054 } else { 00055 handlelist.remove((uint)0); 00056 } 00057 } 00058 00059 _or = orient; 00060 doLayout(); 00061 } 00062 } 00063 00064 00065 Qt::Orientation Splitter::orientation() const 00066 { 00067 return _or; 00068 } 00069 00070 00071 bool Splitter::hasMultipleChildren() const 00072 { 00073 return childlist.count() > 1; 00074 } 00075 00076 00077 QWidget *Splitter::firstChild() 00078 { 00079 return childlist.first(); 00080 } 00081 00082 00083 int Splitter::handleWidth() const 00084 { 00085 return (orientation() == Horizontal)? style().pixelMetric(QStyle::PM_SplitterWidth, this) : 0; 00086 } 00087 00088 00089 void Splitter::addChild(QWidget *w) 00090 { 00091 kdDebug(9000) << "add child" << endl; 00092 // connect( w, SIGNAL(destroyed()), this, SLOT(childDestroyed()) ); 00093 if (childlist.count()) { 00094 // When we already have children, this is the same as 00095 // a split of the last one 00096 splitChild(childlist.last(), w); 00097 } else { 00098 childlist.append(w); 00099 if (orientation() == Horizontal) { 00100 SplitterHandle *handle = new SplitterHandle(w, this, "handle"); 00101 handlelist.append(handle); 00102 } 00103 } 00104 00105 doLayout(); 00106 } 00107 00108 00109 void Splitter::splitChild(QWidget *old, QWidget *w) 00110 { 00111 #if 0 00112 kdDebug(9000) << "splitChild - Old list of splitter children:" << endl; 00113 QPtrListIterator<QWidget> it1(childlist); 00114 for (; it1.current(); ++it1) 00115 kdDebug(9000) << it1.current()->name() << endl; 00116 #endif 00117 00118 int offset = 0; 00119 for (uint i = 0; i < childlist.count(); ++i) { 00120 if (childlist.at(i) == old) { 00121 childlist.insert(i+1, w); 00122 if (orientation() == Horizontal) { 00123 SplitterHandle *handle = new SplitterHandle(w, this, "handle"); 00124 handlelist.insert(i+1, handle); 00125 } 00126 if (i+1 != childlist.count()-1) { 00127 sizes.insert(sizes.at(i), sizes[i]/2 - handleWidth()); 00128 sizes[i+1] = sizes[i]/2; 00129 } else { 00130 int total = (orientation() == Horizontal)? width() : height(); 00131 sizes.insert(sizes.at(i), (total-offset)/2); 00132 } 00133 doLayout(); 00134 return; 00135 } 00136 offset += sizes[i]; 00137 offset += handleWidth(); 00138 } 00139 00140 kdDebug(9000) << "Huh? Old child not in splitter" << endl; 00141 } 00142 00143 00144 void Splitter::replaceChild(QWidget *old, QWidget *w) 00145 { 00146 for (uint i=0; i < childlist.count(); ++i) 00147 if (childlist.at(i) == old) { 00148 childlist.remove(i); 00149 if (orientation() == Horizontal) 00150 handlelist.remove(i); 00151 childlist.insert(i, w); 00152 if (orientation() == Horizontal) { 00153 SplitterHandle *handle = new SplitterHandle(w, this, "handle"); 00154 handlelist.insert(i, handle); 00155 } 00156 doLayout(); 00157 return; 00158 } 00159 00160 kdDebug(9000) << "Huh? Old child not in splitter" << endl; 00161 } 00162 00163 00164 void Splitter::moveSplitter(QWidget *w, int pos) 00165 { 00166 int offset = 0; 00167 for (uint i=0; i < childlist.count(); ++i) { 00168 if (childlist.at(i) == w) { 00169 if (i != childlist.count()) { 00170 sizes[i] = pos-offset; 00171 break; 00172 } 00173 } 00174 offset += sizes[i]; 00175 offset += handleWidth(); 00176 } 00177 00178 doLayout(); 00179 } 00180 00181 00182 void Splitter::doLayout() 00183 { 00184 setUpdatesEnabled(false); 00185 00186 if (orientation() == Horizontal) { 00187 00188 int offset = 0; 00189 uint i; 00190 for (i=0; i+1 < childlist.count(); ++i) { 00191 sizes[i] = QMAX(sizes[i], childlist.at(i)->minimumSizeHint().width()); 00192 childlist.at(i)->setGeometry(offset, 0, sizes[i], height()); 00193 offset += childlist.at(i)->width(); 00194 handlelist.at(i)->setGeometry(offset, 0, style().pixelMetric(QStyle::PM_SplitterWidth, this), height()); 00195 handlelist.at(i)->show(); 00196 offset += handlelist.at(i)->width(); 00197 } 00198 00199 if (childlist.count()) { 00200 childlist.at(i)->setGeometry(offset, 0, width()-offset, height()); 00201 handlelist.at(i)->hide(); 00202 } 00203 00204 } else { 00205 00206 int offset = 0; 00207 uint i; 00208 for (i=0; i+1 < childlist.count(); ++i) { 00209 sizes[i] = QMAX(sizes[i], childlist.at(i)->minimumSizeHint().height()); 00210 childlist.at(i)->setGeometry(0, offset, width(), sizes[i]); 00211 offset += childlist.at(i)->height(); 00212 } 00213 00214 if (childlist.count()) 00215 childlist.at(i)->setGeometry(0, offset, width(), height()-offset); 00216 00217 } 00218 00219 setUpdatesEnabled(true); 00220 } 00221 00222 00223 00224 QSize Splitter::minimumSizeHint() const 00225 { 00226 int extent = 0; 00227 for (uint i = 0; i < childlist.count(); ++i) { 00228 // Bah. 00229 Splitter *that = (Splitter*) this; 00230 QSize s = that->childlist.at(i)->minimumSizeHint(); 00231 extent = QMAX(extent, (orientation()==Horizontal)? s.height() : s.width()); 00232 } 00233 return (orientation()==Horizontal)? QSize(0, extent) : QSize(extent, 0); 00234 } 00235 00236 00237 void Splitter::childEvent(QChildEvent *e) 00238 { 00239 if (e->type() != QEvent::ChildRemoved) 00240 return; 00241 00242 QObject *o = e->child(); 00243 00244 for (uint i=0; i<childlist.count(); ++i) { 00245 if (childlist.at(i) == o) { 00246 childlist.remove(i); 00247 if (orientation() == Horizontal) 00248 handlelist.remove(i); 00249 if (i == childlist.count()) 00250 sizes.remove(i-1); 00251 else 00252 sizes.remove(i); 00253 doLayout(); 00254 if (childlist.count() < 2) 00255 QTimer::singleShot(0, this, SLOT(collapse())); 00256 break; 00257 } 00258 } 00259 } 00260 00261 00262 void Splitter::collapse() 00263 { 00264 emit collapsed(this); 00265 } 00266 00267 00268 void Splitter::resizeEvent(QResizeEvent */*e*/) 00269 { 00270 doLayout(); 00271 } 00272 00273 00274 SplitterBar::SplitterBar(QWidget *parent, const char *name) 00275 : QFrame(parent, name) 00276 { 00277 setFrameStyle(Panel | Raised); 00278 setLineWidth(1); 00279 setFixedHeight(fontMetrics().lineSpacing()+2); 00280 00281 offset = 0; 00282 } 00283 00284 00285 SplitterBar::~SplitterBar() 00286 {} 00287 00288 00289 void SplitterBar::mouseMoveEvent(QMouseEvent *e) 00290 { 00291 if (e->state() & LeftButton) { 00292 QWidget *p = parentWidget(); 00293 QWidget *gp = p->parentWidget(); 00294 if (!gp->inherits("Splitter")) 00295 return; 00296 // If we are in a horizontal splitter, look if this horizontal 00297 // splitter is nested in a vertical splitter, when is then 00298 // used. 00299 if (static_cast<Splitter*>(gp)->orientation() == Horizontal) { 00300 p = gp; 00301 gp = p->parentWidget(); 00302 if (!gp->inherits("Splitter")) 00303 return; 00304 } 00305 int pos = gp->mapFromGlobal(e->globalPos()).y() + offset; 00306 static_cast<Splitter*>(gp)->moveSplitter(p, pos); 00307 } 00308 } 00309 00310 00311 void SplitterBar::mousePressEvent(QMouseEvent *e) 00312 { 00313 if ( e->button() & LeftButton ) 00314 offset = height()-e->pos().y(); 00315 } 00316 00317 00318 void SplitterBar::childEvent(QChildEvent *e) 00319 { 00320 if (e->type() == QEvent::ChildInserted && e->child()->isWidgetType()) 00321 e->child()->installEventFilter(this); 00322 else if (e->type() == QEvent::ChildRemoved && e->child()->isWidgetType()) 00323 e->child()->removeEventFilter(this); 00324 } 00325 00326 00327 bool SplitterBar::eventFilter(QObject *o, QEvent *e) 00328 { 00329 if (e->type() == QEvent::MouseButtonPress) 00330 mousePressEvent(static_cast<QMouseEvent*>(e)); 00331 else if(e->type() == QEvent::MouseMove) 00332 mouseMoveEvent(static_cast<QMouseEvent*>(e)); 00333 00334 return QWidget::eventFilter(o, e); 00335 } 00336 00337 00338 SplitterHandle::SplitterHandle(QWidget *embeddedSibling, Splitter *parent, const char *name) 00339 : QWidget(parent, name) 00340 { 00341 sibling = embeddedSibling; 00342 setCursor(splitHCursor); 00343 // setFixedWidth(QMIN(style().splitterWidth(), QApplication::globalStrut().width())); 00344 } 00345 00346 00347 SplitterHandle::~SplitterHandle() 00348 {} 00349 00350 00351 void SplitterHandle::mouseMoveEvent(QMouseEvent *e) 00352 { 00353 if (e->state() & LeftButton) { 00354 int pos = parentWidget()->mapFromGlobal(e->globalPos()).x() + offset; 00355 static_cast<Splitter*>(parentWidget())->moveSplitter(sibling, pos); 00356 } 00357 } 00358 00359 00360 void SplitterHandle::mousePressEvent(QMouseEvent *e) 00361 { 00362 if ( e->button() & LeftButton ) 00363 offset = -e->pos().x(); 00364 } 00365 00366 00367 void SplitterHandle::paintEvent(QPaintEvent *) 00368 { 00369 QPainter p(this); 00370 style().drawPrimitive(QStyle::PE_Splitter, &p, QRect(0, 0, width(), height()), colorGroup(), QStyle::Style_Horizontal); 00371 } 00372 00373 #include "splitter.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 6 17:39:08 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003