1 /********************************************************************************
2 * *
3 * S c r o l l i n g M e n u P a n e W i d g e t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1997,2005 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: FXScrollPane.cpp,v 1.17 2005/01/16 16:06:07 fox Exp $ *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "fxkeys.h"
28 #include "FXHash.h"
29 #include "FXThread.h"
30 #include "FXStream.h"
31 #include "FXString.h"
32 #include "FXSize.h"
33 #include "FXPoint.h"
34 #include "FXRectangle.h"
35 #include "FXRegistry.h"
36 #include "FXAccelTable.h"
37 #include "FXApp.h"
38 #include "FXDCWindow.h"
39 #include "FXFont.h"
40 #include "FXArrowButton.h"
41 #include "FXMenuPane.h"
42 #include "FXScrollPane.h"
43
44
45 /*
46 Notes:
47 - Should we reset the topmost item each time it is shown?
48 */
49
50 using namespace FX;
51
52 /*******************************************************************************/
53
54 namespace FX {
55
56 // Map
57 FXDEFMAP(FXScrollPane) FXScrollPaneMap[]={
58 FXMAPFUNC(SEL_UPDATE,FXScrollPane::ID_SCROLL_DN,FXScrollPane::onUpdIncrement),
59 FXMAPFUNC(SEL_COMMAND,FXScrollPane::ID_SCROLL_DN,FXScrollPane::onCmdIncrement),
60 FXMAPFUNC(SEL_UPDATE,FXScrollPane::ID_SCROLL_UP,FXScrollPane::onUpdDecrement),
61 FXMAPFUNC(SEL_COMMAND,FXScrollPane::ID_SCROLL_UP,FXScrollPane::onCmdDecrement),
62 };
63
64
65 // Object implementation
FXIMPLEMENT(FXScrollPane,FXPopup,FXScrollPaneMap,ARRAYNUMBER (FXScrollPaneMap))66 FXIMPLEMENT(FXScrollPane,FXPopup,FXScrollPaneMap,ARRAYNUMBER(FXScrollPaneMap))
67
68
69 // Deserialization
70 FXScrollPane::FXScrollPane(){
71 visible=10;
72 top=0;
73 }
74
75
76 // Build empty one
FXScrollPane(FXWindow * owner,FXint nvis,FXuint opts)77 FXScrollPane::FXScrollPane(FXWindow* owner,FXint nvis,FXuint opts):FXMenuPane(owner,opts){
78 up=new FXArrowButton(this,this,ID_SCROLL_UP,ARROW_UP|ARROW_AUTO|ARROW_REPEAT);
79 dn=new FXArrowButton(this,this,ID_SCROLL_DN,ARROW_DOWN|ARROW_AUTO|ARROW_REPEAT);
80 up->setArrowSize(7);
81 dn->setArrowSize(7);
82 visible=nvis;
83 top=0;
84 }
85
86
87 // Show popup and add to popup stack
show()88 void FXScrollPane::show(){
89 FXMenuPane::show();
90 setTopItem(0);
91 }
92
93
94 // Get width
getDefaultWidth()95 FXint FXScrollPane::getDefaultWidth(){
96 register FXWindow* child;
97 register FXint wmax,wcum,w,n;
98 register FXuint hints;
99 wmax=wcum=0;
100 for(child=dn->getNext(); child; child=child->getNext()){
101 if(child->shown()){
102 hints=child->getLayoutHints();
103 if(hints&LAYOUT_FIX_WIDTH) w=child->getWidth();
104 else w=child->getDefaultWidth();
105 if(wmax<w) wmax=w;
106 }
107 }
108 for(child=dn->getNext(),n=0; child && n<visible; child=child->getNext()){
109 if(child->shown()){
110 hints=child->getLayoutHints();
111 if(hints&LAYOUT_FIX_WIDTH) w=child->getWidth();
112 else if(options&PACK_UNIFORM_WIDTH) w=wmax;
113 else w=child->getDefaultWidth();
114 wcum+=w;
115 n++;
116 }
117 }
118 if(options&POPUP_HORIZONTAL){
119 wcum+=up->getDefaultWidth();
120 wcum+=dn->getDefaultWidth();
121 }
122 else{
123 wcum=wmax;
124 }
125 return wcum+(border<<1);
126 }
127
128
129 // Get height
getDefaultHeight()130 FXint FXScrollPane::getDefaultHeight(){
131 register FXWindow* child;
132 register FXint hmax,hcum,h,n;
133 register FXuint hints;
134 hmax=hcum=0;
135 for(child=dn->getNext(); child; child=child->getNext()){
136 if(child->shown()){
137 hints=child->getLayoutHints();
138 if(hints&LAYOUT_FIX_HEIGHT) h=child->getHeight();
139 else h=child->getDefaultHeight();
140 if(hmax<h) hmax=h;
141 }
142 }
143 for(child=dn->getNext(),n=0; child && n<visible; child=child->getNext()){
144 if(child->shown()){
145 hints=child->getLayoutHints();
146 if(hints&LAYOUT_FIX_HEIGHT) h=child->getHeight();
147 else if(options&PACK_UNIFORM_HEIGHT) h=hmax;
148 else h=child->getDefaultHeight();
149 hcum+=h;
150 n++;
151 }
152 }
153 if(options&POPUP_HORIZONTAL){
154 hcum=hmax;
155 }
156 else{
157 hcum+=up->getDefaultHeight();
158 hcum+=dn->getDefaultHeight();
159 }
160 return hcum+(border<<1);
161 }
162
163
164 // Recalculate layout
layout()165 void FXScrollPane::layout(){
166 register FXint w,h,x,y,mw,mh,arrowsize,n;
167 register FXWindow *child;
168 register FXuint hints;
169
170 // Horizontal
171 if(options&POPUP_HORIZONTAL){
172
173 // Width of arrow button
174 arrowsize=up->getDefaultWidth();
175
176 // Get maximum size
177 for(child=dn->getNext(),mw=0; child; child=child->getNext()){
178 if(child->shown()){
179 hints=child->getLayoutHints();
180 if(hints&LAYOUT_FIX_WIDTH) w=child->getWidth();
181 else w=child->getDefaultWidth();
182 if(mw<w) mw=w;
183 }
184 }
185
186 // Do the layout
187 for(child=dn->getNext(),x=border+arrowsize,n=0; child; child=child->getNext()){
188 if(child->shown()){
189 hints=child->getLayoutHints();
190 if(hints&LAYOUT_FIX_WIDTH) w=child->getWidth();
191 else if(options&PACK_UNIFORM_WIDTH) w=mw;
192 else w=child->getDefaultWidth();
193 if(top<=n && n<top+visible){
194 child->position(x,border,w,height-(border<<1));
195 x+=w;
196 }
197 else{
198 child->position(0,height,w,height-(border<<1));
199 }
200 n++;
201 }
202 }
203
204 // Place arrow buttons
205 up->position(border,border,arrowsize,height-(border<<1));
206 dn->position(width-border-arrowsize,border,arrowsize,height-(border<<1));
207
208 // Point arrows left and right
209 up->setArrowStyle(ARROW_LEFT|ARROW_AUTO|ARROW_REPEAT);
210 dn->setArrowStyle(ARROW_RIGHT|ARROW_AUTO|ARROW_REPEAT);
211 }
212
213 // Vertical
214 else{
215
216 // Height of arrow button
217 arrowsize=up->getDefaultHeight();
218
219 // Get maximum size
220 for(child=dn->getNext(),mh=0; child; child=child->getNext()){
221 if(child->shown()){
222 hints=child->getLayoutHints();
223 if(hints&LAYOUT_FIX_HEIGHT) h=child->getHeight();
224 else h=child->getDefaultHeight();
225 if(mh<h) mh=h;
226 }
227 }
228
229 // Do the layout
230 for(child=dn->getNext(),y=border+arrowsize,n=0; child; child=child->getNext()){
231 if(child->shown()){
232 hints=child->getLayoutHints();
233 if(hints&LAYOUT_FIX_HEIGHT) h=child->getHeight();
234 else if(options&PACK_UNIFORM_HEIGHT) h=mh;
235 else h=child->getDefaultHeight();
236 if(top<=n && n<top+visible){
237 child->position(border,y,width-(border<<1),h);
238 y+=h;
239 }
240 else{
241 child->position(width,0,width-(border<<1),h); // Move off to the side
242 }
243 n++;
244 }
245 }
246
247 // Place arrow buttons
248 up->position(border,border,width-(border<<1),arrowsize);
249 dn->position(border,height-border-arrowsize,width-(border<<1),arrowsize);
250
251 // Point arrows up and down
252 up->setArrowStyle(ARROW_UP|ARROW_AUTO|ARROW_REPEAT);
253 dn->setArrowStyle(ARROW_DOWN|ARROW_AUTO|ARROW_REPEAT);
254 }
255
256 // Arrow buttons stay on top
257 up->raise();
258 dn->raise();
259
260 // No more dirty
261 flags&=~FLAG_DIRTY;
262 }
263
264
265 // Gray out scroll up arrow
onUpdIncrement(FXObject *,FXSelector,void *)266 long FXScrollPane::onUpdIncrement(FXObject*,FXSelector,void*){
267 if(top>=numChildren()-visible-2) dn->disable(); else dn->enable();
268 return 1;
269 }
270
271
272 // Scroll contents up
onCmdIncrement(FXObject *,FXSelector,void *)273 long FXScrollPane::onCmdIncrement(FXObject*,FXSelector,void*){
274 setTopItem(top+1);
275 return 1;
276 }
277
278
279 // Gray out scroll down arrow
onUpdDecrement(FXObject *,FXSelector,void *)280 long FXScrollPane::onUpdDecrement(FXObject*,FXSelector,void*){
281 if(top<=0) up->disable(); else up->enable();
282 return 1;
283 }
284
285
286 // Scroll contents down
onCmdDecrement(FXObject *,FXSelector,void *)287 long FXScrollPane::onCmdDecrement(FXObject*,FXSelector,void*){
288 setTopItem(top-1);
289 return 1;
290 }
291
292
293 // Scroll item to top
setTopItem(FXint t)294 void FXScrollPane::setTopItem(FXint t){
295 FXint m=numChildren()-visible-2; // FIXME should really be visible children
296 if(t<0) t=0;
297 if(t>=m) t=m;
298 if(t!=top){
299 top=t;
300 recalc();
301 }
302 }
303
304
305 // Destroy it
~FXScrollPane()306 FXScrollPane::~FXScrollPane(){
307 dn=(FXArrowButton*)-1L;
308 up=(FXArrowButton*)-1L;
309 }
310
311 }
312