//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1992, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of class TLayoutWindow.
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/defs.h>
#include <owl/layoutwi.h>
#include <owl/uimetric.h>
#include <owl/fixedpnt.h>
#include <owl/except.h>
#if defined(__BORLANDC__)
# pragma option -w-ccc // Disable "Condition is always true/false"
#endif
using namespace std;
namespace owl {
OWL_DIAGINFO;
DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlLayout, 1, 0); // diag. group for windows
//----------------------------------------------------------------------------
// Small wrapper around the 'DeferWindowPos' APIs
//
class TDeferWinPos {
public:
TDeferWinPos(int numWindows);
~TDeferWinPos();
bool DeferWindowPos(HWND hwnd, HWND after, int x, int y, int cx, int cy,
uint flags);
bool EndDeferWindowPos();
protected:
HDWP Hdwp;
};
//} // OWL namespace
//
//
//
TDeferWinPos::TDeferWinPos(int numWindows)
{
Hdwp = numWindows ? ::BeginDeferWindowPos(numWindows) : 0;
}
//
//
//
bool
TDeferWinPos::DeferWindowPos(HWND hwnd, HWND after, int x, int y,
int cx, int cy, uint flags)
{
PRECONDITION(Hdwp);
TRACEX(OwlLayout, 0, _T("DeferWindowPos(x => ") << x << _T(", y => ") << y << _T(", cx => ") << cx << _T(", cy => ") << cy);
Hdwp = ::DeferWindowPos(Hdwp, hwnd, after, x, y, cx, cy, flags);
CHECK(Hdwp);
return Hdwp != 0;
}
//
//
//
bool
TDeferWinPos::EndDeferWindowPos()
{
PRECONDITION(Hdwp);
if (::EndDeferWindowPos(Hdwp)) {
Hdwp = 0;
return true;
}
return false;
}
//
//
//
TDeferWinPos::~TDeferWinPos()
{
if (Hdwp)
EndDeferWindowPos();
}
DEFINE_RESPONSE_TABLE1(TLayoutWindow, TWindow)
EV_WM_SIZE,
EV_WM_GETFONT,
EV_WM_SETFONT,
END_RESPONSE_TABLE;
//namespace owl {
/// \addtogroup internal_group
/// @{
/// \class TConstraint
/// Constraints can have up to three input variables
///
/// the method for solving the constraint is represented as an ordered linear
/// combination of the inputs and the constant with the constant expressed last
//
struct TVariable;
struct TConstraint {
TVariable* Inputs[3];
TVariable* Output;
TFixedPoint OrderedCombination[4];
TConstraint* Next;
TConstraint();
bool IsResolved(); // iff its inputs have been resolved
int Evaluate();
int NumActualInputs();
};
inline tostream& operator <<(tostream& os, const TFixedPoint& p){
return os << (int)(TFixedPoint&)p;
}
inline tostream& operator <<(tostream& os, const TLayoutConstraint& c){
return os << _T('(') << static_cast<void*>(c.RelWin) << dec
<< _T(',') << c.MyEdge << _T(',') << (int)c.Relationship << _T(',') << (int)c.Units
<< _T(',') << c.OtherEdge << _T(',') << c.Value << _T(')');
}
inline tostream& operator <<(tostream& os, const TLayoutMetrics& m){
return os << _T('(') << m.X << _T(',') << m.Y << _T('x') << m.Width <<
_T(',') << m.Height << _T(')');
}
inline tostream& operator <<(tostream& os, const TConstraint& c){
return os << _T('(') << static_cast<const void*>(c.Inputs)
<< _T(',') << static_cast<void*>(c.Output) << _T(',') << c.OrderedCombination[0]
<< _T(',') << c.OrderedCombination[1] << _T(',') << c.OrderedCombination[2]
<< c.OrderedCombination[3] << _T(',') << static_cast<void*>(c.Next) << _T(')');
}
struct TVariable {
int Value;
TConstraint* DeterminedBy; // 0 if variable is constant
bool Resolved;
TVariable() {Value = 0; DeterminedBy = 0; Resolved = false;}
};
inline tostream& operator <<(tostream& os, const TVariable& v){
return os << _T('(') << v.Value << _T(',') << static_cast<void*>(v.DeterminedBy)
<< _T("->") << (v.Resolved? _T("Resolved"):_T("No Resolved")) << _T(')');
}
//
/// The layout metrics represent four equations. For equations that are
/// "absolute" or "as is" we don't add a constraint and just set the variable
/// value directly(and mark the variable as constant); otherwise we produce an
/// ordered linear combination from the equation and add a constraint
//
struct TChildMetrics {
public:
bool GeneratedConstraints;
TWindow* Child;
TLayoutMetrics Metrics;
TVariable Variables[4]; // x => 0, y => 1, right => 2, bottom => 3
TChildMetrics* Next;
TChildMetrics(TWindow& child, const TLayoutMetrics& metrics);
};
inline tostream& operator <<(tostream& os, const TChildMetrics& m){
return os << _T('(') << (m.GeneratedConstraints ? _T("true") : _T("false"))
<< _T(',') << static_cast<void*>(m.Child) << _T(',') <<
m.Metrics << _T(',') << m.Variables[0] << _T(',') << m.Variables[1] << _T(',')
<< m.Variables[2] << _T(',') << m.Variables[3] << _T(',') << static_cast<void*>(m.Next)
<< _T(')');
}
/// @}
//} // OWL namespace
//----------------------------------------------------------------------------
/// \class TLayoutWindow
/// The following examples show how to set up various metrics using edge
/// constraints. For purposes of illustration, these examples use a parent-child
/// relationship, but you can also use a child-to-child (sibling) relationship. Keep
/// in mind that moving the parent's origin (the left and top edges) also moves the
/// child window.
/// Example 1
/// To create windows that can grow, set the top and left edges of the child
/// window's boundaries in a fixed relationship to the top and left edges of the
/// parent's window. In this example, if you expand the bottom and right edges of
/// the parent, the child's bottom and right edges grow the same amount. Both the X
/// and Y constraints are 10 units from the parent window's edges. Both the Width
/// and Height constraints are 40 layout units from the parent window's edges.
/// Specifically, Width (lmWidth) is 40 units to the left of the parent's right edge
/// (lmLeftOf = lmSameAs + offset or sameas - 40).
/// \image html bm211.BMP
/// Use the following layout constraints:
/// \code
/// layoutmetrics.X.Set(lmLeft, lmRightOf, lmParent, lmLeft, 10);
/// layoutmetrics.Y.Set(lmTop, lmBelow, lmParent, lmTop, 10);
/// layoutmetrics.Width.Set(lmRight, lmLeftOf, lmParent, lmRight, 40);
/// layoutmetrics.Height.Set(lmBottom, lmAbove, lmParent, lmBottom, 40);
/// SetChildLayoutMetrics(*MyChildWindow, layoutMetrics);
/// \endcode
/// Example 2
/// To create fixed-size and fixed-position windows, set the child's right edge a
/// fixed distance from the parent's left edge, and the child's bottom edge a fixed
/// distance from the parent's top edge. In this example, both the X and Y edge
/// constraints are set to 10 and both the Width and Height edge constraints are set
/// to 100.
/// \image html bm212.BMP
/// Use the following layout constraints:
/// \code
/// layoutmetrics.X.Set(lmLeft, lmRightOf, lmParent, lmLeft, 10);
/// layoutmetrics.Y.Set(lmTop, lmBelow, lmParent, lmTop, 10);
/// layoutmetrics.Width.Absolute(100);
/// layoutmetrics.Height.Absolute(100);
/// SetChildLayoutMetrics(*MyChildWindow, layoutMetrics);
/// \endcode
/// Example 3
/// To create a fixed-size window that remains a constant distance from the parent's
/// right corner, set the child's top and bottom edges a fixed distance (lmLayout
/// unit or pixels) from the parent window's bottom. Also, set the child's left and
/// right edges a fixed distance from the parent's right edge. In this example, both
/// the Width and the Height edge constraints are set to 100 and the X and Y edge
/// constraints are set to 10. In this case, the child window, which stays the same
/// size, moves with the lower right corner of the parent.
/// \image html bm213.BMP
/// Use the following layout constraints:
/// \code
/// layoutmetrics.X.Set(lmRight, lmLeftOf, lmParent, lmRight, 10);
/// layoutmetrics.Y.Set(lmBottom, lmAbove, lmParent, lmBottom, 10);
/// layoutmetrics.Width.Absolute(100);
/// layoutmetrics.Height.Absolute(100);
/// SetChildLayoutMetrics(*MyChildWindow, layoutMetrics);
/// \endcode
/// Example 4
/// To create a window in which the child's edges are a percentage of the parent's
/// window, set the child's edges a percentage of the distance from the parent's
/// edges. Specifically, the child's top and bottom edges are a percentage of the
/// parent's bottom edge. The child's left and right edges are a percentage of the
/// parent's right edge.
/// If you resize the parent window, the child window will change size and origin
/// (that is, the top and left edges will also change).
/// \image html bm214.BMP
/// Use the following layout constraints:
/// \code
/// layoutmetrics.X.Set(lmLeft, lmPercentOf, lmParent, lmRight, 33);
/// layoutmetrics.Y.Set(lmTop, lmPercentOf, lmParent, lmBottom, 33);
/// layoutmetrics.Width.Set(lmRight, lmPercentOf, lmParent, lmRight, 66);
/// layoutmetrics.Height.Set(lmBottom, lmPercentOf, lmParent, lmBottom, 66);
/// SetChildLayoutMetrics(*MyChildWindow, layoutMetrics);
/// \endcode
///
//
/// Creates a TLayoutWindow object with specified parent, window caption, and
/// library ID.
//
TLayoutWindow::TLayoutWindow(TWindow* parent,
LPCTSTR title,
TModule* module)
: TWindow(parent, title, module)
{
Init(parent, title, module);
}
//
/// String-aware overload
//
TLayoutWindow::TLayoutWindow(TWindow* parent, const tstring& title, TModule* module)
: TWindow(parent, title, module)
{
Init(parent, title.c_str(), module);
}
void TLayoutWindow::Init(TWindow* parent, LPCTSTR title, TModule* module)
{
// Initialize virtual bases, in case the derived-most used default ctor
//
TWindow::Init(parent, title, module);
NumChildMetrics = 0;
ChildMetrics = 0;
Constraints = 0;
Plan = 0;
PlanIsDirty = false;
ClientSize.cx = ClientSize.cy = 0;
Font = nullptr;
FontHeight = 0;
// Allocate variables for the parent's left, top, right, and bottom and
// mark them as resolved
//
Variables = new TVariable[4];
Variables[0].Resolved = true;
Variables[1].Resolved = true;
Variables[2].Resolved = true;
Variables[3].Resolved = true;
}
//
/// Deletes variables and frees the child metrics and constraints.
//
TLayoutWindow::~TLayoutWindow()
{
delete[] Variables;
// Free the child metrics
//
for (TChildMetrics* childMetrics = ChildMetrics; childMetrics;) {
TChildMetrics* tmp = childMetrics;
childMetrics = childMetrics->Next;
delete tmp;
}
ChildMetrics = 0; //Bug fix: https://sourceforge.net/forum/message.php?msg_id=4186646
// Free the constraints
//
ClearPlan();
for (TConstraint* c = Constraints; c;) {
TConstraint* tmp = c;
c = c->Next;
delete tmp;
}
Constraints = 0; //Bug fix: https://sourceforge.net/forum/message.php?msg_id=4186646
}
static bool hasBorder(TWindow* win)
{
// We consider it to have a border unless it is a pop-up or child window
// without WS_BORDER set
//
if ((win->GetWindowAttr().Style & (WS_CHILD|WS_POPUP)) && !(win->GetWindowAttr().Style & WS_BORDER))
return false;
else
return true;
}
//
/// Causes the window to resize and position its children according to the specified metrics.
/// If you change the layout metrics for a child window, then you should call Layout to have the
/// changes take effect.
//
void TLayoutWindow::Layout()
{
if (ChildMetrics) {
TChildMetrics* childMetrics;
GetFontHeight();
// Initialize the parent's variables
//
Variables[2].Value = ClientSize.cx - 1;
Variables[3].Value = ClientSize.cy - 1;
TRACEX(OwlLayout, 0, _T("Layout() ClientSize: ") << ClientSize);
if (hasBorder(this)) {
int cxBorder = TUIMetric::CxBorder;
int cyBorder = TUIMetric::CyBorder;
Variables[0].Value = -cxBorder;
Variables[1].Value = -cyBorder;
Variables[2].Value += cxBorder;
Variables[3].Value += cyBorder;
}
else {
Variables[0].Value = 0;
Variables[1].Value = 0;
}
TRACEX(OwlLayout, 1, _T("Layout() Variables: 0=>") << Variables[0] << _T(", 1=>") << Variables[1]<< _T(", 2=>") << Variables[2]<< _T(", 3=>") << Variables[3]);
// Rebuild layout plan if necessary
//
if (PlanIsDirty) {
PlanIsDirty = false;
for (childMetrics = ChildMetrics; childMetrics;
childMetrics = childMetrics->Next)
BuildConstraints(*childMetrics);
BuildPlan();
}
// Use the plan to calculate actual child window position values
//
ExecutePlan();
#if !defined(OWL_NO_DEFERWINDOWPOS_LAYOUT)
// Find out how many windows we're dealing with
//
int numWindows = 0;
for (childMetrics = ChildMetrics; childMetrics; childMetrics = childMetrics->Next) {
TWindow* win = childMetrics->Child;
if (win->GetHandle())
numWindows++;
}
// Helper object to use 'DefWindowPos' API
//
TDeferWinPos dwp(numWindows);
#endif
// Do actual resizing
//
for (childMetrics = ChildMetrics; childMetrics; childMetrics = childMetrics->Next) {
TWindow* win = childMetrics->Child;
TVariable* variables = childMetrics->Variables;
TRACEX(OwlLayout, 0, _T("Layout() variables: ") << variables[0] << _T(',') <<
variables[1] << _T(',') << variables[2] << _T(',') << variables[3]);
if (win->GetHandle()) {
#if defined(OWL_NO_DEFERWINDOWPOS_LAYOUT)
win->SetWindowPos(
0,
variables[0].Value,
variables[1].Value,
variables[2].Value - variables[0].Value + 1,
variables[3].Value - variables[1].Value + 1,
SWP_NOACTIVATE | SWP_NOZORDER
);
#else
dwp.DeferWindowPos(*win, 0,
variables[0].Value,
variables[1].Value,
variables[2].Value - variables[0].Value + 1,
variables[3].Value - variables[1].Value + 1,
SWP_NOACTIVATE | SWP_NOZORDER);
#endif
}
else {
win->GetWindowAttr().X = variables[0].Value;
win->GetWindowAttr().Y = variables[1].Value;
win->GetWindowAttr().W = variables[2].Value - variables[0].Value + 1;
win->GetWindowAttr().H = variables[3].Value - variables[1].Value + 1;
}
}
}
}
//
/// Sets the metrics for the window and removes any existing ones. Set the metrics
/// as shown:
/// \code
/// layoutMetrics->X.Absolute(lmLeft, 10);
/// layoutMetrics->Y.Absolute(lmTop, 10);
/// layoutMetrics->Width.Set(lmWidth, lmRightOf, GetClientWindow(), lmWidth, -40);
/// layoutMetrics->Height.Set(lmHeight, lmRightOf, GetClientWindow(), lmHeight,
/// -40);
/// \endcode
/// Then call SetChildLayoutMetrics to associate them with the position of the child
/// window:
/// \code
/// SetChildLayoutMetrics(* MyChildWindow, * layoutMetrics);
/// \endcode
//
void
TLayoutWindow::SetChildLayoutMetrics(TWindow& child, const TLayoutMetrics& metrics)
{
PRECONDITION(&child);
PRECONDITION(&metrics);
PlanIsDirty = true;
if (ChildMetrics) {
// See if we already have metrics for the child
//
for (TChildMetrics* childMetrics = ChildMetrics; childMetrics;
childMetrics = childMetrics->Next) {
if (childMetrics->Child == &child) {
childMetrics->Child = &child;
childMetrics->Metrics = metrics;
// Get rid of the old constraints
//
RemoveConstraints(*childMetrics);
return;
}
}
}
TChildMetrics* childMetrics = new TChildMetrics(child, metrics);
childMetrics->Next = ChildMetrics;
ChildMetrics = childMetrics;
NumChildMetrics++;
}
//
/// Gets the layout metrics of the child window.
//
bool
TLayoutWindow::GetChildLayoutMetrics(const TWindow& child, TLayoutMetrics& metrics)
{
PRECONDITION(&child);
TChildMetrics* childMetrics = GetChildMetrics(child);
if (childMetrics) {
metrics = childMetrics->Metrics;
return true;
}
return false;
}
//
/// Functional-style overload
/// Throws TXOwl if metrics are not found for the given child window.
//
auto TLayoutWindow::GetChildLayoutMetrics(const TWindow& child) -> TLayoutMetrics
{
auto m = TLayoutMetrics{};
auto r = GetChildLayoutMetrics(child, m);
if (!r) throw TXOwl{_T("TLayoutWindow::GetChildLayoutMetrics failed")};
return m;
}
//
/// Removes child (layout) metrics for a given child (if found) and updates
/// other children as necessary
//
bool
TLayoutWindow::RemoveChildLayoutMetrics(const TWindow& child)
{
PRECONDITION(&child);
for (TChildMetrics** childMetrics = &ChildMetrics; *childMetrics;
childMetrics = &(*childMetrics)->Next) {
if ((*childMetrics)->Child == &child) {
// Unlink target metrics from list & clean up a bit
//
TChildMetrics* tmp = *childMetrics;
*childMetrics = tmp->Next;
RemoveConstraints(*tmp);
NumChildMetrics--;
// Update other child metrics now that removed metric is gone
// Check for case where new relWin is lmParent and adjust other edge
// to be what removed window was using. If an 'edge' is really a size,
// then give up & just leave it asis. If the removed window had an edge
// that was really a size, then use the other constraint in that
// dimension (X or Y)
//
for (TChildMetrics* cm = ChildMetrics; cm; cm = cm->Next) {
if (cm->Metrics.X.RelWin == &child) {
RemoveConstraints(*cm);
cm->Metrics.X.RelWin = tmp->Metrics.X.RelWin;
if (cm->Metrics.X.RelWin == lmParent)
cm->Metrics.X.OtherEdge = tmp->Metrics.X.OtherEdge;
}
if (cm->Metrics.Y.RelWin == &child) {
RemoveConstraints(*cm);
cm->Metrics.Y.RelWin = tmp->Metrics.Y.RelWin;
if (cm->Metrics.Y.RelWin == lmParent)
cm->Metrics.Y.OtherEdge = tmp->Metrics.Y.OtherEdge;
}
if (cm->Metrics.Width.RelWin == &child) {
RemoveConstraints(*cm);
if (cm->Metrics.Width.MyEdge == lmWidth)
cm->Metrics.Width.Relationship = lmAsIs;
else {
if (tmp->Metrics.Width.MyEdge == lmWidth) {
cm->Metrics.Width.RelWin = tmp->Metrics.X.RelWin;
if (cm->Metrics.Width.RelWin == lmParent)
cm->Metrics.Width.OtherEdge = tmp->Metrics.X.OtherEdge;
}
else {
cm->Metrics.Width.RelWin = tmp->Metrics.Width.RelWin;
if (cm->Metrics.Width.RelWin == lmParent)
cm->Metrics.Width.OtherEdge = tmp->Metrics.Width.OtherEdge;
}
}
}
if (cm->Metrics.Height.RelWin == &child) {
RemoveConstraints(*cm);
if (cm->Metrics.Height.MyEdge == lmHeight)
cm->Metrics.Height.Relationship = lmAsIs;
else {
if (tmp->Metrics.Height.MyEdge == lmHeight) {
cm->Metrics.Height.RelWin = tmp->Metrics.Y.RelWin;
if (cm->Metrics.Height.RelWin == lmParent)
cm->Metrics.Height.OtherEdge = tmp->Metrics.Y.OtherEdge;
}
else {
cm->Metrics.Height.RelWin = tmp->Metrics.Height.RelWin;
if (cm->Metrics.Height.RelWin == lmParent)
cm->Metrics.Height.OtherEdge = tmp->Metrics.Height.OtherEdge;
}
}
}
}
// Finaly, delete target metrics
//
delete tmp;
return true;
}
}
return false;
}
//----------------------------------------------------------------------------
//
/// Responds to a change in size by calling Layout() to resize the window.
//
void
TLayoutWindow::EvSize(uint sizeType, const TSize& size)
{
TWindow::EvSize(sizeType, size);
if (sizeType != SIZE_MINIMIZED &&
//sizeType != SIZE_MAXIMIZED && // fix-bug was bug or not ????
size != ClientSize) {
ClientSize = size;
Layout();
}
}
auto TLayoutWindow::EvGetFont() -> HFONT
{
// The default processing may return NULL, even after a previous WM_SETFONT message with a
// non-NULL value. So rather than rely on the default processing, we cache the font in EvSetFont
// and return our cached value here. A reliable return value from WM_GETFONT is needed for the
// layout machinery. See TLayoutWindow::GetFontHeight.
//
return Font ? Font : TWindow::EvGetFont();
}
//
/// Updates the window layout, if "redraw" is true.
/// The layout may depend on the given font metrics. See TMeasurementUnits::lmLayoutUnits.
/// So if you pass "false", remember to update the layout, e.g. by explicitly calling Layout.
//
void TLayoutWindow::EvSetFont(HFONT f, bool redraw)
{
TWindow::EvSetFont(f, redraw);
if (f != Font)
{
// Cache the font setting, so that we can reliably return the font in the WM_GETFONT message.
// See EvGetFont.
//
Font = f;
if (redraw)
Layout();
}
}
//
/// Overrides TWindow virtual to allow cleanup of child metrics.
//
void
TLayoutWindow::RemoveChild(TWindow* child)
{
TWindow::RemoveChild(child);
RemoveChildLayoutMetrics(*child);
}
//----------------------------------------------------------------------------
//
//
//
TChildMetrics*
TLayoutWindow::GetChildMetrics(const TWindow& child)
{
PRECONDITION(&child);
for (TChildMetrics* childMetrics = ChildMetrics; childMetrics;
childMetrics = childMetrics->Next)
if (childMetrics->Child == &child)
return childMetrics;
return 0;
}
//
//
//
void
TLayoutWindow::ExecutePlan()
{
for (TConstraint* c = Plan; c; c = c->Next){
c->Output->Value = c->Evaluate();
TRACEX(OwlLayout, 1, _T("ExecutePlan() c->Output => ") << *c->Output);
}
}
//
//
//
void
TLayoutWindow::ClearPlan()
{
if (Plan) {
// Move all constraints that were in the plan back to the list of
// constraints
//
if (!Constraints)
Constraints = Plan;
else {
TConstraint* c;
for (c = Constraints; c->Next; c = c->Next)
;
c->Next = Plan;
}
Plan = 0;
}
}
//
//
//
void
TLayoutWindow::BuildPlan()
{
TChildMetrics* childMetrics;
TConstraint* lastInPlan = 0;
ClearPlan();
// Mark all variables that aren't determined by a constraint as resolved
//
for (childMetrics = ChildMetrics; childMetrics; childMetrics = childMetrics->Next) {
TVariable* variable = childMetrics->Variables;
variable->Resolved = variable->DeterminedBy ? false : true;
variable++;
variable->Resolved = variable->DeterminedBy ? false : true;
variable++;
variable->Resolved = variable->DeterminedBy ? false : true;
variable++;
variable->Resolved = variable->DeterminedBy ? false : true;
TRACEX(OwlLayout, 1, _T("BuildPlan() variables: ") << childMetrics->Variables[0]
<< _T(',') << childMetrics->Variables[1] << _T(',') << childMetrics->Variables[2]
<< _T(',') << childMetrics->Variables[3]);
}
// Uses local propagation as much as possible (because it's fast)
//
// If cycles exist then we will end up with constraints that haven't been
// added to the plan. we convert the remaining constraints into simultaneous
// linear equations which we solve using Gaussian elimination
//
// Look for constraints that have all their input variables resolved and
// append them to the plan
//
for (bool foundOne = true; foundOne;) {
TConstraint* c = Constraints;
TConstraint* previous = 0;
foundOne = false;
while (c) {
TRACEX(OwlLayout, 1, _T("BuildPlan() *c ") << *c);
if (c->IsResolved()) {
TConstraint* resolved = c;
c->Output->Resolved = true;
foundOne = true;
// Extract the constraint from the list of constraints
//
if (previous)
previous->Next = c->Next;
else
Constraints = c->Next;
c = c->Next;
// Append the constraint to the plan
//
if (lastInPlan)
lastInPlan->Next = resolved;
else
Plan = resolved;
lastInPlan = resolved;
}
else {
previous = c;
c = c->Next;
}
}
}
// Gaussian elimination not currently supported--give up
//
if (Constraints)
TXWindow::Raise(this, IDS_LAYOUTINCOMPLETE);
}
//
//
//
static int
findInput(TConstraint* simplify, TVariable* input)
{
for (int i = 0; i < 3; i++)
if (simplify->Inputs[i] == input)
return i;
return -1;
}
//
// simplify constraint "simplify" by substituting constraint "_using"
//
// we do this when the two constraints are defined in terms of each other
// 1. the output of "simplify" is an input of "_using"
// 2. the output of "_using" is an input of "simplify"
//
// we do this to avoid a layout cycle
//
// "output" is the output variable for constraint "_using"
//
static
void
Simplify(TConstraint* simplify, TVariable* output, TConstraint* _using)
{
if (!simplify)
return;
int outputOfSimplify = findInput(_using, simplify->Output); // check #1
int target = findInput(simplify, output); // check #2
if (outputOfSimplify != -1 && target != -1) {
int commonInputs[3];
int numInputsOfUsing = _using->NumActualInputs();
int i;
// Count how many inputs are common between "simplify" and "_using"
//
for (i = 0; i < numInputsOfUsing; i++)
commonInputs[i] = findInput(simplify, _using->Inputs[i]);
// Since constraints only have room for 3 inputs we can not simplify if the
// total number of the existing inputs minus the input we are going to back
// substitute for plus the number of inputs added by "_using" (i.e. inputs
// not common between the two constraints) exceeds 3
//
int numInputsOfSimplify = simplify->NumActualInputs() - 1;
int newInputs = 0;
// Compute the number of additional inputs contributed by "_using"
//
for (i = 0; i < numInputsOfUsing; i++)
if (commonInputs[i] == -1 && i != outputOfSimplify)
newInputs++;
if (numInputsOfSimplify + newInputs > 3)
return;
TFixedPoint m = simplify->OrderedCombination[target];
// Adjust the constant part
//
simplify->OrderedCombination[3] += m * _using->OrderedCombination[3];
// Merge the common inputs
//
for (i = 0; i < numInputsOfUsing; i++)
if (commonInputs[i] != -1)
simplify->OrderedCombination[commonInputs[i]] +=
m * _using->OrderedCombination[i];
simplify->Inputs[target] = 0; // input has been back substituted out
TRACEX(OwlLayout, 1, _T("Simplify() simplify->Inputs[") << target << _T("]=> 0"));
// If necessary shift the inputs following "output" (and their associated
// mutiplier) left by one...
//
for (i = target + 1; i < 3; i++)
if (simplify->Inputs[i]) {
simplify->Inputs[i - 1] = simplify->Inputs[i];
simplify->Inputs[i] = 0;
TRACEX(OwlLayout, 1, _T("Simplify() simplify->Inputs[") << i << _T(" - 1]=> ") <<
*simplify->Inputs[i - 1] << _T(", simplify->Inputs[") << i << _T("]=> 0"));
simplify->OrderedCombination[i - 1] = simplify->OrderedCombination[i];
}
// Add the new inputs
//
for (i = 0; i < numInputsOfUsing; i++)
if (commonInputs[i] == -1 && i != outputOfSimplify) {
simplify->Inputs[numInputsOfSimplify] = _using->Inputs[i];
TRACEX(OwlLayout, 1, _T("Simplify() simplify->Inputs[") << numInputsOfSimplify
<< _T("]=> ") << *simplify->Inputs[numInputsOfSimplify]);
simplify->OrderedCombination[numInputsOfSimplify] =
m * _using->OrderedCombination[i];
numInputsOfSimplify++;
}
// Now scale things back so that the output of "simplify" is 1
//
TFixedPoint f = 1 - m;
simplify->OrderedCombination[3] /= f;
for (i = 0; i < numInputsOfSimplify; i++)
simplify->OrderedCombination[i] /= f;
}
}
//
//
//
void
TLayoutWindow::AddConstraint(TChildMetrics& metrics,
TLayoutConstraint* c,
TWhichConstraint whichConstraint)
{
int index;
TVariable* output;
TConstraint* result = new TConstraint;
// Set the output variable
//
if (whichConstraint == XConstraint && metrics.Metrics.X.MyEdge == lmRight){
output = &metrics.Variables[2];
TRACEX(OwlLayout, 1, _T("AddConstraint() output =>") << *output);
}
else if (whichConstraint == YConstraint && metrics.Metrics.Y.MyEdge == lmBottom){
output = &metrics.Variables[3];
TRACEX(OwlLayout, 1, _T("AddConstraint() output =>") << *output);
}
else{
output = &metrics.Variables[whichConstraint];
TRACEX(OwlLayout, 1, _T("AddConstraint() output =>") << *output);
}
// Set the inputs based on the edge
//
if (((int)c->Relationship != lmAbsolute) && ((int)c->Relationship != lmAsIs)) {
TVariable* variables;
if (c->RelWin == lmParent){
variables = Variables;
TRACEX(OwlLayout, 1, _T("AddConstraint() variables =>") << *variables);
}
else {
TChildMetrics* relWinMetrics = GetChildMetrics(*c->RelWin);
if (!relWinMetrics) {
delete result;
TXWindow::Raise(this, IDS_LAYOUTBADRELWIN);
}
variables = relWinMetrics->Variables;
TRACEX(OwlLayout, 1, _T("AddConstraint() variables =>") << *variables);
}
switch (c->OtherEdge) {
case lmLeft:
case lmTop:
case lmRight:
case lmBottom:
result->Inputs[0] = &variables[c->OtherEdge];
TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[0]=> ") <<
*result->Inputs[0]);
break;
case lmWidth:
case lmHeight:
// width => right - left + 1
// height => bottom - top + 1
//
result->Inputs[0] = &variables[c->OtherEdge - lmWidth+lmRight];
result->Inputs[1] = &variables[c->OtherEdge - lmWidth+lmLeft];
TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[0]=> ") <<
*result->Inputs[0] << _T(", result->Inputs[1]=> ") << *result->Inputs[1]);
result->OrderedCombination[1] = -1;
result->OrderedCombination[3] = 1;
break;
case lmCenter:
switch (whichConstraint) {
case XConstraint:
case WidthConstraint:
// Center => (left + right) / 2
//
result->Inputs[0] = &variables[0];
result->Inputs[1] = &variables[2];
TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[0]=> ") <<
*result->Inputs[0] << _T(", result->Inputs[1]=> ") << *result->Inputs[1]);
break;
case YConstraint:
case HeightConstraint:
// Center => (top + bottom) / 2
//
result->Inputs[0] = &variables[1];
result->Inputs[1] = &variables[3];
TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[0]=> ") <<
*result->Inputs[0] << _T(", result->Inputs[1]=> ") << *result->Inputs[1]);
break;
}
result->OrderedCombination[0] = result->OrderedCombination[1] = TFixedPoint(1,2);
break;
}
}
// Now store the constant term as the last of the ordered linear combination
//
// We must do this after setting the inputs
//
// NOTE: we cannot assume that the constant part is 0, because it might have
// been set above
//
switch (c->Relationship) {
case lmAsIs:
result->OrderedCombination[3] += whichConstraint == WidthConstraint ?
metrics.Child->GetWindowAttr().W :
metrics.Child->GetWindowAttr().H;
break;
case lmAbsolute:
case lmSameAs:
case lmBelow:
case lmAbove: {
int value = c->Units == lmPixels ? c->Value : LayoutUnitsToPixels(c->Value);
if (c->Relationship == lmAbove)
value = -value - 1;
else if (c->Relationship == lmBelow)
value++;
result->OrderedCombination[3] += value;
break;
}
case lmPercentOf:
TFixedPoint percent = c->Percent;
percent /= 100;
result->OrderedCombination[0] *= percent;
result->OrderedCombination[3] *= percent;
switch (c->OtherEdge) {
case lmWidth:
case lmHeight:
case lmCenter:
result->OrderedCombination[1] *= percent;
break;
}
break;
}
// Now handle cases where the left hand side is width, height, or center
//
// This must be done last...
//
if (result->Inputs[0])
index = result->Inputs[1] ? 2 : 1;
else
index = 0;
switch (c->MyEdge) {
case lmWidth:
if (whichConstraint == XConstraint || metrics.Metrics.X.MyEdge == lmRight) {
// Rewrite "right - left + 1 = " as "left = right - (...) + 1"
//
for (int i = 0; i < index; i++)
result->OrderedCombination[i] = -result->OrderedCombination[i];
result->OrderedCombination[3] = -result->OrderedCombination[3];
(result->OrderedCombination[3])++;
result->Inputs[index] = &(metrics.Variables[2]);
TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[") <<
index << _T("]=> ") << *result->Inputs[index]);
if (whichConstraint == WidthConstraint){
output = &(metrics.Variables[XConstraint]);
TRACEX(OwlLayout, 1, _T("AddConstraint() output=> ") << *output);
}
}
else {
// Rewrite "right - left + 1 = " as "right = left + ... - 1"
//
result->Inputs[index] = &(metrics.Variables[0]);
TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[") <<
index << _T("]=> ") << *result->Inputs[index]);
(result->OrderedCombination[3])--;
Simplify(metrics.Variables[0].DeterminedBy, output, result);
}
break;
case lmHeight:
if (whichConstraint == YConstraint || metrics.Metrics.Y.MyEdge == lmBottom) {
// Rewrite "bottom - top + 1 = " as "top = bottom - (...) + 1"
//
for (int i = 0; i < index; i++)
result->OrderedCombination[i] = -(result->OrderedCombination[i]);
result->OrderedCombination[3] = -(result->OrderedCombination[3]);
(result->OrderedCombination[3])++;
result->Inputs[index] = &(metrics.Variables[3]);
TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[") <<
index << _T("]=> ") << *result->Inputs[index]);
if (whichConstraint == HeightConstraint){
output = &metrics.Variables[YConstraint];
TRACEX(OwlLayout, 1, _T("AddConstraint() lmHeight: output =>") << *output);
}
}
else {
// Rewrite "bottom - top + 1 = " as "bottom = top + ... - 1"
//
result->Inputs[index] = &metrics.Variables[1];
TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[") <<
index << _T("]=> ") << *result->Inputs[index]);
result->OrderedCombination[3]--;
TRACEX(OwlLayout, 1, _T("AddConstraint() lmHeight: result->Inputs[") <<
index << _T("] =>") << *result->Inputs[index]);
Simplify(metrics.Variables[1].DeterminedBy, output, result);
}
break;
case lmCenter:
TVariable* input = &metrics.Variables[0]; // left
switch (whichConstraint) {
case XConstraint:
// Rewrite "(left + right) / 2 = " as "left = -right + 2 * (...)"
//
input += 2; // right
TRACEX(OwlLayout, 1, _T("AddConstraint() XConstraint: input =>") << *input);
break;
case YConstraint:
// Rewrite "(top + bottom) / 2 = " as "top = -bottom + 2 * (...)"
//
input += 3; // bottom
TRACEX(OwlLayout, 1, _T("AddConstraint() YConstraint: input =>") << *input);
break;
case WidthConstraint:
// Rewrite "(left + right) / 2 = " as "right = -left + 2 * (...)" or
// "left = -right + 2 * (...)" depending on whether the "x" constraint
// is left or right
//
if (metrics.Metrics.X.MyEdge == lmRight) {
input += 2; // right
output = &metrics.Variables[XConstraint];
TRACEX(OwlLayout, 1, _T("AddConstraint() WidthConstraint: input =>") <<
*input << _T(",output => ") << *output);
}
break;
case HeightConstraint:
// Rewrite "(top + bottom) / 2 = " as "bottom = -top + 2 * (...)" or
// "top = -bottom + 2 * (...)" depending on whether the "y" constraint
// is top or bottom
//
if (metrics.Metrics.Y.MyEdge != lmBottom)
input++; // top
else {
input += 3; // bottom
output = &metrics.Variables[XConstraint];
}
TRACEX(OwlLayout, 1, _T("AddConstraint() HeightConstraint: input =>") <<
*input << _T(",output => ") << *output);
break;
}
result->Inputs[index] = input;
TRACEX(OwlLayout, 1, _T("AddConstraint() result->Inputs[") << index <<
_T("]=> ") << *result->Inputs[index]);
for (int i = 0; i < index; i++)
result->OrderedCombination[i] <<= 1;
result->OrderedCombination[3] <<= 1;
result->OrderedCombination[index] = -1;
break;
}
// Now set the constraint output
//
output->DeterminedBy = result;
result->Output = output;
// Add the constraint to the list of constraints
//
result->Next = Constraints;
Constraints = result;
}
//
//
//
void
TLayoutWindow::RemoveConstraints(TChildMetrics& childMetrics)
{
TVariable* variable = childMetrics.Variables;
PlanIsDirty = true;
ClearPlan();
childMetrics.GeneratedConstraints = false;
for (int i = 0; i < 4; i++) {
TConstraint* constraint = variable->DeterminedBy;
variable->Value = 0;
if (constraint) {
// Remove the constraint from the list of constraints
//
if (Constraints == constraint)
Constraints = constraint->Next;
else
for (TConstraint* c = Constraints; c->Next; c = c->Next)
if (c->Next == constraint) {
c->Next = constraint->Next;
break;
}
delete constraint;
variable->DeterminedBy = 0;
}
variable++;
}
}
//
//
//
void
TLayoutWindow::BuildConstraints(TChildMetrics& childMetrics)
{
// NOTE: to get uniformity we consider the window edges to sit on pixels
// and not between pixels. so our idea of right is left + width - 1
// and not left + width
//
if (!childMetrics.GeneratedConstraints) {
TLayoutConstraint* c = &childMetrics.Metrics.X;
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Metrics.X =>") << *c);
childMetrics.GeneratedConstraints = true;
// "x" can be one of: left, right, center
//
if (c->Relationship == lmAsIs){
if (c->MyEdge == lmLeft){
childMetrics.Variables[0].Value = childMetrics.Child->GetWindowAttr().X;
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[0] =>") <<
childMetrics.Variables[0]);
}
else{
childMetrics.Variables[2].Value = childMetrics.Child->GetWindowAttr().X +
childMetrics.Child->GetWindowAttr().W - 1;
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[2] =>") <<
childMetrics.Variables[2]);
}
}
else if (c->Relationship == lmAbsolute && c->MyEdge != lmCenter) {
int value = c->Units == lmPixels ? c->Value : LayoutUnitsToPixels(c->Value);
childMetrics.Variables[c->MyEdge == lmLeft ? 0 : 2].Value = value;
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[") <<
(c->MyEdge == lmLeft ? 0 : 2)<< _T("] =>") << childMetrics.Variables[c->MyEdge == lmLeft ? 0 : 2]);
}
else {
AddConstraint(childMetrics, c, XConstraint);
TRACEX(OwlLayout, 1, _T("BuildConstraints() after Add constraints childMetrics.Metrics.X =>") << *c);
}
// "y" can be one of: top, bottom, center
//
c = &childMetrics.Metrics.Y;
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Metrics.Y =>") << *c);
if (c->Relationship == lmAsIs){
if (c->MyEdge == lmTop){
childMetrics.Variables[1].Value = childMetrics.Child->GetWindowAttr().Y;
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[1] =>") <<
childMetrics.Variables[1]);
}
else{
childMetrics.Variables[3].Value = childMetrics.Child->GetWindowAttr().Y +
childMetrics.Child->GetWindowAttr().H - 1;
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[3] =>") <<
childMetrics.Variables[3]);
}
}
else if (c->Relationship == lmAbsolute && c->MyEdge != lmCenter) {
int value = c->Units == lmPixels ? c->Value : LayoutUnitsToPixels(c->Value);
childMetrics.Variables[c->MyEdge == lmTop ? 1 : 3].Value = value;
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[") <<
(c->MyEdge == lmTop ? 1 : 3) << _T("] =>") <<
childMetrics.Variables[c->MyEdge == lmTop ? 1 : 3]);
}
else {
AddConstraint(childMetrics, c, YConstraint);
TRACEX(OwlLayout, 1, _T("BuildConstraints() after AddConstraint childMetrics.Metrics.Y =>") << *c);
}
// "width" can be one of: width, right, center
//
c = &childMetrics.Metrics.Width;
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Metrics.Width =>") << *c);
if (c->MyEdge == lmRight && (c->Relationship == lmAsIs || c->Relationship == lmAbsolute)){
childMetrics.Variables[2].Value = c->Relationship == lmAsIs ?
childMetrics.Child->GetWindowAttr().X +
childMetrics.Child->GetWindowAttr().W - 1 :
c->Units == lmPixels ? c->Value : LayoutUnitsToPixels(c->Value);
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[2] =>") <<
childMetrics.Variables[2]);
}
else{
AddConstraint(childMetrics, c, WidthConstraint);
TRACEX(OwlLayout, 1, _T("BuildConstraints() after AddConstraint childMetrics.Metrics.Width =>") << *c);
}
// "height" can be one of: height, bottom, center
//
c = &childMetrics.Metrics.Height;
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Metrics.Height =>") << *c);
if (c->MyEdge == lmBottom && (c->Relationship == lmAsIs || c->Relationship == lmAbsolute)){
childMetrics.Variables[3].Value = c->Relationship == lmAsIs ?
childMetrics.Child->GetWindowAttr().Y +
childMetrics.Child->GetWindowAttr().H - 1 :
c->Units == lmPixels ? c->Value : LayoutUnitsToPixels(c->Value);
TRACEX(OwlLayout, 1, _T("BuildConstraints() childMetrics.Variables[3] =>") << childMetrics.Variables[3]);
}
else{
AddConstraint(childMetrics, c, HeightConstraint);
TRACEX(OwlLayout, 1, _T("BuildConstraints() after AddConstraint childMetrics.Metrics.Height =>") << *c);
}
}
}
//
//
//
int
TLayoutWindow::LayoutUnitsToPixels(int value)
{
const long UnitsPerEM = 8;
return int((long(value) * FontHeight + UnitsPerEM / 2) / UnitsPerEM);
}
//
//
//
void
TLayoutWindow::GetFontHeight()
{
HFONT hFont = 0;
if (GetHandle())
hFont = HFONT(HandleMessage(WM_GETFONT));
// NOTE: It's fairly customary to return NULL to the WM_GETFONT
// request - specially when the window is using the system
// font - Hence, we'll default to the system font too...
//
if (!hFont)
hFont = HFONT(GetStockObject(SYSTEM_FONT));
CHECK(hFont);
TFont font(hFont);
FontHeight = font.GetHeight();
}
IMPLEMENT_STREAMABLE1(TLayoutWindow, TWindow);
#if OWL_PERSISTENT_STREAMS
//
// Read the object from the persistent stream.
//
void*
TLayoutWindow::Streamer::Read(ipstream&, uint32) const
{
return GetObject();
}
//
// Write the object into a persistent stream.
//
void
TLayoutWindow::Streamer::Write(opstream&) const
{
}
#endif
//----------------------------------------------------------------------------
//
//
//
TChildMetrics::TChildMetrics(TWindow& child,
const TLayoutMetrics& metrics)
:
Child(&child),
Metrics(metrics)
{
GeneratedConstraints = false;
Next = 0;
}
//
//
//
TConstraint::TConstraint()
{
Inputs[0] = Inputs[1] = Inputs[2] = 0;
OrderedCombination[0] = OrderedCombination[1] = OrderedCombination[2] = 1;
// NOTE: OrderedCombination[3] was initialized to 0 by the TFixedPoint ctor
//
Output = 0;
}
//
//
//
bool
TConstraint::IsResolved()
{
return (!Inputs[0] || Inputs[0]->Resolved) &&
(!Inputs[1] || Inputs[1]->Resolved) &&
(!Inputs[2] || Inputs[2]->Resolved);
}
//
//
//
int
TConstraint::Evaluate()
{
TFixedPoint value = OrderedCombination[3]; // initialize to constant part
TRACEX(OwlLayout, 1, _T("Evaluate() value ") << value);
if (Inputs[0]) {
value += OrderedCombination[0] * Inputs[0]->Value;
TRACEX(OwlLayout, 1, _T("Evaluate() value ") << value <<
_T(", OrderedCombination[0] => ") << OrderedCombination[0] <<
_T(", Inputs[0]->Value => ") << Inputs[0]->Value);
}
if (Inputs[1]) {
value += OrderedCombination[1] * Inputs[1]->Value;
TRACEX(OwlLayout, 1, _T("Evaluate() value ") << value <<
_T(", OrderedCombination[1] => ") << OrderedCombination[1] <<
_T(", Inputs[1]->Value => ") << Inputs[1]->Value);
}
if (Inputs[2]) {
value += OrderedCombination[2] * Inputs[2]->Value;
TRACEX(OwlLayout, 1, _T("Evaluate() value ") << value <<
_T(", OrderedCombination[2] => ") << OrderedCombination[1] <<
_T(", Inputs[2]->Value => ") << Inputs[2]->Value);
}
return value;
}
//
//
//
int
TConstraint::NumActualInputs()
{
int i;
for (i = 0; i < 3; i++)
if (!Inputs[i])
break;
return i;
}
//----------------------------------------------------------------------------
//
/// Creates a TLayoutMetrics object and initializes the object. It sets the units
/// for the child and parent window to the specified layout units, and the
/// relationship between the two windows to what is defined in ImAsIs (of
/// TRelationship). TLayoutMetrics sets the following default values:
/// \code
/// X.RelWin = 0;
/// X.MyEdge = lmLeft;
/// X.Relationship = lmAsIs;
/// X.Units = lmLayoutUnits;
/// X.Value = 0;
/// Y.RelWin = 0;
/// Y.MyEdge = lmTop;
/// Y.Relationship = lmAsIs;
/// Y.Units = lmLayoutUnits;
/// Y.Value = 0;
/// Width.RelWin = 0;
/// Width.MyEdge = lmWidth;
/// Width.Relationship = lmAsIs;
/// Width.Units = lmLayoutUnits;
/// Width.Value = 0;
/// Height.RelWin = 0;
/// Height.MyEdge = lmHeight;
/// Height.Relationship = lmAsIs;
/// Height.Units = lmLayoutUnits;
/// Height.Value = 0;
/// \endcode
/// The following program creates two child windows and a frame into which you can
/// add layout constraints.
/// \code
/// #include <owl/owl.h>
/// #include <owl/framewin.h>
/// #include <owl/applicat.h>
/// #include <owl/layoutwi.h>
/// #include <owl/decorate.h>
/// #include <owl/decmdifr.h>
/// #include <owl/layoutco.h>
/// #pragma hdrstop
///
/// // Create a derived class. //
///
/// class TMyDecoratedFrame : public TDecoratedFrame {
/// public:
/// TMyDecoratedFrame(TWindow* parent, const char far* title,
/// TWindow& clientWnd, TWindow* MyChildWindow);
/// void SetupWindow();
/// {
/// TDecoratedFrame::SetupWindow();
/// MyChildWindow->ShowWindow(SW_NORMAL);
/// MyChildWindow->BringWindowToTop();
/// }
/// };
///
/// // Setup a frame window. //
///
/// TMyDecoratedFrame::TMyDecoratedFrame(TWindow * parent,
/// const char far * title,
/// TWindow& clientWnd)
/// : TDecoratedFrame(parent, title, clientWnd),
/// TFrameWindow(parent, title, &clientWnd),
/// TWindow(parent, title)
/// {
/// // Create a new TMyChildWindow. //
///
/// MyChildWindow = new TWindow(this, "");
/// MyChildWindow->Attr.Style |= WS_BORDER |WS_VISIBLE |WS_CHILD;
/// MyChildwindow->SetBkgndColor(RGB(0,100,0));
///
/// // Establish metrics for the child window. //
///
/// TLayoutMetrics layoutMetrics;
///
/// layoutMetrics.X.Absolute(lmLeft, 10);
/// layoutMetrics.Y.Absolute(lmTop, 10);
/// layoutMetrics.Width.Absolute( 80 );
/// layoutMetrics.Height.Absolute( 80 );
/// }
/// SetChildLayoutMetrics(*MyChildWindow, layoutMetrics);
/// class TMyApp : public TApplication {
/// public:
///
/// virtual void InitMainWindow()
/// {
/// TWindow* client = new TWindow(0, "title");
/// MainWindow = new TMyDecoratedFrame(0,
/// "Layout Window Ex",
/// *client);
/// }
/// };
/// int OwlMain(int, char**) {
/// return TMyApp.Run();
/// }
/// \endcode
//
TLayoutMetrics::TLayoutMetrics()
{
X.RelWin = 0;
X.MyEdge = X.OtherEdge = lmLeft;
X.Relationship = lmAsIs;
X.Units = lmLayoutUnits;
X.Value = 0;
Y.RelWin = 0;
Y.MyEdge = Y.OtherEdge = lmTop;
Y.Relationship = lmAsIs;
Y.Units = lmLayoutUnits;
Y.Value = 0;
Width.RelWin = 0;
Width.MyEdge = Width.OtherEdge = lmWidth;
Width.Relationship = lmAsIs;
Width.Units = lmLayoutUnits;
Width.Value = 0;
Height.RelWin = 0;
Height.MyEdge = Height.OtherEdge = lmHeight;
Height.Relationship = lmAsIs;
Height.Units = lmLayoutUnits;
Height.Value = 0;
}
//
//
//
void
TLayoutMetrics::SetMeasurementUnits(TMeasurementUnits units)
{
X.Units = Y.Units = Width.Units = Height.Units = units;
}
} // OWL namespace
/* ========================================================================== */
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: Next.
↑ V1004 The 'relWinMetrics' pointer was used unsafely after it was verified against nullptr. Check lines: 956, 960.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V774 The 'result' pointer was used after the memory was released.
↑ V803 Decreased performance. In case '(result->OrderedCombination[3])' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.
↑ V803 Decreased performance. In case '(result->OrderedCombination[3])' is iterator it's more effective to use prefix form of decrement. Replace iterator-- with --iterator.
↑ V803 Decreased performance. In case '(result->OrderedCombination[3])' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.
↑ V803 Decreased performance. In case 'result->OrderedCombination[3]' is iterator it's more effective to use prefix form of decrement. Replace iterator-- with --iterator.
↑ V807 Decreased performance. Consider creating a reference to avoid using the 'win->GetWindowAttr()' expression repeatedly.