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