1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22 #include "precompiled_sfx2.hxx"
23 #include "sfx2/sidebar/GridLayouter.hxx"
24
25 #include <vcl/window.hxx>
26
27 namespace sfx2 { namespace sidebar {
28
29 typedef std::vector<CellDescriptor> CellData;
30 typedef std::vector<CellData> ColumnData;
31
32 class GridLayouter::Implementation
33 {
34 public:
35 Implementation (Window& rParent);
36 ~Implementation (void);
37
38 CellDescriptor& GetCell (
39 const sal_Int32 nRow,
40 const sal_Int32 nColumn,
41 const sal_Int32 nVariant);
42
43 void Layout (void);
44 void LayoutColumn(
45 ColumnData& rColumn,
46 const sal_Int32 nX,
47 const sal_Int32 nColumnIndex);
48
49 void DistributeWidth (const sal_Int32 nTotalWidth);
50 sal_Int32 GetMinimumColumnWidth (
51 ColumnData& rColumn,
52 const ColumnDescriptor& rDescriptor) const;
53
54 void Paint (void);
55
56 Window& mrParent;
57 ::std::vector<ColumnData> maColumns;
58 ::std::vector<ColumnDescriptor> maColumnDescriptors;
59 };
60
61 #define ForAllColumnDescriptors(I) \
62 for (::std::vector<ColumnDescriptor>::iterator \
63 I(maColumnDescriptors.begin()), \
64 iEnd(maColumnDescriptors.end()); \
65 I!=iEnd; \
66 ++I)
67
68 #define ForAllColumns(I,N) \
69 sal_Int32 N (0); \
70 for (::std::vector<ColumnData>::iterator \
71 I(maColumns.begin()), \
72 iEnd(maColumns.end()); \
73 I!=iEnd; \
74 ++I,++N)
75
76 #define ForAllRows(ColumnData,I) \
77 for (std::vector<CellData>::iterator \
78 I((ColumnData).begin()), \
79 iRowEnd((ColumnData).end()); \
80 I!=iRowEnd; \
81 ++I)
82
83 #define ForAllCells(CellData,I) \
84 for (::std::vector<CellDescriptor>::iterator \
85 I((CellData).begin()), \
86 iCellEnd((CellData).end()); \
87 I!=iCellEnd; \
88 ++I)
89
90
91 //===== GridLayouter ==========================================================
92
GridLayouter(Window & rParent)93 GridLayouter::GridLayouter (Window& rParent)
94 : mpImplementation(new Implementation(rParent))
95 {
96 }
97
98
99
100
~GridLayouter(void)101 GridLayouter::~GridLayouter (void)
102 {
103 }
104
105
106
107
GetCell(const sal_Int32 nRow,const sal_Int32 nColumn,const sal_Int32 nVariant)108 CellDescriptor& GridLayouter::GetCell (
109 const sal_Int32 nRow,
110 const sal_Int32 nColumn,
111 const sal_Int32 nVariant)
112 {
113 return mpImplementation->GetCell(nRow, nColumn, nVariant);
114 }
115
116
117
118
GetColumn(const sal_Int32 nColumn)119 ColumnDescriptor& GridLayouter::GetColumn (
120 const sal_Int32 nColumn)
121 {
122 // Make sure that the specified column exists.
123 mpImplementation->GetCell(0, nColumn, 0);
124 return mpImplementation->maColumnDescriptors[nColumn];
125 }
126
127
128
129
Layout(void)130 void GridLayouter::Layout (void)
131 {
132 mpImplementation->Layout();
133 }
134
135
136
137
Paint(const Rectangle & rBox)138 void GridLayouter::Paint (const Rectangle& rBox)
139 {
140 (void)rBox;
141
142 mpImplementation->Paint();
143 }
144
145
146
147
148 //===== CellDescriptor ========================================================
149
CellDescriptor(void)150 CellDescriptor::CellDescriptor (void)
151 : mpControl(NULL),
152 mnGridWidth(1),
153 mnMinimumWidth(-1),
154 mnMaximumWidth(-1),
155 mnOffset(0)
156 {
157 }
158
159
160
161
~CellDescriptor(void)162 CellDescriptor::~CellDescriptor (void)
163 {
164 }
165
166
167
168
SetGridWidth(const sal_Int32 nColumnCount)169 CellDescriptor& CellDescriptor::SetGridWidth (const sal_Int32 nColumnCount)
170 {
171 mnGridWidth = nColumnCount;
172 return *this;
173 }
174
175
176
177
SetControl(Window & rControl)178 CellDescriptor& CellDescriptor::SetControl (Window& rControl)
179 {
180 mpControl = &rControl;
181 return *this;
182 }
183
184
185
186
SetFixedWidth(const sal_Int32 nWidth)187 CellDescriptor& CellDescriptor::SetFixedWidth (const sal_Int32 nWidth)
188 {
189 mnMinimumWidth = nWidth;
190 mnMaximumWidth = nWidth;
191 return *this;
192 }
193
194
195
SetOffset(const sal_Int32 nOffset)196 CellDescriptor& CellDescriptor::SetOffset (const sal_Int32 nOffset)
197 {
198 mnOffset = nOffset;
199 return *this;
200 }
201
202
203
204
SetFixedWidth(void)205 CellDescriptor& CellDescriptor::SetFixedWidth (void)
206 {
207 sal_Int32 nMaxControlWidth (0);
208 if (mpControl != NULL)
209 {
210 const sal_Int32 nControlWidth (mpControl->GetSizePixel().Width());
211 if (nControlWidth > nMaxControlWidth)
212 nMaxControlWidth = nControlWidth;
213 }
214 mnMinimumWidth = nMaxControlWidth;
215 mnMaximumWidth = nMaxControlWidth;
216
217 return *this;
218 }
219
220
221
222
SetMinimumWidth(const sal_Int32 nWidth)223 CellDescriptor& CellDescriptor::SetMinimumWidth (const sal_Int32 nWidth)
224 {
225 mnMinimumWidth = nWidth;
226 return *this;
227 }
228
229
230
GetGridWidth(void) const231 sal_Int32 CellDescriptor::GetGridWidth (void) const
232 {
233 return mnGridWidth;
234 }
235
236
237
238
GetControl(void) const239 Window* CellDescriptor::GetControl (void) const
240 {
241 return mpControl;
242 }
243
244
245
246
GetMinimumWidth(void) const247 sal_Int32 CellDescriptor::GetMinimumWidth (void) const
248 {
249 return mnMinimumWidth + mnOffset;
250 }
251
252
253
254
GetMaximumWidth(void) const255 sal_Int32 CellDescriptor::GetMaximumWidth (void) const
256 {
257 return mnMaximumWidth;
258 }
259
260
261
GetOffset(void) const262 sal_Int32 CellDescriptor::GetOffset (void) const
263 {
264 return mnOffset;
265 }
266
267
268
269
270 //===== GridLayouter::Implementation ==========================================
271
Implementation(Window & rParent)272 GridLayouter::Implementation::Implementation (Window& rParent)
273 : mrParent(rParent),
274 maColumns(),
275 maColumnDescriptors()
276 {
277 }
278
279
280
281
~Implementation(void)282 GridLayouter::Implementation::~Implementation (void)
283 {
284 }
285
286
287
288
GetCell(const sal_Int32 nRow,const sal_Int32 nColumn,const sal_Int32 nVariant)289 CellDescriptor& GridLayouter::Implementation::GetCell (
290 const sal_Int32 nRow,
291 const sal_Int32 nColumn,
292 const sal_Int32 nVariant)
293 {
294 if (nColumn<0 || nRow<0 || nVariant<0)
295 {
296 OSL_ASSERT(nColumn>=0);
297 OSL_ASSERT(nRow>=0);
298 OSL_ASSERT(nVariant>=0);
299 return GetCell(0,0,0);
300 }
301
302 // Provide missing columns.
303 if (maColumns.size() <= static_cast<size_t>(nColumn))
304 {
305 maColumns.resize(nColumn+1);
306 maColumnDescriptors.resize(nColumn+1);
307 }
308
309 // Provide missing rows.
310 ColumnData& rColumn (maColumns[nColumn]);
311 if (rColumn.size() <= static_cast<size_t>(nRow))
312 rColumn.resize(nRow+1);
313
314 // Provide missing variants.
315 CellData& rCellData (rColumn[nRow]);
316 if (rCellData.size() <= static_cast<size_t>(nVariant))
317 rCellData.resize(nVariant+1);
318
319 return rCellData[nVariant];
320 }
321
322
323
324
Layout(void)325 void GridLayouter::Implementation::Layout (void)
326 {
327 if (maColumns.empty())
328 {
329 // There are no columns and therefore no controls => nothing
330 // to do.
331 return;
332 }
333
334 const Size aParentSize (mrParent.GetSizePixel());
335
336 // Determine the total column weight.
337 sal_Int32 nTotalColumnWeight (0);
338 ForAllColumnDescriptors(iDescriptor)
339 nTotalColumnWeight += iDescriptor->GetWeight();
340 if (nTotalColumnWeight <= 0)
341 {
342 OSL_ASSERT(nTotalColumnWeight>0);
343 return;
344 }
345
346 // Distribute the width of the parent window to the columns.
347 DistributeWidth(aParentSize.Width());
348
349 // Set the new positions and widths.
350 sal_Int32 nX (0);
351 ForAllColumns(iColumn,nColumnIndex)
352 {
353 LayoutColumn(
354 *iColumn,
355 nX,
356 nColumnIndex);
357
358 nX += maColumnDescriptors[nColumnIndex].GetWidth();
359 }
360 }
361
362
363
364
LayoutColumn(ColumnData & rColumn,const sal_Int32 nX,const sal_Int32 nColumnIndex)365 void GridLayouter::Implementation::LayoutColumn(
366 ColumnData& rColumn,
367 const sal_Int32 nX,
368 const sal_Int32 nColumnIndex)
369 {
370 ColumnDescriptor& rDescriptor (maColumnDescriptors[nColumnIndex]);
371 const sal_Int32 nLeft (nX + rDescriptor.GetLeftPadding());
372 const sal_Int32 nWidth (rDescriptor.GetWidth() - rDescriptor.GetLeftPadding() - rDescriptor.GetRightPadding());
373
374 sal_Int32 nRow (-1);
375 ForAllRows(rColumn, iCell)
376 {
377 ++nRow;
378
379 ForAllCells(*iCell, iCellDescriptor)
380 {
381 Window* pControl = iCellDescriptor->GetControl();
382 if (pControl==NULL || ! pControl->IsVisible())
383 continue;
384
385 sal_Int32 nCellWidth (nWidth);
386 const sal_Int32 nGridWidth (iCellDescriptor->GetGridWidth());
387 if (nGridWidth < 0)
388 continue;
389 else if (nGridWidth > 1)
390 {
391 // Cell spans more than one column. Sum all their
392 // widths.
393 for (sal_Int32 nOffset=1;
394 nOffset<nGridWidth && static_cast<size_t>(nColumnIndex+nOffset)<maColumnDescriptors.size();
395 ++nOffset)
396 {
397 nCellWidth += maColumnDescriptors[nColumnIndex+nOffset].GetWidth();
398 }
399 nCellWidth -= maColumnDescriptors[nColumnIndex+nGridWidth-1].GetRightPadding();
400 }
401
402 // Check width against valid range of cell.
403 if (iCellDescriptor->GetMinimumWidth() > 0)
404 if (nCellWidth < iCellDescriptor->GetMinimumWidth())
405 nCellWidth = iCellDescriptor->GetMinimumWidth();
406 if (iCellDescriptor->GetMaximumWidth() > 0)
407 if (nCellWidth > iCellDescriptor->GetMaximumWidth())
408 nCellWidth = iCellDescriptor->GetMaximumWidth();
409
410 pControl->SetPosSizePixel(
411 nLeft + iCellDescriptor->GetOffset(),
412 0,
413 nCellWidth,
414 0,
415 WINDOW_POSSIZE_X | WINDOW_POSSIZE_WIDTH);
416 }
417 }
418 }
419
420
421
422
DistributeWidth(const sal_Int32 nTotalWidth)423 void GridLayouter::Implementation::DistributeWidth (const sal_Int32 nTotalWidth)
424 {
425 // Prepare width distribution:
426 // a) Setup minimum widths for all columns.
427 // b) Sum up the width of columns that have zero weight.
428 // c) Sum up the non-zero weights.
429 sal_Int32 nZeroWeightWidth (0);
430 sal_Int32 nTotalColumnWeight (0);
431 for (sal_uInt32 nColumn=0; nColumn<maColumns.size(); ++nColumn)
432 {
433 ColumnDescriptor& rDescriptor (maColumnDescriptors[nColumn]);
434 ColumnData& rColumn (maColumns[nColumn]);
435
436 const sal_Int32 nWidth (GetMinimumColumnWidth(rColumn, rDescriptor));
437
438 rDescriptor.SetWidth(nWidth);
439
440 if (rDescriptor.GetWeight() <= 0)
441 nZeroWeightWidth += nWidth;
442 else
443 nTotalColumnWeight += rDescriptor.GetWeight();
444 }
445
446 sal_Int32 nRemainingWidth (nTotalWidth - nZeroWeightWidth);
447 if (nRemainingWidth < 0)
448 nRemainingWidth = 0;
449
450
451 // Distribute the remaining width between columns that have
452 // non-zero width.
453 const sal_Int32 nDistributableWidth (nRemainingWidth);
454 for (sal_uInt32 nColumn=0; nColumn<maColumns.size(); ++nColumn)
455 {
456 ColumnDescriptor& rDescriptor (maColumnDescriptors[nColumn]);
457
458 if (rDescriptor.GetWeight() > 0)
459 {
460 sal_Int32 nWidth (nDistributableWidth * rDescriptor.GetWeight() / nTotalColumnWeight);
461 // Make sure the width lies inside the valid range of
462 // column widths.
463 if (nWidth < rDescriptor.GetWidth())
464 nWidth = rDescriptor.GetWidth();
465 if (rDescriptor.GetMaximumWidth()>0)
466 if (nWidth > rDescriptor.GetTotalMaximumWidth())
467 nWidth = rDescriptor.GetTotalMaximumWidth();
468
469 rDescriptor.SetWidth(nWidth);
470 nRemainingWidth -= nWidth;
471 }
472 }
473
474 // If there are some pixels left (due to rounding errors), then
475 // give them to the first column that has non-zero weight.
476 if (nRemainingWidth > 0)
477 for (sal_uInt32 nColumn=0; nColumn<maColumns.size(); ++nColumn)
478 {
479 ColumnDescriptor& rDescriptor (maColumnDescriptors[nColumn]);
480 if (rDescriptor.GetWeight() > 0)
481 {
482 rDescriptor.SetWidth(rDescriptor.GetWidth() + nRemainingWidth);
483 break;
484 }
485 }
486 }
487
488
489
490
GetMinimumColumnWidth(ColumnData & rColumn,const ColumnDescriptor & rDescriptor) const491 sal_Int32 GridLayouter::Implementation::GetMinimumColumnWidth (
492 ColumnData& rColumn,
493 const ColumnDescriptor& rDescriptor) const
494 {
495 // Start with the minimum width of the whole column.
496 sal_Int32 nMinimumWidth (rDescriptor.GetMinimumWidth());
497
498 // Take also into account the minimum widths of all cells in the column.
499 ForAllRows(rColumn, iCell)
500 ForAllCells(*iCell, iCellDescriptor)
501 {
502 if (iCellDescriptor->GetGridWidth() != 1)
503 continue;
504 const sal_Int32 nMinimumCellWidth (iCellDescriptor->GetMinimumWidth());
505 if (nMinimumCellWidth > nMinimumWidth)
506 nMinimumWidth = nMinimumCellWidth;
507 }
508
509 // Make sure that the minimum width does not become larger than
510 // the maximum width of the column.
511 if (nMinimumWidth > rDescriptor.GetMaximumWidth() && rDescriptor.GetMaximumWidth()>0)
512 nMinimumWidth = rDescriptor.GetMaximumWidth();
513
514 // Add the horizontal padding.
515 return nMinimumWidth
516 + rDescriptor.GetLeftPadding()
517 + rDescriptor.GetRightPadding();
518 }
519
520
521
522
Paint(void)523 void GridLayouter::Implementation::Paint (void)
524 {
525 const Size aParentSize (mrParent.GetSizePixel());
526
527 static const Color aSeparatorColor (0x66cdaa);
528 static const Color aLeftPaddingColor (0x98fb98);
529 static const Color aRightPaddingColor (0xff69b4);
530 static const Color aControlOverlayColor (0xffff00);
531
532 sal_Int32 nX (0);
533 mrParent.SetLineColor();
534 mrParent.SetFillColor(aLeftPaddingColor);
535 ForAllColumnDescriptors(iColumn)
536 {
537 if (iColumn->GetLeftPadding() > 0)
538 {
539 mrParent.DrawRect(Rectangle(
540 nX,0,
541 nX+iColumn->GetLeftPadding(),aParentSize.Height()));
542 }
543
544 nX += iColumn->GetWidth();
545 }
546
547 nX = 0;
548 mrParent.SetFillColor(aRightPaddingColor);
549 ForAllColumnDescriptors(iColumn)
550 {
551 if (iColumn->GetRightPadding() > 0)
552 {
553 const sal_Int32 nRight (nX + iColumn->GetWidth());
554 const sal_Int32 nLeft (nRight - iColumn->GetRightPadding());
555 mrParent.DrawRect(Rectangle(
556 nLeft,0,
557 nRight,aParentSize.Height()));
558 }
559
560 nX += iColumn->GetWidth();
561 }
562
563 nX = 0;
564 mrParent.SetFillColor();
565 mrParent.SetLineColor(aSeparatorColor);
566 ForAllColumnDescriptors(iColumn)
567 {
568 mrParent.DrawLine(Point(nX,0), Point(nX,aParentSize.Height()));
569 nX += iColumn->GetWidth();
570 }
571
572 mrParent.SetFillColor();
573 mrParent.SetLineColor(aControlOverlayColor);
574 ForAllColumns(iColumn,nColumnIndex)
575 ForAllRows(*iColumn, iCell)
576 ForAllCells(*iCell, iCellDescriptor)
577 {
578 Window* pControl (iCellDescriptor->GetControl());
579 if (pControl!=NULL && pControl->IsVisible())
580 {
581 Rectangle aBox (
582 pControl->GetPosPixel(),
583 pControl->GetSizePixel());
584 --aBox.Left();
585 --aBox.Top();
586 ++aBox.Right();
587 ++aBox.Bottom();
588 mrParent.DrawRect(aBox);
589 }
590 }
591 }
592
593
594
595
596 //===== ColumnDescriptor ======================================================
597
ColumnDescriptor(void)598 ColumnDescriptor::ColumnDescriptor (void)
599 : mnWeight(1),
600 mnMinimumWidth(0),
601 mnMaximumWidth(-1),
602 mnLeftPadding(0),
603 mnRightPadding(0),
604 mnWidth(0)
605 {
606 }
607
608
609
610
~ColumnDescriptor(void)611 ColumnDescriptor::~ColumnDescriptor (void)
612 {
613 }
614
615
616
617
SetWeight(const sal_Int32 nWeight)618 ColumnDescriptor& ColumnDescriptor::SetWeight (const sal_Int32 nWeight)
619 {
620 mnWeight = nWeight;
621
622 return *this;
623 }
624
625
626
627
SetMinimumWidth(const sal_Int32 nWidth)628 ColumnDescriptor& ColumnDescriptor::SetMinimumWidth (const sal_Int32 nWidth)
629 {
630 mnMinimumWidth = nWidth;
631
632 return *this;
633 }
634
635
636
SetFixedWidth(const sal_Int32 nWidth)637 ColumnDescriptor& ColumnDescriptor::SetFixedWidth (const sal_Int32 nWidth)
638 {
639 mnMinimumWidth = nWidth;
640 mnMaximumWidth = nWidth;
641
642 return *this;
643 }
644
645
646
SetLeftPadding(const sal_Int32 nPadding)647 ColumnDescriptor& ColumnDescriptor::SetLeftPadding (const sal_Int32 nPadding)
648 {
649 mnLeftPadding = nPadding;
650
651 return *this;
652 }
653
654
655
656
SetRightPadding(const sal_Int32 nPadding)657 ColumnDescriptor& ColumnDescriptor::SetRightPadding (const sal_Int32 nPadding)
658 {
659 mnRightPadding = nPadding;
660
661 return *this;
662 }
663
664
665
666
GetWeight(void) const667 sal_Int32 ColumnDescriptor::GetWeight (void) const
668 {
669 return mnWeight;
670 }
671
672
673
674
GetMinimumWidth(void) const675 sal_Int32 ColumnDescriptor::GetMinimumWidth (void) const
676 {
677 return mnMinimumWidth;
678 }
679
680
681
682
GetMaximumWidth(void) const683 sal_Int32 ColumnDescriptor::GetMaximumWidth (void) const
684 {
685 return mnMaximumWidth;
686 }
687
688
689
690
GetTotalMaximumWidth(void) const691 sal_Int32 ColumnDescriptor::GetTotalMaximumWidth (void) const
692 {
693 return mnMaximumWidth + mnLeftPadding + mnRightPadding;
694 }
695
696
697
698
GetLeftPadding(void) const699 sal_Int32 ColumnDescriptor::GetLeftPadding (void) const
700 {
701 return mnLeftPadding;
702 }
703
704
705
706
GetRightPadding(void) const707 sal_Int32 ColumnDescriptor::GetRightPadding (void) const
708 {
709 return mnRightPadding;
710 }
711
712
713
714
SetWidth(const sal_Int32 nWidth)715 void ColumnDescriptor::SetWidth (const sal_Int32 nWidth)
716 {
717 mnWidth = nWidth;
718 }
719
720
721
722
GetWidth(void) const723 sal_Int32 ColumnDescriptor::GetWidth (void) const
724 {
725 return mnWidth;
726 }
727
728 } } // end of namespace sfx2::sidebar
729