1 /* BEGIN_COMMON_COPYRIGHT_HEADER
2  * (c)LGPL2+
3  *
4  * LXQt - a lightweight, Qt based, desktop toolset
5  * https://lxqt.org
6  *
7  * Copyright: 2010-2011 Razor team
8  * Authors:
9  *   Alexander Sokoloff <sokoloff.a@gmail.com>
10  *
11  * This program or library is free software; you can redistribute it
12  * and/or modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20 
21  * You should have received a copy of the GNU Lesser General
22  * Public License along with this library; if not, write to the
23  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA 02110-1301 USA
25  *
26  * END_COMMON_COPYRIGHT_HEADER */
27 
28 
29 #include "lxqtpanellayout.h"
30 #include <QSize>
31 #include <QWidget>
32 #include <QEvent>
33 #include <QCursor>
34 #include <QApplication>
35 #include <QDebug>
36 #include <QPoint>
37 #include <QMouseEvent>
38 #include <QtAlgorithms>
39 #include <QPoint>
40 #include <QMouseEvent>
41 #include <QPropertyAnimation>
42 #include "plugin.h"
43 #include "lxqtpanellimits.h"
44 #include "ilxqtpanelplugin.h"
45 #include "lxqtpanel.h"
46 #include "pluginmoveprocessor.h"
47 #include <QToolButton>
48 #include <QStyle>
49 
50 #define ANIMATION_DURATION 250
51 
52 class ItemMoveAnimation : public QVariantAnimation
53 {
54 public:
ItemMoveAnimation(QLayoutItem * item)55     ItemMoveAnimation(QLayoutItem *item) :
56             mItem(item)
57     {
58         setEasingCurve(QEasingCurve::OutBack);
59         setDuration(ANIMATION_DURATION);
60     }
61 
updateCurrentValue(const QVariant & current)62     void updateCurrentValue(const QVariant &current) override
63     {
64         mItem->setGeometry(current.toRect());
65     }
66 
67 private:
68     QLayoutItem* mItem;
69 
70 };
71 
72 
73 struct LayoutItemInfo
74 {
75     LayoutItemInfo(QLayoutItem *layoutItem=nullptr);
76     QLayoutItem *item;
77     QRect geometry;
78     bool separate{false};
79     bool expandable{false};
80 };
81 
82 
LayoutItemInfo(QLayoutItem * layoutItem)83 LayoutItemInfo::LayoutItemInfo(QLayoutItem *layoutItem):
84     item(layoutItem)
85 {
86     if (!item)
87         return;
88 
89     Plugin *p = qobject_cast<Plugin*>(item->widget());
90     if (p)
91     {
92         separate = p->isSeparate();
93         expandable = p->isExpandable();
94         return;
95     }
96 }
97 
98 
99 
100 /************************************************
101   This is logical plugins grid, it's same for
102   horizontal and vertical panel. Plugins keeps as:
103 
104    <---LineCount-->
105    + ---+----+----+
106    | P1 | P2 | P3 |
107    +----+----+----+
108    | P4 | P5 |    |
109    +----+----+----+
110          ...
111    +----+----+----+
112    | PN |    |    |
113    +----+----+----+
114  ************************************************/
115 class LayoutItemGrid
116 {
117 public:
118     explicit LayoutItemGrid();
119     ~LayoutItemGrid();
120 
121     void addItem(QLayoutItem *item);
count() const122     int count() const { return mItems.count(); }
itemAt(int index) const123     QLayoutItem *itemAt(int index) const { return mItems[index]; }
124     QLayoutItem *takeAt(int index);
125 
126 
127     const LayoutItemInfo &itemInfo(int row, int col) const;
128     LayoutItemInfo &itemInfo(int row, int col);
129 
130     void update();
131 
lineSize() const132     int lineSize() const { return mLineSize; }
133     void setLineSize(int value);
134 
colCount() const135     int colCount() const { return mColCount; }
136     void setColCount(int value);
137 
usedColCount() const138     int usedColCount() const { return mUsedColCount; }
139 
rowCount() const140     int rowCount() const { return mRowCount; }
141 
invalidate()142     void invalidate() { mValid = false; }
isValid() const143     bool isValid() const { return mValid; }
144 
sizeHint() const145     QSize sizeHint() const { return mSizeHint; }
146 
horiz() const147     bool horiz() const { return mHoriz; }
148     void setHoriz(bool value);
149 
150     void clear();
151     void rebuild();
152 
isExpandable() const153     bool isExpandable() const { return mExpandable; }
expandableSize() const154     int expandableSize() const { return mExpandableSize; }
155 
156     void moveItem(int from, int to);
157 
158 private:
159     QVector<LayoutItemInfo> mInfoItems;
160     int mColCount;
161     int mUsedColCount;
162     int mRowCount;
163     bool mValid;
164     int mExpandableSize;
165     int mLineSize;
166 
167     QSize mSizeHint;
168     QSize mMinSize;
169     bool mHoriz;
170 
171     int mNextRow;
172     int mNextCol;
173     bool mExpandable;
174     QList<QLayoutItem*> mItems;
175 
176     void doAddToGrid(QLayoutItem *item);
177 };
178 
179 
180 /************************************************
181 
182  ************************************************/
LayoutItemGrid()183 LayoutItemGrid::LayoutItemGrid()
184 {
185     mLineSize = 0;
186     mHoriz = true;
187     clear();
188 }
189 
~LayoutItemGrid()190 LayoutItemGrid::~LayoutItemGrid()
191 {
192     qDeleteAll(mItems);
193 }
194 
195 
196 /************************************************
197 
198  ************************************************/
clear()199 void LayoutItemGrid::clear()
200 {
201     mRowCount = 0;
202     mNextRow = 0;
203     mNextCol = 0;
204     mInfoItems.resize(0);
205     mValid = false;
206     mExpandable = false;
207     mExpandableSize = 0;
208     mUsedColCount = 0;
209     mSizeHint = QSize(0,0);
210     mMinSize = QSize(0,0);
211 }
212 
213 
214 /************************************************
215 
216  ************************************************/
rebuild()217 void LayoutItemGrid::rebuild()
218 {
219     clear();
220 
221     for(QLayoutItem *item : qAsConst(mItems))
222     {
223         doAddToGrid(item);
224     }
225 }
226 
227 
228 /************************************************
229 
230  ************************************************/
addItem(QLayoutItem * item)231 void LayoutItemGrid::addItem(QLayoutItem *item)
232 {
233     doAddToGrid(item);
234     mItems.append(item);
235 }
236 
237 
238 /************************************************
239 
240  ************************************************/
doAddToGrid(QLayoutItem * item)241 void LayoutItemGrid::doAddToGrid(QLayoutItem *item)
242 {
243     LayoutItemInfo info(item);
244 
245     if (info.separate && mNextCol > 0)
246     {
247         mNextCol = 0;
248         mNextRow++;
249     }
250 
251     int cnt = (mNextRow + 1 ) * mColCount;
252     if (mInfoItems.count() <= cnt)
253         mInfoItems.resize(cnt);
254 
255     int idx = mNextRow * mColCount + mNextCol;
256     mInfoItems[idx] = info;
257     mUsedColCount = qMax(mUsedColCount, mNextCol + 1);
258     mExpandable = mExpandable || info.expandable;
259     mRowCount = qMax(mRowCount, mNextRow+1);
260 
261     if (info.separate || mNextCol >= mColCount-1)
262     {
263         mNextRow++;
264         mNextCol = 0;
265     }
266     else
267     {
268         mNextCol++;
269     }
270 
271     invalidate();
272 }
273 
274 
275 /************************************************
276 
277  ************************************************/
takeAt(int index)278 QLayoutItem *LayoutItemGrid::takeAt(int index)
279 {
280     QLayoutItem *item = mItems.takeAt(index);
281     rebuild();
282     return item;
283 }
284 
285 
286 /************************************************
287 
288  ************************************************/
moveItem(int from,int to)289 void LayoutItemGrid::moveItem(int from, int to)
290 {
291     mItems.move(from, to);
292     rebuild();
293 }
294 
295 
296 /************************************************
297 
298  ************************************************/
itemInfo(int row,int col) const299 const LayoutItemInfo &LayoutItemGrid::itemInfo(int row, int col) const
300 {
301     return mInfoItems[row * mColCount + col];
302 }
303 
304 
305 /************************************************
306 
307  ************************************************/
itemInfo(int row,int col)308 LayoutItemInfo &LayoutItemGrid::itemInfo(int row, int col)
309 {
310     return mInfoItems[row * mColCount + col];
311 }
312 
313 
314 /************************************************
315 
316  ************************************************/
update()317 void LayoutItemGrid::update()
318 {
319     mExpandableSize = 0;
320     mSizeHint = QSize(0,0);
321 
322     if (mHoriz)
323     {
324         mSizeHint.setHeight(mLineSize * mColCount);
325         int x = 0;
326         for (int r=0; r<mRowCount; ++r)
327         {
328             int y = 0;
329             int rw = 0;
330             for (int c=0; c<mColCount; ++c)
331             {
332                 LayoutItemInfo &info = itemInfo(r, c);
333                 if (!info.item)
334                     continue;
335 
336                 QSize sz = info.item->sizeHint();
337                 info.geometry = QRect(QPoint(x,y), sz);
338                 y += sz.height();
339                 rw = qMax(rw, sz.width());
340             }
341             x += rw;
342 
343             if (itemInfo(r, 0).expandable)
344                 mExpandableSize += rw;
345 
346             mSizeHint.setWidth(x);
347             mSizeHint.rheight() = qMax(mSizeHint.rheight(), y);
348         }
349     }
350     else
351     {
352         mSizeHint.setWidth(mLineSize * mColCount);
353         int y = 0;
354         for (int r=0; r<mRowCount; ++r)
355         {
356             int x = 0;
357             int rh = 0;
358             for (int c=0; c<mColCount; ++c)
359             {
360                 LayoutItemInfo &info = itemInfo(r, c);
361                 if (!info.item)
362                     continue;
363 
364                 QSize sz = info.item->sizeHint();
365                 info.geometry = QRect(QPoint(x,y), sz);
366                 x += sz.width();
367                 rh = qMax(rh, sz.height());
368             }
369             y += rh;
370 
371             if (itemInfo(r, 0).expandable)
372                 mExpandableSize += rh;
373 
374             mSizeHint.setHeight(y);
375             mSizeHint.rwidth() = qMax(mSizeHint.rwidth(), x);
376         }
377     }
378 
379     mValid = true;
380 }
381 
382 
383 /************************************************
384 
385  ************************************************/
setLineSize(int value)386 void LayoutItemGrid::setLineSize(int value)
387 {
388     mLineSize = qMax(1, value);
389     invalidate();
390 }
391 
392 
393 /************************************************
394 
395  ************************************************/
setColCount(int value)396 void LayoutItemGrid::setColCount(int value)
397 {
398     mColCount = qMax(1, value);
399     rebuild();
400 }
401 
402 /************************************************
403 
404  ************************************************/
setHoriz(bool value)405 void LayoutItemGrid::setHoriz(bool value)
406 {
407     mHoriz = value;
408     invalidate();
409 }
410 
411 
412 
413 /************************************************
414 
415  ************************************************/
LXQtPanelLayout(QWidget * parent)416 LXQtPanelLayout::LXQtPanelLayout(QWidget *parent) :
417     QLayout(parent),
418     mLeftGrid(new LayoutItemGrid()),
419     mRightGrid(new LayoutItemGrid()),
420     mPosition(ILXQtPanel::PositionBottom),
421     mAnimate(false)
422 {
423     setContentsMargins(0, 0, 0, 0);
424 }
425 
426 
427 /************************************************
428 
429  ************************************************/
~LXQtPanelLayout()430 LXQtPanelLayout::~LXQtPanelLayout()
431 {
432     delete mLeftGrid;
433     delete mRightGrid;
434 }
435 
436 
437 /************************************************
438 
439  ************************************************/
addItem(QLayoutItem * item)440 void LXQtPanelLayout::addItem(QLayoutItem *item)
441 {
442     LayoutItemGrid *grid = mRightGrid;
443 
444     Plugin *p = qobject_cast<Plugin*>(item->widget());
445     if (p && p->alignment() == Plugin::AlignLeft)
446         grid = mLeftGrid;
447 
448     grid->addItem(item);
449 }
450 
451 
452 /************************************************
453 
454  ************************************************/
globalIndexToLocal(int index,LayoutItemGrid ** grid,int * gridIndex)455 void LXQtPanelLayout::globalIndexToLocal(int index, LayoutItemGrid **grid, int *gridIndex)
456 {
457     if (index < mLeftGrid->count())
458     {
459         *grid = mLeftGrid;
460         *gridIndex = index;
461         return;
462     }
463 
464     *grid = mRightGrid;
465     *gridIndex = index - mLeftGrid->count();
466 }
467 
468 /************************************************
469 
470  ************************************************/
globalIndexToLocal(int index,LayoutItemGrid ** grid,int * gridIndex) const471 void LXQtPanelLayout::globalIndexToLocal(int index, LayoutItemGrid **grid, int *gridIndex) const
472 {
473     if (index < mLeftGrid->count())
474     {
475         *grid = mLeftGrid;
476         *gridIndex = index;
477         return;
478     }
479 
480     *grid = mRightGrid;
481     *gridIndex = index - mLeftGrid->count();
482 }
483 
484 
485 /************************************************
486 
487  ************************************************/
itemAt(int index) const488 QLayoutItem *LXQtPanelLayout::itemAt(int index) const
489 {
490     if (index < 0 || index >= count())
491         return nullptr;
492 
493     LayoutItemGrid *grid=nullptr;
494     int idx=0;
495     globalIndexToLocal(index, &grid, &idx);
496 
497     return grid->itemAt(idx);
498 }
499 
500 
501 /************************************************
502 
503  ************************************************/
takeAt(int index)504 QLayoutItem *LXQtPanelLayout::takeAt(int index)
505 {
506     if (index < 0 || index >= count())
507         return nullptr;
508 
509     LayoutItemGrid *grid=nullptr;
510     int idx=0;
511     globalIndexToLocal(index, &grid, &idx);
512 
513     return grid->takeAt(idx);
514 }
515 
516 
517 /************************************************
518 
519  ************************************************/
count() const520 int LXQtPanelLayout::count() const
521 {
522     return mLeftGrid->count() + mRightGrid->count();
523 }
524 
525 
526 /************************************************
527 
528  ************************************************/
moveItem(int from,int to,bool withAnimation)529 void LXQtPanelLayout::moveItem(int from, int to, bool withAnimation)
530 {
531     if (from != to)
532     {
533         LayoutItemGrid *fromGrid=nullptr;
534         int fromIdx=0;
535         globalIndexToLocal(from, &fromGrid, &fromIdx);
536 
537         LayoutItemGrid *toGrid=nullptr;
538         int toIdx=0;
539         globalIndexToLocal(to, &toGrid, &toIdx);
540 
541         if (fromGrid == toGrid)
542         {
543             fromGrid->moveItem(fromIdx, toIdx);
544         }
545         else
546         {
547             QLayoutItem *item = fromGrid->takeAt(fromIdx);
548             toGrid->addItem(item);
549             //recalculate position because we removed from one and put to another grid
550             LayoutItemGrid *toGridAux=nullptr;
551             globalIndexToLocal(to, &toGridAux, &toIdx);
552             Q_ASSERT(toGrid == toGridAux); //grid must be the same (if not something is wrong with our logic)
553             toGrid->moveItem(toGridAux->count()-1, toIdx);
554         }
555     }
556 
557     mAnimate = withAnimation;
558     invalidate();
559 }
560 
561 
562 /************************************************
563 
564  ************************************************/
sizeHint() const565 QSize LXQtPanelLayout::sizeHint() const
566 {
567     if (!mLeftGrid->isValid())
568         mLeftGrid->update();
569 
570     if (!mRightGrid->isValid())
571         mRightGrid->update();
572 
573     QSize ls = mLeftGrid->sizeHint();
574     QSize rs = mRightGrid->sizeHint();
575 
576     if (isHorizontal())
577     {
578         return QSize(ls.width() + rs.width(),
579                      qMax(ls.height(), rs.height()));
580     }
581     else
582     {
583         return QSize(qMax(ls.width(), rs.width()),
584                      ls.height() + rs.height());
585     }
586 }
587 
588 
589 /************************************************
590 
591  ************************************************/
setGeometry(const QRect & geometry)592 void LXQtPanelLayout::setGeometry(const QRect &geometry)
593 {
594     if (!mLeftGrid->isValid())
595         mLeftGrid->update();
596 
597     if (!mRightGrid->isValid())
598         mRightGrid->update();
599 
600     QRect my_geometry{geometry};
601     my_geometry -= contentsMargins();
602     if (count())
603     {
604         if (isHorizontal())
605             setGeometryHoriz(my_geometry);
606         else
607             setGeometryVert(my_geometry);
608     }
609 
610     mAnimate = false;
611     QLayout::setGeometry(my_geometry);
612 }
613 
614 
615 /************************************************
616 
617  ************************************************/
setItemGeometry(QLayoutItem * item,const QRect & geometry,bool withAnimation)618 void LXQtPanelLayout::setItemGeometry(QLayoutItem *item, const QRect &geometry, bool withAnimation)
619 {
620     Plugin *plugin = qobject_cast<Plugin*>(item->widget());
621     if (withAnimation && plugin)
622     {
623         ItemMoveAnimation* animation = new ItemMoveAnimation(item);
624         animation->setStartValue(item->geometry());
625         animation->setEndValue(geometry);
626         animation->start(animation->DeleteWhenStopped);
627     }
628     else
629     {
630         item->setGeometry(geometry);
631     }
632 }
633 
634 
635 /************************************************
636 
637  ************************************************/
setGeometryHoriz(const QRect & geometry)638 void LXQtPanelLayout::setGeometryHoriz(const QRect &geometry)
639 {
640     const bool visual_h_reversed = parentWidget() && parentWidget()->isRightToLeft();
641     // Calc expFactor for expandable plugins like TaskBar.
642     double expFactor;
643     {
644         int expWidth = mLeftGrid->expandableSize() + mRightGrid->expandableSize();
645         int nonExpWidth = mLeftGrid->sizeHint().width()  - mLeftGrid->expandableSize() +
646                       mRightGrid->sizeHint().width() - mRightGrid->expandableSize();
647         expFactor = expWidth ? ((1.0 * geometry.width() - nonExpWidth) / expWidth) : 1;
648     }
649 
650     // Calc baselines for plugins like button.
651     QVector<int> baseLines(qMax(mLeftGrid->colCount(), mRightGrid->colCount()));
652     const int bh = geometry.height() / baseLines.count();
653     const int base_center = bh >> 1;
654     const int height_remain = 0 < bh ? geometry.height() % baseLines.size() : 0;
655     {
656         int base = geometry.top();
657         for (auto i = baseLines.begin(), i_e = baseLines.end(); i_e != i; ++i, base += bh)
658         {
659             *i = base;
660         }
661     }
662 
663 #if 0
664     qDebug() << "** LXQtPanelLayout::setGeometryHoriz **************";
665     qDebug() << "geometry: " << geometry;
666 
667     qDebug() << "Left grid";
668     qDebug() << "  cols:" << mLeftGrid->colCount() << " rows:" << mLeftGrid->rowCount();
669     qDebug() << "  usedCols" << mLeftGrid->usedColCount();
670 
671     qDebug() << "Right grid";
672     qDebug() << "  cols:" << mRightGrid->colCount() << " rows:" << mRightGrid->rowCount();
673     qDebug() << "  usedCols" << mRightGrid->usedColCount();
674 #endif
675 
676 
677     // Left aligned plugins.
678     int left=geometry.left();
679     for (int r=0; r<mLeftGrid->rowCount(); ++r)
680     {
681         int rw = 0;
682         int remain = height_remain;
683         for (int c=0; c<mLeftGrid->usedColCount(); ++c)
684         {
685             const LayoutItemInfo &info = mLeftGrid->itemInfo(r, c);
686             if (info.item)
687             {
688                 QRect rect;
689                 if (info.separate)
690                 {
691                     rect.setLeft(left);
692                     rect.setTop(geometry.top());
693                     rect.setHeight(geometry.height());
694 
695                     if (info.expandable)
696                         rect.setWidth(info.geometry.width() * expFactor);
697                     else
698                         rect.setWidth(info.geometry.width());
699                 }
700                 else
701                 {
702                     int height = bh + (0 < remain-- ? 1 : 0);
703                     if (!info.item->expandingDirections().testFlag(Qt::Orientation::Vertical))
704                         height = qMin(info.geometry.height(), height);
705                     height = qMin(geometry.height(), height);
706                     rect.setHeight(height);
707                     rect.setWidth(qMin(info.geometry.width(), geometry.width()));
708                     if (height < bh)
709                         rect.moveCenter(QPoint(0, baseLines[c] + base_center));
710                     else
711                         rect.moveTop(baseLines[c]);
712                     rect.moveLeft(left);
713                 }
714 
715                 rw = qMax(rw, rect.width());
716                 if (visual_h_reversed)
717                     rect.moveLeft(geometry.left() + geometry.right() - rect.x() - rect.width() + 1);
718                 setItemGeometry(info.item, rect, mAnimate);
719             }
720         }
721         left += rw;
722     }
723 
724     // Right aligned plugins.
725     int right=geometry.right();
726     for (int r=mRightGrid->rowCount()-1; r>=0; --r)
727     {
728         int rw = 0;
729         int remain = height_remain;
730         for (int c=0; c<mRightGrid->usedColCount(); ++c)
731         {
732             const LayoutItemInfo &info = mRightGrid->itemInfo(r, c);
733             if (info.item)
734             {
735                 QRect rect;
736                 if (info.separate)
737                 {
738                     rect.setTop(geometry.top());
739                     rect.setHeight(geometry.height());
740 
741                     if (info.expandable)
742                         rect.setWidth(info.geometry.width() * expFactor);
743                     else
744                         rect.setWidth(info.geometry.width());
745 
746                     rect.moveRight(right);
747                 }
748                 else
749                 {
750                     int height = bh + (0 < remain-- ? 1 : 0);
751                     if (!info.item->expandingDirections().testFlag(Qt::Orientation::Vertical))
752                         height = qMin(info.geometry.height(), height);
753                     height = qMin(geometry.height(), height);
754                     rect.setHeight(height);
755                     rect.setWidth(qMin(info.geometry.width(), geometry.width()));
756                     if (height < bh)
757                         rect.moveCenter(QPoint(0, baseLines[c] + base_center));
758                     else
759                         rect.moveTop(baseLines[c]);
760                     rect.moveRight(right);
761                 }
762 
763                 rw = qMax(rw, rect.width());
764                 if (visual_h_reversed)
765                     rect.moveLeft(geometry.left() + geometry.right() - rect.x() - rect.width() + 1);
766                 setItemGeometry(info.item, rect, mAnimate);
767             }
768         }
769         right -= rw;
770     }
771 }
772 
773 
774 /************************************************
775 
776  ************************************************/
setGeometryVert(const QRect & geometry)777 void LXQtPanelLayout::setGeometryVert(const QRect &geometry)
778 {
779     const bool visual_h_reversed = parentWidget() && parentWidget()->isRightToLeft();
780     // Calc expFactor for expandable plugins like TaskBar.
781     double expFactor;
782     {
783         int expHeight = mLeftGrid->expandableSize() + mRightGrid->expandableSize();
784         int nonExpHeight = mLeftGrid->sizeHint().height()  - mLeftGrid->expandableSize() +
785                            mRightGrid->sizeHint().height() - mRightGrid->expandableSize();
786         expFactor = expHeight ? ((1.0 * geometry.height() - nonExpHeight) / expHeight) : 1;
787     }
788 
789     // Calc baselines for plugins like button.
790     QVector<int> baseLines(qMax(mLeftGrid->colCount(), mRightGrid->colCount()));
791     const int bw = geometry.width() / baseLines.count();
792     const int base_center = bw >> 1;
793     const int width_remain = 0 < bw ? geometry.width() % baseLines.size() : 0;
794     {
795         int base = geometry.left();
796         for (auto i = baseLines.begin(), i_e = baseLines.end(); i_e != i; ++i, base += bw)
797         {
798             *i = base;
799         }
800     }
801 
802 #if 0
803     qDebug() << "** LXQtPanelLayout::setGeometryVert **************";
804     qDebug() << "geometry: " << geometry;
805 
806     qDebug() << "Left grid";
807     qDebug() << "  cols:" << mLeftGrid->colCount() << " rows:" << mLeftGrid->rowCount();
808     qDebug() << "  usedCols" << mLeftGrid->usedColCount();
809 
810     qDebug() << "Right grid";
811     qDebug() << "  cols:" << mRightGrid->colCount() << " rows:" << mRightGrid->rowCount();
812     qDebug() << "  usedCols" << mRightGrid->usedColCount();
813 #endif
814 
815     // Top aligned plugins.
816     int top=geometry.top();
817     for (int r=0; r<mLeftGrid->rowCount(); ++r)
818     {
819         int rh = 0;
820         int remain = width_remain;
821         for (int c=0; c<mLeftGrid->usedColCount(); ++c)
822         {
823             const LayoutItemInfo &info = mLeftGrid->itemInfo(r, c);
824             if (info.item)
825             {
826                 QRect rect;
827                 if (info.separate)
828                 {
829                     rect.moveTop(top);
830                     rect.setLeft(geometry.left());
831                     rect.setWidth(geometry.width());
832 
833                     if (info.expandable)
834                         rect.setHeight(info.geometry.height() * expFactor);
835                     else
836                         rect.setHeight(info.geometry.height());
837                 }
838                 else
839                 {
840                     rect.setHeight(qMin(info.geometry.height(), geometry.height()));
841                     int width = bw + (0 < remain-- ? 1 : 0);
842                     if (!info.item->expandingDirections().testFlag(Qt::Orientation::Horizontal))
843                         width = qMin(info.geometry.width(), width);
844                     width = qMin(geometry.width(), width);
845                     rect.setWidth(width);
846                     if (width < bw)
847                         rect.moveCenter(QPoint(baseLines[c] + base_center, 0));
848                     else
849                         rect.moveLeft(baseLines[c]);
850                     rect.moveTop(top);
851                 }
852 
853                 rh = qMax(rh, rect.height());
854                 if (visual_h_reversed)
855                     rect.moveLeft(geometry.left() + geometry.right() - rect.x() - rect.width() + 1);
856                 setItemGeometry(info.item, rect, mAnimate);
857             }
858         }
859         top += rh;
860     }
861 
862 
863     // Bottom aligned plugins.
864     int bottom=geometry.bottom();
865     for (int r=mRightGrid->rowCount()-1; r>=0; --r)
866     {
867         int rh = 0;
868         int remain = width_remain;
869         for (int c=0; c<mRightGrid->usedColCount(); ++c)
870         {
871             const LayoutItemInfo &info = mRightGrid->itemInfo(r, c);
872             if (info.item)
873             {
874                 QRect rect;
875                 if (info.separate)
876                 {
877                     rect.setLeft(geometry.left());
878                     rect.setWidth(geometry.width());
879 
880                     if (info.expandable)
881                         rect.setHeight(info.geometry.height() * expFactor);
882                     else
883                         rect.setHeight(info.geometry.height());
884                     rect.moveBottom(bottom);
885                 }
886                 else
887                 {
888                     rect.setHeight(qMin(info.geometry.height(), geometry.height()));
889                     int width = bw + (0 < remain-- ? 1 : 0);
890                     if (!info.item->expandingDirections().testFlag(Qt::Orientation::Horizontal))
891                         width = qMin(info.geometry.width(), width);
892                     width = qMin(geometry.width(), width);
893                     rect.setWidth(width);
894                     if (width < bw)
895                         rect.moveCenter(QPoint(baseLines[c] + base_center, 0));
896                     else
897                         rect.moveLeft(baseLines[c]);
898                     rect.moveBottom(bottom);
899                 }
900 
901                 rh = qMax(rh, rect.height());
902                 if (visual_h_reversed)
903                     rect.moveLeft(geometry.left() + geometry.right() - rect.x() - rect.width() + 1);
904                 setItemGeometry(info.item, rect, mAnimate);
905             }
906         }
907         bottom -= rh;
908     }
909 }
910 
911 
912 /************************************************
913 
914  ************************************************/
invalidate()915 void LXQtPanelLayout::invalidate()
916 {
917     mLeftGrid->invalidate();
918     mRightGrid->invalidate();
919     mMinPluginSize = QSize();
920     QLayout::invalidate();
921 }
922 
923 
924 /************************************************
925 
926  ************************************************/
lineCount() const927 int LXQtPanelLayout::lineCount() const
928 {
929     return mLeftGrid->colCount();
930 }
931 
932 
933 /************************************************
934 
935  ************************************************/
setLineCount(int value)936 void LXQtPanelLayout::setLineCount(int value)
937 {
938     mLeftGrid->setColCount(value);
939     mRightGrid->setColCount(value);
940     invalidate();
941 }
942 
943 
944 /************************************************
945 
946  ************************************************/
rebuild()947 void LXQtPanelLayout::rebuild()
948 {
949     mLeftGrid->rebuild();
950     mRightGrid->rebuild();
951 }
952 
953 
954 /************************************************
955 
956  ************************************************/
lineSize() const957 int LXQtPanelLayout::lineSize() const
958 {
959     return mLeftGrid->lineSize();
960 }
961 
962 
963 /************************************************
964 
965  ************************************************/
setLineSize(int value)966 void LXQtPanelLayout::setLineSize(int value)
967 {
968     mLeftGrid->setLineSize(value);
969     mRightGrid->setLineSize(value);
970     invalidate();
971 }
972 
973 
974 /************************************************
975 
976  ************************************************/
setPosition(ILXQtPanel::Position value)977 void LXQtPanelLayout::setPosition(ILXQtPanel::Position value)
978 {
979     mPosition = value;
980     mLeftGrid->setHoriz(isHorizontal());
981     mRightGrid->setHoriz(isHorizontal());
982 }
983 
984 
985 /************************************************
986 
987  ************************************************/
isHorizontal() const988 bool LXQtPanelLayout::isHorizontal() const
989 {
990     return mPosition == ILXQtPanel::PositionTop ||
991             mPosition == ILXQtPanel::PositionBottom;
992 }
993 
994 
995 /************************************************
996 
997  ************************************************/
itemIsSeparate(QLayoutItem * item)998 bool LXQtPanelLayout::itemIsSeparate(QLayoutItem *item)
999 {
1000     if (!item)
1001         return true;
1002 
1003     Plugin *p = qobject_cast<Plugin*>(item->widget());
1004     if (!p)
1005         return true;
1006 
1007     return p->isSeparate();
1008 }
1009 
1010 
1011 /************************************************
1012 
1013  ************************************************/
startMovePlugin()1014 void LXQtPanelLayout::startMovePlugin()
1015 {
1016     Plugin *plugin = qobject_cast<Plugin*>(sender());
1017     if (plugin)
1018     {
1019         // We have not memoryleaks there.
1020         // The processor will be automatically deleted when stopped.
1021         PluginMoveProcessor *moveProcessor = new PluginMoveProcessor(this, plugin);
1022         moveProcessor->start();
1023         connect(moveProcessor, &PluginMoveProcessor::finished, this, &LXQtPanelLayout::finishMovePlugin);
1024     }
1025 }
1026 
1027 
1028 /************************************************
1029 
1030  ************************************************/
finishMovePlugin()1031 void LXQtPanelLayout::finishMovePlugin()
1032 {
1033     PluginMoveProcessor *moveProcessor = qobject_cast<PluginMoveProcessor*>(sender());
1034     if (moveProcessor)
1035     {
1036         Plugin *plugin = moveProcessor->plugin();
1037         int n = indexOf(plugin);
1038         plugin->setAlignment(n<mLeftGrid->count() ? Plugin::AlignLeft : Plugin::AlignRight);
1039         emit pluginMoved(plugin);
1040     }
1041 }
1042 
1043 /************************************************
1044 
1045  ************************************************/
moveUpPlugin(Plugin * plugin)1046 void LXQtPanelLayout::moveUpPlugin(Plugin * plugin)
1047 {
1048     const int i = indexOf(plugin);
1049     if (0 < i)
1050         moveItem(i, i - 1, true);
1051 }
1052 
1053 /************************************************
1054 
1055  ************************************************/
addPlugin(Plugin * plugin)1056 void LXQtPanelLayout::addPlugin(Plugin * plugin)
1057 {
1058     connect(plugin, &Plugin::startMove, this, &LXQtPanelLayout::startMovePlugin);
1059 
1060     const int prev_count = count();
1061     addWidget(plugin);
1062 
1063     //check actual position
1064     const int pos = indexOf(plugin);
1065     if (prev_count > pos)
1066         moveItem(pos, prev_count, false);
1067 }
1068