OWLNext    7.0
Borland's Object Windows Library for the modern age
Loading...
Searching...
No Matches
layoutwi.cpp
Go to the documentation of this file.
1//----------------------------------------------------------------------------
2// ObjectWindows
3// Copyright (c) 1992, 1996 by Borland International, All Rights Reserved
4//
5/// \file
6/// Implementation of class TLayoutWindow.
7//----------------------------------------------------------------------------
8#include <owl/pch.h>
9#include <owl/defs.h>
10#include <owl/layoutwi.h>
11#include <owl/uimetric.h>
12#include <owl/fixedpnt.h>
13#include <owl/except.h>
14
15#if defined(__BORLANDC__)
16# pragma option -w-ccc // Disable "Condition is always true/false"
17#endif
18
19using namespace std;
20
21namespace owl {
22
24DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlLayout, 1, 0); // diag. group for windows
25//----------------------------------------------------------------------------
26
27// Small wrapper around the 'DeferWindowPos' APIs
28//
29class TDeferWinPos {
30 public:
31 TDeferWinPos(int numWindows);
32 ~TDeferWinPos();
33 bool DeferWindowPos(HWND hwnd, HWND after, int x, int y, int cx, int cy,
34 uint flags);
35 bool EndDeferWindowPos();
36 protected:
37 HDWP Hdwp;
38};
39
40//} // OWL namespace
41
42//
43//
44//
45TDeferWinPos::TDeferWinPos(int numWindows)
46{
48}
49
50//
51//
52//
53bool
54TDeferWinPos::DeferWindowPos(HWND hwnd, HWND after, int x, int y,
55 int cx, int cy, uint flags)
56{
57 PRECONDITION(Hdwp);
58 TRACEX(OwlLayout, 0, _T("DeferWindowPos(x => ") << x << _T(", y => ") << y << _T(", cx => ") << cx << _T(", cy => ") << cy);
59 Hdwp = ::DeferWindowPos(Hdwp, hwnd, after, x, y, cx, cy, flags);
60 CHECK(Hdwp);
61 return Hdwp != 0;
62}
63
64//
65//
66//
67bool
68TDeferWinPos::EndDeferWindowPos()
69{
70 PRECONDITION(Hdwp);
71 if (::EndDeferWindowPos(Hdwp)) {
72 Hdwp = 0;
73 return true;
74 }
75 return false;
76}
77
78//
79//
80//
81TDeferWinPos::~TDeferWinPos()
82{
83 if (Hdwp)
84 EndDeferWindowPos();
85}
86
87
88DEFINE_RESPONSE_TABLE1(TLayoutWindow, TWindow)
93
94//namespace owl {
95
96/// \addtogroup internal
97/// @{
98
99
100
101/// \class TConstraint
102/// Constraints can have up to three input variables
103///
104/// the method for solving the constraint is represented as an ordered linear
105/// combination of the inputs and the constant with the constant expressed last
106//
107struct TVariable;
108struct TConstraint {
109 TVariable* Inputs[3];
110 TVariable* Output;
111 TFixedPoint OrderedCombination[4];
112 TConstraint* Next;
113
114 TConstraint();
115
116 bool IsResolved(); // iff its inputs have been resolved
117 int Evaluate();
118 int NumActualInputs();
119};
120
122 return os << static_cast<int>(const_cast<TFixedPoint&>(p));
123}
126 << _T(',') << c.MyEdge << _T(',') << static_cast<int>(c.Relationship) << _T(',') << static_cast<int>(c.Units)
127 << _T(',') << c.OtherEdge << _T(',') << c.Value << _T(')');
128}
130 return os << _T('(') << m.X << _T(',') << m.Y << _T('x') << m.Width <<
131 _T(',') << m.Height << _T(')');
132}
133inline tostream& operator <<(tostream& os, const TConstraint& c){
135 << _T(',') << static_cast<void*>(c.Output) << _T(',') << c.OrderedCombination[0]
136 << _T(',') << c.OrderedCombination[1] << _T(',') << c.OrderedCombination[2]
137 << c.OrderedCombination[3] << _T(',') << static_cast<void*>(c.Next) << _T(')');
138}
139
140struct TVariable {
141 int Value;
142 TConstraint* DeterminedBy; // 0 if variable is constant
143 bool Resolved;
144
145 TVariable() {Value = 0; DeterminedBy = nullptr; Resolved = false;}
146};
147inline tostream& operator <<(tostream& os, const TVariable& v){
148 return os << _T('(') << v.Value << _T(',') << static_cast<void*>(v.DeterminedBy)
149 << _T("->") << (v.Resolved? _T("Resolved"):_T("No Resolved")) << _T(')');
150}
151//
152/// The layout metrics represent four equations. For equations that are
153/// "absolute" or "as is" we don't add a constraint and just set the variable
154/// value directly(and mark the variable as constant); otherwise we produce an
155/// ordered linear combination from the equation and add a constraint
156//
157struct TChildMetrics {
158 public:
159 bool GeneratedConstraints;
160 TWindow* Child;
161 TLayoutMetrics Metrics;
162 TVariable Variables[4]; // x => 0, y => 1, right => 2, bottom => 3
163 TChildMetrics* Next;
164
165 TChildMetrics(TWindow& child, const TLayoutMetrics& metrics);
166};
167inline tostream& operator <<(tostream& os, const TChildMetrics& m){
168 return os << _T('(') << (m.GeneratedConstraints ? _T("true") : _T("false"))
169 << _T(',') << static_cast<void*>(m.Child) << _T(',') <<
170 m.Metrics << _T(',') << m.Variables[0] << _T(',') << m.Variables[1] << _T(',')
171 << m.Variables[2] << _T(',') << m.Variables[3] << _T(',') << static_cast<void*>(m.Next)
172 << _T(')');
173}
174
175/// @}
176
177//} // OWL namespace
178
179//----------------------------------------------------------------------------
180
181
182/// \class TLayoutWindow
183/// The following examples show how to set up various metrics using edge
184/// constraints. For purposes of illustration, these examples use a parent-child
185/// relationship, but you can also use a child-to-child (sibling) relationship. Keep
186/// in mind that moving the parent's origin (the left and top edges) also moves the
187/// child window.
188/// Example 1
189/// To create windows that can grow, set the top and left edges of the child
190/// window's boundaries in a fixed relationship to the top and left edges of the
191/// parent's window. In this example, if you expand the bottom and right edges of
192/// the parent, the child's bottom and right edges grow the same amount. Both the X
193/// and Y constraints are 10 units from the parent window's edges. Both the Width
194/// and Height constraints are 40 layout units from the parent window's edges.
195/// Specifically, Width (lmWidth) is 40 units to the left of the parent's right edge
196/// (lmLeftOf = lmSameAs + offset or sameas - 40).
197/// \image html bm211.BMP
198/// Use the following layout constraints:
199/// \code
200/// layoutmetrics.X.Set(lmLeft, lmRightOf, lmParent, lmLeft, 10);
201/// layoutmetrics.Y.Set(lmTop, lmBelow, lmParent, lmTop, 10);
202/// layoutmetrics.Width.Set(lmRight, lmLeftOf, lmParent, lmRight, 40);
203/// layoutmetrics.Height.Set(lmBottom, lmAbove, lmParent, lmBottom, 40);
204/// SetChildLayoutMetrics(*MyChildWindow, layoutMetrics);
205/// \endcode
206/// Example 2
207/// To create fixed-size and fixed-position windows, set the child's right edge a
208/// fixed distance from the parent's left edge, and the child's bottom edge a fixed
209/// distance from the parent's top edge. In this example, both the X and Y edge
210/// constraints are set to 10 and both the Width and Height edge constraints are set
211/// to 100.
212/// \image html bm212.BMP
213/// Use the following layout constraints:
214/// \code
215/// layoutmetrics.X.Set(lmLeft, lmRightOf, lmParent, lmLeft, 10);
216/// layoutmetrics.Y.Set(lmTop, lmBelow, lmParent, lmTop, 10);
217/// layoutmetrics.Width.Absolute(100);
218/// layoutmetrics.Height.Absolute(100);
219/// SetChildLayoutMetrics(*MyChildWindow, layoutMetrics);
220/// \endcode
221/// Example 3
222/// To create a fixed-size window that remains a constant distance from the parent's
223/// right corner, set the child's top and bottom edges a fixed distance (lmLayout
224/// unit or pixels) from the parent window's bottom. Also, set the child's left and
225/// right edges a fixed distance from the parent's right edge. In this example, both
226/// the Width and the Height edge constraints are set to 100 and the X and Y edge
227/// constraints are set to 10. In this case, the child window, which stays the same
228/// size, moves with the lower right corner of the parent.
229/// \image html bm213.BMP
230/// Use the following layout constraints:
231/// \code
232/// layoutmetrics.X.Set(lmRight, lmLeftOf, lmParent, lmRight, 10);
233/// layoutmetrics.Y.Set(lmBottom, lmAbove, lmParent, lmBottom, 10);
234/// layoutmetrics.Width.Absolute(100);
235/// layoutmetrics.Height.Absolute(100);
236/// SetChildLayoutMetrics(*MyChildWindow, layoutMetrics);
237/// \endcode
238/// Example 4
239/// To create a window in which the child's edges are a percentage of the parent's
240/// window, set the child's edges a percentage of the distance from the parent's
241/// edges. Specifically, the child's top and bottom edges are a percentage of the
242/// parent's bottom edge. The child's left and right edges are a percentage of the
243/// parent's right edge.
244/// If you resize the parent window, the child window will change size and origin
245/// (that is, the top and left edges will also change).
246/// \image html bm214.BMP
247/// Use the following layout constraints:
248/// \code
249/// layoutmetrics.X.Set(lmLeft, lmPercentOf, lmParent, lmRight, 33);
250/// layoutmetrics.Y.Set(lmTop, lmPercentOf, lmParent, lmBottom, 33);
251/// layoutmetrics.Width.Set(lmRight, lmPercentOf, lmParent, lmRight, 66);
252/// layoutmetrics.Height.Set(lmBottom, lmPercentOf, lmParent, lmBottom, 66);
253/// SetChildLayoutMetrics(*MyChildWindow, layoutMetrics);
254/// \endcode
255///
256
257
258//
259/// Creates a TLayoutWindow object with specified parent, window caption, and
260/// library ID.
261//
264 TModule* module)
265 : TWindow(parent, title, module)
266{
267 Init(parent, title, module);
268}
269
270//
271/// String-aware overload
272//
274 : TWindow(parent, title, module)
275{
276 Init(parent, title.c_str(), module);
277}
278
280{
281 // Initialize virtual bases, in case the derived-most used default ctor
282 //
283 TWindow::Init(parent, title, module);
284
285 NumChildMetrics = 0;
286 ChildMetrics = nullptr;
287 Constraints = nullptr;
288 Plan = nullptr;
289 PlanIsDirty = false;
290 ClientSize.cx = ClientSize.cy = 0;
291 Font = nullptr;
292 FontHeight = 0;
293
294 // Allocate variables for the parent's left, top, right, and bottom and
295 // mark them as resolved
296 //
297 Variables = new TVariable[4];
298 Variables[0].Resolved = true;
299 Variables[1].Resolved = true;
300 Variables[2].Resolved = true;
301 Variables[3].Resolved = true;
302}
303
304//
305/// Deletes variables and frees the child metrics and constraints.
306//
308{
309 delete[] Variables;
310
311 // Free the child metrics
312 //
313 for (TChildMetrics* childMetrics = ChildMetrics; childMetrics;) {
314 TChildMetrics* tmp = childMetrics;
316 delete tmp;
317 }
318
319 ChildMetrics = nullptr; //Bug fix: https://sourceforge.net/forum/message.php?msg_id=4186646
320
321
322 // Free the constraints
323 //
324 ClearPlan();
325 for (TConstraint* c = Constraints; c;) {
326 TConstraint* tmp = c;
327 c = c->Next;
328 delete tmp;
329 }
330
331 Constraints = nullptr; //Bug fix: https://sourceforge.net/forum/message.php?msg_id=4186646
332}
333
334static bool hasBorder(TWindow* win)
335{
336 // We consider it to have a border unless it is a pop-up or child window
337 // without WS_BORDER set
338 //
339 if ((win->GetWindowAttr().Style & (WS_CHILD|WS_POPUP)) && !(win->GetWindowAttr().Style & WS_BORDER))
340 return false;
341
342 else
343 return true;
344}
345
346//
347/// Causes the window to resize and position its children according to the specified metrics.
348/// If you change the layout metrics for a child window, then you should call Layout to have the
349/// changes take effect.
350//
352{
353 if (ChildMetrics) {
354 TChildMetrics* childMetrics;
355
356 GetFontHeight();
357
358 // Initialize the parent's variables
359 //
360 Variables[2].Value = ClientSize.cx - 1;
361 Variables[3].Value = ClientSize.cy - 1;
362 TRACEX(OwlLayout, 0, _T("Layout() ClientSize: ") << ClientSize);
363
364 if (hasBorder(this)) {
367
368 Variables[0].Value = -cxBorder;
369 Variables[1].Value = -cyBorder;
370 Variables[2].Value += cxBorder;
371 Variables[3].Value += cyBorder;
372 }
373 else {
374 Variables[0].Value = 0;
375 Variables[1].Value = 0;
376 }
377 TRACEX(OwlLayout, 1, _T("Layout() Variables: 0=>") << Variables[0] << _T(", 1=>") << Variables[1]<< _T(", 2=>") << Variables[2]<< _T(", 3=>") << Variables[3]);
378
379 // Rebuild layout plan if necessary
380 //
381 if (PlanIsDirty) {
382 PlanIsDirty = false;
383
384 for (childMetrics = ChildMetrics; childMetrics;
386 BuildConstraints(*childMetrics);
387 BuildPlan();
388 }
389
390 // Use the plan to calculate actual child window position values
391 //
392 ExecutePlan();
393
394#if !defined(OWL_NO_DEFERWINDOWPOS_LAYOUT)
395
396 // Find out how many windows we're dealing with
397 //
398 int numWindows = 0;
399 for (childMetrics = ChildMetrics; childMetrics; childMetrics = childMetrics->Next) {
400 TWindow* win = childMetrics->Child;
401 if (win->GetHandle())
402 numWindows++;
403 }
404
405 // Helper object to use 'DefWindowPos' API
406 //
407 TDeferWinPos dwp(numWindows);
408
409#endif
410
411 // Do actual resizing
412 //
413 for (childMetrics = ChildMetrics; childMetrics; childMetrics = childMetrics->Next) {
414 TWindow* win = childMetrics->Child;
415 TVariable* variables = childMetrics->Variables;
416 TRACEX(OwlLayout, 0, _T("Layout() variables: ") << variables[0] << _T(',') <<
417 variables[1] << _T(',') << variables[2] << _T(',') << variables[3]);
418
419 if (win->GetHandle()) {
420
421#if defined(OWL_NO_DEFERWINDOWPOS_LAYOUT)
422 win->SetWindowPos(
423 0,
424 variables[0].Value,
425 variables[1].Value,
426 variables[2].Value - variables[0].Value + 1,
427 variables[3].Value - variables[1].Value + 1,
429 );
430#else
431 dwp.DeferWindowPos(*win, 0,
432 variables[0].Value,
433 variables[1].Value,
434 variables[2].Value - variables[0].Value + 1,
435 variables[3].Value - variables[1].Value + 1,
437#endif
438 }
439 else {
440 win->GetWindowAttr().X = variables[0].Value;
441 win->GetWindowAttr().Y = variables[1].Value;
442 win->GetWindowAttr().W = variables[2].Value - variables[0].Value + 1;
443 win->GetWindowAttr().H = variables[3].Value - variables[1].Value + 1;
444 }
445 }
446 }
447}
448//
449/// Sets the metrics for the window and removes any existing ones. Set the metrics
450/// as shown:
451/// \code
452/// layoutMetrics->X.Absolute(lmLeft, 10);
453/// layoutMetrics->Y.Absolute(lmTop, 10);
454/// layoutMetrics->Width.Set(lmWidth, lmRightOf, GetClientWindow(), lmWidth, -40);
455/// layoutMetrics->Height.Set(lmHeight, lmRightOf, GetClientWindow(), lmHeight,
456/// -40);
457/// \endcode
458/// Then call SetChildLayoutMetrics to associate them with the position of the child
459/// window:
460/// \code
461/// SetChildLayoutMetrics(* MyChildWindow, * layoutMetrics);
462/// \endcode
463//
464void
466{
469
470 PlanIsDirty = true;
471
472 if (ChildMetrics) {
473
474 // See if we already have metrics for the child
475 //
476 for (TChildMetrics* childMetrics = ChildMetrics; childMetrics;
477 childMetrics = childMetrics->Next) {
478 if (childMetrics->Child == &child) {
479 childMetrics->Child = &child;
480 childMetrics->Metrics = metrics;
481
482 // Get rid of the old constraints
483 //
484 RemoveConstraints(*childMetrics);
485 return;
486 }
487 }
488 }
489
490 TChildMetrics* childMetrics = new TChildMetrics(child, metrics);
491 childMetrics->Next = ChildMetrics;
492 ChildMetrics = childMetrics;
493 NumChildMetrics++;
494}
495
496//
497/// Gets the layout metrics of the child window.
498//
499bool
501{
503
504 TChildMetrics* childMetrics = GetChildMetrics(child);
505 if (childMetrics) {
506 metrics = childMetrics->Metrics;
507 return true;
508 }
509 return false;
510}
511
512//
513/// Functional-style overload
514/// Throws TXOwl if metrics are not found for the given child window.
515//
517{
518 auto m = TLayoutMetrics{};
519 auto r = GetChildLayoutMetrics(child, m);
520 if (!r) throw TXOwl{_T("TLayoutWindow::GetChildLayoutMetrics failed")};
521 return m;
522}
523
524//
525/// Removes child (layout) metrics for a given child (if found) and updates
526/// other children as necessary
527//
528bool
530{
532
533 for (TChildMetrics** childMetrics = &ChildMetrics; *childMetrics;
534 childMetrics = &(*childMetrics)->Next) {
535 if ((*childMetrics)->Child == &child) {
536
537 // Unlink target metrics from list & clean up a bit
538 //
539 TChildMetrics* tmp = *childMetrics;
540 *childMetrics = tmp->Next;
541 RemoveConstraints(*tmp);
542 NumChildMetrics--;
543
544 // Update other child metrics now that removed metric is gone
545 // Check for case where new relWin is lmParent and adjust other edge
546 // to be what removed window was using. If an 'edge' is really a size,
547 // then give up & just leave it asis. If the removed window had an edge
548 // that was really a size, then use the other constraint in that
549 // dimension (X or Y)
550 //
551 for (TChildMetrics* cm = ChildMetrics; cm; cm = cm->Next) {
552 if (cm->Metrics.X.RelWin == &child) {
553 RemoveConstraints(*cm);
554 cm->Metrics.X.RelWin = tmp->Metrics.X.RelWin;
555 if (cm->Metrics.X.RelWin == lmParent)
556 cm->Metrics.X.OtherEdge = tmp->Metrics.X.OtherEdge;
557 }
558 if (cm->Metrics.Y.RelWin == &child) {
559 RemoveConstraints(*cm);
560 cm->Metrics.Y.RelWin = tmp->Metrics.Y.RelWin;
561 if (cm->Metrics.Y.RelWin == lmParent)
562 cm->Metrics.Y.OtherEdge = tmp->Metrics.Y.OtherEdge;
563 }
564 if (cm->Metrics.Width.RelWin == &child) {
565 RemoveConstraints(*cm);
566 if (cm->Metrics.Width.MyEdge == lmWidth)
567 cm->Metrics.Width.Relationship = lmAsIs;
568 else {
569 if (tmp->Metrics.Width.MyEdge == lmWidth) {
570 cm->Metrics.Width.RelWin = tmp->Metrics.X.RelWin;
571 if (cm->Metrics.Width.RelWin == lmParent)
572 cm->Metrics.Width.OtherEdge = tmp->Metrics.X.OtherEdge;
573 }
574 else {
575 cm->Metrics.Width.RelWin = tmp->Metrics.Width.RelWin;
576 if (cm->Metrics.Width.RelWin == lmParent)
577 cm->Metrics.Width.OtherEdge = tmp->Metrics.Width.OtherEdge;
578 }
579 }
580 }
581 if (cm->Metrics.Height.RelWin == &child) {
582 RemoveConstraints(*cm);
583 if (cm->Metrics.Height.MyEdge == lmHeight)
584 cm->Metrics.Height.Relationship = lmAsIs;
585 else {
586 if (tmp->Metrics.Height.MyEdge == lmHeight) {
587 cm->Metrics.Height.RelWin = tmp->Metrics.Y.RelWin;
588 if (cm->Metrics.Height.RelWin == lmParent)
589 cm->Metrics.Height.OtherEdge = tmp->Metrics.Y.OtherEdge;
590 }
591 else {
592 cm->Metrics.Height.RelWin = tmp->Metrics.Height.RelWin;
593 if (cm->Metrics.Height.RelWin == lmParent)
594 cm->Metrics.Height.OtherEdge = tmp->Metrics.Height.OtherEdge;
595 }
596 }
597 }
598 }
599
600 // Finaly, delete target metrics
601 //
602 delete tmp;
603 return true;
604 }
605 }
606 return false;
607}
608
609//----------------------------------------------------------------------------
610
611//
612/// Responds to a change in size by calling Layout() to resize the window.
613//
614void
616{
618
619 if (sizeType != SIZE_MINIMIZED &&
620 //sizeType != SIZE_MAXIMIZED && // fix-bug was bug or not ????
621 size != ClientSize) {
622 ClientSize = size;
623 Layout();
624 }
625}
626
628{
629 // The default processing may return NULL, even after a previous WM_SETFONT message with a
630 // non-NULL value. So rather than rely on the default processing, we cache the font in EvSetFont
631 // and return our cached value here. A reliable return value from WM_GETFONT is needed for the
632 // layout machinery. See TLayoutWindow::GetFontHeight.
633 //
634 return Font ? Font : TWindow::EvGetFont();
635}
636
637//
638/// Updates the window layout, if "redraw" is true.
639/// The layout may depend on the given font metrics. See TMeasurementUnits::lmLayoutUnits.
640/// So if you pass "false", remember to update the layout, e.g. by explicitly calling Layout.
641//
643{
645 if (f != Font)
646 {
647 // Cache the font setting, so that we can reliably return the font in the WM_GETFONT message.
648 // See EvGetFont.
649 //
650 Font = f;
651 if (redraw)
652 Layout();
653 }
654}
655
656//
657/// Overrides TWindow virtual to allow cleanup of child metrics.
658//
659void
665
666//----------------------------------------------------------------------------
667
668//
669//
670//
671TChildMetrics*
672TLayoutWindow::GetChildMetrics(const TWindow& child)
673{
675
676 for (TChildMetrics* childMetrics = ChildMetrics; childMetrics;
678 if (childMetrics->Child == &child)
679 return childMetrics;
680
681 return nullptr;
682}
683
684//
685//
686//
687void
688TLayoutWindow::ExecutePlan()
689{
690 for (TConstraint* c = Plan; c; c = c->Next){
691 c->Output->Value = c->Evaluate();
692 TRACEX(OwlLayout, 1, _T("ExecutePlan() c->Output => ") << *c->Output);
693 }
694}
695
696//
697//
698//
699void
700TLayoutWindow::ClearPlan()
701{
702 if (Plan) {
703 // Move all constraints that were in the plan back to the list of
704 // constraints
705 //
706 if (!Constraints)
707 Constraints = Plan;
708
709 else {
710 TConstraint* c;
711 for (c = Constraints; c->Next; c = c->Next)
712 ;
713
714 c->Next = Plan;
715 }
716
717 Plan = nullptr;
718 }
719}
720
721//
722//
723//
724void
725TLayoutWindow::BuildPlan()
726{
727 TChildMetrics* childMetrics;
728 TConstraint* lastInPlan = 0;
729
730 ClearPlan();
731
732 // Mark all variables that aren't determined by a constraint as resolved
733 //
734 for (childMetrics = ChildMetrics; childMetrics; childMetrics = childMetrics->Next) {
735 TVariable* variable = childMetrics->Variables;
736 variable->Resolved = variable->DeterminedBy ? false : true;
737 variable++;
738 variable->Resolved = variable->DeterminedBy ? false : true;
739 variable++;
740 variable->Resolved = variable->DeterminedBy ? false : true;
741 variable++;
742 variable->Resolved = variable->DeterminedBy ? false : true;
743 TRACEX(OwlLayout, 1, _T("BuildPlan() variables: ") << childMetrics->Variables[0]
744 << _T(',') << childMetrics->Variables[1] << _T(',') << childMetrics->Variables[2]
745 << _T(',') << childMetrics->Variables[3]);
746 }
747
748 // Uses local propagation as much as possible (because it's fast)
749 //
750 // If cycles exist then we will end up with constraints that haven't been
751 // added to the plan. we convert the remaining constraints into simultaneous
752 // linear equations which we solve using Gaussian elimination
753 //
754 // Look for constraints that have all their input variables resolved and
755 // append them to the plan
756 //
757 for (bool foundOne = true; foundOne;) {
758 TConstraint* c = Constraints;
759 TConstraint* previous = 0;
760
761 foundOne = false;
762
763 while (c) {
764 TRACEX(OwlLayout, 1, _T("BuildPlan() *c ") << *c);
765 if (c->IsResolved()) {
766 TConstraint* resolved = c;
767
768 c->Output->Resolved = true;
769 foundOne = true;
770
771 // Extract the constraint from the list of constraints
772 //
773 if (previous)
774 previous->Next = c->Next;
775
776 else
777 Constraints = c->Next;
778
779 c = c->Next;
780
781 // Append the constraint to the plan
782 //
783 if (lastInPlan)
784 lastInPlan->Next = resolved;
785
786 else
787 Plan = resolved;
788
790 }
791 else {
792 previous = c;
793 c = c->Next;
794 }
795 }
796 }
797
798 // Gaussian elimination not currently supported--give up
799 //
800 if (Constraints)
802}
803
804//
805//
806//
807static int
808findInput(TConstraint* simplify, TVariable* input)
809{
810 for (int i = 0; i < 3; i++)
811 if (simplify->Inputs[i] == input)
812 return i;
813
814 return -1;
815}
816
817//
818// simplify constraint "simplify" by substituting constraint "_using"
819//
820// we do this when the two constraints are defined in terms of each other
821// 1. the output of "simplify" is an input of "_using"
822// 2. the output of "_using" is an input of "simplify"
823//
824// we do this to avoid a layout cycle
825//
826// "output" is the output variable for constraint "_using"
827//
828static
829void
830Simplify(TConstraint* simplify, TVariable* output, TConstraint* _using)
831{
832 if (!simplify)
833 return;
834
835 int outputOfSimplify = findInput(_using, simplify->Output); // check #1
836 int target = findInput(simplify, output); // check #2
837
838 if (outputOfSimplify != -1 && target != -1) {
839 int commonInputs[3];
840 int numInputsOfUsing = _using->NumActualInputs();
841 int i;
842
843 // Count how many inputs are common between "simplify" and "_using"
844 //
845 for (i = 0; i < numInputsOfUsing; i++)
846 commonInputs[i] = findInput(simplify, _using->Inputs[i]);
847
848 // Since constraints only have room for 3 inputs we can not simplify if the
849 // total number of the existing inputs minus the input we are going to back
850 // substitute for plus the number of inputs added by "_using" (i.e. inputs
851 // not common between the two constraints) exceeds 3
852 //
853 int numInputsOfSimplify = simplify->NumActualInputs() - 1;
854 int newInputs = 0;
855
856 // Compute the number of additional inputs contributed by "_using"
857 //
858 for (i = 0; i < numInputsOfUsing; i++)
859 if (commonInputs[i] == -1 && i != outputOfSimplify)
860 newInputs++;
861
863 return;
864
865 TFixedPoint m = simplify->OrderedCombination[target];
866
867 // Adjust the constant part
868 //
869 simplify->OrderedCombination[3] += m * _using->OrderedCombination[3];
870
871 // Merge the common inputs
872 //
873 for (i = 0; i < numInputsOfUsing; i++)
874 if (commonInputs[i] != -1)
875 simplify->OrderedCombination[commonInputs[i]] +=
876 m * _using->OrderedCombination[i];
877
878 simplify->Inputs[target] = nullptr; // input has been back substituted out
879 TRACEX(OwlLayout, 1, _T("Simplify() simplify->Inputs[") << target << _T("]=> 0"));
880
881 // If necessary shift the inputs following "output" (and their associated
882 // mutiplier) left by one...
883 //
884 for (i = target + 1; i < 3; i++)
885 if (simplify->Inputs[i]) {
886 simplify->Inputs[i - 1] = simplify->Inputs[i];
887 simplify->Inputs[i] = nullptr;
888 TRACEX(OwlLayout, 1, _T("Simplify() simplify->Inputs[") << i << _T(" - 1]=> ") <<
889 *simplify->Inputs[i - 1] << _T(", simplify->Inputs[") << i << _T("]=> 0"));
890 simplify->OrderedCombination[i - 1] = simplify->OrderedCombination[i];
891 }
892
893 // Add the new inputs
894 //
895 for (i = 0; i < numInputsOfUsing; i++)
896 if (commonInputs[i] == -1 && i != outputOfSimplify) {
897 simplify->Inputs[numInputsOfSimplify] = _using->Inputs[i];
898 TRACEX(OwlLayout, 1, _T("Simplify() simplify->Inputs[") << numInputsOfSimplify
899 << _T("]=> ") << *simplify->Inputs[numInputsOfSimplify]);
900 simplify->OrderedCombination[numInputsOfSimplify] =
901 m * _using->OrderedCombination[i];
903 }
904
905 // Now scale things back so that the output of "simplify" is 1
906 //
907 TFixedPoint f = 1 - m;
908
909 simplify->OrderedCombination[3] /= f;
910 for (i = 0; i < numInputsOfSimplify; i++)
911 simplify->OrderedCombination[i] /= f;
912 }
913}
914
915//
916//
917//
918void
919TLayoutWindow::AddConstraint(TChildMetrics& metrics,
920 TLayoutConstraint* c,
921 TWhichConstraint whichConstraint)
922{
923 int index;
924 TVariable* output;
925 TConstraint* result = new TConstraint;
926
927 // Set the output variable
928 //
929 if (whichConstraint == XConstraint && metrics.Metrics.X.MyEdge == lmRight){
930 output = &metrics.Variables[2];
931 TRACEX(OwlLayout, 1, _T("AddConstraint() output =>") << *output);
932 }
933
934 else if (whichConstraint == YConstraint && metrics.Metrics.Y.MyEdge == lmBottom){
935 output = &metrics.Variables[3];
936 TRACEX(OwlLayout, 1, _T("AddConstraint() output =>") << *output);
937 }
938
939 else{
940 output = &metrics.Variables[whichConstraint];
941 TRACEX(OwlLayout, 1, _T("AddConstraint() output =>") << *output);
942 }
943
944 // Set the inputs based on the edge
945 //
946 if ((static_cast<int>(c->Relationship) != lmAbsolute) && (static_cast<int>(c->Relationship) != lmAsIs)) {
947 TVariable* variables;
948
949 if (c->RelWin == lmParent){
950 variables = Variables;
951 TRACEX(OwlLayout, 1, _T("AddConstraint() variables =>") << *variables);
952 }
953
954 else {
955 TChildMetrics* relWinMetrics = GetChildMetrics(*c->RelWin);
956 if (!relWinMetrics) {
957 delete result;
959 }
960 variables = relWinMetrics->Variables;
961 TRACEX(OwlLayout, 1, _T("AddConstraint() variables =>") << *variables);
962 }
963
964 switch (c->OtherEdge) {
965 case lmLeft:
966 case lmTop:
967 case lmRight:
968 case lmBottom:
969 result->Inputs[0] = &variables[c->OtherEdge];
970 TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[0]=> ") <<
971 *result->Inputs[0]);
972 break;
973
974 case lmWidth:
975 case lmHeight:
976 // width => right - left + 1
977 // height => bottom - top + 1
978 //
979 result->Inputs[0] = &variables[c->OtherEdge - lmWidth+lmRight];
980 result->Inputs[1] = &variables[c->OtherEdge - lmWidth+lmLeft];
981 TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[0]=> ") <<
982 *result->Inputs[0] << _T(", result->Inputs[1]=> ") << *result->Inputs[1]);
983 result->OrderedCombination[1] = -1;
984 result->OrderedCombination[3] = 1;
985 break;
986
987 case lmCenter:
988 switch (whichConstraint) {
989 case XConstraint:
990 case WidthConstraint:
991 // Center => (left + right) / 2
992 //
993 result->Inputs[0] = &variables[0];
994 result->Inputs[1] = &variables[2];
995 TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[0]=> ") <<
996 *result->Inputs[0] << _T(", result->Inputs[1]=> ") << *result->Inputs[1]);
997 break;
998
999 case YConstraint:
1000 case HeightConstraint:
1001 // Center => (top + bottom) / 2
1002 //
1003 result->Inputs[0] = &variables[1];
1004 result->Inputs[1] = &variables[3];
1005 TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[0]=> ") <<
1006 *result->Inputs[0] << _T(", result->Inputs[1]=> ") << *result->Inputs[1]);
1007 break;
1008 }
1009 result->OrderedCombination[0] = result->OrderedCombination[1] = TFixedPoint(1,2);
1010 break;
1011 }
1012 }
1013
1014 // Now store the constant term as the last of the ordered linear combination
1015 //
1016 // We must do this after setting the inputs
1017 //
1018 // NOTE: we cannot assume that the constant part is 0, because it might have
1019 // been set above
1020 //
1021 switch (c->Relationship) {
1022 case lmAsIs:
1023 result->OrderedCombination[3] += whichConstraint == WidthConstraint ?
1024 metrics.Child->GetWindowAttr().W :
1025 metrics.Child->GetWindowAttr().H;
1026 break;
1027
1028 case lmAbsolute:
1029 case lmSameAs:
1030 case lmBelow:
1031 case lmAbove: {
1032 int value = c->Units == lmPixels ? c->Value : LayoutUnitsToPixels(c->Value);
1033
1034 if (c->Relationship == lmAbove)
1035 value = -value - 1;
1036
1037 else if (c->Relationship == lmBelow)
1038 value++;
1039
1040 result->OrderedCombination[3] += value;
1041 break;
1042 }
1043
1044 case lmPercentOf:
1045 TFixedPoint percent = c->Percent;
1046
1047 percent /= 100;
1048 result->OrderedCombination[0] *= percent;
1049 result->OrderedCombination[3] *= percent;
1050
1051 switch (c->OtherEdge) {
1052 case lmWidth:
1053 case lmHeight:
1054 case lmCenter:
1055 result->OrderedCombination[1] *= percent;
1056 break;
1057 }
1058 break;
1059 }
1060
1061 // Now handle cases where the left hand side is width, height, or center
1062 //
1063 // This must be done last...
1064 //
1065 if (result->Inputs[0])
1066 index = result->Inputs[1] ? 2 : 1;
1067
1068 else
1069 index = 0;
1070
1071 switch (c->MyEdge) {
1072 case lmWidth:
1073 if (whichConstraint == XConstraint || metrics.Metrics.X.MyEdge == lmRight) {
1074 // Rewrite "right - left + 1 = " as "left = right - (...) + 1"
1075 //
1076 for (int i = 0; i < index; i++)
1077 result->OrderedCombination[i] = -result->OrderedCombination[i];
1078
1079 result->OrderedCombination[3] = -result->OrderedCombination[3];
1080 (result->OrderedCombination[3])++;
1081 result->Inputs[index] = &(metrics.Variables[2]);
1082 TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[") <<
1083 index << _T("]=> ") << *result->Inputs[index]);
1084
1085 if (whichConstraint == WidthConstraint){
1086 output = &(metrics.Variables[XConstraint]);
1087 TRACEX(OwlLayout, 1, _T("AddConstraint() output=> ") << *output);
1088 }
1089 }
1090 else {
1091 // Rewrite "right - left + 1 = " as "right = left + ... - 1"
1092 //
1093 result->Inputs[index] = &(metrics.Variables[0]);
1094 TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[") <<
1095 index << _T("]=> ") << *result->Inputs[index]);
1096 (result->OrderedCombination[3])--;
1097
1098 Simplify(metrics.Variables[0].DeterminedBy, output, result);
1099 }
1100 break;
1101
1102 case lmHeight:
1103 if (whichConstraint == YConstraint || metrics.Metrics.Y.MyEdge == lmBottom) {
1104 // Rewrite "bottom - top + 1 = " as "top = bottom - (...) + 1"
1105 //
1106 for (int i = 0; i < index; i++)
1107 result->OrderedCombination[i] = -(result->OrderedCombination[i]);
1108
1109 result->OrderedCombination[3] = -(result->OrderedCombination[3]);
1110 (result->OrderedCombination[3])++;
1111 result->Inputs[index] = &(metrics.Variables[3]);
1112 TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[") <<
1113 index << _T("]=> ") << *result->Inputs[index]);
1114
1115 if (whichConstraint == HeightConstraint){
1116 output = &metrics.Variables[YConstraint];
1117 TRACEX(OwlLayout, 1, _T("AddConstraint() lmHeight: output =>") << *output);
1118 }
1119 }
1120 else {
1121 // Rewrite "bottom - top + 1 = " as "bottom = top + ... - 1"
1122 //
1123 result->Inputs[index] = &metrics.Variables[1];
1124 TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[") <<
1125 index << _T("]=> ") << *result->Inputs[index]);
1126 result->OrderedCombination[3]--;
1127 TRACEX(OwlLayout, 1, _T("AddConstraint() lmHeight: result->Inputs[") <<
1128 index << _T("] =>") << *result->Inputs[index]);
1129
1130 Simplify(metrics.Variables[1].DeterminedBy, output, result);
1131 }
1132 break;
1133
1134 case lmCenter:
1135 TVariable* input = &metrics.Variables[0]; // left
1136
1137 switch (whichConstraint) {
1138 case XConstraint:
1139 // Rewrite "(left + right) / 2 = " as "left = -right + 2 * (...)"
1140 //
1141 input += 2; // right
1142 TRACEX(OwlLayout, 1, _T("AddConstraint() XConstraint: input =>") << *input);
1143 break;
1144
1145 case YConstraint:
1146 // Rewrite "(top + bottom) / 2 = " as "top = -bottom + 2 * (...)"
1147 //
1148 input += 3; // bottom
1149 TRACEX(OwlLayout, 1, _T("AddConstraint() YConstraint: input =>") << *input);
1150 break;
1151
1152 case WidthConstraint:
1153 // Rewrite "(left + right) / 2 = " as "right = -left + 2 * (...)" or
1154 // "left = -right + 2 * (...)" depending on whether the "x" constraint
1155 // is left or right
1156 //
1157 if (metrics.Metrics.X.MyEdge == lmRight) {
1158 input += 2; // right
1159 output = &metrics.Variables[XConstraint];
1160 TRACEX(OwlLayout, 1, _T("AddConstraint() WidthConstraint: input =>") <<
1161 *input << _T(",output => ") << *output);
1162 }
1163 break;
1164
1165 case HeightConstraint:
1166 // Rewrite "(top + bottom) / 2 = " as "bottom = -top + 2 * (...)" or
1167 // "top = -bottom + 2 * (...)" depending on whether the "y" constraint
1168 // is top or bottom
1169 //
1170 if (metrics.Metrics.Y.MyEdge != lmBottom)
1171 input++; // top
1172
1173 else {
1174 input += 3; // bottom
1175 output = &metrics.Variables[XConstraint];
1176 }
1177 TRACEX(OwlLayout, 1, _T("AddConstraint() HeightConstraint: input =>") <<
1178 *input << _T(",output => ") << *output);
1179 break;
1180 }
1181 result->Inputs[index] = input;
1182 TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[") << index <<
1183 _T("]=> ") << *result->Inputs[index]);
1184 for (int i = 0; i < index; i++)
1185 result->OrderedCombination[i] <<= 1;
1186
1187 result->OrderedCombination[3] <<= 1;
1188 result->OrderedCombination[index] = -1;
1189 break;
1190 }
1191
1192 // Now set the constraint output
1193 //
1194 output->DeterminedBy = result;
1195 result->Output = output;
1196
1197 // Add the constraint to the list of constraints
1198 //
1199 result->Next = Constraints;
1200 Constraints = result;
1201}
1202
1203//
1204//
1205//
1206void
1207TLayoutWindow::RemoveConstraints(TChildMetrics& childMetrics)
1208{
1209 TVariable* variable = childMetrics.Variables;
1210
1211 PlanIsDirty = true;
1212 ClearPlan();
1213 childMetrics.GeneratedConstraints = false;
1214
1215 for (int i = 0; i < 4; i++) {
1216 TConstraint* constraint = variable->DeterminedBy;
1217
1218 variable->Value = 0;
1219
1220 if (constraint) {
1221
1222 // Remove the constraint from the list of constraints
1223 //
1224 if (Constraints == constraint)
1225 Constraints = constraint->Next;
1226
1227 else
1228 for (TConstraint* c = Constraints; c->Next; c = c->Next)
1229 if (c->Next == constraint) {
1230 c->Next = constraint->Next;
1231 break;
1232 }
1233
1234 delete constraint;
1235 variable->DeterminedBy = nullptr;
1236 }
1237
1238 variable++;
1239 }
1240}
1241
1242//
1243//
1244//
1245void
1246TLayoutWindow::BuildConstraints(TChildMetrics& childMetrics)
1247{
1248 // NOTE: to get uniformity we consider the window edges to sit on pixels
1249 // and not between pixels. so our idea of right is left + width - 1
1250 // and not left + width
1251 //
1252 if (!childMetrics.GeneratedConstraints) {
1253 TLayoutConstraint* c = &childMetrics.Metrics.X;
1254 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Metrics.X =>") << *c);
1255
1256 childMetrics.GeneratedConstraints = true;
1257
1258 // "x" can be one of: left, right, center
1259 //
1260 if (c->Relationship == lmAsIs){
1261 if (c->MyEdge == lmLeft){
1262 childMetrics.Variables[0].Value = childMetrics.Child->GetWindowAttr().X;
1263 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[0] =>") <<
1264 childMetrics.Variables[0]);
1265 }
1266 else{
1267 childMetrics.Variables[2].Value = childMetrics.Child->GetWindowAttr().X +
1268 childMetrics.Child->GetWindowAttr().W - 1;
1269 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[2] =>") <<
1270 childMetrics.Variables[2]);
1271 }
1272 }
1273 else if (c->Relationship == lmAbsolute && c->MyEdge != lmCenter) {
1274 int value = c->Units == lmPixels ? c->Value : LayoutUnitsToPixels(c->Value);
1275
1276 childMetrics.Variables[c->MyEdge == lmLeft ? 0 : 2].Value = value;
1277 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[") <<
1278 (c->MyEdge == lmLeft ? 0 : 2)<< _T("] =>") << childMetrics.Variables[c->MyEdge == lmLeft ? 0 : 2]);
1279 }
1280 else {
1281 AddConstraint(childMetrics, c, XConstraint);
1282 TRACEX(OwlLayout, 1, _T("BuildConstraints() after Add constraints childMetrics.Metrics.X =>") << *c);
1283 }
1284
1285 // "y" can be one of: top, bottom, center
1286 //
1287 c = &childMetrics.Metrics.Y;
1288 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Metrics.Y =>") << *c);
1289
1290 if (c->Relationship == lmAsIs){
1291 if (c->MyEdge == lmTop){
1292 childMetrics.Variables[1].Value = childMetrics.Child->GetWindowAttr().Y;
1293 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[1] =>") <<
1294 childMetrics.Variables[1]);
1295 }
1296 else{
1297 childMetrics.Variables[3].Value = childMetrics.Child->GetWindowAttr().Y +
1298 childMetrics.Child->GetWindowAttr().H - 1;
1299 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[3] =>") <<
1300 childMetrics.Variables[3]);
1301 }
1302 }
1303 else if (c->Relationship == lmAbsolute && c->MyEdge != lmCenter) {
1304 int value = c->Units == lmPixels ? c->Value : LayoutUnitsToPixels(c->Value);
1305
1306 childMetrics.Variables[c->MyEdge == lmTop ? 1 : 3].Value = value;
1307 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[") <<
1308 (c->MyEdge == lmTop ? 1 : 3) << _T("] =>") <<
1309 childMetrics.Variables[c->MyEdge == lmTop ? 1 : 3]);
1310 }
1311 else {
1312 AddConstraint(childMetrics, c, YConstraint);
1313 TRACEX(OwlLayout, 1, _T("BuildConstraints() after AddConstraint childMetrics.Metrics.Y =>") << *c);
1314 }
1315
1316 // "width" can be one of: width, right, center
1317 //
1318 c = &childMetrics.Metrics.Width;
1319 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Metrics.Width =>") << *c);
1320
1321 if (c->MyEdge == lmRight && (c->Relationship == lmAsIs || c->Relationship == lmAbsolute)){
1322 childMetrics.Variables[2].Value = c->Relationship == lmAsIs ?
1323 childMetrics.Child->GetWindowAttr().X +
1324 childMetrics.Child->GetWindowAttr().W - 1 :
1325 c->Units == lmPixels ? c->Value : LayoutUnitsToPixels(c->Value);
1326 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[2] =>") <<
1327 childMetrics.Variables[2]);
1328 }
1329 else{
1330 AddConstraint(childMetrics, c, WidthConstraint);
1331 TRACEX(OwlLayout, 1, _T("BuildConstraints() after AddConstraint childMetrics.Metrics.Width =>") << *c);
1332 }
1333
1334 // "height" can be one of: height, bottom, center
1335 //
1336 c = &childMetrics.Metrics.Height;
1337 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Metrics.Height =>") << *c);
1338
1339 if (c->MyEdge == lmBottom && (c->Relationship == lmAsIs || c->Relationship == lmAbsolute)){
1340 childMetrics.Variables[3].Value = c->Relationship == lmAsIs ?
1341 childMetrics.Child->GetWindowAttr().Y +
1342 childMetrics.Child->GetWindowAttr().H - 1 :
1343 c->Units == lmPixels ? c->Value : LayoutUnitsToPixels(c->Value);
1344 TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[3] =>") << childMetrics.Variables[3]);
1345 }
1346 else{
1347 AddConstraint(childMetrics, c, HeightConstraint);
1348 TRACEX(OwlLayout, 1, _T("BuildConstraints() after AddConstraint childMetrics.Metrics.Height =>") << *c);
1349 }
1350 }
1351}
1352
1353//
1354//
1355//
1356int
1357TLayoutWindow::LayoutUnitsToPixels(int value)
1358{
1359 const long UnitsPerEM = 8;
1360
1361 return int((long(value) * FontHeight + UnitsPerEM / 2) / UnitsPerEM);
1362}
1363
1364//
1365//
1366//
1367void
1368TLayoutWindow::GetFontHeight()
1369{
1370 HFONT hFont = 0;
1371 if (GetHandle())
1373
1374 // NOTE: It's fairly customary to return NULL to the WM_GETFONT
1375 // request - specially when the window is using the system
1376 // font - Hence, we'll default to the system font too...
1377 //
1378 if (!hFont)
1380
1381 CHECK(hFont);
1382 TFont font(hFont);
1383 FontHeight = font.GetHeight();
1384}
1385
1386
1388
1389#if OWL_PERSISTENT_STREAMS
1390
1391//
1392// Read the object from the persistent stream.
1393//
1394void*
1395TLayoutWindow::Streamer::Read(ipstream&, uint32) const
1396{
1397 return GetObject();
1398}
1399
1400//
1401// Write the object into a persistent stream.
1402//
1403void
1404TLayoutWindow::Streamer::Write(opstream&) const
1405{
1406}
1407#endif
1408
1409
1410//----------------------------------------------------------------------------
1411
1412//
1413//
1414//
1415TChildMetrics::TChildMetrics(TWindow& child,
1416 const TLayoutMetrics& metrics)
1417:
1418 Child(&child),
1419 Metrics(metrics)
1420{
1421 GeneratedConstraints = false;
1422 Next = nullptr;
1423}
1424
1425//
1426//
1427//
1428TConstraint::TConstraint()
1429{
1430 Inputs[0] = Inputs[1] = Inputs[2] = nullptr;
1431 OrderedCombination[0] = OrderedCombination[1] = OrderedCombination[2] = 1;
1432
1433 // NOTE: OrderedCombination[3] was initialized to 0 by the TFixedPoint ctor
1434 //
1435 Output = nullptr;
1436}
1437
1438//
1439//
1440//
1441bool
1442TConstraint::IsResolved()
1443{
1444 return (!Inputs[0] || Inputs[0]->Resolved) &&
1445 (!Inputs[1] || Inputs[1]->Resolved) &&
1446 (!Inputs[2] || Inputs[2]->Resolved);
1447}
1448
1449//
1450//
1451//
1452int
1453TConstraint::Evaluate()
1454{
1455 TFixedPoint value = OrderedCombination[3]; // initialize to constant part
1456 TRACEX(OwlLayout, 1, _T("Evaluate() value ") << value);
1457
1458 if (Inputs[0]) {
1459 value += OrderedCombination[0] * Inputs[0]->Value;
1460 TRACEX(OwlLayout, 1, _T("Evaluate() value ") << value <<
1461 _T(", OrderedCombination[0] => ") << OrderedCombination[0] <<
1462 _T(", Inputs[0]->Value => ") << Inputs[0]->Value);
1463 }
1464
1465 if (Inputs[1]) {
1466 value += OrderedCombination[1] * Inputs[1]->Value;
1467 TRACEX(OwlLayout, 1, _T("Evaluate() value ") << value <<
1468 _T(", OrderedCombination[1] => ") << OrderedCombination[1] <<
1469 _T(", Inputs[1]->Value => ") << Inputs[1]->Value);
1470 }
1471
1472 if (Inputs[2]) {
1473 value += OrderedCombination[2] * Inputs[2]->Value;
1474 TRACEX(OwlLayout, 1, _T("Evaluate() value ") << value <<
1475 _T(", OrderedCombination[2] => ") << OrderedCombination[1] <<
1476 _T(", Inputs[2]->Value => ") << Inputs[2]->Value);
1477 }
1478 return value;
1479}
1480
1481//
1482//
1483//
1484int
1485TConstraint::NumActualInputs()
1486{
1487 int i;
1488 for (i = 0; i < 3; i++)
1489 if (!Inputs[i])
1490 break;
1491
1492 return i;
1493}
1494
1495//----------------------------------------------------------------------------
1496
1497//
1498/// Creates a TLayoutMetrics object and initializes the object. It sets the units
1499/// for the child and parent window to the specified layout units, and the
1500/// relationship between the two windows to what is defined in ImAsIs (of
1501/// TRelationship). TLayoutMetrics sets the following default values:
1502/// \code
1503/// X.RelWin = 0;
1504/// X.MyEdge = lmLeft;
1505/// X.Relationship = lmAsIs;
1506/// X.Units = lmLayoutUnits;
1507/// X.Value = 0;
1508/// Y.RelWin = 0;
1509/// Y.MyEdge = lmTop;
1510/// Y.Relationship = lmAsIs;
1511/// Y.Units = lmLayoutUnits;
1512/// Y.Value = 0;
1513/// Width.RelWin = 0;
1514/// Width.MyEdge = lmWidth;
1515/// Width.Relationship = lmAsIs;
1516/// Width.Units = lmLayoutUnits;
1517/// Width.Value = 0;
1518/// Height.RelWin = 0;
1519/// Height.MyEdge = lmHeight;
1520/// Height.Relationship = lmAsIs;
1521/// Height.Units = lmLayoutUnits;
1522/// Height.Value = 0;
1523/// \endcode
1524/// The following program creates two child windows and a frame into which you can
1525/// add layout constraints.
1526/// \code
1527/// #include <owl/owl.h>
1528/// #include <owl/framewin.h>
1529/// #include <owl/applicat.h>
1530/// #include <owl/layoutwi.h>
1531/// #include <owl/decorate.h>
1532/// #include <owl/decmdifr.h>
1533/// #include <owl/layoutco.h>
1534/// #pragma hdrstop
1535///
1536/// // Create a derived class. //
1537///
1538/// class TMyDecoratedFrame : public TDecoratedFrame {
1539/// public:
1540/// TMyDecoratedFrame(TWindow* parent, const char far* title,
1541/// TWindow& clientWnd, TWindow* MyChildWindow);
1542/// void SetupWindow();
1543/// {
1544/// TDecoratedFrame::SetupWindow();
1545/// MyChildWindow->ShowWindow(SW_NORMAL);
1546/// MyChildWindow->BringWindowToTop();
1547/// }
1548/// };
1549///
1550/// // Setup a frame window. //
1551///
1552/// TMyDecoratedFrame::TMyDecoratedFrame(TWindow * parent,
1553/// const char far * title,
1554/// TWindow& clientWnd)
1555/// : TDecoratedFrame(parent, title, clientWnd),
1556/// TFrameWindow(parent, title, &clientWnd),
1557/// TWindow(parent, title)
1558/// {
1559/// // Create a new TMyChildWindow. //
1560///
1561/// MyChildWindow = new TWindow(this, "");
1562/// MyChildWindow->Attr.Style |= WS_BORDER |WS_VISIBLE |WS_CHILD;
1563/// MyChildwindow->SetBkgndColor(RGB(0,100,0));
1564///
1565/// // Establish metrics for the child window. //
1566///
1567/// TLayoutMetrics layoutMetrics;
1568///
1569/// layoutMetrics.X.Absolute(lmLeft, 10);
1570/// layoutMetrics.Y.Absolute(lmTop, 10);
1571/// layoutMetrics.Width.Absolute( 80 );
1572/// layoutMetrics.Height.Absolute( 80 );
1573/// }
1574/// SetChildLayoutMetrics(*MyChildWindow, layoutMetrics);
1575/// class TMyApp : public TApplication {
1576/// public:
1577///
1578/// virtual void InitMainWindow()
1579/// {
1580/// TWindow* client = new TWindow(0, "title");
1581/// MainWindow = new TMyDecoratedFrame(0,
1582/// "Layout Window Ex",
1583/// *client);
1584/// }
1585/// };
1586/// int OwlMain(int, char**) {
1587/// return TMyApp.Run();
1588/// }
1589/// \endcode
1590//
1591TLayoutMetrics::TLayoutMetrics()
1592{
1593 X.RelWin = nullptr;
1594 X.MyEdge = X.OtherEdge = lmLeft;
1595 X.Relationship = lmAsIs;
1596 X.Units = lmLayoutUnits;
1597 X.Value = 0;
1598
1599 Y.RelWin = nullptr;
1600 Y.MyEdge = Y.OtherEdge = lmTop;
1601 Y.Relationship = lmAsIs;
1602 Y.Units = lmLayoutUnits;
1603 Y.Value = 0;
1604
1605 Width.RelWin = nullptr;
1606 Width.MyEdge = Width.OtherEdge = lmWidth;
1607 Width.Relationship = lmAsIs;
1608 Width.Units = lmLayoutUnits;
1609 Width.Value = 0;
1610
1611 Height.RelWin = nullptr;
1612 Height.MyEdge = Height.OtherEdge = lmHeight;
1613 Height.Relationship = lmAsIs;
1614 Height.Units = lmLayoutUnits;
1615 Height.Value = 0;
1616}
1617
1618//
1619//
1620//
1621void
1622TLayoutMetrics::SetMeasurementUnits(TMeasurementUnits units)
1623{
1624 X.Units = Y.Units = Width.Units = Height.Units = units;
1625}
1626
1627} // OWL namespace
1628
1629/* ========================================================================== */
1630
#define CHECK(condition)
Definition checks.h:239
#define PRECONDITION(condition)
Definition checks.h:227
#define TRACEX(group, level, message)
Definition checks.h:263
#define DIAG_DEFINE_GROUP_INIT(f, g, e, l)
Definition checks.h:429
When specifying the layout metrics for a window, four layout constraints are needed.
Definition layoutwi.h:54
Derived from TWindow, TLayoutWindow provides functionality for defining the layout metrics for a wind...
Definition layoutwi.h:122
void EvSetFont(HFONT, bool redraw)
Updates the window layout, if "redraw" is true.
Definition layoutwi.cpp:642
TLayoutWindow(TWindow *parent, LPCTSTR title=0, TModule *module=0)
Creates a TLayoutWindow object with specified parent, window caption, and library ID.
Definition layoutwi.cpp:262
void EvSize(uint sizeType, const TSize &size)
Responds to a change in size by calling Layout() to resize the window.
Definition layoutwi.cpp:615
virtual void Layout()
Causes the window to resize and position its children according to the specified metrics.
Definition layoutwi.cpp:351
bool GetChildLayoutMetrics(const TWindow &child, TLayoutMetrics &metrics)
Gets the layout metrics of the child window.
Definition layoutwi.cpp:500
auto EvGetFont() -> HFONT
Definition layoutwi.cpp:627
void SetChildLayoutMetrics(TWindow &child, const TLayoutMetrics &metrics)
Sets the metrics for the window and removes any existing ones.
Definition layoutwi.cpp:465
void RemoveChild(TWindow *) override
Overrides TWindow virtual to allow cleanup of child metrics.
Definition layoutwi.cpp:660
bool RemoveChildLayoutMetrics(const TWindow &child)
Removes child (layout) metrics for a given child (if found) and updates other children as necessary.
Definition layoutwi.cpp:529
~TLayoutWindow() override
Deletes variables and frees the child metrics and constraints.
Definition layoutwi.cpp:307
void Init(TWindow *parent, LPCTSTR title, TModule *module)
Definition layoutwi.cpp:279
ObjectWindows dynamic-link libraries (DLLs) construct an instance of TModule, which acts as an object...
Definition module.h:75
The tagSIZE struct is defined as.
Definition geometry.h:234
static const TUIMetric CyBorder
Definition uimetric.h:40
static const TUIMetric CxBorder
Definition uimetric.h:39
TWindow, derived from TEventHandler and TStreamableBase, provides window-specific behavior and encaps...
Definition window.h:414
bool SetWindowPos(HWND hWndInsertAfter, const TRect &rect, uint flags)
Changes the size of the window pointed to by rect.
Definition window.h:2809
virtual void RemoveChild(TWindow *child)
Removes a child window.
Definition window.cpp:707
void Init(TWindow *parent, LPCTSTR title, TModule *module)
Normal initialization of a default constructed TWindow.
Definition window.cpp:401
TWindowAttr & GetWindowAttr()
Returns the TWindowAttr structure, which contains the window's creation attributes.
Definition window.h:1886
TResult HandleMessage(TMsgId, TParam1=0, TParam2=0)
Dispatches the given message using the response table.
Definition window.cpp:1392
void EvSize(uint sizeType, const TSize &size)
Response method for an incoming WM_SIZE message.
Definition window.cpp:1632
HFONT EvGetFont()
The default message handler for WM_GETFONT.
Definition window.h:3705
void EvSetFont(HFONT hFont, bool redraw)
The default message handler for WM_SETFONT.
Definition window.h:4094
HWND GetHandle() const
Returns the handle of the window.
Definition window.h:2020
TXOwl is root class of the ObjectWindows exception hierarchy.
Definition except.h:38
static void Raise(TWindow *win=nullptr, uint resourceId=IDS_INVALIDWINDOW)
Creates the TXWindow exception and throws it.
Definition window.cpp:4612
ipstream, a specialized input stream derivative of pstream, is the base class for reading (extracting...
Definition objstrm.h:391
#define _T(x)
Definition cygwin.h:51
#define DEFINE_RESPONSE_TABLE1(cls, base)
Macro to define a response table for a class with one base.
Definition eventhan.h:492
Simple fixed point class that maintains numbers as 16.16 Fixed by Bidus Yura to work with Micro$oft V...
TMeasurementUnits
Used by the TLayoutConstraint struct, TMeasurementUnits enumerates the measurement units (lmPixels or...
Definition layoutco.h:58
#define lmParent
Use to represent the parent in layout metrics.
Definition layoutco.h:31
@ lmTop
The top edge of the window.
Definition layoutco.h:38
@ lmBottom
The bottom edge of the window.
Definition layoutco.h:40
@ lmCenter
The center of the window.
Definition layoutco.h:41
@ lmRight
The right edge of the window.
Definition layoutco.h:39
@ lmLeft
The left edge of the window.
Definition layoutco.h:37
@ lmLayoutUnits
Definition layoutco.h:58
@ lmPixels
Definition layoutco.h:58
@ lmAbove
Definition layoutco.h:71
@ lmAbsolute
Definition layoutco.h:74
@ lmSameAs
Definition layoutco.h:73
@ lmPercentOf
Definition layoutco.h:70
@ lmBelow
Definition layoutco.h:72
@ lmAsIs
Definition layoutco.h:69
@ lmWidth
Definition layoutco.h:48
@ lmHeight
Definition layoutco.h:48
#define IMPLEMENT_STREAMABLE1(cls, base1)
Definition objstrm.h:1725
Definition of classes TLayoutMetrics & TLayoutWindow.
Object Windows Library (OWLNext Core)
Definition animctrl.h:22
EV_WM_GETFONT
Definition glyphbtn.cpp:308
owl::opstream & operator<<(owl::opstream &os, const TColor &c)
Insert the color value into a persistent output stream.
Definition color.h:498
EV_WM_SETFONT
Definition glyphbtn.cpp:309
OWL_DIAGINFO
Definition animctrl.cpp:14
END_RESPONSE_TABLE
Definition button.cpp:26
std::string tstring
Definition defs.h:79
unsigned int uint
Definition number.h:25
std::ostream tostream
Definition strmdefs.h:40
EV_WM_SIZE
Definition decframe.cpp:34
General definitions used by all ObjectWindows programs.
#define OWL_INI
Definition defs.h:170
ObjectWindows exception class & function definitions.
TLayoutConstraint is a structure that defines a relationship (a layout constraint) between an edge or...
Definition layoutco.h:121
int X
horizontal position of top left corenr of the window
Definition window.h:339
int W
width of the window
Definition window.h:341
int H
height of the window
Definition window.h:342
int Y
vertical position of top left corenr of the window
Definition window.h:340
uint32 Style
Contains the values that define the style, shape, and size of your window.
Definition window.h:331
Definition of TUIMetric, a UI metrics provider class.