1 /********************************************************************************
2 *                                                                               *
3 *                              D a t a   T a r g e t                            *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1997,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 "fxkeys.h"
26 #include "FXArray.h"
27 #include "FXHash.h"
28 #include "FXMutex.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXStringDictionary.h"
35 #include "FXSettings.h"
36 #include "FXRegistry.h"
37 #include "FXEvent.h"
38 #include "FXWindow.h"
39 #include "FXApp.h"
40 #include "FXDataTarget.h"
41 
42 
43 /*
44   Notes:
45   - DataTarget connects GUI to basic values such as flags (FXbool), integral
46     or real numbers, and strings (FXString).
47   - Values in the application program may get updated from the GUI, and
48     vice-versa GUI gets updated when the program has changed a value as well.
49   - Would be nice to set value from message ID also...
50   - When the sender of onCmdValue does not understand the ID_GETXXXXVALUE message,
51     the data target keeps the same value as before.
52   - Catch SEL_CHANGED when we have expunged this from FXTextField.
53   - DT_VOID, i.e. unconnected FXDataTarget maybe it should grey out corresponding
54     widgets.
55   - Need to add ID_GETLONGVALUE/ID_SETLONGVALUE message handlers some day.
56   - onCmdValue, onUpdValue, onCmdOption, and onUpdOption now return 0 if the type
57     variable is not one of the known types.  This allows more easy subclassing of
58     FXDataTarget to add custom data types.
59   - When the type is DT_VOID, a change message does not change any data but simply
60     passes along the message to data target's target; an update message will be a
61     no-op, but return 1 so that the sending message will remain sensitized if auto-
62     gray is on.
63 */
64 
65 using namespace FX;
66 
67 /*******************************************************************************/
68 
69 namespace FX {
70 
71 // Map
72 FXDEFMAP(FXDataTarget) FXDataTargetMap[]={
73   FXMAPFUNC(SEL_COMMAND,FXDataTarget::ID_VALUE,FXDataTarget::onCmdValue),
74   FXMAPFUNC(SEL_CHANGED,FXDataTarget::ID_VALUE,FXDataTarget::onCmdValue),
75   FXMAPFUNC(SEL_UPDATE,FXDataTarget::ID_VALUE,FXDataTarget::onUpdValue),
76   FXMAPFUNCS(SEL_COMMAND,FXDataTarget::ID_OPTION-10001,FXDataTarget::ID_OPTION+10000,FXDataTarget::onCmdOption),
77   FXMAPFUNCS(SEL_UPDATE,FXDataTarget::ID_OPTION-10001,FXDataTarget::ID_OPTION+10000,FXDataTarget::onUpdOption),
78   };
79 
80 
81 // Object implementation
FXIMPLEMENT(FXDataTarget,FXObject,FXDataTargetMap,ARRAYNUMBER (FXDataTargetMap))82 FXIMPLEMENT(FXDataTarget,FXObject,FXDataTargetMap,ARRAYNUMBER(FXDataTargetMap))
83 
84 
85 // Value changed from widget
86 long FXDataTarget::onCmdValue(FXObject* sender,FXSelector sel,void*){
87   FXdouble d;
88   FXint    i;
89   switch(type){
90     case DT_VOID:
91       break;
92     case DT_BOOL:
93       i=*((FXbool*)data);
94       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_GETINTVALUE),(void*)&i);
95       *((FXbool*)data)=(i!=0);
96       break;
97     case DT_CHAR:
98       i=*((FXchar*)data);
99       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_GETINTVALUE),(void*)&i);
100       *((FXchar*)data)=i;
101       break;
102     case DT_UCHAR:
103       i=*((FXuchar*)data);
104       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_GETINTVALUE),(void*)&i);
105       *((FXuchar*)data)=i;
106       break;
107     case DT_SHORT:
108       i=*((FXshort*)data);
109       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_GETINTVALUE),(void*)&i);
110       *((FXshort*)data)=i;
111       break;
112     case DT_USHORT:
113       i=*((FXushort*)data);
114       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_GETINTVALUE),(void*)&i);
115       *((FXushort*)data)=i;
116       break;
117     case DT_INT:
118     case DT_UINT:
119       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_GETINTVALUE),data);
120       break;
121     case DT_LONG:
122     case DT_ULONG:
123       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_GETLONGVALUE),data);
124       break;
125     case DT_FLOAT:
126       d=*((FXfloat*)data);
127       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_GETREALVALUE),(void*)&d);
128       *((FXfloat*)data)=(FXfloat)d;
129       break;
130     case DT_DOUBLE:
131       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_GETREALVALUE),data);
132       break;
133     case DT_STRING:
134       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_GETSTRINGVALUE),data);
135       break;
136     default:
137       return 0;
138     }
139   if(target){
140     target->handle(this,FXSEL(FXSELTYPE(sel),message),data);
141     }
142   return 1;
143   }
144 
145 
146 // Widget changed from value
onUpdValue(FXObject * sender,FXSelector,void *)147 long FXDataTarget::onUpdValue(FXObject* sender,FXSelector,void*){
148   FXdouble d;
149   FXint    i;
150   switch(type){
151     case DT_VOID:
152       break;
153     case DT_BOOL:
154       i=*((FXbool*)data);
155       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETINTVALUE),(void*)&i);
156       break;
157     case DT_CHAR:
158       i=*((FXchar*)data);
159       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETINTVALUE),(void*)&i);
160       break;
161     case DT_UCHAR:
162       i=*((FXuchar*)data);
163       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETINTVALUE),(void*)&i);
164       break;
165     case DT_SHORT:
166       i=*((FXshort*)data);
167       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETINTVALUE),(void*)&i);
168       break;
169     case DT_USHORT:
170       i=*((FXushort*)data);
171       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETINTVALUE),(void*)&i);
172       break;
173     case DT_INT:
174     case DT_UINT:
175       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETINTVALUE),data);
176       break;
177     case DT_LONG:
178     case DT_ULONG:
179       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETLONGVALUE),data);
180       break;
181     case DT_FLOAT:
182       d=*((FXfloat*)data);
183       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETREALVALUE),(void*)&d);
184       break;
185     case DT_DOUBLE:
186       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETREALVALUE),data);
187       break;
188     case DT_STRING:
189       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETSTRINGVALUE),data);
190       break;
191     default:
192       return 0;
193     }
194   return 1;
195   }
196 
197 
198 // Value set from message id
onCmdOption(FXObject *,FXSelector sel,void *)199 long FXDataTarget::onCmdOption(FXObject*,FXSelector sel,void*){
200   FXint num=((FXint)FXSELID(sel))-ID_OPTION;
201   switch(type){
202     case DT_VOID:
203       break;
204     case DT_BOOL:
205       *((FXbool*)data)=(num!=0);
206       break;
207     case DT_CHAR:
208       *((FXchar*)data)=num;
209       break;
210     case DT_UCHAR:
211       *((FXuchar*)data)=num;
212       break;
213     case DT_SHORT:
214       *((FXshort*)data)=num;
215       break;
216     case DT_USHORT:
217       *((FXushort*)data)=num;
218       break;
219     case DT_INT:
220       *((FXint*)data)=num;
221       break;
222     case DT_UINT:
223       *((FXuint*)data)=num;
224       break;
225     case DT_LONG:
226       *((FXlong*)data)=num;
227       break;
228     case DT_ULONG:
229       *((FXulong*)data)=num;
230       break;
231     case DT_FLOAT:
232       *((FXfloat*)data)=(FXfloat)num;
233       break;
234     case DT_DOUBLE:
235       *((FXdouble*)data)=num;
236       break;
237     default:
238       return 0;
239     }
240   if(target){
241     target->handle(this,FXSEL(FXSELTYPE(sel),message),data);
242     }
243   return 1;
244   }
245 
246 
247 // Check widget whose message id matches
onUpdOption(FXObject * sender,FXSelector sel,void *)248 long FXDataTarget::onUpdOption(FXObject* sender,FXSelector sel,void*){
249   FXint num=((FXint)FXSELID(sel))-ID_OPTION;
250   FXint i=0;
251   switch(type){
252     case DT_VOID:
253       break;
254     case DT_BOOL:
255       i=*((FXbool*)data);
256       sender->handle(this,(num==i)?FXSEL(SEL_COMMAND,FXWindow::ID_CHECK):FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
257       break;
258     case DT_CHAR:
259       i=*((FXchar*)data);
260       sender->handle(this,(num==i)?FXSEL(SEL_COMMAND,FXWindow::ID_CHECK):FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
261       break;
262     case DT_UCHAR:
263       i=*((FXuchar*)data);
264       sender->handle(this,(num==i)?FXSEL(SEL_COMMAND,FXWindow::ID_CHECK):FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
265       break;
266     case DT_SHORT:
267       i=*((FXshort*)data);
268       sender->handle(this,(num==i)?FXSEL(SEL_COMMAND,FXWindow::ID_CHECK):FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
269       break;
270     case DT_USHORT:
271       i=*((FXushort*)data);
272       sender->handle(this,(num==i)?FXSEL(SEL_COMMAND,FXWindow::ID_CHECK):FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
273       break;
274     case DT_INT:
275       i=*((FXint*)data);
276       sender->handle(this,(num==i)?FXSEL(SEL_COMMAND,FXWindow::ID_CHECK):FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
277       break;
278     case DT_UINT:
279       i=*((FXuint*)data);
280       sender->handle(this,(num==i)?FXSEL(SEL_COMMAND,FXWindow::ID_CHECK):FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
281       break;
282     case DT_LONG:
283       i=(FXint) *((FXlong*)data);
284       sender->handle(this,(num==i)?FXSEL(SEL_COMMAND,FXWindow::ID_CHECK):FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
285       break;
286     case DT_ULONG:
287       i=(FXint) *((FXulong*)data);
288       sender->handle(this,(num==i)?FXSEL(SEL_COMMAND,FXWindow::ID_CHECK):FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
289       break;
290     case DT_FLOAT:
291       i=(FXint) *((FXfloat*)data);
292       sender->handle(this,(num==i)?FXSEL(SEL_COMMAND,FXWindow::ID_CHECK):FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
293       break;
294     case DT_DOUBLE:
295       i=(FXint) *((FXdouble*)data);
296       sender->handle(this,(num==i)?FXSEL(SEL_COMMAND,FXWindow::ID_CHECK):FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
297       break;
298     default:
299       return 0;
300     }
301   return 1;
302   }
303 
304 
305 // Destroy
~FXDataTarget()306 FXDataTarget::~FXDataTarget(){
307   target=(FXObject*)-1L;
308   data=(void*)-1L;
309   }
310 
311 }
312 
313