1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2009 Bastian Holst <bastianholst@gmx.de>
4 //
5 
6 // Self
7 #include "MarbleGraphicsGridLayout.h"
8 
9 // Marble
10 #include "MarbleDebug.h"
11 #include "ScreenGraphicsItem.h"
12 
13 // Qt
14 #include <QHash>
15 #include <QRectF>
16 #include <QSizeF>
17 #include <QVector>
18 
19 namespace Marble
20 {
21 
22 class MarbleGraphicsGridLayoutPrivate
23 {
24  public:
MarbleGraphicsGridLayoutPrivate(int rows,int columns)25     MarbleGraphicsGridLayoutPrivate( int rows, int columns )
26             : m_rows( rows ),
27               m_columns( columns ),
28               m_spacing( 0 ),
29               m_alignment( Qt::AlignLeft | Qt::AlignTop )
30     {
31         m_items = new ScreenGraphicsItem **[rows];
32         for ( int i = 0; i < rows; ++i ) {
33             m_items[i] = new ScreenGraphicsItem *[columns];
34         }
35         for ( int row = 0; row < rows; row++ ) {
36             for ( int column = 0; column < columns; column++ ) {
37                 m_items[row][column] = nullptr;
38             }
39         }
40     }
41 
~MarbleGraphicsGridLayoutPrivate()42     ~MarbleGraphicsGridLayoutPrivate()
43     {
44         for ( int i = 0; i < m_rows; ++i ) {
45             delete[] m_items[i];
46         }
47         delete[] m_items;
48     }
49 
50     // A two dimensional array of pointers to ScreenGraphicsItems
51     ScreenGraphicsItem ***m_items;
52     int m_rows;
53     int m_columns;
54     int m_spacing;
55     Qt::Alignment m_alignment;
56     QHash<ScreenGraphicsItem*, Qt::Alignment> m_itemAlignment;
57 };
58 
MarbleGraphicsGridLayout(int rows,int columns)59 MarbleGraphicsGridLayout::MarbleGraphicsGridLayout( int rows, int columns )
60         : d( new MarbleGraphicsGridLayoutPrivate( rows, columns ) )
61 {
62 }
63 
~MarbleGraphicsGridLayout()64 MarbleGraphicsGridLayout::~MarbleGraphicsGridLayout()
65 {
66     delete d;
67 }
68 
addItem(ScreenGraphicsItem * item,int row,int column)69 void MarbleGraphicsGridLayout::addItem( ScreenGraphicsItem *item, int row, int column )
70 {
71     if ( row < d->m_rows
72          && column < d->m_columns )
73     {
74         d->m_items[row][column] = item;
75     }
76 }
77 
updatePositions(MarbleGraphicsItem * parent)78 void MarbleGraphicsGridLayout::updatePositions( MarbleGraphicsItem *parent )
79 {
80     // Initialize with 0.0
81     QVector<double> maxWidth( d->m_columns, 0.0 );
82     QVector<double> maxHeight( d->m_rows, 0.0 );
83 
84     // Determining the cell sizes
85     for ( int row = 0; row < d->m_rows; row++ ) {
86         for ( int column = 0; column < d->m_columns; column++ ) {
87             if ( d->m_items[row][column] == nullptr ) {
88                 continue;
89             }
90 
91             QSizeF size = d->m_items[row][column]->size();
92             double width = size.width();
93             double height = size.height();
94 
95             if ( width > maxWidth[column] ) {
96                 maxWidth[column] = width;
97             }
98             if ( height > maxHeight[row] ) {
99                 maxHeight[row] = height;
100             }
101         }
102     }
103 
104     QVector<double> startX( d->m_columns );
105     QVector<double> endX( d->m_columns );
106     QVector<double> startY( d->m_rows );
107     QVector<double> endY( d->m_rows );
108     QRectF contentRect = parent->contentRect();
109 
110     for ( int i = 0; i < d->m_columns; i++ ) {
111         if ( i == 0 ) {
112             startX[0] = contentRect.left();
113         }
114         else if ( maxWidth[i] == 0 ) {
115             startX[i] = endX[i-1];
116         }
117         else {
118             startX[i] = endX[i-1] + d->m_spacing;
119         }
120 
121         endX[i] = startX[i] + maxWidth[i];
122     }
123 
124     for ( int i = 0; i < d->m_rows; i++ ) {
125         if ( i == 0 ) {
126             startY[0] = contentRect.left();
127         }
128         else if ( maxHeight[i] == 0 ) {
129             startY[i] = endY[i-1];
130         }
131         else {
132             startY[i] = endY[i-1] + d->m_spacing;
133         }
134 
135         endY[i] = startY[i] + maxHeight[i];
136     }
137 
138     // Setting the positions
139     for ( int row = 0; row < d->m_rows; row++ ) {
140         for ( int column = 0; column < d->m_columns; column++ ) {
141             if ( d->m_items[row][column] == nullptr ) {
142                 continue;
143             }
144 
145             double xPos, yPos;
146 
147             Qt::Alignment align = alignment( d->m_items[row][column] );
148 
149             if ( align & Qt::AlignRight ) {
150                 xPos = endX[column] - d->m_items[row][column]->size().width();
151             }
152             else if ( align & Qt::AlignHCenter ) {
153                 xPos = startX[column]
154                        + ( maxWidth[column] - d->m_items[row][column]->size().width() ) / 2.0;
155             }
156             else {
157                 xPos = startX[column];
158             }
159 
160             if ( align & Qt::AlignBottom ) {
161                 yPos = endY[row] - d->m_items[row][column]->size().height();
162             }
163             else if ( align & Qt::AlignVCenter ) {
164                 yPos = startY[row]
165                        + ( maxHeight[row] - d->m_items[row][column]->size().height() ) / 2.0;
166             }
167             else {
168                 yPos = startY[row];
169             }
170 
171             d->m_items[row][column]->setPosition( QPointF( xPos, yPos ) );
172         }
173     }
174 
175     parent->setContentSize( QSizeF( endX[d->m_columns - 1] - contentRect.left(),
176                                     endY[d->m_rows - 1] - contentRect.top() ) );
177 }
178 
alignment() const179 Qt::Alignment MarbleGraphicsGridLayout::alignment() const
180 {
181     return d->m_alignment;
182 }
183 
alignment(ScreenGraphicsItem * item) const184 Qt::Alignment MarbleGraphicsGridLayout::alignment( ScreenGraphicsItem *item ) const
185 {
186     return d->m_itemAlignment.value( item, d->m_alignment );
187 }
188 
setAlignment(Qt::Alignment align)189 void MarbleGraphicsGridLayout::setAlignment( Qt::Alignment align )
190 {
191     d->m_alignment = align;
192 }
193 
setAlignment(ScreenGraphicsItem * item,Qt::Alignment align)194 void MarbleGraphicsGridLayout::setAlignment( ScreenGraphicsItem *item, Qt::Alignment align )
195 {
196     d->m_itemAlignment.insert( item, align );
197 }
198 
spacing() const199 int MarbleGraphicsGridLayout::spacing() const
200 {
201     return d->m_spacing;
202 }
203 
setSpacing(int spacing)204 void MarbleGraphicsGridLayout::setSpacing( int spacing )
205 {
206     d->m_spacing = spacing;
207 }
208 
209 } // namespace Marble
210