00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
00093 if (childlist.count()) {
00094
00095
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
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 *)
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
00297
00298
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
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"