1 //------------------------------------------------------------------------------
2 // emRasterLayout.cpp
3 //
4 // Copyright (C) 2015,2020 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20
21 #include <emCore/emRasterLayout.h>
22
23
emRasterLayout(ParentArg parent,const emString & name,const emString & caption,const emString & description,const emImage & icon)24 emRasterLayout::emRasterLayout(
25 ParentArg parent, const emString & name, const emString & caption,
26 const emString & description, const emImage & icon
27 )
28 : emBorder(parent,name,caption,description,icon)
29 {
30 PrefCT=0.2;
31 MinCT=1E-4;
32 MaxCT=1E4;
33 SpaceL=0.0;
34 SpaceT=0.0;
35 SpaceH=0.0;
36 SpaceV=0.0;
37 SpaceR=0.0;
38 SpaceB=0.0;
39 FixedColumnCount=0;
40 FixedRowCount=0;
41 MinCellCount=0;
42 Alignment=EM_ALIGN_CENTER;
43 StrictRaster=false;
44 RowByRow=false;
45 SetFocusable(false);
46 }
47
48
~emRasterLayout()49 emRasterLayout::~emRasterLayout()
50 {
51 }
52
53
SetRowByRow(bool rowByRow)54 void emRasterLayout::SetRowByRow(bool rowByRow)
55 {
56 if ((bool)RowByRow!=rowByRow) {
57 RowByRow=rowByRow?1:0;
58 InvalidateChildrenLayout();
59 }
60 }
61
62
SetFixedColumnCount(int fixedColumnCount)63 void emRasterLayout::SetFixedColumnCount(int fixedColumnCount)
64 {
65 if (fixedColumnCount<0) fixedColumnCount=0;
66 if (FixedColumnCount!=fixedColumnCount) {
67 FixedColumnCount=fixedColumnCount;
68 InvalidateChildrenLayout();
69 }
70 }
71
72
SetFixedRowCount(int fixedRowCount)73 void emRasterLayout::SetFixedRowCount(int fixedRowCount)
74 {
75 if (fixedRowCount<0) fixedRowCount=0;
76 if (FixedRowCount!=fixedRowCount) {
77 FixedRowCount=fixedRowCount;
78 InvalidateChildrenLayout();
79 }
80 }
81
82
SetMinCellCount(int minCellCount)83 void emRasterLayout::SetMinCellCount(int minCellCount)
84 {
85 if (minCellCount<0) minCellCount=0;
86 if (MinCellCount!=minCellCount) {
87 MinCellCount=minCellCount;
88 InvalidateChildrenLayout();
89 }
90 }
91
92
SetPrefChildTallness(double prefCT)93 void emRasterLayout::SetPrefChildTallness(double prefCT)
94 {
95 if (PrefCT!=prefCT) {
96 PrefCT=prefCT;
97 InvalidateChildrenLayout();
98 }
99 }
100
101
SetMinChildTallness(double minCT)102 void emRasterLayout::SetMinChildTallness(double minCT)
103 {
104 if (MinCT!=minCT) {
105 MinCT=minCT;
106 InvalidateChildrenLayout();
107 }
108 }
109
110
SetMaxChildTallness(double maxCT)111 void emRasterLayout::SetMaxChildTallness(double maxCT)
112 {
113 if (MaxCT!=maxCT) {
114 MaxCT=maxCT;
115 InvalidateChildrenLayout();
116 }
117 }
118
119
SetChildTallness(double tallness)120 void emRasterLayout::SetChildTallness(double tallness)
121 {
122 if (PrefCT!=tallness || MinCT!=tallness || MaxCT!=tallness) {
123 PrefCT=tallness;
124 MinCT=tallness;
125 MaxCT=tallness;
126 InvalidateChildrenLayout();
127 }
128 }
129
130
SetStrictRaster(bool strictRaster)131 void emRasterLayout::SetStrictRaster(bool strictRaster)
132 {
133 if (StrictRaster!=strictRaster) {
134 StrictRaster=strictRaster;
135 InvalidateChildrenLayout();
136 }
137 }
138
139
SetAlignment(emAlignment alignment)140 void emRasterLayout::SetAlignment(emAlignment alignment)
141 {
142 if (Alignment!=alignment) {
143 Alignment=alignment;
144 InvalidateChildrenLayout();
145 }
146 }
147
148
SetSpaceL(double l)149 void emRasterLayout::SetSpaceL(double l)
150 {
151 if (l<0.0) l=0.0;
152 if (SpaceL!=l) {
153 SpaceL=l;
154 InvalidateChildrenLayout();
155 }
156 }
157
158
SetSpaceT(double t)159 void emRasterLayout::SetSpaceT(double t)
160 {
161 if (t<0.0) t=0.0;
162 if (SpaceT!=t) {
163 SpaceT=t;
164 InvalidateChildrenLayout();
165 }
166 }
167
168
SetSpaceH(double h)169 void emRasterLayout::SetSpaceH(double h)
170 {
171 if (h<0.0) h=0.0;
172 if (SpaceH!=h) {
173 SpaceH=h;
174 InvalidateChildrenLayout();
175 }
176 }
177
178
SetSpaceV(double v)179 void emRasterLayout::SetSpaceV(double v)
180 {
181 if (v<0.0) v=0.0;
182 if (SpaceV!=v) {
183 SpaceV=v;
184 InvalidateChildrenLayout();
185 }
186 }
187
188
SetSpaceR(double r)189 void emRasterLayout::SetSpaceR(double r)
190 {
191 if (r<0.0) r=0.0;
192 if (SpaceR!=r) {
193 SpaceR=r;
194 InvalidateChildrenLayout();
195 }
196 }
197
198
SetSpaceB(double b)199 void emRasterLayout::SetSpaceB(double b)
200 {
201 if (b<0.0) b=0.0;
202 if (SpaceB!=b) {
203 SpaceB=b;
204 InvalidateChildrenLayout();
205 }
206 }
207
208
SetSpace(double l,double t,double h,double v,double r,double b)209 void emRasterLayout::SetSpace(
210 double l, double t, double h, double v, double r, double b
211 )
212 {
213 SetSpaceL(l);
214 SetSpaceT(t);
215 SetSpaceH(h);
216 SetSpaceV(v);
217 SetSpaceR(r);
218 SetSpaceB(b);
219 }
220
221
SetSpace(double lr,double tb,double h,double v)222 void emRasterLayout::SetSpace(double lr, double tb, double h, double v)
223 {
224 SetSpace(lr,tb,h,v,lr,tb);
225 }
226
227
SetInnerSpace(double h,double v)228 void emRasterLayout::SetInnerSpace(double h, double v)
229 {
230 SetSpaceH(h);
231 SetSpaceV(v);
232 }
233
234
SetOuterSpace(double l,double t,double r,double b)235 void emRasterLayout::SetOuterSpace(double l, double t, double r, double b)
236 {
237 SetSpaceL(l);
238 SetSpaceT(t);
239 SetSpaceR(r);
240 SetSpaceB(b);
241 }
242
243
SetOuterSpace(double lr,double tb)244 void emRasterLayout::SetOuterSpace(double lr, double tb)
245 {
246 SetOuterSpace(lr,tb,lr,tb);
247 }
248
249
LayoutChildren()250 void emRasterLayout::LayoutChildren()
251 {
252 emPanel * p, * aux;
253 double minCT,maxCT,prefCT,x,y,w,h,t,err,errBest;
254 double cx,cy,cw,ch,ct,sx,sy,ux,uy;
255 int cells,cols,rows,rowsBest,col,row;
256 emColor cc;
257
258 emBorder::LayoutChildren();
259
260 aux=GetAuxPanel();
261
262 for (cells=0, p=GetFirstChild(); p; p=p->GetNext()) {
263 if (p!=aux) cells++;
264 }
265 if (!cells) return;
266 if (cells<MinCellCount) cells=MinCellCount;
267
268 GetContentRectUnobscured(&x,&y,&w,&h,&cc);
269 if (w<1E-100) w=1E-100;
270 if (h<1E-100) h=1E-100;
271
272 minCT=MinCT;
273 if (minCT<0.0) minCT=0.0;
274 maxCT=MaxCT;
275 if (maxCT<minCT) maxCT=minCT;
276 prefCT=PrefCT;
277 if (prefCT<minCT) prefCT=minCT;
278 if (prefCT>maxCT) prefCT=maxCT;
279
280 if (FixedColumnCount>0) {
281 cols=FixedColumnCount;
282 rows=(cells+cols-1)/cols;
283 if (rows<FixedRowCount) rows=FixedRowCount;
284 }
285 else if (FixedRowCount>0) {
286 rows=FixedRowCount;
287 cols=(cells+rows-1)/rows;
288 }
289 else {
290 rowsBest=1;
291 errBest=0.0;
292 for (rows=1;;) {
293 cols=(cells+rows-1)/rows;
294 sx=SpaceL+SpaceR+SpaceH*(cols-1);
295 sy=SpaceT+SpaceB+SpaceV*(rows-1);
296 ux=sx/cols+1.0;
297 uy=sy/rows+1.0;
298 ct=h*ux*cols/(w*uy*rows);
299 err=fabs(log(prefCT/ct));
300 if (rows==1 || err<errBest) {
301 rowsBest=rows;
302 errBest=err;
303 }
304 if (cols==1) break;
305 rows=(cells+cols-2)/(cols-1); // skip rows until cols decreases
306 }
307 rows=rowsBest;
308 cols=(cells+rows-1)/rows;
309 }
310
311 sx=SpaceL+SpaceR+SpaceH*(cols-1);
312 sy=SpaceT+SpaceB+SpaceV*(rows-1);
313 ux=sx/cols+1.0;
314 uy=sy/rows+1.0;
315 ct=h*ux*cols/(w*uy*rows);
316
317 if (StrictRaster) {
318 if (RowByRow) {
319 if (FixedColumnCount<=0) {
320 while (cols<cells && ct<minCT) {
321 cols++;
322 rows=(cells+cols-1)/cols;
323 if (rows<FixedRowCount) rows=FixedRowCount;
324 sx=SpaceL+SpaceR+SpaceH*(cols-1);
325 sy=SpaceT+SpaceB+SpaceV*(rows-1);
326 ux=sx/cols+1.0;
327 uy=sy/rows+1.0;
328 ct=h*ux*cols/(w*uy*rows);
329 }
330 }
331 }
332 else {
333 if (FixedRowCount<=0) {
334 while (rows<cells && ct>maxCT) {
335 rows++;
336 cols=(cells+rows-1)/rows;
337 if (cols<FixedColumnCount) cols=FixedColumnCount;
338 sx=SpaceL+SpaceR+SpaceH*(cols-1);
339 sy=SpaceT+SpaceB+SpaceV*(rows-1);
340 ux=sx/cols+1.0;
341 uy=sy/rows+1.0;
342 ct=h*ux*cols/(w*uy*rows);
343 }
344 }
345 }
346 }
347
348 if (ct<minCT) ct=minCT;
349 else if (ct>maxCT) ct=maxCT;
350 cw=cols*ux;
351 ch=ct*rows*uy;
352
353 if (w*ch >= h*cw) {
354 t=h*cw/ch;
355 if (Alignment&EM_ALIGN_RIGHT) x+=w-t;
356 else if (!(Alignment&EM_ALIGN_LEFT)) x+=(w-t)*0.5;
357 w=t;
358 }
359 else {
360 t=w*ch/cw;
361 if (Alignment&EM_ALIGN_BOTTOM) y+=h-t;
362 else if (!(Alignment&EM_ALIGN_TOP)) y+=(h-t)*0.5;
363 h=t;
364 }
365
366 if (sx>=1E-100) {
367 sx=(w-w/ux)/sx;
368 x+=sx*SpaceL;
369 sx*=SpaceH;
370 }
371 else sx=0.0;
372
373 if (sy>=1E-100) {
374 sy=(h-h/uy)/sy;
375 y+=sy*SpaceT;
376 sy*=SpaceV;
377 }
378 else sy=0.0;
379
380 cw=w/cols/ux;
381 ch=h/rows/uy;
382
383 for (cx=x, cy=y, row=0, col=0, p=GetFirstChild(); p; p=p->GetNext()) {
384 if (p==aux) continue;
385 p->Layout(cx,cy,cw,ch,cc);
386 if (RowByRow) {
387 cx+=cw+sx;
388 col++;
389 if (col>=cols) {
390 row++;
391 cy+=ch+sy;
392 col=0;
393 cx=x;
394 }
395 }
396 else {
397 cy+=ch+sy;
398 row++;
399 if (row>=rows) {
400 col++;
401 cx+=cw+sx;
402 row=0;
403 cy=y;
404 }
405 }
406 }
407 }
408