1 /********************************************************************************
2 *                                                                               *
3 *                            C h o i c e   B o x                                *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 2004,2020 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 "FXObjectList.h"
34 #include "FXStringDictionary.h"
35 #include "FXSettings.h"
36 #include "FXRegistry.h"
37 #include "FXAccelTable.h"
38 #include "FXEvent.h"
39 #include "FXWindow.h"
40 #include "FXApp.h"
41 #include "FXIcon.h"
42 #include "FXSeparator.h"
43 #include "FXLabel.h"
44 #include "FXButton.h"
45 #include "FXHorizontalFrame.h"
46 #include "FXVerticalFrame.h"
47 #include "FXScrollBar.h"
48 #include "FXList.h"
49 #include "FXChoiceBox.h"
50 #include "icons.h"
51 
52 /*
53   Notes:
54   - Maybe allow setting initial value which selected.
55   - Maybe have multiple choice capability.
56   - Maybe have list of icons for each list item.
57 */
58 
59 // Padding for message box buttons
60 #define HORZ_PAD 30
61 #define VERT_PAD 2
62 
63 using namespace FX;
64 
65 /*******************************************************************************/
66 
67 namespace FX {
68 
69 // Map
70 FXDEFMAP(FXChoiceBox) FXChoiceBoxMap[]={
71   FXMAPFUNC(SEL_COMMAND,FXChoiceBox::ID_CANCEL,FXChoiceBox::onCmdCancel),
72   FXMAPFUNC(SEL_COMMAND,FXChoiceBox::ID_ACCEPT,FXChoiceBox::onCmdClicked),
73   FXMAPFUNC(SEL_DOUBLECLICKED,FXChoiceBox::ID_CLICKED,FXChoiceBox::onCmdClicked),
74   };
75 
76 
77 
78 // Object implementation
FXIMPLEMENT(FXChoiceBox,FXDialogBox,FXChoiceBoxMap,ARRAYNUMBER (FXChoiceBoxMap))79 FXIMPLEMENT(FXChoiceBox,FXDialogBox,FXChoiceBoxMap,ARRAYNUMBER(FXChoiceBoxMap))
80 
81 
82 // Construct choice box with given caption, icon, message text, and with choices from array of strings
83 FXChoiceBox::FXChoiceBox(FXWindow* own,const FXString& caption,const FXString& text,FXIcon* icn,const FXchar** choices,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXDialogBox(own,caption,opts|DECOR_TITLE|DECOR_BORDER,x,y,w,h,10,10,10,10, 10,10){
84   FXint n;
85   initialize(text,icn);
86   n=list->fillItems(choices);
87   list->setNumVisible(FXMIN(n,5));
88   }
89 
90 
91 // Construct choice box with given caption, icon, message text, and with choices from newline separated strings
FXChoiceBox(FXWindow * own,const FXString & caption,const FXString & text,FXIcon * icn,const FXString & choices,FXuint opts,FXint x,FXint y,FXint w,FXint h)92 FXChoiceBox::FXChoiceBox(FXWindow* own,const FXString& caption,const FXString& text,FXIcon* icn,const FXString& choices,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXDialogBox(own,caption,opts|DECOR_TITLE|DECOR_BORDER,x,y,w,h,10,10,10,10, 10,10){
93   FXint n;
94   initialize(text,icn);
95   n=list->fillItems(choices);
96   list->setNumVisible(FXMIN(n,5));
97   }
98 
99 
100 // Construct free floating choice box with given caption, icon, message text, and with choices from array of strings
FXChoiceBox(FXApp * a,const FXString & caption,const FXString & text,FXIcon * icn,const FXchar ** choices,FXuint opts,FXint x,FXint y,FXint w,FXint h)101 FXChoiceBox::FXChoiceBox(FXApp* a,const FXString& caption,const FXString& text,FXIcon* icn,const FXchar** choices,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXDialogBox(a,caption,opts|DECOR_TITLE|DECOR_BORDER,x,y,w,h,10,10,10,10, 10,10){
102   FXint n;
103   initialize(text,icn);
104   n=list->fillItems(choices);
105   list->setNumVisible(FXMIN(n,5));
106   }
107 
108 
109 // Construct free floating choice box with given caption, icon, message text, and with choices from newline separated strings
FXChoiceBox(FXApp * a,const FXString & caption,const FXString & text,FXIcon * icn,const FXString & choices,FXuint opts,FXint x,FXint y,FXint w,FXint h)110 FXChoiceBox::FXChoiceBox(FXApp* a,const FXString& caption,const FXString& text,FXIcon* icn,const FXString& choices,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXDialogBox(a,caption,opts|DECOR_TITLE|DECOR_BORDER,x,y,w,h,10,10,10,10, 10,10){
111   FXint n;
112   initialize(text,icn);
113   n=list->fillItems(choices);
114   list->setNumVisible(FXMIN(n,5));
115   }
116 
117 
118 // Build contents
initialize(const FXString & text,FXIcon * icn)119 void FXChoiceBox::initialize(const FXString& text,FXIcon* icn){
120   FXHorizontalFrame* buttons=new FXHorizontalFrame(this,LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|PACK_UNIFORM_WIDTH,0,0,0,0,0,0,0,0);
121   new FXButton(buttons,tr("&OK"),NULL,this,ID_ACCEPT,BUTTON_INITIAL|BUTTON_DEFAULT|FRAME_RAISED|FRAME_THICK|LAYOUT_CENTER_Y|LAYOUT_RIGHT,0,0,0,0,HORZ_PAD,HORZ_PAD,VERT_PAD,VERT_PAD);
122   new FXButton(buttons,tr("&Cancel"),NULL,this,ID_CANCEL,BUTTON_DEFAULT|FRAME_RAISED|FRAME_THICK|LAYOUT_CENTER_Y|LAYOUT_RIGHT,0,0,0,0,HORZ_PAD,HORZ_PAD,VERT_PAD,VERT_PAD);
123   new FXHorizontalSeparator(this,SEPARATOR_GROOVE|LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X);
124   FXHorizontalFrame* toppart=new FXHorizontalFrame(this,LAYOUT_SIDE_TOP|LAYOUT_FILL_X,0,0,0,0, 0,0,0,0, 10,10);
125   new FXLabel(toppart,FXString::null,icn,ICON_BEFORE_TEXT|JUSTIFY_CENTER_X|JUSTIFY_CENTER_Y|LAYOUT_FILL_Y|LAYOUT_FILL_X);
126   new FXLabel(toppart,text,NULL,JUSTIFY_LEFT|ICON_BEFORE_TEXT|LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FILL_X);
127   FXHorizontalFrame* midpart=new FXHorizontalFrame(this,FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0, 0,0,0,0, 10,10);
128   list=new FXList(midpart,this,ID_CLICKED,LIST_BROWSESELECT|LAYOUT_FILL_Y|LAYOUT_FILL_X|HSCROLLING_OFF);
129   }
130 
131 
132 // Close dialog when double-clicked in list or hit accept
onCmdClicked(FXObject *,FXSelector,void *)133 long FXChoiceBox::onCmdClicked(FXObject*,FXSelector,void*){
134   getApp()->stopModal(this,list->getCurrentItem());
135   hide();
136   return 1;
137   }
138 
139 
140 // Close dialog with a cancel
onCmdCancel(FXObject *,FXSelector,void *)141 long FXChoiceBox::onCmdCancel(FXObject*,FXSelector,void*){
142   getApp()->stopModal(this,-1);
143   hide();
144   return 1;
145   }
146 
147 
148 // We have to do this so as to force the initial text to be seleced
execute(FXuint placement)149 FXuint FXChoiceBox::execute(FXuint placement){
150   create();
151   list->setFocus();
152   show(placement);
153   return getApp()->runModalFor(this);
154   }
155 
156 
157 // Save object to stream
save(FXStream & store) const158 void FXChoiceBox::save(FXStream& store) const {
159   FXDialogBox::save(store);
160   store << list;
161   }
162 
163 
164 // Load object from stream
load(FXStream & store)165 void FXChoiceBox::load(FXStream& store){
166   FXDialogBox::load(store);
167   store >> list;
168   }
169 
170 
171 // Destroy choice box
~FXChoiceBox()172 FXChoiceBox::~FXChoiceBox(){
173   list=(FXList*)-1L;
174   }
175 
176 
177 /*******************************************************************************/
178 
179 
180 // Show a modal choice dialog
ask(FXWindow * owner,FXuint opts,const FXString & caption,const FXString & text,FXIcon * icon,const FXchar ** choices)181 FXint FXChoiceBox::ask(FXWindow* owner,FXuint opts,const FXString& caption,const FXString& text,FXIcon* icon,const FXchar** choices){
182   FXChoiceBox box(owner,caption,text,icon,choices,opts);
183   return box.execute(PLACEMENT_OWNER);
184   }
185 
186 
187 // Show a modal choice dialog
ask(FXWindow * owner,FXuint opts,const FXString & caption,const FXString & text,FXIcon * icon,const FXString & choices)188 FXint FXChoiceBox::ask(FXWindow* owner,FXuint opts,const FXString& caption,const FXString& text,FXIcon* icon,const FXString& choices){
189   FXChoiceBox box(owner,caption,text,icon,choices,opts);
190   return box.execute(PLACEMENT_OWNER);
191   }
192 
193 
194 // Show a modal choice dialog, in free floating window
ask(FXApp * app,FXuint opts,const FXString & caption,const FXString & text,FXIcon * icon,const FXchar ** choices)195 FXint FXChoiceBox::ask(FXApp* app,FXuint opts,const FXString& caption,const FXString& text,FXIcon* icon,const FXchar** choices){
196   FXChoiceBox box(app,caption,text,icon,choices,opts);
197   return box.execute(PLACEMENT_SCREEN);
198   }
199 
200 
201 // Show a modal choice dialog, in free floating window
ask(FXApp * app,FXuint opts,const FXString & caption,const FXString & text,FXIcon * icon,const FXString & choices)202 FXint FXChoiceBox::ask(FXApp* app,FXuint opts,const FXString& caption,const FXString& text,FXIcon* icon,const FXString& choices){
203   FXChoiceBox box(app,caption,text,icon,choices,opts);
204   return box.execute(PLACEMENT_SCREEN);
205   }
206 
207 }
208 
209