1 /*
2    Copyright (c) by Valery Goryachev (Wal)
3 */
4 
5 
6 #include "swl.h"
7 
8 namespace wal
9 {
10 
11 
AddWin(Win * w,int r1,int c1,int r2,int c2,int al)12 	void Layout::AddWin( Win* w, int r1, int c1, int r2, int c2, int al )
13 	{
14 		if ( r2 < 0 ) { r2 = r1; }
15 
16 		if ( c2 < 0 ) { c2 = c1; }
17 
18 		if ( r1 > r2 || c1 > c2 ) { return; }
19 
20 		if ( r1 < 0 || c1 < 0 || r2 >= lines.count() || c2 >= columns.count() ) { return; }
21 
22 		//if (w->layout) w->layout->DelObj(w);
23 		if ( w->upLayout ) { w->upLayout->DelObj( w ); }
24 
25 		w->upLayout = this;
26 		objList.emplace_back( new LItemWin( w, r1, r2, c1, c2, al ) );
27 	}
28 
AddWinAndEnable(Win * w,int r1,int c1,int r2,int c2,int al)29 	void Layout::AddWinAndEnable( Win* w, int r1, int c1, int r2, int c2, int al )
30 	{
31 		if ( !w ) { return; }
32 
33 		this->AddWin( w, r1, c1, r2, c2, al );
34 		w->Enable();
35 		w->Show();
36 	}
37 
AddLayout(Layout * l,int r1,int c1,int r2,int c2,int al)38 	void Layout::AddLayout( Layout* l, int r1, int c1, int r2, int c2, int al )
39 	{
40 		if ( r2 < 0 ) { r2 = r1; }
41 
42 		if ( c2 < 0 ) { c2 = c1; }
43 
44 		if ( r1 > r2 || c1 > c2 ) { return; }
45 
46 		if ( r1 < 0 || c1 < 0 || r2 >= lines.count() || c2 >= columns.count() ) { return; }
47 
48 //??? if (w->layout) w->layout->DelObj(w);
49 		objList.emplace_back( new LItemLayout( l, r1, r2, c1, c2, al ) );
50 	}
51 
AddRect(crect * rect,int r1,int c1,int r2,int c2)52 	void Layout::AddRect( crect* rect, int r1, int c1, int r2, int c2 )
53 	{
54 		if ( !rect ) { return; }
55 
56 		if ( r2 < 0 ) { r2 = r1; }
57 
58 		if ( c2 < 0 ) { c2 = c1; }
59 
60 		if ( r1 > r2 || c1 > c2 ) { return; }
61 
62 		if ( r1 < 0 || c1 < 0 || r2 >= lines.count() || c2 >= columns.count() ) { return; }
63 
64 		objList.emplace_back( new LItemRect( rect, r1, r2, c1, c2 ) );
65 	}
66 
67 
Layout(int lineCount,int colCount)68 	Layout::Layout( int lineCount, int colCount )
69 		:
70 		lines( lineCount ),
71 		columns( colCount ),
72 		currentRect( 0, 0, 0, 0 ),
73 		valid( false )
74 	{
75 //	int i; //ошибка была в конструсторе ccollect(int n)
76 //	for (i=0; i<lineCount; i++) lines.append();
77 //	for (i=0; i<colCount; i++) columns.append();
78 	}
79 
~Layout()80 	Layout::~Layout() {}
81 
GetLSize(LSize * pls)82 	void Layout::GetLSize( LSize* pls )
83 	{
84 		/* !!!??
85 		   if (valid)
86 		   {
87 		      *pls = size;
88 		      return;
89 		   }
90 		*/
91 		Recalc();
92 		int i;
93 		LSize ls;
94 
95 		for ( i = 0; i < lines.count(); i++ )
96 		{
97 			ls.y.Plus( lines[i].range );
98 		}
99 
100 		for ( i = 0; i < columns.count(); i++ )
101 		{
102 			ls.x.Plus( columns[i].range );
103 		}
104 
105 		size = ls;
106 		*pls = ls;
107 	}
108 
SetPos(crect rect,wal::ccollect<WSS> & wList)109 	void Layout::SetPos( crect rect, wal::ccollect<WSS>& wList )
110 	{
111 //	if (currentRect == rect) return;
112 		currentRect = rect;
113 		valid = false;
114 		this->Recalc();
115 
116 		for ( int i = 0; i < ( int )objList.size(); i++ )
117 		{
118 			int j;
119 			crect r( rect.left, rect.top, 0, 0 );
120 
121 			for ( j = 0; j < objList[i]->r1; j++ ) { r.top += lines[j].size; }
122 
123 			r.bottom = r.top;
124 
125 			for ( ;  j <= objList[i]->r2; j++ ) { r.bottom += lines[j].size; }
126 
127 			for ( j = 0; j < objList[i]->c1; j++ ) { r.left += columns[j].size; }
128 
129 			r.right = r.left;
130 
131 			for ( ; j <= objList[i]->c2; j++ ) { r.right += columns[j].size; }
132 
133 			objList[i]->SetPos( r, wList );
134 		}
135 	}
136 
DelObj(void * p)137 	void Layout::DelObj( void* p )
138 	{
139 		for ( int i = 0; i < ( int )objList.size(); i++ )
140 		{
141 			if ( objList[i]->ObjPtr() == p )
142 			{
143 				valid = false;
144 				objList.erase( objList.begin() + i );
145 				return;
146 			}
147 		}
148 	}
149 
150 
LineSet(int nLine,int _min,int _max,int _ideal)151 	void Layout::LineSet( int nLine, int _min, int _max, int _ideal )
152 	{
153 		if ( nLine < 0 || nLine >= lines.count() ) { return; }
154 
155 		if ( _min >= 0 ) { lines[nLine].initRange.minimal = _min; }
156 
157 		if ( _max >= 0 ) { lines[nLine].initRange.maximal = _max; }
158 
159 		if ( _ideal >= 0 ) { lines[nLine].initRange.ideal = _ideal; }
160 
161 		lines[nLine].initRange.Check();
162 	}
163 
ColSet(int nCol,int _min,int _max,int _ideal)164 	void Layout::ColSet( int nCol, int _min, int _max, int _ideal )
165 	{
166 		if ( nCol < 0 || nCol >= columns.count() ) { return; }
167 
168 		if ( _min >= 0 ) { columns[nCol].initRange.minimal = _min; }
169 
170 		if ( _max >= 0 ) { columns[nCol].initRange.maximal = _max; }
171 
172 		if ( _ideal >= 0 ) { columns[nCol].initRange.ideal = _ideal; }
173 
174 		/*lines*/ columns[nCol].initRange.Check();
175 	}
176 
SetLineGrowth(int n,bool enable)177 	void Layout::SetLineGrowth( int n, bool enable )
178 	{
179 		if ( n >= 0 && n < lines.count() )
180 		{
181 			lines[n].growth = enable;
182 		}
183 	}
184 
SetColGrowth(int n,bool enable)185 	void Layout::SetColGrowth( int n, bool enable )
186 	{
187 		if ( n >= 0 && n < columns.count() )
188 		{
189 			columns[n].growth = enable;
190 		}
191 	}
192 
SetMinRangeN(SpaceStruct * list,int count,int size)193 	static void SetMinRangeN( SpaceStruct* list, int count, int size )
194 	{
195 		int i, n, addon, rem, space;
196 
197 		for ( i = 0; i < count; i++ ) //выставляем по минимуму
198 		{
199 			size -=  list[i].range.minimal;
200 		}
201 
202 		if ( size <= 0 ) { return; }
203 
204 		n = 0;
205 
206 		for ( i = 0; i < count; i++ )
207 			if ( list[i].growth ) { n++; }
208 
209 		if ( n > 0 )
210 		{
211 			addon = size / n;
212 			rem = size % n;
213 
214 			for ( i = 0; i < count; i++ )
215 				if ( list[i].growth )
216 				{
217 					list[i].range.minimal += addon;
218 					size -= addon;
219 
220 					if ( rem > 0 ) { list[i].range.minimal++; rem--; size--; }
221 				}
222 
223 			return;
224 		}
225 
226 		while ( true )
227 		{
228 			n = 0;
229 
230 			for ( i = 0; i < count; i++ )
231 				if ( list[i].range.minimal < list[i].range.maximal ) { n++; }
232 
233 			if ( !n ) { break; }
234 
235 			addon = size / n;
236 
237 			if ( addon == 0 ) { addon = 1; }
238 
239 			for ( i = 0; i < count; i++ )
240 			{
241 				space = list[i].range.maximal - list[i].range.minimal;
242 
243 				if ( space <= 0 ) { continue; }
244 
245 				if ( space > addon ) { space = addon; }
246 
247 				list[i].range.minimal += space;
248 				size -= space;
249 
250 				if ( size <= 0 ) { return; }
251 			}
252 
253 			if ( size <= 0 ) { return; }
254 		}
255 
256 		addon = size / count;
257 		rem = size % count;
258 
259 		for ( i = 0; i < count; i++ )
260 		{
261 			list[i].range.minimal += addon;
262 			size -= addon;
263 
264 			if ( rem > 0 ) { list[i].range.minimal++; rem--; size--; }
265 		}
266 	}
267 
SetIdealRangeN(SpaceStruct * list,int count,int size)268 	static void SetIdealRangeN( SpaceStruct* list, int count, int size )
269 	{
270 		int i, n, addon, rem, space;
271 
272 		for ( i = 0; i < count; i++ )
273 		{
274 			size -=  list[i].range.ideal;
275 		}
276 
277 		if ( size <= 0 ) { return; }
278 
279 		n = 0;
280 
281 		for ( i = 0; i < count; i++ )
282 			if ( list[i].growth ) { n++; }
283 
284 		if ( n > 0 )
285 		{
286 			addon = size / n;
287 			rem = size % n;
288 
289 			for ( i = 0; i < count; i++ )
290 				if ( list[i].growth )
291 				{
292 					list[i].range.ideal += addon;
293 					size -= addon;
294 
295 					if ( rem > 0 ) { list[i].range.ideal++; rem--; size--; }
296 				}
297 
298 			return;
299 		}
300 
301 		while ( true )
302 		{
303 			n = 0;
304 
305 			for ( i = 0; i < count; i++ )
306 				if ( list[i].range.ideal < list[i].range.maximal ) { n++; }
307 
308 			if ( !n ) { break; }
309 
310 			addon = size / n;
311 
312 			if ( addon == 0 ) { addon = 1; }
313 
314 			for ( i = 0; i < count; i++ )
315 			{
316 				space = list[i].range.maximal - list[i].range.ideal;
317 
318 				if ( space <= 0 ) { continue; }
319 
320 				if ( space > addon ) { space = addon; }
321 
322 				list[i].range.ideal += space;
323 				size -= space;
324 
325 				if ( size <= 0 ) { return; }
326 			}
327 
328 			if ( size <= 0 ) { return; }
329 		}
330 
331 		addon = size / count;
332 		rem = size % count;
333 
334 		for ( i = 0; i < count; i++ )
335 		{
336 			list[i].range.ideal += addon;
337 			size -= addon;
338 
339 			if ( rem > 0 ) { list[i].range.ideal++; rem--; size--; }
340 		}
341 	}
342 
343 
SetMaxRangeN(SpaceStruct * list,int count,int size)344 	static void SetMaxRangeN( SpaceStruct* list, int count, int size )
345 	{
346 		int i, n, addon, rem;
347 
348 		for ( i = 0; i < count; i++ )
349 		{
350 			size -=  list[i].range.maximal;
351 		}
352 
353 		if ( size <= 0 ) { return; }
354 
355 		n = 0;
356 
357 		for ( i = 0; i < count; i++ )
358 			if ( list[i].growth ) { n++; }
359 
360 		if ( n > 0 )
361 		{
362 			addon = size / n;
363 			rem = size % n;
364 
365 			for ( i = 0; i < count; i++ )
366 				if ( list[i].growth )
367 				{
368 					list[i].range.maximal += addon;
369 					size -= addon;
370 
371 					if ( rem > 0 ) { list[i].range.maximal++; rem--; size--; }
372 				}
373 
374 			return;
375 		}
376 
377 		addon = size / count;
378 		rem = size % count;
379 
380 		for ( i = 0; i < count; i++ )
381 		{
382 			list[i].range.maximal += addon;
383 			size -= addon;
384 
385 			if ( rem > 0 ) { list[i].range.maximal++; rem--; size--; }
386 		}
387 	}
388 
389 
390 
SetOptimalRange(SpaceStruct * list,int count,int size)391 	static void SetOptimalRange( SpaceStruct* list, int count, int size )
392 	{
393 		int i, n, addon, rem;
394 
395 		for ( i = 0; i < count; i++ ) //выставляем по минимуму
396 		{
397 			size -= ( list[i].size = list[i].range.minimal );
398 		}
399 
400 		if ( size <= 0 ) { return; }
401 
402 		n = 0;
403 
404 		for ( i = 0; i < count; i++ )
405 			if ( list[i].growth ) { n++; }
406 
407 		if ( n > 0 )
408 		{
409 			addon = size / n;
410 			rem = size % n;
411 
412 			for ( i = 0; i < count; i++ )
413 				if ( list[i].growth )
414 				{
415 					list[i].size += addon;
416 					size -= addon;
417 
418 					if ( rem > 0 ) { list[i].size++; rem--; size--; }
419 				}
420 
421 			return;
422 		}
423 
424 		while ( true )
425 		{
426 			n = 0;
427 
428 			for ( i = 0; i < count; i++ )
429 				if ( list[i].size < list[i].range.maximal ) { n++; }
430 
431 			if ( !n ) { break; }
432 
433 			addon = size / n;
434 
435 			//int rem = size % n;
436 			if ( !addon ) { addon = 1; }
437 
438 			for ( i = 0; i < count; i++ )
439 			{
440 				int space = list[i].range.maximal - list[i].size;
441 
442 				if ( space <= 0 ) { continue; }
443 
444 				if ( space > addon ) { space = addon; }
445 
446 				list[i].size += space;
447 				size -= space;
448 
449 				if ( size <= 0 ) { break; }
450 			}
451 
452 			if ( size <= 0 ) { break; }
453 		}
454 
455 //ret:
456 //	size = 0;
457 //	for (i = 0; i<count; i++) size+=list[i].size;
458 //	return size;
459 	}
460 
461 
Recalc()462 	void Layout::Recalc()
463 	{
464 //!?  if (valid) return;
465 		int i;
466 
467 		for ( i = 0; i < lines.count(); i++ )
468 		{
469 			lines[i].Clear();
470 		}
471 
472 		for ( i = 0; i < columns.count(); i++ )
473 		{
474 			columns[i].Clear();
475 		}
476 
477 
478 		wal::ccollect<LSize> lSize( ( int )objList.size() );
479 
480 		for ( i = 0; i < ( int )objList.size(); i++ )
481 		{
482 			objList[i]->GetLSize( lSize.ptr() + i );
483 		}
484 
485 		for ( i = 0; i < ( int )objList.size(); i++ )
486 		{
487 			LItem* p = objList[i].ptr();
488 			LSize* ls = lSize.ptr() + i;
489 
490 			if ( p->r1 == p->r2 )
491 			{
492 				int r = p->r1;
493 
494 				if ( lines[r].range.minimal < ls->y.minimal )
495 				{
496 					lines[r].range.minimal = ls->y.minimal;
497 				}
498 
499 				if ( lines[r].range.maximal < ls->y.maximal )
500 				{
501 					lines[r].range.maximal = ls->y.maximal;
502 				}
503 
504 				if ( lines[r].range.ideal < ls->y.ideal )
505 				{
506 					lines[r].range.ideal = ls->y.ideal;
507 				}
508 			}
509 
510 			if ( p->c1 == p->c2 )
511 			{
512 				int c = p->c1;
513 
514 				if ( columns[c].range.minimal < ls->x.minimal )
515 				{
516 					columns[c].range.minimal = ls->x.minimal;
517 				}
518 
519 				if ( columns[c].range.maximal < ls->x.maximal )
520 				{
521 					columns[c].range.maximal = ls->x.maximal;
522 				}
523 
524 				if ( columns[c].range.ideal < ls->x.ideal )
525 				{
526 					columns[c].range.ideal = ls->x.ideal;
527 				}
528 			}
529 		}
530 
531 
532 		for ( i = 0; i < ( int )objList.size(); i++ )
533 		{
534 			LItem* p = objList[i].ptr();
535 			LSize* ls = lSize.ptr() + i;
536 
537 			if ( p->r1 != p->r2 )
538 			{
539 				SetMinRangeN( lines.ptr() + p->r1, p->r2 - p->r1 + 1, ls->y.minimal );
540 				SetIdealRangeN( lines.ptr() + p->r1, p->r2 - p->r1 + 1, ls->y.ideal );
541 				SetMaxRangeN( lines.ptr() + p->r1, p->r2 - p->r1 + 1, ls->y.maximal );
542 			}
543 
544 			if ( p->c1 != p->c2 )
545 			{
546 				SetMinRangeN  ( columns.ptr() + p->c1, p->c2 - p->c1 + 1, ls->x.minimal );
547 				SetIdealRangeN( columns.ptr() + p->c1, p->c2 - p->c1 + 1, ls->x.ideal );
548 				SetMaxRangeN  ( columns.ptr() + p->c1, p->c2 - p->c1 + 1, ls->x.maximal );
549 
550 				/*чо за херня тут была
551 				SetMinRangeN(columns.ptr()+p->r1, p->r2-p->r1+1,ls->x.minimal);
552 				SetIdealRangeN(columns.ptr()+p->r1, p->r2-p->r1+1,ls->x.ideal);
553 				SetMaxRangeN(columns.ptr()+p->r1, p->r2-p->r1+1,ls->x.maximal);
554 				*/
555 			}
556 		}
557 
558 		for ( i = 0; i < lines.count(); i++ ) { lines[i].range.Check(); }
559 
560 		for ( i = 0; i < columns.count(); i++ ) { columns[i].range.Check(); }
561 
562 		SetOptimalRange( lines.ptr(), lines.count(), currentRect.Height() );
563 		SetOptimalRange( columns.ptr(), columns.count(), currentRect.Width() );
564 
565 		valid = true;
566 	}
567 
~LItem()568 	LItem::~LItem() {}
569 
~LItemWin()570 	LItemWin::~LItemWin() { if ( w ) { w->upLayout = 0; } }
~LItemRect()571 	LItemRect::~LItemRect() {}
~LItemLayout()572 	LItemLayout::~LItemLayout() {};
573 
GetLSize(LSize * ls)574 	void LItemLayout::GetLSize( LSize* ls )
575 	{
576 		l->GetLSize( ls );
577 	}
578 
SetPos(crect rect,wal::ccollect<WSS> & wList)579 	void LItemLayout::SetPos( crect rect, wal::ccollect<WSS>& wList )
580 	{
581 		LSize ls;
582 		l->GetLSize( &ls );
583 		// if (rect.Width() > ls.x.maximal) rect.right = rect.left + ls.x.maximal;
584 		// if (rect.Height() > ls.y.maximal) rect.bottom = rect.top + ls.y.maximal;
585 
586 		int width = rect.Width();
587 
588 		if ( width > ls.x.maximal )
589 		{
590 			switch ( align & ( Layout::LEFT + Layout::RIGHT ) )
591 			{
592 				case Layout::LEFT:
593 					rect.right = rect.left + ls.x.maximal;
594 					break;
595 
596 				case Layout::RIGHT:
597 					rect.left = rect.right - ls.x.maximal;
598 					break;
599 
600 				default:
601 				{
602 					int n = ( width - ls.x.maximal ) / 2;
603 					rect.left += n;
604 					rect.right += n;
605 				}
606 			}
607 		}
608 
609 		int height = rect.Height();
610 
611 		if ( rect.Height() > ls.y.maximal )
612 		{
613 			switch ( align & ( Layout::TOP + Layout::BOTTOM ) )
614 			{
615 				case Layout::TOP:
616 					rect.bottom = rect.top + ls.y.maximal;
617 					break;
618 
619 				case Layout::RIGHT:
620 					rect.top = rect.bottom - ls.y.maximal;
621 					break;
622 
623 				default:
624 				{
625 					int n = ( height - ls.y.maximal ) / 2;
626 					rect.top += n;
627 					rect.bottom += n;
628 				}
629 			}
630 		};
631 
632 		l->SetPos( rect, wList );
633 	}
634 
GetLSize(LSize * ls)635 	void LItemWin::GetLSize( LSize* ls )
636 	{
637 		if ( w->IsVisible() ) { w->GetLSize( ls ); }
638 		else
639 		{
640 			ls->Set( cpoint( 0, 0 ) );
641 		}
642 	}
643 
644 
SetPos(crect rect,wal::ccollect<WSS> & wList)645 	void LItemWin::SetPos( crect rect, wal::ccollect<WSS>& wList )
646 	{
647 		LSize ls;
648 
649 		if ( !w->IsVisible() ) { return; }
650 
651 		w->GetLSize( &ls );
652 
653 		int width = rect.Width();
654 
655 		if ( width > ls.x.maximal )
656 		{
657 			switch ( align & ( Layout::LEFT + Layout::RIGHT ) )
658 			{
659 				case Layout::LEFT:
660 					rect.right = rect.left + ls.x.maximal;
661 					break;
662 
663 				case Layout::RIGHT:
664 					rect.left = rect.right - ls.x.maximal;
665 					break;
666 
667 				default:
668 				{
669 					int n = ( width - ls.x.maximal ) / 2;
670 					rect.left += n;
671 					rect.right = rect.left + ls.x.maximal;
672 				}
673 			}
674 		}
675 
676 		int height = rect.Height();
677 
678 		if ( rect.Height() > ls.y.maximal )
679 		{
680 			switch ( align & ( Layout::TOP + Layout::BOTTOM ) )
681 			{
682 				case Layout::TOP:
683 					rect.bottom = rect.top + ls.y.maximal;
684 					break;
685 
686 				case Layout::RIGHT:
687 					rect.top = rect.bottom - ls.y.maximal;
688 					break;
689 
690 				default:
691 				{
692 					int n = ( height - ls.y.maximal ) / 2;
693 					rect.top += n;
694 					rect.bottom = rect.top + ls.y.maximal;
695 				}
696 			}
697 		};
698 
699 		if ( w->Rect() != rect )
700 		{
701 			WSS wss;
702 			wss.rect = rect;
703 			wss.w = w;
704 			wList.append( wss );
705 		}
706 	}
707 
ObjPtr()708 	void* LItemLayout::ObjPtr() { return l; }
ObjPtr()709 	void* LItemWin::ObjPtr() { return w; }
710 
711 
GetLSize(LSize * ls)712 	void LItemRect::GetLSize( LSize* ls )
713 	{
714 		static LSize l( cpoint( 0, 0 ) );
715 		*ls = l;
716 	}
717 
SetPos(crect _rect,wal::ccollect<WSS> & wList)718 	void LItemRect::SetPos( crect _rect, wal::ccollect<WSS>& wList )
719 	{
720 		if ( rect ) { *rect = _rect; }
721 	}
722 
ObjPtr()723 	void* LItemRect::ObjPtr() { return rect; }
724 
725 
726 
727 }; //namespace wal
728