1 //------------------------------------------------------------------------------
2 // emPackLayout.h
3 //
4 // Copyright (C) 2015 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20 
21 #ifndef emPackLayout_h
22 #define emPackLayout_h
23 
24 #ifndef emBorder_h
25 #include <emCore/emBorder.h>
26 #endif
27 
28 
29 //==============================================================================
30 //================================ emPackLayout ================================
31 //==============================================================================
32 
33 class emPackLayout : public emBorder {
34 
35 public:
36 
37 	// A panel of this class automatically lays out its child panels within
38 	// the content area by a special "pack" algorithm, which allows to give
39 	// each child panel a weight (area proportion) and a preferred tallness
40 	// (height/width ratio). This should be used only for up to about seven
41 	// child panels. With more, the algorithm may not find an optimal
42 	// layout.
43 	//
44 	//                    Pack layout
45 	//   +---------------------------------------------+
46 	//   | +------------------+  +---------+  +-----+  |
47 	//   | |                  |  |         |  |     |  |
48 	//   | |                  |  |         |  |     |  |
49 	//   | |                  |  |         |  |     |  |
50 	//   | |                  |  |         |  +-----+  |
51 	//   | |                  |  |         |           |
52 	//   | |                  |  |         |  +-----+  |
53 	//   | |                  |  |         |  |     |  |
54 	//   | +------------------+  |         |  |     |  |
55 	//   |                       |         |  |     |  |
56 	//   | +------------------+  |         |  |     |  |
57 	//   | |                  |  |         |  |     |  |
58 	//   | |                  |  |         |  |     |  |
59 	//   | +------------------+  +---------+  +-----+  |
60 	//   +---------------------------------------------+
61 	//
62 	// The algorithm recursively divides the available area and the child
63 	// panel set into two areas and two child panel sets until each area has
64 	// only one panel. Thereby, the order of child panels is kept. The area
65 	// proportions are calculated from the given weights. The decision where
66 	// (at which child panel) and how (horizontally or vertically) the
67 	// dividing in each recursive step is made, is determined by iterating
68 	// multiple possibilities until a solution is found which satisfies the
69 	// preferred tallnesses best possible. Because this would be too time
70 	// consuming for large sets, the algorithm reduces the number of
71 	// iterations in a recursive step depending on the size of the set (down
72 	// to zero for large sets). This way, an optimum is guaranteed only for
73 	// up to seven child panels.
74 	//
75 	// By default, a panel of this class is not focusable and has no border,
76 	// because it is meant as a pure layout programming tool. For other use,
77 	// please see the derived class emPackGroup.
78 
79 	emPackLayout(
80 		ParentArg parent, const emString & name,
81 		const emString & caption=emString(),
82 		const emString & description=emString(),
83 		const emImage & icon=emImage()
84 	);
85 		// Like emBorder, but sets non-focusable.
86 
87 	virtual ~emPackLayout();
88 		// Destructor.
89 
90 	int GetMinCellCount() const;
91 	void SetMinCellCount(int minCellCount);
92 		// Minimum number of cells to be generated. The layout algorithm
93 		// behaves like if there were at least this number of child
94 		// panels. The additional cells are simply making up unused
95 		// space. The default is zero.
96 
97 	double GetChildWeight(int index) const;
98 	void SetChildWeight(int index, double weight);
99 		// Get or set the weight of a child panel. The bigger the weight
100 		// of a child panel, the bigger is the proportion of the
101 		// available area given to that panel by the layout algorithm.
102 		// It is a simple linear relation. The index argument denotes a
103 		// child panel. Zero means first child, one means second, and so
104 		// on. The default weight is 1.0.
105 
106 	void SetChildWeight(double weight);
107 		// Set the weight of all child panels to the given value.
108 
109 	double GetPrefChildTallness(int index) const;
110 	void SetPrefChildTallness(int index, double pct);
111 		// Get or set the preferred tallness (height/width ratio) of a
112 		// child panel. The index argument denotes a child panel. Zero
113 		// means first child, one means second, and so on. The default
114 		// preferred tallness is 0.2.
115 
116 	void SetPrefChildTallness(double pct);
117 		// Set the preferred tallness of all child panels to the given
118 		// value.
119 
120 protected:
121 
122 	virtual void LayoutChildren();
123 		// Lays out all child panels in the content area (except for an
124 		// auxiliary panel, which is laid out in the border).
125 
126 private:
127 
128 	struct TmpPanelInfo {
129 		double PCT;
130 		double CumulativeWeight;
131 		double CumulativeLogPCT;
132 		emPanel * Panel;
133 	};
134 
135 	struct TmpInfo {
136 		TmpPanelInfo * TPIs;
137 		emColor CanvasColor;
138 	};
139 
140 	int CountCells();
141 	void FillTPIs(int count);
142 	double GetTPIWeightSum(int index, int count) const;
143 	double GetTPILogPCTSum(int index, int count) const;
144 
145 	double RateCell(int index, double w, double h);
146 
147 	double Pack1(
148 		int index,
149 		double x, double y, double w, double h,
150 		bool execute
151 	);
152 
153 	double Pack2(
154 		int index,
155 		double x, double y, double w, double h,
156 		double bestError, bool execute
157 	);
158 
159 	double Pack3(
160 		int index,
161 		double x, double y, double w, double h,
162 		double bestError, bool execute
163 	);
164 
165 	double PackN(
166 		int index, int count,
167 		double x, double y, double w, double h,
168 		double bestError, bool execute
169 	);
170 
171 	double RateHorizontally(
172 		int index, int count, int div,
173 		double x, double y, double w1, double w2, double h,
174 		double bestError
175 	);
176 
177 	double RateVertically(
178 		int index, int count, int div,
179 		double x, double y, double w, double h1, double h2,
180 		double bestError
181 	);
182 
183 	double DefaultWeight;
184 	double DefaultPCT;
185 	emArray<double> WeightArray;
186 	emArray<double> PCTArray;
187 	int MinCellCount;
188 	TmpInfo * TI;
189 	int Ratings;
190 };
191 
192 
GetMinCellCount()193 inline int emPackLayout::GetMinCellCount() const
194 {
195 	return MinCellCount;
196 }
197 
198 
199 #endif
200