1 /********************************************************************************
2 * *
3 * G r o u p B o x W i n d o w O b j e c t *
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 "FXFont.h"
37 #include "FXEvent.h"
38 #include "FXWindow.h"
39 #include "FXDCWindow.h"
40 #include "FXApp.h"
41 #include "FXLabel.h"
42 #include "FXGroupBox.h"
43
44
45 /*
46 Notes:
47
48 - Radio behaviour of groupbox has been dropped; groupbox is now
49 purely a decorative layout manager.
50 */
51
52
53 #define FRAME_MASK (FRAME_SUNKEN|FRAME_RAISED|FRAME_THICK)
54 #define GROUPBOX_TITLE_MASK (GROUPBOX_TITLE_LEFT|GROUPBOX_TITLE_CENTER|GROUPBOX_TITLE_RIGHT)
55
56 using namespace FX;
57
58 /*******************************************************************************/
59
60 namespace FX {
61
62 // Map
63 FXDEFMAP(FXGroupBox) FXGroupBoxMap[]={
64 FXMAPFUNC(SEL_PAINT,0,FXGroupBox::onPaint),
65 FXMAPFUNC(SEL_COMMAND,FXGroupBox::ID_SETVALUE,FXGroupBox::onCmdSetValue),
66 FXMAPFUNC(SEL_COMMAND,FXGroupBox::ID_SETSTRINGVALUE,FXGroupBox::onCmdSetStringValue),
67 FXMAPFUNC(SEL_COMMAND,FXGroupBox::ID_GETSTRINGVALUE,FXGroupBox::onCmdGetStringValue),
68 };
69
70
71 // Object implementation
FXIMPLEMENT(FXGroupBox,FXPacker,FXGroupBoxMap,ARRAYNUMBER (FXGroupBoxMap))72 FXIMPLEMENT(FXGroupBox,FXPacker,FXGroupBoxMap,ARRAYNUMBER(FXGroupBoxMap))
73
74
75 // Deserialization
76 FXGroupBox::FXGroupBox(){
77 flags|=FLAG_ENABLED;
78 font=(FXFont*)-1L;
79 textColor=0;
80 }
81
82
83 // Make a groupbox
FXGroupBox(FXComposite * p,const FXString & text,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb,FXint hs,FXint vs)84 FXGroupBox::FXGroupBox(FXComposite* p,const FXString& text,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb,FXint hs,FXint vs):
85 FXPacker(p,opts,x,y,w,h,pl,pr,pt,pb,hs,vs),label(text){
86 flags|=FLAG_ENABLED;
87 font=getApp()->getNormalFont();
88 textColor=getApp()->getForeColor();
89 }
90
91
92 // Create window
create()93 void FXGroupBox::create(){
94 FXPacker::create();
95 font->create();
96 }
97
98
99 // Detach window
detach()100 void FXGroupBox::detach(){
101 FXPacker::detach();
102 font->detach();
103 }
104
105
106 // Enable the window
enable()107 void FXGroupBox::enable(){
108 if(!(flags&FLAG_ENABLED)){
109 FXPacker::enable();
110 update();
111 }
112 }
113
114
115 // Disable the window
disable()116 void FXGroupBox::disable(){
117 if(flags&FLAG_ENABLED){
118 FXPacker::disable();
119 update();
120 }
121 }
122
123
124 // Change the font
setFont(FXFont * fnt)125 void FXGroupBox::setFont(FXFont* fnt){
126 if(!fnt){ fxerror("%s::setFont: NULL font specified.\n",getClassName()); }
127 if(font!=fnt){
128 font=fnt;
129 recalc();
130 update();
131 }
132 }
133
134
135 // Get default width
getDefaultWidth()136 FXint FXGroupBox::getDefaultWidth(){
137 FXint cw=FXPacker::getDefaultWidth();
138 if(!label.empty()){
139 FXint tw=font->getTextWidth(label)+16;
140 return FXMAX(cw,tw);
141 }
142 return cw;
143 }
144
145
146 // Get default height
getDefaultHeight()147 FXint FXGroupBox::getDefaultHeight(){
148 FXint ch=FXPacker::getDefaultHeight();
149 if(!label.empty()){
150 return ch+font->getFontHeight()+4-border; // Have text instead of border
151 }
152 return ch;
153 }
154
155
156 // Recompute layout
layout()157 void FXGroupBox::layout(){
158 FXint tmp=padtop;
159 if(!label.empty()){
160 padtop=padtop+font->getFontHeight()+4-border; // Have text instead of border
161 }
162 FXPacker::layout();
163 flags&=~FLAG_DIRTY;
164 padtop=tmp;
165 }
166
167
168 // Update value from a message
onCmdSetValue(FXObject *,FXSelector,void * ptr)169 long FXGroupBox::onCmdSetValue(FXObject*,FXSelector,void* ptr){
170 setText((const FXchar*)ptr);
171 return 1;
172 }
173
174
175 // Update value from a message
onCmdSetStringValue(FXObject *,FXSelector,void * ptr)176 long FXGroupBox::onCmdSetStringValue(FXObject*,FXSelector,void* ptr){
177 setText(*((FXString*)ptr));
178 return 1;
179 }
180
181
182 // Obtain value from text field
onCmdGetStringValue(FXObject *,FXSelector,void * ptr)183 long FXGroupBox::onCmdGetStringValue(FXObject*,FXSelector,void* ptr){
184 *((FXString*)ptr)=getText();
185 return 1;
186 }
187
188
189 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)190 long FXGroupBox::onPaint(FXObject*,FXSelector,void* ptr){
191 FXEvent *event=(FXEvent*)ptr;
192 FXDCWindow dc(this,event);
193 FXint tw,th,yy,xx;
194
195 xx=0;
196 yy=0;
197
198 // Paint background
199 dc.setForeground(backColor);
200 dc.fillRectangle(event->rect.x,event->rect.y,event->rect.w,event->rect.h);
201
202 // Draw label if there is one
203 if(!label.empty()){
204 yy=2+font->getFontAscent()/2;
205 }
206
207 // We should really just draw what's exposed!
208 switch(options&FRAME_MASK) {
209 case FRAME_LINE: drawBorderRectangle(dc,0,yy,width,height-yy); break;
210 case FRAME_SUNKEN: drawSunkenRectangle(dc,0,yy,width,height-yy); break;
211 case FRAME_RAISED: drawRaisedRectangle(dc,0,yy,width,height-yy); break;
212 case FRAME_GROOVE: drawGrooveRectangle(dc,0,yy,width,height-yy); break;
213 case FRAME_RIDGE: drawRidgeRectangle(dc,0,yy,width,height-yy); break;
214 case FRAME_SUNKEN|FRAME_THICK: drawDoubleSunkenRectangle(dc,0,yy,width,height-yy); break;
215 case FRAME_RAISED|FRAME_THICK: drawDoubleRaisedRectangle(dc,0,yy,width,height-yy); break;
216 }
217
218 // Draw label
219 if(!label.empty()){
220 tw=font->getTextWidth(label);
221 th=font->getFontHeight()+4;
222 if(options&GROUPBOX_TITLE_RIGHT) xx=width-tw-12;
223 else if(options&GROUPBOX_TITLE_CENTER) xx=(width-tw)/2-4;
224 else xx=4;
225 if(xx<4) xx=4;
226 if(tw+16>width) tw=width-16;
227 if(0<tw){
228 dc.setForeground(backColor);
229 dc.setFont(font);
230 dc.fillRectangle(xx,yy,tw+8,2);
231 dc.setClipRectangle(xx+4,0,tw,th);
232 if(isEnabled()){
233 dc.setForeground(textColor);
234 dc.drawText(xx+4,2+font->getFontAscent(),label);
235 }
236 else{
237 dc.setForeground(hiliteColor);
238 dc.drawText(xx+5,3+font->getFontAscent(),label);
239 dc.setForeground(shadowColor);
240 dc.drawText(xx+4,2+font->getFontAscent(),label);
241 }
242 }
243 }
244 return 1;
245 }
246
247
248 // Get group box style
getGroupBoxStyle() const249 FXuint FXGroupBox::getGroupBoxStyle() const {
250 return (options&GROUPBOX_TITLE_MASK);
251 }
252
253
254 // Set group box style
setGroupBoxStyle(FXuint style)255 void FXGroupBox::setGroupBoxStyle(FXuint style){
256 FXuint opts=(options&~GROUPBOX_TITLE_MASK) | (style&GROUPBOX_TITLE_MASK);
257 if(options!=opts){
258 options=opts;
259 recalc();
260 update();
261 }
262 }
263
264
265 // Change text
setText(const FXString & text)266 void FXGroupBox::setText(const FXString& text){
267 if(label!=text){
268 label=text;
269 recalc();
270 update();
271 }
272 }
273
274
275 // Set text color
setTextColor(FXColor clr)276 void FXGroupBox::setTextColor(FXColor clr){
277 if(textColor!=clr){
278 textColor=clr;
279 update();
280 }
281 }
282
283
284 // Save object to stream
save(FXStream & store) const285 void FXGroupBox::save(FXStream& store) const {
286 FXPacker::save(store);
287 store << label;
288 store << font;
289 store << textColor;
290 }
291
292
293 // Load object from stream
load(FXStream & store)294 void FXGroupBox::load(FXStream& store){
295 FXPacker::load(store);
296 store >> label;
297 store >> font;
298 store >> textColor;
299 }
300
301 }
302