1 /********************************************************************************
2 * *
3 * H o r i z o n t a l C o n t a i n e r O b j e c t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1997,2006 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
21 *********************************************************************************
22 * $Id: FXHorizontalFrame.cpp 4937 2019-03-10 19:59:30Z arthurcnorman $ *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "FXHash.h"
28 #include "FXThread.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXRegistry.h"
35 #include "FXApp.h"
36 #include "FXHorizontalFrame.h"
37
38
39 /*
40 Notes:
41 - Filled items shrink as well as stretch.
42 - Stretch is proportional to default size; this way, at default size,
43 it is exactly correct.
44 - Tabbing order takes widget layout into account
45 */
46
47
48 using namespace FX;
49
50 /*******************************************************************************/
51
52 namespace FX {
53
54 // Map
55 FXDEFMAP(FXHorizontalFrame) FXHorizontalFrameMap[]={
56 FXMAPFUNC(SEL_FOCUS_PREV,0,FXHorizontalFrame::onFocusLeft),
57 FXMAPFUNC(SEL_FOCUS_NEXT,0,FXHorizontalFrame::onFocusRight),
58 };
59
60
61 // Object implementation
FXIMPLEMENT(FXHorizontalFrame,FXPacker,FXHorizontalFrameMap,ARRAYNUMBER (FXHorizontalFrameMap))62 FXIMPLEMENT(FXHorizontalFrame,FXPacker,FXHorizontalFrameMap,ARRAYNUMBER(FXHorizontalFrameMap))
63
64
65 // Make a horizontal one
66 FXHorizontalFrame::FXHorizontalFrame(FXComposite* p,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb,FXint hs,FXint vs):
67 FXPacker(p,opts,x,y,w,h,pl,pr,pt,pb,hs,vs){
68 }
69
70
71 // Compute minimum width based on child layout hints
getDefaultWidth()72 FXint FXHorizontalFrame::getDefaultWidth(){
73 FXint w,wcum,wmax,mw;
74 FXWindow* child;
75 FXuint hints;
76 wcum=wmax=mw=0;
77 if(options&PACK_UNIFORM_WIDTH) mw=maxChildWidth();
78 for(child=getFirst(); child; child=child->getNext()){
79 if(child->shown()){
80 hints=child->getLayoutHints();
81 if(hints&LAYOUT_FIX_WIDTH) w=child->getWidth();
82 else if(options&PACK_UNIFORM_WIDTH) w=mw;
83 else w=child->getDefaultWidth();
84 if((hints&LAYOUT_RIGHT)&&(hints&LAYOUT_CENTER_X)){ // LAYOUT_FIX_X
85 w=child->getX()+w;
86 if(w>wmax) wmax=w;
87 }
88 else{
89 if(wcum) wcum+=hspacing;
90 wcum+=w;
91 }
92 }
93 }
94 wcum+=padleft+padright+(border<<1);
95 return FXMAX(wcum,wmax);
96 }
97
98
99 // Compute minimum height based on child layout hints
getDefaultHeight()100 FXint FXHorizontalFrame::getDefaultHeight(){
101 FXint h,hmax,hcum,mh;
102 FXWindow* child;
103 FXuint hints;
104 hmax=hcum=mh=0;
105 if(options&PACK_UNIFORM_HEIGHT) mh=maxChildHeight();
106 for(child=getFirst(); child; child=child->getNext()){
107 if(child->shown()){
108 hints=child->getLayoutHints();
109 if(hints&LAYOUT_FIX_HEIGHT) h=child->getHeight();
110 else if(options&PACK_UNIFORM_HEIGHT) h=mh;
111 else h=child->getDefaultHeight();
112 if((hints&LAYOUT_BOTTOM)&&(hints&LAYOUT_CENTER_Y)){ // LAYOUT_FIX_Y
113 h=child->getY()+h;
114 if(h>hmax) hmax=h;
115 }
116 else{
117 if(h>hcum) hcum=h;
118 }
119 }
120 }
121 hcum+=padtop+padbottom+(border<<1);
122 return FXMAX(hcum,hmax);
123 }
124
125
126 // Recalculate layout
layout()127 void FXHorizontalFrame::layout(){
128 FXint left,right,top,bottom,remain,extra_space,total_space,t,x,y,w,h;
129 FXWindow* child;
130 FXint sumexpand=0;
131 FXint numexpand=0;
132 FXint mw=0;
133 FXint mh=0;
134 FXint e=0;
135 FXuint hints;
136
137 // Placement rectangle; right/bottom non-inclusive
138 left=border+padleft;
139 right=width-border-padright;
140 top=border+padtop;
141 bottom=height-border-padbottom;
142 remain=right-left;
143
144 // Get maximum child size
145 if(options&PACK_UNIFORM_WIDTH) mw=maxChildWidth();
146 if(options&PACK_UNIFORM_HEIGHT) mh=maxChildHeight();
147
148 // Find number of paddable children and total width
149 for(child=getFirst(); child; child=child->getNext()){
150 if(child->shown()){
151 hints=child->getLayoutHints();
152 if(!((hints&LAYOUT_RIGHT)&&(hints&LAYOUT_CENTER_X))){ // LAYOUT_FIX_X
153 if(hints&LAYOUT_FIX_WIDTH) w=child->getWidth();
154 else if(options&PACK_UNIFORM_WIDTH) w=mw;
155 else w=child->getDefaultWidth();
156 FXASSERT(w>=0);
157 if((hints&LAYOUT_CENTER_X) || ((hints&LAYOUT_FILL_X) && !(hints&LAYOUT_FIX_WIDTH))){
158 sumexpand+=w;
159 numexpand+=1;
160 }
161 else{
162 remain-=w;
163 }
164 remain-=hspacing;
165 }
166 }
167 }
168
169 // Child spacing correction
170 remain+=hspacing;
171
172 // Do the layout
173 for(child=getFirst(); child; child=child->getNext()){
174 if(child->shown()){
175 hints=child->getLayoutHints();
176
177 // Determine child height
178 if(hints&LAYOUT_FIX_HEIGHT) h=child->getHeight();
179 else if(options&PACK_UNIFORM_HEIGHT) h=mh;
180 else if(hints&LAYOUT_FILL_Y) h=bottom-top;
181 else h=child->getDefaultHeight();
182
183 // Determine child y-position
184 if((hints&LAYOUT_BOTTOM)&&(hints&LAYOUT_CENTER_Y)) y=child->getY();
185 else if(hints&LAYOUT_CENTER_Y) y=top+(bottom-top-h)/2;
186 else if(hints&LAYOUT_BOTTOM) y=bottom-h;
187 else y=top;
188
189 // Layout child in X
190 x=child->getX();
191 if(hints&LAYOUT_FIX_WIDTH) w=child->getWidth();
192 else if(options&PACK_UNIFORM_WIDTH) w=mw;
193 else w=child->getDefaultWidth();
194 if(!((hints&LAYOUT_RIGHT)&&(hints&LAYOUT_CENTER_X))){ // LAYOUT_FIX_X
195 extra_space=0;
196 total_space=0;
197 if((hints&LAYOUT_FILL_X) && !(hints&LAYOUT_FIX_WIDTH)){
198 if(sumexpand>0){ // Divide space proportionally to width
199 t=w*remain;
200 FXASSERT(sumexpand>0);
201 w=t/sumexpand;
202 e+=t%sumexpand;
203 if(e>=sumexpand){w++;e-=sumexpand;}
204 }
205 else{ // Divide the space equally
206 FXASSERT(numexpand>0);
207 w=remain/numexpand;
208 e+=remain%numexpand;
209 if(e>=numexpand){w++;e-=numexpand;}
210 }
211 }
212 else if(hints&LAYOUT_CENTER_X){
213 if(sumexpand>0){ // Divide space proportionally to width
214 t=w*remain;
215 FXASSERT(sumexpand>0);
216 total_space=t/sumexpand-w;
217 e+=t%sumexpand;
218 if(e>=sumexpand){total_space++;e-=sumexpand;}
219 }
220 else{ // Divide the space equally
221 FXASSERT(numexpand>0);
222 total_space=remain/numexpand-w;
223 e+=remain%numexpand;
224 if(e>=numexpand){total_space++;e-=numexpand;}
225 }
226 extra_space=total_space/2;
227 }
228 if(hints&LAYOUT_RIGHT){
229 x=right-w-extra_space;
230 right=right-w-hspacing-total_space;
231 }
232 else{
233 x=left+extra_space;
234 left=left+w+hspacing+total_space;
235 }
236 }
237 child->position(x,y,w,h);
238 }
239 }
240 flags&=~FLAG_DIRTY;
241 }
242
243 }
244
245