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