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