1 /********************************************************************************
2 * *
3 * S w i t c h P a n e l C l a s s *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1997,2021 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as published by *
10 * the Free Software Foundation; either version 3 of the License, or *
11 * (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 *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/> *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "FXArray.h"
26 #include "FXHash.h"
27 #include "FXMutex.h"
28 #include "FXStream.h"
29 #include "FXString.h"
30 #include "FXSize.h"
31 #include "FXPoint.h"
32 #include "FXRectangle.h"
33 #include "FXStringDictionary.h"
34 #include "FXSettings.h"
35 #include "FXRegistry.h"
36 #include "FXEvent.h"
37 #include "FXWindow.h"
38 #include "FXDCWindow.h"
39 #include "FXApp.h"
40 #include "FXSwitcher.h"
41
42
43 /*
44 Notes:
45 - We do not look at LAYOUT_FIX_WIDTH and LAYOUT_FIX_HEIGHT because
46 FXSwitcher resizes its children anyway and doing this would cause
47 the size to grow instead of shrinkwrap to the biggest child.
48 - Thanks to Charles Warren for the suggestion for the collapse
49 modes.
50 - The current panel number is adjusted if the number of panels changes.
51 */
52
53
54 // Switcher styles
55 #define SWITCHER_MASK (SWITCHER_HCOLLAPSE|SWITCHER_VCOLLAPSE)
56
57 using namespace FX;
58
59 /*******************************************************************************/
60
61 namespace FX {
62
63 // Map
64 FXDEFMAP(FXSwitcher) FXSwitcherMap[]={
65 FXMAPFUNC(SEL_PAINT,0,FXSwitcher::onPaint),
66 FXMAPFUNCS(SEL_UPDATE,FXSwitcher::ID_OPEN_FIRST,FXSwitcher::ID_OPEN_LAST,FXSwitcher::onUpdOpen),
67 FXMAPFUNC(SEL_COMMAND,FXSwitcher::ID_SETVALUE,FXSwitcher::onCmdSetValue),
68 FXMAPFUNC(SEL_COMMAND,FXSwitcher::ID_SETINTVALUE,FXSwitcher::onCmdSetIntValue),
69 FXMAPFUNC(SEL_COMMAND,FXSwitcher::ID_GETINTVALUE,FXSwitcher::onCmdGetIntValue),
70 FXMAPFUNCS(SEL_COMMAND,FXSwitcher::ID_OPEN_FIRST,FXSwitcher::ID_OPEN_LAST,FXSwitcher::onCmdOpen),
71 };
72
73
74 // Object implementation
FXIMPLEMENT(FXSwitcher,FXPacker,FXSwitcherMap,ARRAYNUMBER (FXSwitcherMap))75 FXIMPLEMENT(FXSwitcher,FXPacker,FXSwitcherMap,ARRAYNUMBER(FXSwitcherMap))
76
77
78 // Serialization
79 FXSwitcher::FXSwitcher():current(-1){
80 }
81
82
83 // Make a switcher window
FXSwitcher(FXComposite * p,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb)84 FXSwitcher::FXSwitcher(FXComposite *p,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb):FXPacker(p,opts,x,y,w,h,pl,pr,pt,pb,0,0),current(-1){
85 }
86
87
88 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)89 long FXSwitcher::onPaint(FXObject*,FXSelector,void* ptr){
90 FXEvent *ev=(FXEvent*)ptr;
91 FXDCWindow dc(this,ev);
92 dc.setForeground(backColor);
93 dc.fillRectangle(ev->rect.x,ev->rect.y,ev->rect.w,ev->rect.h);
94 drawFrame(dc,0,0,width,height);
95 return 1;
96 }
97
98
99 // Update value from a message
onCmdSetValue(FXObject *,FXSelector,void * ptr)100 long FXSwitcher::onCmdSetValue(FXObject*,FXSelector,void* ptr){
101 setCurrent((FXint)(FXuval)ptr);
102 return 1;
103 }
104
105
106 // Update value from a message
onCmdSetIntValue(FXObject *,FXSelector,void * ptr)107 long FXSwitcher::onCmdSetIntValue(FXObject*,FXSelector,void* ptr){
108 setCurrent(*((FXint*)ptr));
109 return 1;
110 }
111
112
113 // Obtain value from text field
onCmdGetIntValue(FXObject *,FXSelector,void * ptr)114 long FXSwitcher::onCmdGetIntValue(FXObject*,FXSelector,void* ptr){
115 *((FXint*)ptr)=getCurrent();
116 return 1;
117 }
118
119
120 // Bring nth to the top
onCmdOpen(FXObject *,FXSelector sel,void *)121 long FXSwitcher::onCmdOpen(FXObject*,FXSelector sel,void*){
122 setCurrent(FXSELID(sel)-ID_OPEN_FIRST,true);
123 return 1;
124 }
125
126
127 // Update the nth button
onUpdOpen(FXObject * sender,FXSelector sel,void * ptr)128 long FXSwitcher::onUpdOpen(FXObject* sender,FXSelector sel,void* ptr){
129 sender->handle(this,((FXSELID(sel)-ID_OPEN_FIRST)==current) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),ptr);
130 return 1;
131 }
132
133
134 // Get maximum child width
getDefaultWidth()135 FXint FXSwitcher::getDefaultWidth(){
136 FXWindow* child;
137 FXint i,w,wmax=0,wcur=0;
138 for(i=0,child=getFirst(); child; child=child->getNext(),i++){
139 if(i==current) wcur=child->getDefaultWidth();
140 if(wmax<(w=child->getDefaultWidth())) wmax=w;
141 }
142 if(options&SWITCHER_HCOLLAPSE) wmax=wcur;
143 return padleft+padright+(border<<1)+wmax;
144 }
145
146
147 // Get maximum child height
getDefaultHeight()148 FXint FXSwitcher::getDefaultHeight(){
149 FXWindow* child;
150 FXint i,h,hmax=0,hcur=0;
151 for(i=0,child=getFirst(); child; child=child->getNext(),i++){
152 if(i==current) hcur=child->getDefaultHeight();
153 if(hmax<(h=child->getDefaultHeight())) hmax=h;
154 }
155 if(options&SWITCHER_VCOLLAPSE) hmax=hcur;
156 return padtop+padbottom+(border<<1)+hmax;
157 }
158
159
160 // Recalculate layout
layout()161 void FXSwitcher::layout(){
162 FXWindow *child;
163 FXint i,x,y,w,h;
164 x=border+padleft;
165 y=border+padtop;
166 w=width-padright-padleft-(border<<1);
167 h=height-padtop-padbottom-(border<<1);
168 if(current<0) current=0;
169 if(current>=numChildren()) current=numChildren()-1;
170 for(child=getFirst(),i=0; child; child=child->getNext(),i++){
171 child->position(x,y,w,h);
172 if(i==current){
173 child->show();
174 }
175 else{
176 child->hide();
177 }
178 }
179 flags&=~FLAG_DIRTY;
180 }
181
182
183 // Set current subwindow
setCurrent(FXint panel,FXbool notify)184 void FXSwitcher::setCurrent(FXint panel,FXbool notify){
185 if(current!=panel && 0<=panel && panel<numChildren()){
186 current=panel;
187 recalc();
188 if(notify && target){ target->tryHandle(this,FXSEL(SEL_COMMAND,message),(void*)(FXival)current); }
189 }
190 }
191
192
193 // Set switcher style
setSwitcherStyle(FXuint style)194 void FXSwitcher::setSwitcherStyle(FXuint style){
195 FXuint opts=(options&~SWITCHER_MASK) | (style&SWITCHER_MASK);
196 if(options!=opts){
197 options=opts;
198 recalc();
199 }
200 }
201
202
203 // Get switcher style
getSwitcherStyle() const204 FXuint FXSwitcher::getSwitcherStyle() const {
205 return (options&SWITCHER_MASK);
206 }
207
208
209 // Save object to stream
save(FXStream & store) const210 void FXSwitcher::save(FXStream& store) const {
211 FXPacker::save(store);
212 store << current;
213 }
214
215
216 // Load object from stream
load(FXStream & store)217 void FXSwitcher::load(FXStream& store){
218 FXPacker::load(store);
219 store >> current;
220 }
221
222 }
223